diff --git a/apps/oauth/views.py b/apps/oauth/views.py index 98c090034..16c15158e 100644 --- a/apps/oauth/views.py +++ b/apps/oauth/views.py @@ -733,7 +733,7 @@ def api_save_new_story(request): } story = MStarredStory.objects.create(**story_db) logging.user(request, "~FCStarring by ~SBIFTTT~SN: ~SB%s~SN in ~SB%s" % (story_db['story_title'][:50], original_feed and original_feed)) - MStarredStoryCounts.count_tags_for_user(user.pk) + MStarredStoryCounts.count_for_user(user.pk) except OperationError: logging.user(request, "~FCAlready starred by ~SBIFTTT~SN: ~SB%s" % (story_db['story_title'][:50])) pass diff --git a/apps/profile/models.py b/apps/profile/models.py index 86d41f5fe..f2ea70375 100644 --- a/apps/profile/models.py +++ b/apps/profile/models.py @@ -620,7 +620,7 @@ NewsBlur""" % {'user': self.user.username, 'feeds': subs.count()} email_type='premium_expire_grace') day_ago = datetime.datetime.now() - datetime.timedelta(days=360) for email in emails_sent: - if email.date_sent > day_ago: + if email.date_sent > day_ago and not force: logging.user(self.user, "~SN~FMNot sending premium expire grace email, already sent before.") return @@ -652,7 +652,7 @@ NewsBlur""" % {'user': self.user.username, 'feeds': subs.count()} email_type='premium_expire') day_ago = datetime.datetime.now() - datetime.timedelta(days=360) for email in emails_sent: - if email.date_sent > day_ago: + if email.date_sent > day_ago and not force: logging.user(self.user, "~FM~SBNot sending premium expire email, already sent before.") return diff --git a/apps/reader/views.py b/apps/reader/views.py index cf066c54d..80fc0013f 100644 --- a/apps/reader/views.py +++ b/apps/reader/views.py @@ -3,6 +3,7 @@ import time import boto import redis import requests +import random import zlib from django.shortcuts import get_object_or_404 from django.shortcuts import render @@ -538,6 +539,12 @@ def load_single_feed(request, feed_id): else: stories = [] message = "You must be a premium subscriber to search." + elif read_filter == 'starred': + mstories = MStarredStory.objects( + user_id=user.pk, + story_feed_id=feed_id + ).order_by('%sstarred_date' % ('-' if order == 'newest' else ''))[offset:offset+limit] + stories = Feed.format_stories(mstories) elif usersub and (read_filter == 'unread' or order == 'oldest'): stories = usersub.get_stories(order=order, read_filter=read_filter, offset=offset, limit=limit, default_cutoff_date=user.profile.unread_cutoff) @@ -919,7 +926,7 @@ def load_river_stories__redis(request): code = 1 user_search = None offset = (page-1) * limit - limit = page * limit - 1 + limit = page * limit story_date_order = "%sstory_date" % ('' if order == 'oldest' else '-') if story_hashes: @@ -944,6 +951,12 @@ def load_river_stories__redis(request): stories = [] mstories = [] message = "You must be a premium subscriber to search." + elif read_filter == 'starred': + mstories = MStarredStory.objects( + user_id=user.pk, + story_feed_id__in=feed_ids + ).order_by('%sstarred_date' % ('-' if order == 'newest' else ''))[offset:offset+limit] + stories = Feed.format_stories(mstories) else: usersubs = UserSubscription.subs_for_feeds(user.pk, feed_ids=feed_ids, read_filter=read_filter) @@ -981,10 +994,13 @@ def load_river_stories__redis(request): # Find starred stories if found_feed_ids: - starred_stories = MStarredStory.objects( - user_id=user.pk, - story_feed_id__in=found_feed_ids - ).only('story_hash', 'starred_date') + if read_filter == 'starred': + starred_stories = mstories + else: + starred_stories = MStarredStory.objects( + user_id=user.pk, + story_feed_id__in=found_feed_ids + ).only('story_hash', 'starred_date') starred_stories = dict([(story.story_hash, dict(starred_date=story.starred_date, user_tags=story.user_tags)) for story in starred_stories]) @@ -1012,11 +1028,13 @@ def load_river_stories__redis(request): classifier_titles=classifier_titles, classifier_tags=classifier_tags) - # Just need to format stories nowtz = localtime_for_timezone(now, user.profile.timezone) for story in stories: - story['read_status'] = 0 + if read_filter == 'starred': + story['read_status'] = 1 + else: + story['read_status'] = 0 if read_filter == 'all' or query: if (unread_feed_story_hashes is not None and story['story_hash'] not in unread_feed_story_hashes): @@ -1795,6 +1813,7 @@ def _mark_story_as_starred(request): message = "" if story_hash: story, _ = MStory.find_story(story_hash=story_hash) + feed_id = story and story.story_feed_id else: story, _ = MStory.find_story(story_feed_id=feed_id, story_id=story_id) @@ -1822,6 +1841,7 @@ def _mark_story_as_starred(request): story_feed_id=feed_id, story_id=starred_story.story_guid) new_user_tags = user_tags + MStarredStoryCounts.adjust_count(request.user.pk, feed_id=feed_id, amount=1) else: starred_story = starred_story[0] new_user_tags = list(set(user_tags) - set(starred_story.user_tags or [])) @@ -1830,29 +1850,13 @@ def _mark_story_as_starred(request): starred_story.save() for tag in new_user_tags: - try: - story_count = MStarredStoryCounts.objects.get(user_id=request.user.pk, - tag=tag) - except MStarredStoryCounts.DoesNotExist: - story_count = MStarredStoryCounts.objects.create(user_id=request.user.pk, - tag=tag) - if not story_count.count: - story_count.count = 0 - story_count.count += 1 - story_count.save() + MStarredStoryCounts.adjust_count(request.user.pk, tag=tag, amount=1) for tag in removed_user_tags: - try: - story_count = MStarredStoryCounts.objects.get(user_id=request.user.pk, - tag=tag) - story_count.count -= 1 - story_count.save() - if story_count.count <= 0: - story_count.delete() - except MStarredStoryCounts.DoesNotExist: - pass - - MStarredStoryCounts.schedule_count_tags_for_user(request.user.pk) - MStarredStoryCounts.count_tags_for_user(request.user.pk, total_only=True) + MStarredStoryCounts.adjust_count(request.user.pk, tag=tag, amount=-1) + + if random.random() < 0.01: + MStarredStoryCounts.schedule_count_tags_for_user(request.user.pk) + MStarredStoryCounts.count_for_user(request.user.pk, total_only=True) starred_counts = MStarredStoryCounts.user_counts(request.user.pk) if created: @@ -1889,6 +1893,7 @@ def _mark_story_as_unstarred(request): starred_story = starred_story[0] logging.user(request, "~FCUnstarring: ~SB%s" % (starred_story.story_title[:50])) user_tags = starred_story.user_tags + feed_id = starred_story.story_feed_id MActivity.remove_starred_story(user_id=request.user.pk, story_feed_id=starred_story.story_feed_id, story_id=starred_story.story_guid) @@ -1897,18 +1902,16 @@ def _mark_story_as_unstarred(request): starred_story.save() except NotUniqueError: starred_story.delete() + + MStarredStoryCounts.adjust_count(request.user.pk, feed_id=feed_id, amount=-1) + for tag in user_tags: try: - story_count = MStarredStoryCounts.objects.get(user_id=request.user.pk, - tag=tag) - story_count.count -= 1 - story_count.save() - if story_count.count <= 0: - story_count.delete() + MStarredStoryCounts.adjust_count(request.user.pk, tag=tag, amount=-1) except MStarredStoryCounts.DoesNotExist: pass # MStarredStoryCounts.schedule_count_tags_for_user(request.user.pk) - MStarredStoryCounts.count_tags_for_user(request.user.pk, total_only=True) + MStarredStoryCounts.count_for_user(request.user.pk, total_only=True) starred_counts = MStarredStoryCounts.user_counts(request.user.pk) else: code = -1 diff --git a/apps/rss_feeds/models.py b/apps/rss_feeds/models.py index 775f11241..b50b431f2 100644 --- a/apps/rss_feeds/models.py +++ b/apps/rss_feeds/models.py @@ -2190,8 +2190,9 @@ class MStarredStory(mongo.Document): class MStarredStoryCounts(mongo.Document): user_id = mongo.IntField() tag = mongo.StringField(max_length=128) + feed_id = mongo.IntField() slug = mongo.StringField(max_length=128) - count = mongo.IntField() + count = mongo.IntField(default=0) meta = { 'collection': 'starred_stories_counts', @@ -2202,59 +2203,117 @@ class MStarredStoryCounts(mongo.Document): @property def rss_url(self, secret_token=None): + if self.feed_id: + return + if not secret_token: user = User.objects.select_related('profile').get(pk=self.user_id) secret_token = user.profile.secret_token - + + slug = self.slug if self.slug else "" return "%s/reader/starred_rss/%s/%s/%s" % (settings.NEWSBLUR_URL, self.user_id, - secret_token, self.slug) + secret_token, slug) @classmethod def user_counts(cls, user_id, include_total=False, try_counting=True): counts = cls.objects.filter(user_id=user_id) counts = sorted([{'tag': c.tag, 'count': c.count, - 'feed_address': c.rss_url} + 'feed_address': c.rss_url, + 'feed_id': c.feed_id} for c in counts], key=lambda x: (x.get('tag', '') or '').lower()) - if counts == [] and try_counting: - cls.count_tags_for_user(user_id) + total = 0 + feed_total = 0 + for c in counts: + if not c['tag'] and not c['feed_id']: + total = c['count'] + if c['feed_id']: + feed_total += c['count'] + + if try_counting and (total != feed_total or not len(counts)): + user = User.objects.get(pk=user_id) + logging.user(user, "~FC~SBCounting~SN saved stories (%s total vs. %s counted)..." % + (total, feed_total)) + cls.count_for_user(user_id) return cls.user_counts(user_id, include_total=include_total, try_counting=False) if include_total: - for c in counts: - if c['tag'] == "": - return counts, c['count'] - return counts, 0 - + return counts, total return counts @classmethod def schedule_count_tags_for_user(cls, user_id): ScheduleCountTagsForUser.apply_async(kwargs=dict(user_id=user_id)) - - @classmethod - def count_tags_for_user(cls, user_id, total_only=False): - user_tags = [] - if not total_only: - all_tags = MStarredStory.objects(user_id=user_id, - user_tags__exists=True).item_frequencies('user_tags') - user_tags = sorted([(k, v) for k, v in all_tags.items() if int(v) > 0 and k], - key=lambda x: x[0].lower(), - reverse=True) - - cls.objects(user_id=user_id).delete() - for tag, count in dict(user_tags).items(): - cls.objects.create(user_id=user_id, tag=tag, slug=slugify(tag), count=count) - - total_stories_count = MStarredStory.objects(user_id=user_id).count() - cls.objects.filter(user_id=user_id, tag="").update_one(set__count=total_stories_count, - upsert=True) - - return dict(total=total_stories_count, tags=user_tags) + @classmethod + def count_for_user(cls, user_id, total_only=False): + user_tags = [] + user_feeds = [] + + if not total_only: + cls.objects(user_id=user_id).delete() + user_tags = cls.count_tags_for_user(user_id) + user_feeds = cls.count_feeds_for_user(user_id) + + total_stories_count = MStarredStory.objects(user_id=user_id).count() + cls.objects(user_id=user_id, tag=None, feed_id=None).update_one(set__count=total_stories_count, + upsert=True) + + return dict(total=total_stories_count, tags=user_tags, feeds=user_feeds) + + @classmethod + def count_tags_for_user(cls, user_id): + all_tags = MStarredStory.objects(user_id=user_id, + user_tags__exists=True).item_frequencies('user_tags') + user_tags = sorted([(k, v) for k, v in all_tags.items() if int(v) > 0 and k], + key=lambda x: x[0].lower(), + reverse=True) + + for tag, count in dict(user_tags).items(): + cls.objects(user_id=user_id, tag=tag, slug=slugify(tag)).update_one(set__count=count, + upsert=True) + + return user_tags + + @classmethod + def count_feeds_for_user(cls, user_id): + all_feeds = MStarredStory.objects(user_id=user_id).item_frequencies('story_feed_id') + user_feeds = dict([(k, v) for k, v in all_feeds.items() if v]) + + # Clean up None'd and 0'd feed_ids, so they can be counted against the total + if user_feeds.get(None, False): + user_feeds[0] = user_feeds.get(0, 0) + user_feeds[0] += user_feeds.get(None) + del user_feeds[None] + if user_feeds.get(0, False): + user_feeds[-1] = user_feeds.get(0, 0) + del user_feeds[0] + + for feed_id, count in user_feeds.items(): + cls.objects(user_id=user_id, + feed_id=feed_id, + slug="feed:%s" % feed_id).update_one(set__count=count, + upsert=True) + + return user_feeds + + @classmethod + def adjust_count(cls, user_id, feed_id=None, tag=None, amount=0): + params = dict(user_id=user_id) + if feed_id: + params['feed_id'] = feed_id + if tag: + params['tag'] = tag + + cls.objects(**params).update_one(inc__count=amount, upsert=True) + story_count = cls.objects.get(**params) + if story_count.count <= 0: + story_count.delete() + + class MFetchHistory(mongo.Document): feed_id = mongo.IntField(unique=True) feed_fetch_history = mongo.DynamicField() diff --git a/apps/rss_feeds/tasks.py b/apps/rss_feeds/tasks.py index 58ae25b7f..ec6b16099 100644 --- a/apps/rss_feeds/tasks.py +++ b/apps/rss_feeds/tasks.py @@ -222,4 +222,4 @@ class ScheduleCountTagsForUser(Task): def run(self, user_id): from apps.rss_feeds.models import MStarredStoryCounts - MStarredStoryCounts.count_tags_for_user(user_id) + MStarredStoryCounts.count_for_user(user_id) diff --git a/media/css/reader.css b/media/css/reader.css index e6e0065d4..17730b3b7 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -558,7 +558,9 @@ a img { .NB-feedlist-hide-read-feeds .NB-feedlist .feed.NB-feed-self-blurblog { display: block; } - +.NB-intelligence-starred .NB-feedlist .feed.NB-feed-self-blurblog { + display: none; +} .NB-feedlist .feed.NB-feed-unfetched { } @@ -833,6 +835,9 @@ a img { .NB-feedlist-hide-read-feeds .NB-feedlist .feed { display: none; } +.NB-feedlist-hide-read-feeds .NB-sidebar.unread_view_starred .unread_starred { + display: block; +} .NB-feedlist-hide-read-feeds .NB-sidebar.unread_view_positive .unread_positive { display: block; } @@ -889,6 +894,13 @@ a img { /* border-top: 1px solid rgba(255, 255, 255, .4);*/ border-bottom: 1px solid rgba(0, 0, 0, .1); } +.unread_count_starred { + background-color: #506B9A; + text-shadow: 0 1px 0 rgba(0, 0, 0, .3); + border-bottom: 1px solid rgba(0, 0, 0, .2); +/* text-shadow: none;*/ +} + .unread_count_positive { background-color: #6EA74A; text-shadow: 0 1px 0 rgba(0, 0, 0, .3); @@ -907,6 +919,11 @@ a img { /* text-shadow: 0 1px 0 rgba(0, 0, 0, .3);*/ } +.unread_view_starred .unread_count { + padding-left: 6px; + padding-right: 6px; +} + .unread_view_positive .unread_count { padding-left: 6px; padding-right: 6px; @@ -919,6 +936,9 @@ a img { /* Showing unread counts above threshold */ +.unread_view_starred .unread_starred .unread_count_starred { + display: block; +} .unread_view_positive .unread_positive .unread_count_positive { display: block; } @@ -934,6 +954,9 @@ a img { display: block; } +.unread_view_starred .unread_starred { + font-weight: bold; +} .unread_view_positive .unread_positive { font-weight: bold; } @@ -962,6 +985,10 @@ a img { display: block; } +.NB-starred-folder .unread_starred .unread_count_positive { + display: block; +} + /* ====================== */ /* = Feeds Progress Bar = */ /* ====================== */ @@ -1191,6 +1218,9 @@ a img { font-weight: bold; float: right; } +.NB-intelligence-starred .NB-feedbar .NB-feedbar-mark-feed-read-container { + display: none; +} .NB-feedbar .NB-feedbar-mark-feed-read, .NB-feedbar .NB-feedbar-mark-feed-read-expand, .NB-feedbar .NB-feedbar-mark-feed-read-time { @@ -1401,6 +1431,9 @@ a img { .NB-feedbar .NB-story-title-indicator .NB-story-title-indicator-count { float: left; } +.NB-feedbar .NB-story-title-indicator .NB-story-title-indicator-count .unread_count_starred { + display: none; +} .NB-feedbar .NB-story-title-indicator.unread_threshold_negative { display: none; } @@ -1528,6 +1561,10 @@ a img { background: transparent url('/media/embed/icons/circular/g_icn_hidden.png') no-repeat 13px 6px; background-size: 8px; } +#story_titles .NB-story-title.NB-story-starred .NB-storytitles-sentiment { + background: transparent url('/media/embed/icons/circular/g_icn_starred.png') no-repeat 13px 6px; + background-size: 8px; +} #story_titles .NB-story-title.NB-story-starred .NB-storytitles-star, #story_titles .NB-story-title.read.NB-story-starred .NB-storytitles-star { @@ -2304,6 +2341,11 @@ body { /* display: none;*/ } +.NB-feed-story.NB-story-starred .NB-feed-story-sentiment { + background: transparent url('/media/embed/icons/circular/g_icn_starred.png') no-repeat 4px 4px; + background-size: 8px; +} + .NB-feed-story.NB-story-positive .NB-feed-story-sentiment { background: transparent url('/media/embed/icons/circular/g_icn_focus.png') no-repeat 4px 4px; background-size: 8px; @@ -3657,6 +3699,10 @@ body { background: transparent url('/media/embed/icons/circular/g_icn_focus.png') no-repeat 6px 2px; background-size: 8px; } +.NB-feeds-header-dashboard .NB-feeds-header-starred { + background: transparent url('/media/embed/icons/circular/g_icn_starred.png') no-repeat 6px 2px; + background-size: 8px; +} .NB-feeds-header-dashboard .NB-feeds-header-right { position: relative; } @@ -3998,6 +4044,13 @@ background: transparent; background-image: url('/media/embed/icons/circular/exclamation.png'); background-size: 16px; } +.NB-taskbar .NB-task-story-next-starred .NB-task-image { + background: transparent url('/media/embed/icons/circular/g_icn_starred.png') no-repeat 0 0; + background-size: 8px; + width: 8px; + height: 8px; + margin-top: 5px; +} .NB-taskbar .NB-task-story-next-positive .NB-task-image { background: transparent url('/media/embed/icons/circular/g_icn_focus.png') no-repeat 0 0; background-size: 8px; @@ -4830,6 +4883,12 @@ form.opml_import_form input { background-size: 8px; } +.NB-taskbar-intelligence .NB-taskbar-intelligence-starred { + right: -4px; + background: transparent url(/media/embed/icons/circular/g_icn_starred.png) no-repeat 0 0; + background-size: 8px; +} + .NB-intelligence-slider { display: inline-block; } @@ -4842,13 +4901,13 @@ form.opml_import_form input { position: relative; padding: 5px 8px 4px; } -.NB-narrow .NB-intelligence-slider .NB-intelligence-slider-blue .NB-intelligence-label { +.NB-narrow-pane-blue .NB-intelligence-slider .NB-intelligence-slider-blue .NB-intelligence-label { display: none; } -.NB-narrow .NB-intelligence-slider .NB-intelligence-slider-green .NB-intelligence-label { +.NB-narrow-pane-green .NB-intelligence-slider .NB-intelligence-slider-green .NB-intelligence-label { display: none; } -.NB-extra-narrow .NB-intelligence-slider .NB-intelligence-slider-yellow .NB-intelligence-label { +.NB-narrow-pane-yellow .NB-intelligence-slider .NB-intelligence-slider-yellow .NB-intelligence-label { display: none; } .NB-intelligence-slider img { @@ -4863,14 +4922,14 @@ form.opml_import_form input { height: 12px; margin: -1px 5px -1px 0px; } -.NB-narrow .NB-intelligence-slider .NB-intelligence-slider-green img { - margin: 1px 8px 2px; +.NB-narrow-pane-green .NB-intelligence-slider .NB-intelligence-slider-green img { + margin: 1px 6px 2px; } -.NB-narrow .NB-intelligence-slider .NB-intelligence-slider-blue img { - margin: 1px 8px 2px; +.NB-narrow-pane-blue .NB-intelligence-slider .NB-intelligence-slider-blue img { + margin: -1px 4px 0px; } -.NB-extra-narrow .NB-intelligence-slider .NB-intelligence-slider-yellow img { - margin: 1px 8px 2px; +.NB-narrow-pane-yellow .NB-intelligence-slider .NB-intelligence-slider-yellow img { + margin: 1px 6px 2px; } /* ===================== */ diff --git a/media/img/icons/circular/g_icn_starred.png b/media/img/icons/circular/g_icn_starred.png new file mode 100644 index 000000000..5ffd3a992 Binary files /dev/null and b/media/img/icons/circular/g_icn_starred.png differ diff --git a/media/js/newsblur/common/assetmodel.js b/media/js/newsblur/common/assetmodel.js index 4e81429b7..992adac4e 100644 --- a/media/js/newsblur/common/assetmodel.js +++ b/media/js/newsblur/common/assetmodel.js @@ -234,6 +234,8 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({ var pre_callback = function(data) { if (data.starred_counts) { self.starred_feeds.reset(data.starred_counts, {parse: true}); + var feed = self.get_feed(story.get('story_feed_id')); + if (feed && feed.views) _.invoke(feed.views, 'render'); } if (selected) { @@ -257,6 +259,8 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({ var pre_callback = function(data) { if (data.starred_counts) { self.starred_feeds.reset(data.starred_counts, {parse: true, update: true}); + var feed = self.get_feed(story.get('story_feed_id')); + if (feed && feed.views) _.invoke(feed.views, 'render'); } if (selected && self.starred_feeds.get(selected)) { @@ -1101,6 +1105,8 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({ }, view_setting: function(feed_id, setting, callback) { + if (NEWSBLUR.reader.flags['feed_list_showing_starred'] && + setting == 'read_filter') return "starred"; if (feed_id == "river:global" && setting == "order") return "newest"; if (_.isUndefined(setting) || _.isString(setting)) { setting = setting || 'view'; diff --git a/media/js/newsblur/models/feeds.js b/media/js/newsblur/models/feeds.js index d01d7ad71..1f5511664 100644 --- a/media/js/newsblur/models/feeds.js +++ b/media/js/newsblur/models/feeds.js @@ -137,10 +137,13 @@ NEWSBLUR.Models.Feed = Backbone.Model.extend({ }, unread_counts: function() { + var starred_feed = NEWSBLUR.assets.starred_feeds.get_feed(this.id); + return { ps: this.get('ps') || 0, nt: this.get('nt') || 0, - ng: this.get('ng') || 0 + ng: this.get('ng') || 0, + st: starred_feed && starred_feed.get('count') || 0 }; }, @@ -158,6 +161,9 @@ NEWSBLUR.Models.Feed = Backbone.Model.extend({ return !!(this.get('ng') || this.get('nt') || this.get('ps')); } else if (unread_view == 0) { return !!(this.get('nt') || this.get('ps')); + } else if (unread_view >= 2) { + var starred_feed = NEWSBLUR.assets.starred_feeds.get_feed(this.id); + return starred_feed && starred_feed.get('count'); } else if (unread_view > 0) { return !!(this.get('ps')); } diff --git a/media/js/newsblur/models/starred_counts.js b/media/js/newsblur/models/starred_counts.js index 08efa4b66..2387d0c8b 100644 --- a/media/js/newsblur/models/starred_counts.js +++ b/media/js/newsblur/models/starred_counts.js @@ -26,7 +26,7 @@ NEWSBLUR.Models.StarredFeed = Backbone.Model.extend({ }, tag_slug: function() { - return Inflector.sluggify(this.get('tag')); + return Inflector.sluggify(this.get('tag') || ''); } }); @@ -37,15 +37,10 @@ NEWSBLUR.Collections.StarredFeeds = Backbone.Collection.extend({ parse: function(models) { _.each(models, function(feed) { - feed.id = 'starred:' + feed.tag; + feed.id = 'starred:' + (feed.tag || feed.feed_id); // feed.selected = false; feed.ps = feed.count; }); - - // Remove below, only used for transition to tag/feed_id. - models = _.filter(models, function(feed) { - return feed['tag']; - }); return models; }, @@ -83,6 +78,12 @@ NEWSBLUR.Collections.StarredFeeds = Backbone.Collection.extend({ all_tags: function() { return this.pluck('tag'); + }, + + get_feed: function(feed_id) { + return this.detect(function(feed) { + return feed.get('feed_id') == feed_id; + }); } }); \ No newline at end of file diff --git a/media/js/newsblur/models/stories.js b/media/js/newsblur/models/stories.js index 885e12bb0..809b4ae1f 100644 --- a/media/js/newsblur/models/stories.js +++ b/media/js/newsblur/models/stories.js @@ -19,7 +19,7 @@ NEWSBLUR.Models.Story = Backbone.Model.extend({ score: function() { if (NEWSBLUR.reader.flags['starred_view']) { - return 1; + return 2; } else { return NEWSBLUR.utils.compute_story_score(this); } @@ -349,6 +349,7 @@ NEWSBLUR.Collections.Stories = Backbone.Collection.extend({ clear_previous_stories_stack: function() { this.previous_stories_stack = []; + this.active_story = null; }, select_previous_story: function() { diff --git a/media/js/newsblur/reader/reader.js b/media/js/newsblur/reader/reader.js index 4550d2deb..20a528250 100644 --- a/media/js/newsblur/reader/reader.js +++ b/media/js/newsblur/reader/reader.js @@ -236,6 +236,12 @@ $windows.removeClass('NB-narrow'); } + var pane = this.layout.outerLayout.panes.west; + var width = this.layout.outerLayout.state.west.size; + pane.toggleClass("NB-narrow-pane-blue", width < 290); + pane.toggleClass("NB-narrow-pane-green", width < 254); + pane.toggleClass("NB-narrow-pane-yellow", width < 236); + this.apply_tipsy_titles(); }, @@ -400,6 +406,8 @@ this.$s.$story_titles.append(story_titles_bin.children()); this.resize_window(); } + + this.adjust_for_narrow_window(); }, apply_tipsy_titles: function() { @@ -437,8 +445,7 @@ var feed_pane_size = state.size; $('#NB-splash').css('left', feed_pane_size); - $pane.toggleClass("NB-narrow", this.layout.outerLayout.state.west.size < 240); - $pane.toggleClass("NB-extra-narrow", this.layout.outerLayout.state.west.size < 218); + this.adjust_for_narrow_window(); this.flags.set_feed_pane_size = this.flags.set_feed_pane_size || _.debounce( _.bind(function() { var feed_pane_size = this.layout.outerLayout.state.west.size; this.model.preference('feed_pane_size', feed_pane_size); @@ -603,8 +610,12 @@ show_next_unread_story: function() { var unread_count = this.get_total_unread_count(); - - if (unread_count) { + + if (this.flags['feed_list_showing_starred']) { + this.slide_intelligence_slider(0); + this.flags['feed_list_showing_starred'] = false; + this.open_next_unread_story_across_feeds(); + } else if (unread_count) { var next_story = NEWSBLUR.assets.stories.get_next_unread_story(); if (next_story) { this.counts['find_next_unread_on_page_of_feed_stories_load'] = 0; @@ -624,8 +635,8 @@ open_next_unread_story_across_feeds: function(force_next_feed) { var unread_count = !force_next_feed && this.active_feed && this.get_total_unread_count(); - - if (!unread_count) { + + if (!unread_count && !this.flags['feed_list_showing_starred']) { if (this.flags.river_view && !this.flags.social_view) { var $next_folder = this.get_next_unread_folder(1); var folder = NEWSBLUR.assets.folders.get_view($next_folder); @@ -1252,7 +1263,7 @@ this.active_folder.folder_view.$el, this.active_folder, options); - } else { + } else if (this.active_feed) { this.open_feed(this.active_feed, options); } @@ -1308,7 +1319,6 @@ NEWSBLUR.app.story_titles.show_loading(options); } NEWSBLUR.app.taskbar_info.hide_stories_error(); - // this.show_stories_progress_bar(); this.iframe_scroll = null; this.set_correct_story_view_for_feed(feed.id); this.make_feed_title_in_stories(); @@ -1613,18 +1623,19 @@ }, post_open_starred_stories: function(data, first_load) { - if (this.flags['starred_view']) { - // NEWSBLUR.log(['post_open_starred_stories', data.stories.length, first_load]); - this.flags['opening_feed'] = false; - if (this.counts['select_story_in_feed'] || this.flags['select_story_in_feed']) { - this.select_story_in_feed(); - } - if (first_load) { - this.find_story_with_action_preference_on_open_feed(); - } - // this.show_story_titles_above_intelligence_level({'animate': false}); - this.flags['story_titles_loaded'] = true; + if (!this.flags['starred_view']) return; + + // NEWSBLUR.log(['post_open_starred_stories', data.stories.length, first_load]); + this.flags['opening_feed'] = false; + if (this.counts['select_story_in_feed'] || this.flags['select_story_in_feed']) { + this.select_story_in_feed(); } + if (first_load) { + this.find_story_with_action_preference_on_open_feed(); + } + this.make_story_titles_pane_counter(); + // this.show_story_titles_above_intelligence_level({'animate': false}); + this.flags['story_titles_loaded'] = true; }, // ================= @@ -1680,6 +1691,7 @@ var visible_only = this.model.view_setting(this.active_feed, 'read_filter') == 'unread'; if (NEWSBLUR.reader.flags.search) visible_only = false; + if (NEWSBLUR.reader.flags.feed_list_showing_starred) visible_only = false; var feeds; if (visible_only) { feeds = _.pluck(this.active_folder.feeds_with_unreads(), 'id'); @@ -2298,6 +2310,11 @@ // ===================== make_story_titles_pane_counter: function(options) { + if (NEWSBLUR.app.story_unread_counter) { + NEWSBLUR.app.story_unread_counter.remove(); + NEWSBLUR.app.story_unread_counter.destroy(); + } + options = options || { 'fade': true }; @@ -2312,14 +2329,7 @@ if (!feed && !folder) return; if (this.active_feed == 'river:global') return; - if (NEWSBLUR.app.story_unread_counter) { - NEWSBLUR.app.story_unread_counter.remove(); - } - if (feed) { - if (NEWSBLUR.app.story_unread_counter) { - NEWSBLUR.app.story_unread_counter.destroy(); - } NEWSBLUR.app.story_unread_counter = new NEWSBLUR.Views.UnreadCount({ model: feed }).render(); @@ -2331,15 +2341,12 @@ } else { collection = folder.folder_view.collection; } - if (NEWSBLUR.app.story_unread_counter) { - NEWSBLUR.app.story_unread_counter.destroy(); - } NEWSBLUR.app.story_unread_counter = new NEWSBLUR.Views.UnreadCount({ collection: collection }).render(); } - if (options.fade) { + if (options.fade && NEWSBLUR.app.story_unread_counter) { NEWSBLUR.app.story_unread_counter.$el.css({'opacity': 0}); this.$s.$story_taskbar.append(NEWSBLUR.app.story_unread_counter.$el); _.delay(function() { @@ -2348,14 +2355,13 @@ 'opacity': .2 }, {'duration': 600, 'queue': false}); }, 200); - } else { + } else if (NEWSBLUR.app.story_unread_counter) { this.$s.$story_taskbar.append(NEWSBLUR.app.story_unread_counter.$el); _.delay(function() { NEWSBLUR.app.story_unread_counter.center(); NEWSBLUR.app.story_unread_counter.$el.css({'opacity': .2}); }, 200); } - }, // =========== @@ -3860,12 +3866,17 @@ var $slider = this.$s.$intelligence_slider; var $focus = $(".NB-intelligence-slider-green", $slider); var $unread = $(".NB-intelligence-slider-yellow", $slider); - var unread_view = this.get_unread_view_score(); + var unread_view = this.get_unread_view_name(); var all_mode = !NEWSBLUR.assets.preference('hide_read_feeds'); + var starred_mode = this.flags['feed_list_showing_starred']; if (!NEWSBLUR.assets.feeds.size()) return; var view_not_empty; - if (unread_view >= 1) { + if (unread_view == 'starred') { + view_not_empty = NEWSBLUR.assets.starred_feeds.any(function(feed) { + return feed.get('count'); + }); + } else if (unread_view == 'positive') { view_not_empty = NEWSBLUR.assets.feeds.any(function(feed) { return feed.get('ps'); }) || NEWSBLUR.assets.social_feeds.any(function(feed) { @@ -3879,13 +3890,22 @@ }); } $(".NB-feeds-list-empty").remove(); - if (!view_not_empty && !all_mode) { + console.log(["toggle_focus_in_slider", unread_view, view_not_empty, starred_mode]); + if (!view_not_empty && !all_mode && !starred_mode) { var $empty = $.make("div", { className: "NB-feeds-list-empty" }, [ 'You have no unread stories', - unread_view >= 1 ? " in Focus mode." : ".", + unread_view == 'positive' ? " in Focus mode." : ".", $.make('br'), $.make('br'), - unread_view >= 1 ? 'Switch to All or Unread.' : "" + unread_view == 'positive' ? 'Switch to All or Unread.' : "" + ]); + this.$s.$feed_list.after($empty); + } else if (!view_not_empty && starred_mode) { + var $empty = $.make("div", { className: "NB-feeds-list-empty" }, [ + 'You have no saved stories.', + $.make('br'), + $.make('br'), + 'Switch to All or Unread.' ]); this.$s.$feed_list.after($empty); } @@ -3905,7 +3925,10 @@ var $slider = this.$s.$intelligence_slider; var real_value = value; - if (value < 0) { + var showing_starred = this.flags['feed_list_showing_starred']; + this.flags['feed_list_showing_starred'] = value == 2; + + if (value <= -1) { value = 0; if (!initial_load) { NEWSBLUR.assets.preference('hide_read_feeds', 0); @@ -3916,6 +3939,11 @@ NEWSBLUR.assets.preference('hide_read_feeds', 1); } NEWSBLUR.assets.preference('unread_view', 0); + } else if (value >= 2) { + if (!initial_load) { + NEWSBLUR.assets.preference('hide_read_feeds', 1); + } + NEWSBLUR.assets.preference('unread_view', 2); } else if (value > 0) { if (!initial_load) { NEWSBLUR.assets.preference('hide_read_feeds', 1); @@ -3929,13 +3957,18 @@ } this.show_story_titles_above_intelligence_level({'animate': true, 'follow': true}); this.toggle_focus_in_slider(); + if (!initial_load && this.flags['feed_list_showing_starred'] != showing_starred) { + this.reload_feed(); + } NEWSBLUR.app.sidebar_header.toggle_hide_read_preference(); NEWSBLUR.app.sidebar_header.count(); NEWSBLUR.assets.folders.update_all_folder_visibility(); NEWSBLUR.app.feed_list.scroll_to_selected(); $('.NB-active', $slider).removeClass('NB-active'); - if (real_value < 0) { + if (this.flags['feed_list_showing_starred']) { + $('.NB-intelligence-slider-blue', $slider).addClass('NB-active'); + } else if (real_value < 0) { $('.NB-intelligence-slider-red', $slider).addClass('NB-active'); } else if (real_value > 0) { $('.NB-intelligence-slider-green', $slider).addClass('NB-active'); @@ -3945,7 +3978,9 @@ }, move_intelligence_slider: function(direction) { - var value = this.model.preference('unread_view') + direction; + var unread_view = this.model.preference('unread_view'); + if (!this.model.preference('hide_read_feeds')) unread_view = -1; + var value = unread_view + direction; this.slide_intelligence_slider(value); }, @@ -3959,21 +3994,25 @@ this.$s.$body.removeClass('NB-intelligence-positive') .removeClass('NB-intelligence-neutral') .removeClass('NB-intelligence-negative') + .removeClass('NB-intelligence-starred') .addClass('NB-intelligence-'+unread_view_name); $sidebar.removeClass('unread_view_positive') .removeClass('unread_view_neutral') .removeClass('unread_view_negative') + .removeClass('unread_view_starred') .addClass('unread_view_'+unread_view_name); $next_story_button.removeClass('NB-task-story-next-positive') .removeClass('NB-task-story-next-neutral') .removeClass('NB-task-story-next-negative') + .removeClass('NB-task-story-next-starred') .addClass('NB-task-story-next-'+unread_view_name); $story_title_indicator.removeClass('unread_threshold_positive') .removeClass('unread_threshold_neutral') .removeClass('unread_threshold_negative') + .removeClass('unread_threshold_starred') .addClass('unread_threshold_'+unread_view_name); NEWSBLUR.assets.stories.each(function(story){ @@ -3982,6 +4021,7 @@ }, get_unread_view_score: function() { + if (this.flags['feed_list_showing_starred']) return -1; if (this.flags['unread_threshold_temporarily']) { var score_name = this.flags['unread_threshold_temporarily']; if (score_name == 'neutral') { @@ -4002,7 +4042,9 @@ if (typeof unread_view == 'undefined') { unread_view = this.get_unread_view_score(); } - + + if (this.flags['feed_list_showing_starred']) return 'starred'; + return (unread_view > 0 ? 'positive' : unread_view < 0 @@ -4045,6 +4087,8 @@ return counts['ps'] + counts['nt']; } else if (unread_view_name == 'negative') { return counts['ps'] + counts['nt'] + counts['ng']; + } else if (unread_view_name == 'starred') { + return counts['st']; } }, @@ -5482,6 +5526,8 @@ unread_value = 0; } else if ($t.hasClass('NB-intelligence-slider-green')) { unread_value = 1; + } else if ($t.hasClass('NB-intelligence-slider-blue')) { + unread_value = 2; } self.slide_intelligence_slider(unread_value); diff --git a/media/js/newsblur/reader/reader_taskbar_info.js b/media/js/newsblur/reader/reader_taskbar_info.js index 2d377e623..53241b66a 100644 --- a/media/js/newsblur/reader/reader_taskbar_info.js +++ b/media/js/newsblur/reader/reader_taskbar_info.js @@ -14,7 +14,7 @@ NEWSBLUR.Views.ReaderTaskbarInfo = Backbone.View.extend({ center: function(force) { var count_width = this.$el.width(); var left_buttons_offset = $('.NB-taskbar-view').outerWidth(true); - var right_buttons_offset = $(".NB-taskbar-layout").position().left; + var right_buttons_offset = $(".NB-taskbar-options-container").position().left; var usable_space = right_buttons_offset - left_buttons_offset; var left = (usable_space / 2) - (count_width / 2) + left_buttons_offset; // console.log(["Taskbar info center", count_width, left, left_buttons_offset, right_buttons_offset, usable_space]); diff --git a/media/js/newsblur/views/feed_list_view.js b/media/js/newsblur/views/feed_list_view.js index bc60ac2eb..ba3389814 100644 --- a/media/js/newsblur/views/feed_list_view.js +++ b/media/js/newsblur/views/feed_list_view.js @@ -167,7 +167,7 @@ NEWSBLUR.Views.FeedList = Backbone.View.extend({ options = options || {}; var $starred_feeds = $('.NB-starred-feeds', this.$s.$starred_feeds); var $feeds = _.compact(NEWSBLUR.assets.starred_feeds.map(function(feed) { - if (feed.get('tag') == "") return; + if (feed.get('tag') == "" || !feed.get('tag')) return; var feed_view = new NEWSBLUR.Views.FeedTitleView({ model: feed, type: 'feed', diff --git a/media/js/newsblur/views/feed_title_view.js b/media/js/newsblur/views/feed_title_view.js index 50ba34d28..92e8b001f 100644 --- a/media/js/newsblur/views/feed_title_view.js +++ b/media/js/newsblur/views/feed_title_view.js @@ -148,6 +148,7 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({ extra_classes: function() { var feed = this.model; var extra_classes = ''; + var starred_feed = NEWSBLUR.assets.starred_feeds.get_feed(feed.id); if (feed.get('ps')) { extra_classes += ' unread_positive'; @@ -158,6 +159,9 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({ if (feed.get('ng')) { extra_classes += ' unread_negative'; } + if ((starred_feed && starred_feed.get('count')) || feed.is_starred()) { + extra_classes += ' unread_starred'; + } if (feed.is_feed()) { if (feed.get('has_exception') && feed.get('exception_type') == 'feed') { @@ -188,7 +192,10 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({ if (this.counts_view) { this.counts_view.destroy(); } - this.counts_view = new NEWSBLUR.Views.UnreadCount({model: this.model}).render(); + this.counts_view = new NEWSBLUR.Views.UnreadCount({ + model: this.model, + include_starred: true + }).render(); this.$('.feed_counts').html(this.counts_view.el); if (this.options.type == 'story') { this.$('.NB-story-title-indicator-count').html(this.counts_view.$el.clone()); @@ -248,7 +255,7 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({ add_extra_classes: function() { var extra_classes = this.extra_classes(); - $(this.el).removeClass("unread_positive unread_neutral unread_negative"); + $(this.el).removeClass("unread_positive unread_neutral unread_negative unread_starred"); $(this.el).addClass(extra_classes); }, diff --git a/media/js/newsblur/views/sidebar_header_view.js b/media/js/newsblur/views/sidebar_header_view.js index 8f4d50001..7cecbfd1c 100644 --- a/media/js/newsblur/views/sidebar_header_view.js +++ b/media/js/newsblur/views/sidebar_header_view.js @@ -60,6 +60,7 @@ NEWSBLUR.Views.SidebarHeader = Backbone.View.extend({ toggle_hide_read_preference: function() { var hide_read_feeds = NEWSBLUR.assets.preference('hide_read_feeds'); + if (NEWSBLUR.reader.flags['feed_list_showing_starred']) hide_read_feeds = true; this.$('.NB-feeds-header-sites').toggleClass('NB-feedlist-hide-read-feeds', !!hide_read_feeds); $("body").toggleClass("NB-feedlist-hide-read-feeds", !!hide_read_feeds); }, diff --git a/media/js/newsblur/views/story_titles_header_view.js b/media/js/newsblur/views/story_titles_header_view.js index 7ece9aa2b..fc4095775 100644 --- a/media/js/newsblur/views/story_titles_header_view.js +++ b/media/js/newsblur/views/story_titles_header_view.js @@ -134,6 +134,7 @@ NEWSBLUR.Views.StoryTitlesHeader = Backbone.View.extend({ if (!is_feed_load) return; if (!NEWSBLUR.reader.active_feed) return; if (NEWSBLUR.reader.flags.search) return; + if (NEWSBLUR.reader.flags['feed_list_showing_starred']) return; NEWSBLUR.reader.flags['unread_threshold_temporarily'] = null; var unread_view_name = NEWSBLUR.reader.get_unread_view_name(); diff --git a/media/js/newsblur/views/unread_count_view.js b/media/js/newsblur/views/unread_count_view.js index cf5ec6325..6d0fba0cf 100644 --- a/media/js/newsblur/views/unread_count_view.js +++ b/media/js/newsblur/views/unread_count_view.js @@ -6,6 +6,10 @@ NEWSBLUR.Views.UnreadCount = Backbone.View.extend({ _.bindAll(this, 'render'); if (!this.options.stale) { if (this.model) { + var starred_feed = NEWSBLUR.assets.starred_feeds.get_feed(this.model.id); + if (starred_feed) { + starred_feed.bind('change:count', this.render, this); + } this.model.bind('change:ps', this.render, this); this.model.bind('change:nt', this.render, this); this.model.bind('change:ng', this.render, this); @@ -37,11 +41,15 @@ NEWSBLUR.Views.UnreadCount = Backbone.View.extend({ if (counts['ng']) { unread_class += ' unread_negative'; } + if ((counts['st'] && this.options.include_starred) || (this.model && this.model.is_starred())) { + unread_class += ' unread_starred'; + } this.$el.html(this.template({ ps : counts['ps'], nt : counts['nt'], ng : counts['ng'], + st : this.options.include_starred && counts['st'], unread_class : unread_class })); @@ -68,6 +76,11 @@ NEWSBLUR.Views.UnreadCount = Backbone.View.extend({ \ <%= ng %>\ \ + <% if (st) { %>\ + \ + <%= st %>\ + \ + <% } %>\ \ '), @@ -78,7 +91,7 @@ NEWSBLUR.Views.UnreadCount = Backbone.View.extend({ center: function() { var count_width = this.$el.width(); var left_buttons_offset = $('.NB-taskbar-view').outerWidth(true); - var right_buttons_offset = $(".NB-taskbar-layout").position().left; + var right_buttons_offset = $(".NB-taskbar-options-container").position().left; var usable_space = right_buttons_offset - left_buttons_offset; var left = (usable_space / 2) - (count_width / 2) + left_buttons_offset; diff --git a/templates/base.html b/templates/base.html index a336fdd98..e8c8217f1 100644 --- a/templates/base.html +++ b/templates/base.html @@ -34,7 +34,7 @@ NEWSBLUR.Preferences = { 'unread_view' : 0, 'lock_mouse_indicator' : 100, - 'feed_pane_size' : {% firstof user_profile.feed_pane_size 242 %}, + 'feed_pane_size' : {% firstof user_profile.feed_pane_size 258 %}, 'hide_getting_started' : {{ user_profile.hide_getting_started|yesno:"true,false" }}, 'has_setup_feeds' : {{ user_profile.has_setup_feeds|yesno:"true,false" }}, 'has_found_friends' : {{ user_profile.has_found_friends|yesno:"true,false" }}, diff --git a/templates/mail/email_first_share_to_blurblog.xhtml b/templates/mail/email_first_share_to_blurblog.xhtml index be5f74167..85be1111f 100644 --- a/templates/mail/email_first_share_to_blurblog.xhtml +++ b/templates/mail/email_first_share_to_blurblog.xhtml @@ -1,7 +1,7 @@ {% extends "mail/email_base.xhtml" %} {% block body %} -
Your shared story is now on your Blurblog
+Your shared story is now on your Blurblog
You can view your Blurblog here: {{ blurblog_url }}
Your Blurblog also has an RSS feed: {{ blurblog_rss }}
{% if shared_stories > 1 %}You've already shared {{ shared_stories }} stories, but you may not have known that your shared stories are on your Blurblog.{% else %}You just shared your first story on NewsBlur. All of your shared stories are available on your Blurblog.{% endif %}
diff --git a/templates/mail/email_follow_request.xhtml b/templates/mail/email_follow_request.xhtml index 5792b0cb7..5750b6424 100644 --- a/templates/mail/email_follow_request.xhtml +++ b/templates/mail/email_follow_request.xhtml @@ -2,7 +2,7 @@ {% load utils_tags %} {% block body %} -+
You have a follow request:
Forgot your password? No problem.
+Forgot your password? No problem.
You can change your password by visiting this link:
http://{% current_domain %}{{ user.profile.autologin_url }}?next=/profile/forgot_password_return
You will be auto-logged into your account and presented with a form to change your password.
diff --git a/templates/mail/email_launch_social.xhtml b/templates/mail/email_launch_social.xhtml index 4efa8a9c3..e3897bc1c 100644 --- a/templates/mail/email_launch_social.xhtml +++ b/templates/mail/email_launch_social.xhtml @@ -3,7 +3,7 @@ {% load utils_tags %} {% block body %} -Hey {{ user.username }}, we're launching a new NewsBlur...
+Hey {{ user.username }}, we're launching a new NewsBlur...
{% if months_ago >= 1 %}It's been {{ months_ago }} month{{ months_ago|pluralize }} since you last saw NewsBlur. A lot has changed since then.{% else %}You've recently been on NewsBlur, but a lot has changed since even then.{% endif %} NewsBlur is now a social news reader. We just launched shared stories and if you miss the old Google Reader features, you'll love the new NewsBlur.
We've worked hard to make a great app, so congratulations on discovering a handcrafted experience.
Here are some easy ways to have a great time on NewsBlur:
diff --git a/templates/mail/email_new_account.xhtml b/templates/mail/email_new_account.xhtml index ee1ebf9f2..ac7bec90f 100644 --- a/templates/mail/email_new_account.xhtml +++ b/templates/mail/email_new_account.xhtml @@ -3,7 +3,7 @@ {% load utils_tags %} {% block body %} -Welcome to NewsBlur, {{ user.username }}.
+Welcome to NewsBlur, {{ user.username }}.
Thanks for trying out NewsBlur! I hope NewsBlur can make your daily reading more personal, sociable, and pleasurable.
Here are some ways to make NewsBlur work for you:
diff --git a/templates/mail/email_new_follower.xhtml b/templates/mail/email_new_follower.xhtml index 79394e9c9..9fcdd638f 100644 --- a/templates/mail/email_new_follower.xhtml +++ b/templates/mail/email_new_follower.xhtml @@ -1,7 +1,7 @@ {% extends "mail/email_base.xhtml" %} {% block body %} -
+
Say hello to your newest follower:
Thank you, thank you, thank you!
+Thank you, thank you, thank you!
A huge thanks for going premium.
Your subscription goes a long way towards funding the further development of NewsBlur.
There's still a ton of great work to be done, and you are personally keeping the dream alive. Thanks again, paying users like you make this entire endeavor worthwhile.
diff --git a/templates/mail/email_new_user_queue.xhtml b/templates/mail/email_new_user_queue.xhtml index 355fc8d6d..ea7e18815 100644 --- a/templates/mail/email_new_user_queue.xhtml +++ b/templates/mail/email_new_user_queue.xhtml @@ -3,7 +3,7 @@ {% load utils_tags %} {% block body %} -Your free account is ready, {{ user.username }}.
+Your free account is ready, {{ user.username }}.
Thanks again for trying out NewsBlur! Your account is ready to go. Just log right in and start reading.
http://{% current_domain dev=True %}{{ user.profile.autologin_url }}
I made NewsBlur because I wanted a better way to read the news and talk about it with people. I hope you love it, too.
diff --git a/templates/mail/email_premium_expire.txt b/templates/mail/email_premium_expire.txt index 8f4da2ce0..7742880b0 100644 --- a/templates/mail/email_premium_expire.txt +++ b/templates/mail/email_premium_expire.txt @@ -4,14 +4,8 @@ {% block body %}Hey {{ user.username }}, your premium account has just expired. -{% if months_ago >= 1 %}It's been {{ months_ago }} month{{ months_ago|pluralize }} since you last saw NewsBlur. We just launched a full-scale re-design, complete with shared stories (blurblogs) and native iOS/Android apps. If you miss the old Google Reader features, you'll love the new NewsBlur.{% else %}You've recently been on NewsBlur, but now your premium account is going to expire!{% endif %} +You now have a free account with all the limitations of a free account. But that doesn't mean you can't renew your premium subscription and enjoy the many benefits of using NewsBlur. -Your premium account has just expired, but that doesn't mean you can't renew your premium subscription and enjoy the many benefits of using NewsBlur. - -Here are some easy ways to have a great time on NewsBlur: - - * Follow friends from Twitter, Facebook, and NewsBlur: http://{% current_domain %}{{ user.profile.autologin_url }} - * Visit the popular blurblog, The People Have Spoken: http://popular.newsblur.com - * Renew your premium account for only $24/year: http://{% current_domain %}{{ user.profile.autologin_url }}?next=chooser +Renew now: http://{% current_domain %}{{ user.profile.autologin_url }}?next=chooser Spend a few days trying out NewsBlur again. We hope you love it.{% endblock body %} \ No newline at end of file diff --git a/templates/mail/email_premium_expire.xhtml b/templates/mail/email_premium_expire.xhtml index 5b945e12d..48c5f2efb 100644 --- a/templates/mail/email_premium_expire.xhtml +++ b/templates/mail/email_premium_expire.xhtml @@ -3,30 +3,9 @@ {% load utils_tags %} {% block body %} -Hey {{ user.username }}, your premium account has just expired.
-{% if months_ago >= 1 %}It's been {{ months_ago }} month{{ months_ago|pluralize }} since you last saw NewsBlur. We just launched a full-scale re-design, complete with shared stories (blurblogs) and native iOS/Android apps. If you miss the old Google Reader features, you'll love the new NewsBlur.{% else %}You've recently been on NewsBlur, but now your premium account is going to expire!{% endif %}
-Your premium account has just expired, but that doesn't mean you can't renew your premium subscription and enjoy the many benefits of using NewsBlur.
-Here are some easy ways to have a great time on NewsBlur:
--
NEW: Sharing and discussing stories with friends
- -IT'S FUN: There's serendipity in your news reader
- -IMPROVED: Everything is now incredibly fast
- -Hey {{ user.username }}, your premium account has just expired.
+You now have a free account with all the limitations of a free account. But that doesn't mean you can't renew your premium subscription and enjoy the many benefits of using NewsBlur.
+Renew now: http://{% current_domain %}{{ user.profile.autologin_url }}?next=chooser
Spend a few days trying out NewsBlur again. We hope you love it.
{% endblock %} diff --git a/templates/mail/email_premium_expire_grace.txt b/templates/mail/email_premium_expire_grace.txt index bd0683820..c172720ad 100644 --- a/templates/mail/email_premium_expire_grace.txt +++ b/templates/mail/email_premium_expire_grace.txt @@ -4,10 +4,12 @@ {% block body %}Hey {{ user.username }}, your premium account is about to expire... -{% if months_ago >= 1 %}It's been {{ months_ago }} month{{ months_ago|pluralize }} since you last saw NewsBlur. A lot has changed since then.{% else %}You've recently been on NewsBlur, but a lot has changed since even then.{% endif %} We just launched a full-scale re-design, complete with shared stories (blurblogs) and native iOS/Android apps. If you miss the old Google Reader features, you'll love the new NewsBlur. - Your premium account was set to expire today, but you've been given a free month grace period, so you can continue using your premium account to try out NewsBlur. +{% if months_ago >= 1 %}It's been {{ months_ago }} month{{ months_ago|pluralize }} since you last saw NewsBlur. A lot has changed since then. We just launched a full-scale re-design, complete with shared stories (blurblogs) and native iOS/Android apps. If you miss the old Google Reader features, you'll love the new NewsBlur.{% else %}You've recently been on NewsBlur, so maybe you didn't mean to transition back to the free account? Maybe you just need to renew your premium account? Let's help you do that.{% endif %} + +Renew now: http://{% current_domain %}{{ user.profile.autologin_url }}?next=chooser + Here are some easy ways to have a great time on NewsBlur: * Follow friends from Twitter, Facebook, and NewsBlur: http://{% current_domain %}{{ user.profile.autologin_url }} diff --git a/templates/mail/email_premium_expire_grace.xhtml b/templates/mail/email_premium_expire_grace.xhtml index dafc6ecfc..eda75bdcd 100644 --- a/templates/mail/email_premium_expire_grace.xhtml +++ b/templates/mail/email_premium_expire_grace.xhtml @@ -3,9 +3,10 @@ {% load utils_tags %} {% block body %} -Hey {{ user.username }}, your premium account is about to expire...
-{% if months_ago >= 1 %}It's been {{ months_ago }} month{{ months_ago|pluralize }} since you last saw NewsBlur. A lot has changed since then.{% else %}You've recently been on NewsBlur, but a lot has changed since even then.{% endif %} We just launched a full-scale re-design, complete with shared stories (blurblogs) and native iOS/Android apps. If you miss the old Google Reader features, you'll love the new NewsBlur.
+Hey {{ user.username }}, your premium account is about to expire...
Your premium account was set to expire today, but you've been given a free month grace period, so you can continue using your premium account to try out NewsBlur.
+{% if months_ago >= 1 %}It's been {{ months_ago }} month{{ months_ago|pluralize }} since you last saw NewsBlur. A lot has changed since then. We just launched a full-scale re-design, complete with shared stories (blurblogs) and native iOS/Android apps. If you miss the old Google Reader features, you'll love the new NewsBlur.{% else %}You've recently been on NewsBlur, so maybe you didn't mean to transition back to the free account? Maybe you just need to renew your premium account? Let's help you do that.{% endif %}
+Renew now: http://{% current_domain %}{{ user.profile.autologin_url }}?next=renew
Here are some easy ways to have a great time on NewsBlur:
+
{{ reply_user_profile.username }} replied to you: