Merge remote-tracking branch 'upstream/master'

Conflicts:
	clients/android/NewsBlur/res/values/colors.xml
	clients/android/NewsBlur/src/com/newsblur/activity/Main.java
	clients/android/NewsBlur/src/com/newsblur/fragment/DeleteFeedFragment.java
	clients/android/NewsBlur/src/com/newsblur/fragment/ReadingItemFragment.java
	clients/android/NewsBlur/src/com/newsblur/util/PrefConstants.java
	clients/android/NewsBlur/src/com/newsblur/util/PrefsUtils.java
This commit is contained in:
dosiecki 2014-08-04 14:11:27 -07:00
commit 7ec3a93531
216 changed files with 3183 additions and 1863 deletions

View file

@ -334,7 +334,7 @@ def api_saved_tag_list(request):
tags = []
for tag in starred_counts:
if tag['tag'] == "": continue
if not tag['tag'] or tag['tag'] == "": continue
tags.append(dict(label="%s (%s %s)" % (tag['tag'], tag['count'],
'story' if tag['count'] == 1 else 'stories'),
value=tag['tag']))
@ -380,7 +380,10 @@ def api_unread_story(request, trigger_slug=None):
if isinstance(feed_or_folder, int) or feed_or_folder.isdigit():
feed_id = int(feed_or_folder)
usersub = UserSubscription.objects.get(user=user, feed_id=feed_id)
try:
usersub = UserSubscription.objects.get(user=user, feed_id=feed_id)
except UserSubscription.DoesNotExist:
return dict(data=[])
found_feed_ids = [feed_id]
found_trained_feed_ids = [feed_id] if usersub.is_trained else []
stories = usersub.get_stories(order="newest", read_filter="unread",
@ -639,10 +642,11 @@ def api_share_new_story(request):
story_content = original_story['content']
if not story_title:
story_title = original_story['title']
story_content = lxml.html.fromstring(story_content)
story_content.make_links_absolute(story_url)
story_content = lxml.html.tostring(story_content)
if story_content:
story_content = lxml.html.fromstring(story_content)
story_content.make_links_absolute(story_url)
story_content = lxml.html.tostring(story_content)
shared_story = MSharedStory.objects.filter(user_id=user.pk,
story_feed_id=original_feed and original_feed.pk or 0,
@ -732,7 +736,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

View file

@ -74,7 +74,7 @@ class DBProfilerMiddleware:
class SQLLogToConsoleMiddleware:
def activated(self, request):
return (settings.DEBUG or
return (settings.DEBUG_QUERIES or
(hasattr(request, 'activated_segments') and
'db_profiler' in request.activated_segments))

View file

@ -88,7 +88,7 @@ class Profile(models.Model):
except DatabaseError:
print " ---> Profile not saved. Table isn't there yet."
def delete_user(self, confirm=False):
def delete_user(self, confirm=False, fast=False):
if not confirm:
print " ---> You must pass confirm=True to delete this user."
return
@ -119,8 +119,9 @@ class Profile(models.Model):
logging.user(self.user, "Deleting %s shared stories" % shared_stories.count())
for story in shared_stories:
try:
original_story = MStory.objects.get(story_hash=story.story_hash)
original_story.sync_redis()
if not fast:
original_story = MStory.objects.get(story_hash=story.story_hash)
original_story.sync_redis()
except MStory.DoesNotExist:
pass
story.delete()
@ -151,6 +152,14 @@ class Profile(models.Model):
logging.user(self.user, "Deleting user: %s" % self.user)
self.user.delete()
def check_if_spammer(self):
feed_opens = UserSubscription.objects.filter(user=self.user)\
.aggregate(sum=Sum('feed_opens'))['sum']
feed_count = UserSubscription.objects.filter(user=self.user).count()
if not feed_opens and not feed_count:
return True
def activate_premium(self):
from apps.profile.tasks import EmailNewPremium
@ -620,7 +629,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 +661,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

View file

@ -18,6 +18,7 @@ urlpatterns = patterns('',
url(r'^cancel_premium/?', views.cancel_premium, name='profile-cancel-premium'),
url(r'^refund_premium/?', views.refund_premium, name='profile-refund-premium'),
url(r'^upgrade_premium/?', views.upgrade_premium, name='profile-upgrade-premium'),
url(r'^update_payment_history/?', views.update_payment_history, name='profile-update-payment-history'),
url(r'^delete_account/?', views.delete_account, name='profile-delete-account'),
url(r'^forgot_password_return/?', views.forgot_password_return, name='profile-forgot-password-return'),
url(r'^forgot_password/?', views.forgot_password, name='profile-forgot-password'),

View file

@ -398,7 +398,17 @@ def upgrade_premium(request):
user = User.objects.get(pk=user_id)
upgraded = user.profile.activate_premium()
return {'code': 1 if upgraded else -1}
return {'code': 1 if upgraded else -1}
@staff_member_required
@ajax_login_required
@json.json_view
def update_payment_history(request):
user_id = request.REQUEST.get('user_id')
user = User.objects.get(pk=user_id)
user.profile.setup_premium_history()
return {'code': 1}
@login_required
@render_to('profile/delete_account.xhtml')

View file

@ -71,17 +71,17 @@ class SignupForm(forms.Form):
username = forms.RegexField(regex=r'^\w+$',
max_length=30,
widget=forms.TextInput(attrs={'class': 'NB-input'}),
label=_(u'username'),
label=_(u'Username'),
error_messages={
'required': 'Please enter a username.',
'invalid': "Your username may only contain letters and numbers."
})
email = forms.EmailField(widget=forms.TextInput(attrs={'maxlength': 75, 'class': 'NB-input'}),
label=_(u'email'),
label=_(u'Email'),
required=True,
error_messages={'required': 'Please enter an email.'})
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'NB-input'}),
label=_(u'password'),
label=_(u'Password'),
required=False)
# error_messages={'required': 'Please enter a password.'})

View file

@ -10,6 +10,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.core.cache import cache
from mongoengine.queryset import OperationError
from mongoengine.queryset import NotUniqueError
from apps.reader.managers import UserSubscriptionManager
from apps.rss_feeds.models import Feed, MStory, DuplicateFeed
from apps.analyzer.models import MClassifierFeed, MClassifierAuthor, MClassifierTag, MClassifierTitle
@ -61,10 +62,6 @@ class UserSubscription(models.Model):
feed['subscribed'] = True
if classifiers:
feed['classifiers'] = classifiers
if not self.active and self.user.profile.is_premium:
feed['active'] = True
self.active = True
self.save()
return feed
@ -72,8 +69,6 @@ class UserSubscription(models.Model):
user_title_max = self._meta.get_field('user_title').max_length
if self.user_title and len(self.user_title) > user_title_max:
self.user_title = self.user_title[:user_title_max]
if not self.active and self.user.profile.is_premium:
self.active = True
try:
super(UserSubscription, self).save(*args, **kwargs)
except IntegrityError:
@ -85,7 +80,7 @@ class UserSubscription(models.Model):
super(UserSubscription, self).save(*args, **kwargs)
break
else:
self.delete()
if self: self.delete()
@classmethod
def subs_for_feeds(cls, user_id, feed_ids=None, read_filter="unread"):
@ -421,6 +416,60 @@ class UserSubscription(models.Model):
return feeds
@classmethod
def identify_deleted_feed_users(cls, old_feed_id):
users = UserSubscriptionFolders.objects.filter(folders__contains="5636682").only('user')
user_ids = [usf.user_id for usf in users]
f = open('users.txt', 'w')
f.write('\n'.join([str(u) for u in user_ids]))
return user_ids
@classmethod
def recreate_deleted_feed(cls, new_feed_id, old_feed_id=None, skip=0):
user_ids = sorted([int(u) for u in open('users.txt').read().split('\n') if u])
count = len(user_ids)
for i, user_id in enumerate(user_ids):
if i < skip: continue
if i % 1000 == 0:
print "\n\n ------------------------------------------------"
print "\n ---> %s/%s (%s%%)" % (i, count, round(float(i)/count))
print "\n ------------------------------------------------\n"
try:
user = User.objects.get(pk=user_id)
except User.DoesNotExist:
print " ***> %s has no account" % user_id
continue
us, created = UserSubscription.objects.get_or_create(user_id=user_id, feed_id=new_feed_id, defaults={
'needs_unread_recalc': True,
'active': True,
'is_trained': True
})
if not created:
print " ***> %s already subscribed" % user.username
try:
usf = UserSubscriptionFolders.objects.get(user_id=user_id)
usf.add_missing_feeds()
except UserSubscriptionFolders.DoesNotExist:
print " ***> %s has no USF" % user.username
# Move classifiers
if old_feed_id:
classifier_count = 0
for classifier_type in (MClassifierAuthor, MClassifierFeed, MClassifierTag, MClassifierTitle):
classifiers = classifier_type.objects.filter(user_id=user_id, feed_id=old_feed_id)
classifier_count += classifiers.count()
for classifier in classifiers:
classifier.feed_id = new_feed_id
try:
classifier.save()
except NotUniqueError:
continue
if classifier_count:
print " Moved %s classifiers for %s" % (classifier_count, user.username)
def trim_read_stories(self, r=None):
if not r:
r = redis.Redis(connection_pool=settings.REDIS_STORY_HASH_POOL)
@ -527,11 +576,11 @@ class UserSubscription(models.Model):
cutoff_date = cutoff_date - datetime.timedelta(seconds=1)
story_hashes = self.get_stories(limit=500, order="newest", cutoff_date=cutoff_date,
read_filter="unread", hashes_only=True)
data = self.mark_story_ids_as_read(story_hashes)
data = self.mark_story_ids_as_read(story_hashes, aggregated=True)
return data
def mark_story_ids_as_read(self, story_hashes, request=None):
def mark_story_ids_as_read(self, story_hashes, request=None, aggregated=False):
data = dict(code=0, payload=story_hashes)
if not request:
@ -547,7 +596,7 @@ class UserSubscription(models.Model):
logging.user(request, "~FYRead story in feed: %s" % (self.feed))
for story_hash in set(story_hashes):
RUserStory.mark_read(self.user_id, self.feed_id, story_hash)
RUserStory.mark_read(self.user_id, self.feed_id, story_hash, aggregated=aggregated)
return data
@ -568,7 +617,7 @@ class UserSubscription(models.Model):
# Mark stories as read only after the mark_read_date has been moved, otherwise
# these would be ignored.
data = self.mark_story_ids_as_read(newer_stories, request=request)
data = self.mark_story_ids_as_read(newer_stories, request=request, aggregated=True)
return data
@ -837,7 +886,8 @@ class RUserStory:
return feed_id, list(friend_ids)
@classmethod
def mark_read(cls, user_id, story_feed_id, story_hash, social_user_ids=None, r=None):
def mark_read(cls, user_id, story_feed_id, story_hash, social_user_ids=None,
aggregated=False, r=None):
if not r:
r = redis.Redis(connection_pool=settings.REDIS_STORY_HASH_POOL)
# if not r2:
@ -863,6 +913,12 @@ class RUserStory:
for social_user_id in social_user_ids:
social_read_story_key = 'RS:%s:B:%s' % (user_id, social_user_id)
redis_commands(social_read_story_key)
if not aggregated:
key = 'lRS:%s' % user_id
r.lpush(key, story_hash)
r.ltrim(key, 0, 1000)
r.expire(key, settings.DAYS_OF_STORY_HASHES*24*60*60)
@staticmethod
def story_can_be_marked_read_by_user(story, user):
@ -901,17 +957,35 @@ class RUserStory:
read_story_key = 'RS:%s:%s' % (user_id, story_feed_id)
redis_commands(read_story_key)
read_stories_list_key = 'lRS:%s' % user_id
r.lrem(read_stories_list_key, story_hash)
if social_user_ids:
for social_user_id in social_user_ids:
social_read_story_key = 'RS:%s:B:%s' % (user_id, social_user_id)
redis_commands(social_read_story_key)
@staticmethod
def get_stories(user_id, feed_id, r=None):
if not r:
r = redis.Redis(connection_pool=settings.REDIS_STORY_HASH_POOL)
story_hashes = r.smembers("RS:%s:%s" % (user_id, feed_id))
return story_hashes
@staticmethod
def get_read_stories(user_id, offset=0, limit=12, order="newest"):
r = redis.Redis(connection_pool=settings.REDIS_STORY_HASH_POOL)
key = "lRS:%s" % user_id
if order == "oldest":
count = r.llen(key)
if offset >= count: return []
offset = max(0, count - (offset+limit))
story_hashes = r.lrange(key, offset, offset+limit)
elif order == "newest":
story_hashes = r.lrange(key, offset, offset+limit)
return story_hashes
@classmethod
def switch_feed(cls, user_id, old_feed_id, new_feed_id):
@ -1266,6 +1340,25 @@ class UserSubscriptionFolders(models.Model):
user_sub_folders = add_object_to_folder(feed_id, "", user_sub_folders)
self.folders = json.encode(user_sub_folders)
self.save()
def auto_activate(self):
if self.user.profile.is_premium: return
active_count = UserSubscription.objects.filter(user=self.user, active=True).count()
if active_count: return
all_feeds = self.flat()
if not all_feeds: return
for feed in all_feeds[:64]:
try:
sub = UserSubscription.objects.get(user=self.user, feed=feed)
except UserSubscription.DoesNotExist:
continue
sub.active = True
sub.save()
if sub.feed.active_subscribers <= 0:
sub.feed.count_subscribers()
class Feature(models.Model):

View file

@ -18,6 +18,7 @@ urlpatterns = patterns('',
url(r'^interactions_count', views.interactions_count, name='interactions-count'),
url(r'^feed_unread_count', views.feed_unread_count, name='feed-unread-count'),
url(r'^starred_stories', views.load_starred_stories, name='load-starred-stories'),
url(r'^read_stories', views.load_read_stories, name='load-read-stories'),
url(r'^starred_story_hashes', views.starred_story_hashes, name='starred-story-hashes'),
url(r'^starred_rss/(?P<user_id>\d+)/(?P<secret_token>\w+)/(?P<tag_slug>[-\w]+)?/?$', views.starred_stories_rss_feed, name='starred-stories-rss-feed'),
url(r'^unread_story_hashes', views.unread_story_hashes, name='unread-story-hashes'),

View file

@ -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
@ -313,6 +314,8 @@ def load_feeds_flat(request):
update_counts = is_true(request.REQUEST.get('update_counts', True))
feeds = {}
day_ago = datetime.datetime.now() - datetime.timedelta(days=1)
scheduled_feeds = []
iphone_version = "2.1"
if include_favicons == 'false': include_favicons = False
@ -327,8 +330,9 @@ def load_feeds_flat(request):
folders = []
user_subs = UserSubscription.objects.select_related('feed').filter(user=user, active=True)
day_ago = datetime.datetime.now() - datetime.timedelta(days=1)
scheduled_feeds = []
if not user_subs and folders:
folders.auto_activate()
user_subs = UserSubscription.objects.select_related('feed').filter(user=user, active=True)
for sub in user_subs:
if update_counts and sub.needs_unread_recalc:
@ -392,7 +396,6 @@ def refresh_feeds(request):
feed_ids = request.REQUEST.getlist('feed_id')
check_fetch_status = request.REQUEST.get('check_fetch_status')
favicons_fetching = request.REQUEST.getlist('favicons_fetching')
social_feed_ids = [feed_id for feed_id in feed_ids if 'social:' in feed_id]
feed_ids = list(set(feed_ids) - set(social_feed_ids))
@ -405,7 +408,9 @@ def refresh_feeds(request):
social_feeds = MSocialSubscription.feeds_with_updated_counts(user, social_feed_ids=social_feed_ids)
favicons_fetching = [int(f) for f in favicons_fetching if f]
feed_icons = dict([(i.feed_id, i) for i in MFeedIcon.objects(feed_id__in=favicons_fetching)])
feed_icons = {}
if favicons_fetching:
feed_icons = dict([(i.feed_id, i) for i in MFeedIcon.objects(feed_id__in=favicons_fetching)])
for feed_id, feed in feeds.items():
if feed_id in favicons_fetching and feed_id in feed_icons:
@ -413,7 +418,7 @@ def refresh_feeds(request):
feeds[feed_id]['favicon_color'] = feed_icons[feed_id].color
feeds[feed_id]['favicon_fetching'] = feed.get('favicon_fetching')
user_subs = UserSubscription.objects.filter(user=user, active=True)
user_subs = UserSubscription.objects.filter(user=user, active=True).only('feed')
sub_feed_ids = [s.feed_id for s in user_subs]
if favicons_fetching:
@ -537,6 +542,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)
@ -740,18 +751,21 @@ def load_starred_stories(request):
limit = int(request.REQUEST.get('limit', 10))
page = int(request.REQUEST.get('page', 0))
query = request.REQUEST.get('query')
order = request.REQUEST.get('order', 'newest')
tag = request.REQUEST.get('tag')
story_hashes = request.REQUEST.getlist('h')[:100]
version = int(request.REQUEST.get('v', 1))
now = localtime_for_timezone(datetime.datetime.now(), user.profile.timezone)
message = None
order_by = '-' if order == "newest" else ""
if page: offset = limit * (page - 1)
if query:
# results = SearchStarredStory.query(user.pk, query)
# story_ids = [result.db_id for result in results]
if user.profile.is_premium:
stories = MStarredStory.find_stories(query, user.pk, tag=tag, offset=offset, limit=limit)
stories = MStarredStory.find_stories(query, user.pk, tag=tag, offset=offset, limit=limit,
order=order)
else:
stories = []
message = "You must be a premium subscriber to search."
@ -760,7 +774,7 @@ def load_starred_stories(request):
mstories = MStarredStory.objects(
user_id=user.pk,
user_tags__contains=tag
).order_by('-starred_date')[offset:offset+limit]
).order_by('%sstarred_date' % order_by)[offset:offset+limit]
stories = Feed.format_stories(mstories)
else:
stories = []
@ -769,12 +783,12 @@ def load_starred_stories(request):
mstories = MStarredStory.objects(
user_id=user.pk,
story_hash__in=story_hashes
).order_by('-starred_date')[offset:offset+limit]
).order_by('%sstarred_date' % order_by)[offset:offset+limit]
stories = Feed.format_stories(mstories)
else:
mstories = MStarredStory.objects(
user_id=user.pk
).order_by('-starred_date')[offset:offset+limit]
).order_by('%sstarred_date' % order_by)[offset:offset+limit]
stories = Feed.format_stories(mstories)
stories, user_profiles = MSharedStory.stories_with_comments_and_profiles(stories, user.pk, check_all=True)
@ -852,6 +866,8 @@ def starred_stories_rss_feed(request, user_id, secret_token, tag_slug):
try:
tag_counts = MStarredStoryCounts.objects.get(user_id=user_id, slug=tag_slug)
except MStarredStoryCounts.MultipleObjectsReturned:
tag_counts = MStarredStoryCounts.objects(user_id=user_id, slug=tag_slug).first()
except MStarredStoryCounts.DoesNotExist:
raise Http404
@ -898,6 +914,86 @@ def starred_stories_rss_feed(request, user_id, secret_token, tag_slug):
))
return HttpResponse(rss.writeString('utf-8'), content_type='application/rss+xml')
@json.json_view
def load_read_stories(request):
user = get_user(request)
offset = int(request.REQUEST.get('offset', 0))
limit = int(request.REQUEST.get('limit', 10))
page = int(request.REQUEST.get('page', 0))
order = request.REQUEST.get('order', 'newest')
query = request.REQUEST.get('query')
now = localtime_for_timezone(datetime.datetime.now(), user.profile.timezone)
message = None
if page: offset = limit * (page - 1)
if query:
stories = []
message = "Not implemented yet."
# if user.profile.is_premium:
# stories = MStarredStory.find_stories(query, user.pk, offset=offset, limit=limit)
# else:
# stories = []
# message = "You must be a premium subscriber to search."
else:
story_hashes = RUserStory.get_read_stories(user.pk, offset=offset, limit=limit, order=order)
mstories = MStory.objects(story_hash__in=story_hashes)
stories = Feed.format_stories(mstories)
stories = sorted(stories, key=lambda story: story_hashes.index(story['story_hash']),
reverse=bool(order=="oldest"))
stories, user_profiles = MSharedStory.stories_with_comments_and_profiles(stories, user.pk, check_all=True)
story_hashes = [story['story_hash'] for story in stories]
story_feed_ids = list(set(s['story_feed_id'] for s in stories))
usersub_ids = UserSubscription.objects.filter(user__pk=user.pk, feed__pk__in=story_feed_ids).values('feed__pk')
usersub_ids = [us['feed__pk'] for us in usersub_ids]
unsub_feed_ids = list(set(story_feed_ids).difference(set(usersub_ids)))
unsub_feeds = Feed.objects.filter(pk__in=unsub_feed_ids)
unsub_feeds = [feed.canonical(include_favicon=False) for feed in unsub_feeds]
shared_stories = MSharedStory.objects(user_id=user.pk,
story_hash__in=story_hashes)\
.only('story_hash', 'shared_date', 'comments')
shared_stories = dict([(story.story_hash, dict(shared_date=story.shared_date,
comments=story.comments))
for story in shared_stories])
starred_stories = MStarredStory.objects(user_id=user.pk,
story_hash__in=story_hashes)\
.only('story_hash', 'starred_date')
starred_stories = dict([(story.story_hash, story.starred_date)
for story in starred_stories])
nowtz = localtime_for_timezone(now, user.profile.timezone)
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, nowtz)
story['long_parsed_date'] = format_story_link_date__long(story_date, nowtz)
story['read_status'] = 1
story['intelligence'] = {
'feed': 1,
'author': 0,
'tags': 0,
'title': 0,
}
if story['story_hash'] in starred_stories:
story['starred'] = True
starred_date = localtime_for_timezone(starred_stories[story['story_hash']],
user.profile.timezone)
story['starred_date'] = format_story_link_date__long(starred_date, now)
if story['story_hash'] in shared_stories:
story['shared'] = True
story['shared_comments'] = strip_tags(shared_stories[story['story_hash']]['comments'])
search_log = "~SN~FG(~SB%s~SN)" % query if query else ""
logging.user(request, "~FCLoading read stories: ~SB%s stories %s" % (len(stories), search_log))
return {
"stories": stories,
"user_profiles": user_profiles,
"feeds": unsub_feeds,
"message": message,
}
@json.json_view
def load_river_stories__redis(request):
limit = 12
@ -918,7 +1014,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:
@ -943,6 +1039,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)
@ -980,10 +1082,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])
@ -1011,11 +1116,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):
@ -1694,16 +1801,15 @@ def feeds_trainer(request):
@json.json_view
def save_feed_chooser(request):
is_premium = request.user.profile.is_premium
if is_premium:
approved_feeds = []
else:
approved_feeds = [int(feed_id) for feed_id in request.POST.getlist('approved_feeds') if feed_id][:64]
approved_feeds = [int(feed_id) for feed_id in request.POST.getlist('approved_feeds') if feed_id]
if not is_premium:
approved_feeds = approved_feeds[:64]
activated = 0
usersubs = UserSubscription.objects.filter(user=request.user)
for sub in usersubs:
try:
if is_premium or sub.feed_id in approved_feeds:
if sub.feed_id in approved_feeds:
activated += 1
if not sub.active:
sub.active = True
@ -1715,14 +1821,14 @@ def save_feed_chooser(request):
sub.save()
except Feed.DoesNotExist:
pass
request.user.profile.queue_new_feeds()
request.user.profile.refresh_stale_feeds(exclude_new=True)
r = redis.Redis(connection_pool=settings.REDIS_PUBSUB_POOL)
r.publish(request.user.username, 'reload:feeds')
logging.user(request, "~BB~FW~SBActivated standard account: ~FC%s~SN/~SB%s" % (
logging.user(request, "~BB~FW~SBFeed chooser: ~FC%s~SN/~SB%s" % (
activated,
usersubs.count()
))
@ -1794,6 +1900,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)
@ -1821,6 +1928,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 []))
@ -1829,29 +1937,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:
@ -1888,6 +1980,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)
@ -1896,18 +1989,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

View file

@ -64,6 +64,7 @@ class Command(BaseCommand):
options['compute_scores'] = True
options['quick'] = float(MStatistics.get('quick_fetch', 0))
options['updates_off'] = MStatistics.get('updates_off', False)
disp = feed_fetcher.Dispatcher(options, num_workers)

View file

@ -441,13 +441,18 @@ class Feed(models.Model):
UpdateFeeds.apply_async(args=(feed_id,), queue='update_feeds')
@classmethod
def drain_task_feeds(cls, empty=False):
def drain_task_feeds(cls):
r = redis.Redis(connection_pool=settings.REDIS_FEED_POOL)
if not empty:
tasked_feeds = r.zrange('tasked_feeds', 0, -1)
logging.debug(" ---> ~FRDraining %s feeds..." % len(tasked_feeds))
r.sadd('queued_feeds', *tasked_feeds)
tasked_feeds = r.zrange('tasked_feeds', 0, -1)
logging.debug(" ---> ~FRDraining %s tasked feeds..." % len(tasked_feeds))
r.sadd('queued_feeds', *tasked_feeds)
r.zremrangebyrank('tasked_feeds', 0, -1)
errored_feeds = r.zrange('error_feeds', 0, -1)
logging.debug(" ---> ~FRDraining %s errored feeds..." % len(errored_feeds))
r.sadd('queued_feeds', *errored_feeds)
r.zremrangebyrank('error_feeds', 0, -1)
def update_all_statistics(self, full=True, force=False):
self.count_subscribers()
@ -881,6 +886,7 @@ class Feed(models.Model):
'mongodb_replication_lag': kwargs.get('mongodb_replication_lag', None),
'fake': kwargs.get('fake'),
'quick': kwargs.get('quick'),
'updates_off': kwargs.get('updates_off'),
'debug': kwargs.get('debug'),
'fpf': kwargs.get('fpf'),
'feed_xml': kwargs.get('feed_xml'),
@ -931,7 +937,7 @@ class Feed(models.Model):
else:
return [Feed.get_by_id(f) for f in feed_ids][:limit]
def add_update_stories(self, stories, existing_stories, verbose=False):
def add_update_stories(self, stories, existing_stories, verbose=False, updates_off=False):
ret_values = dict(new=0, updated=0, same=0, error=0)
error_count = self.error_count
new_story_hashes = [s.get('story_hash') for s in stories]
@ -991,7 +997,7 @@ class Feed(models.Model):
logging.info(' ---> [%-30s] ~SN~FRIntegrityError on new story: %s - %s' % (self.feed_title[:30], story.get('guid'), e))
if self.search_indexed:
s.index_story_for_search()
elif existing_story and story_has_changed:
elif existing_story and story_has_changed and not updates_off and ret_values['updated'] < 3:
# update story
original_content = None
try:
@ -1506,7 +1512,7 @@ class Feed(models.Model):
self.min_to_decay = total
delta = self.next_scheduled_update - datetime.datetime.now()
minutes_to_next_fetch = delta.total_seconds() / 60
minutes_to_next_fetch = (delta.seconds + (delta.days * 24 * 3600)) / 60
if minutes_to_next_fetch > self.min_to_decay or not skip_scheduling:
self.next_scheduled_update = next_scheduled_update
if self.active_subscribers >= 1:
@ -2041,12 +2047,12 @@ class MStory(mongo.Document):
self.image_urls = image_urls
return self.image_urls
def fetch_original_text(self, force=False, request=None):
def fetch_original_text(self, force=False, request=None, debug=False):
original_text_z = self.original_text_z
feed = Feed.get_by_id(self.story_feed_id)
if not original_text_z or force:
ti = TextImporter(self, feed=feed, request=request)
ti = TextImporter(self, feed=feed, request=request, debug=debug)
original_text = ti.fetch()
else:
logging.user(request, "~FYFetching ~FGoriginal~FY story text, ~SBfound.")
@ -2097,7 +2103,7 @@ class MStarredStory(mongo.Document):
return super(MStarredStory, self).save(*args, **kwargs)
@classmethod
def find_stories(cls, query, user_id, tag=None, offset=0, limit=25):
def find_stories(cls, query, user_id, tag=None, offset=0, limit=25, order="newest"):
stories_db = cls.objects(
Q(user_id=user_id) &
(Q(story_title__icontains=query) |
@ -2107,7 +2113,8 @@ class MStarredStory(mongo.Document):
if tag:
stories_db = stories_db.filter(user_tags__contains=tag)
stories_db = stories_db.order_by('-starred_date')[offset:offset+limit]
stories_db = stories_db.order_by('%sstarred_date' %
('-' if order == "newest" else ""))[offset:offset+limit]
stories = Feed.format_stories(stories_db)
return stories
@ -2168,12 +2175,12 @@ class MStarredStory(mongo.Document):
def feed_guid_hash(self):
return "%s:%s" % (self.story_feed_id or "0", self.guid_hash)
def fetch_original_text(self, force=False, request=None):
def fetch_original_text(self, force=False, request=None, debug=False):
original_text_z = self.original_text_z
feed = Feed.get_by_id(self.story_feed_id)
if not original_text_z or force:
ti = TextImporter(self, feed, request=request)
ti = TextImporter(self, feed=feed, request=request, debug=debug)
original_text = ti.fetch()
else:
logging.user(request, "~FYFetching ~FGoriginal~FY story text, ~SBfound.")
@ -2183,9 +2190,10 @@ class MStarredStory(mongo.Document):
class MStarredStoryCounts(mongo.Document):
user_id = mongo.IntField()
tag = mongo.StringField(max_length=128, unique_with=['user_id'])
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',
@ -2196,55 +2204,120 @@ 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 = [{'tag': c.tag, 'count': c.count, 'feed_address': c.rss_url} for c in counts]
counts = sorted([{'tag': c.tag,
'count': c.count,
'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=itemgetter(1),
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)
try:
story_count = cls.objects.get(**params)
except cls.MultipleObjectsReturned:
story_count = cls.objects(**params).first()
if story_count and story_count.count <= 0:
story_count.delete()
class MFetchHistory(mongo.Document):
feed_id = mongo.IntField(unique=True)
feed_fetch_history = mongo.DynamicField()

View file

@ -13,6 +13,8 @@ from django.utils.text import compress_string
from utils import log as logging
from apps.rss_feeds.models import MFeedPage
from utils.feed_functions import timelimit
from OpenSSL.SSL import Error as OpenSSLError
from pyasn1.error import PyAsn1Error
# from utils.feed_functions import mail_feed_error_to_admin
BROKEN_PAGES = [
@ -50,7 +52,6 @@ class PageImporter(object):
's' if self.feed.num_subscribers != 1 else '',
self.feed.permalink,
),
'Connection': 'close',
}
@timelimit(15)
@ -79,9 +80,10 @@ class PageImporter(object):
else:
try:
response = requests.get(feed_link, headers=self.headers)
response.connection.close()
except requests.exceptions.TooManyRedirects:
response = requests.get(feed_link)
except (AttributeError, SocketError), e:
except (AttributeError, SocketError, OpenSSLError, PyAsn1Error), e:
logging.debug(' ***> [%-30s] Page fetch failed using requests: %s' % (self.feed, e))
self.save_no_page()
return

View file

@ -112,6 +112,7 @@ class UpdateFeeds(Task):
options = {
'quick': float(MStatistics.get('quick_fetch', 0)),
'updates_off': MStatistics.get('updates_off', False),
'compute_scores': compute_scores,
'mongodb_replication_lag': mongodb_replication_lag,
}
@ -219,6 +220,6 @@ class SchedulePremiumSetup(Task):
class ScheduleCountTagsForUser(Task):
def run(self, user_id):
from apps.rss_feeds.models import MStarredStory
from apps.rss_feeds.models import MStarredStoryCounts
MStarredStory.count_tags_for_user(user_id)
MStarredStoryCounts.count_for_user(user_id)

View file

@ -7,14 +7,17 @@ from mongoengine.queryset import NotUniqueError
from vendor.readability import readability
from utils import log as logging
from utils.feed_functions import timelimit, TimeoutError
from OpenSSL.SSL import Error as OpenSSLError
from pyasn1.error import PyAsn1Error
class TextImporter:
def __init__(self, story=None, feed=None, story_url=None, request=None):
def __init__(self, story=None, feed=None, story_url=None, request=None, debug=False):
self.story = story
self.story_url = story_url
self.feed = feed
self.request = request
self.debug = debug
@property
def headers(self):
@ -27,7 +30,6 @@ class TextImporter:
's' if self.feed.num_subscribers != 1 else '',
self.feed.permalink,
),
'Connection': 'close',
}
def fetch(self, skip_save=False, return_document=False):
@ -54,7 +56,9 @@ class TextImporter:
text = text.encode(resp.encoding)
except (LookupError, UnicodeEncodeError):
pass
original_text_doc = readability.Document(text, url=resp.url, debug=settings.DEBUG)
original_text_doc = readability.Document(text, url=resp.url,
debug=self.debug,
positive_keywords=["postContent", "postField"])
try:
content = original_text_doc.summary(html_partial=True)
except readability.Unparseable:
@ -94,9 +98,10 @@ class TextImporter:
url = self.story.story_permalink
try:
r = requests.get(url, headers=self.headers, verify=False)
r.connection.close()
except (AttributeError, SocketError, requests.ConnectionError,
requests.models.MissingSchema, requests.sessions.InvalidSchema,
LocationParseError), e:
LocationParseError, OpenSSLError, PyAsn1Error), e:
logging.user(self.request, "~SN~FRFailed~FY to fetch ~FGoriginal text~FY: %s" % e)
return
return r

View file

@ -442,6 +442,7 @@ def original_text(request):
story_id = request.REQUEST.get('story_id')
feed_id = request.REQUEST.get('feed_id')
force = request.REQUEST.get('force', False)
debug = request.REQUEST.get('debug', False)
story, _ = MStory.find_story(story_id=story_id, story_feed_id=feed_id)
@ -449,7 +450,7 @@ def original_text(request):
logging.user(request, "~FYFetching ~FGoriginal~FY story text: ~FRstory not found")
return {'code': -1, 'message': 'Story not found.', 'original_text': None, 'failed': True}
original_text = story.fetch_original_text(force=force, request=request)
original_text = story.fetch_original_text(force=force, request=request, debug=debug)
return {
'feed_id': feed_id,

View file

@ -9,12 +9,14 @@ import random
import requests
import HTMLParser
from collections import defaultdict
from pprint import pprint
from BeautifulSoup import BeautifulSoup
from mongoengine.queryset import Q
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.db.models.aggregates import Sum
from django.template.loader import render_to_string
from django.template.defaultfilters import slugify
from django.core.mail import EmailMultiAlternatives
@ -1118,7 +1120,8 @@ class MSocialSubscription(mongo.Document):
share_key = "S:%s" % (story_hash)
friends_with_shares = [int(f) for f in r.sinter(share_key, friend_key)]
RUserStory.mark_read(self.user_id, feed_id, story_hash, social_user_ids=friends_with_shares)
RUserStory.mark_read(self.user_id, feed_id, story_hash, social_user_ids=friends_with_shares,
aggregated=mark_all_read)
if self.user_id in friends_with_shares:
friends_with_shares.remove(self.user_id)
@ -1486,7 +1489,39 @@ class MSharedStory(mongo.Document):
socialsub.save()
self.delete()
@classmethod
def feed_quota(cls, user_id, feed_id, days=1, quota=1):
day_ago = datetime.datetime.now()-datetime.timedelta(days=days)
shared_count = cls.objects.filter(shared_date__gte=day_ago, story_feed_id=feed_id).count()
return shared_count >= quota
@classmethod
def count_potential_spammers(cls, days=1):
day_ago = datetime.datetime.now()-datetime.timedelta(days=days)
stories = cls.objects.filter(shared_date__gte=day_ago)
shared = [{'u': s.user_id, 'f': s.story_feed_id} for s in stories]
ddusers = defaultdict(lambda: defaultdict(int))
for story in shared:
ddusers[story['u']][story['f']] += 1
users = {}
for user_id, feeds in ddusers.items():
users[user_id] = dict(feeds)
pprint(users)
guaranteed_spammers = []
for user_id in ddusers.keys():
u = User.objects.get(pk=user_id)
feed_opens = UserSubscription.objects.filter(user=u).aggregate(sum=Sum('feed_opens'))['sum']
if not feed_opens: guaranteed_spammers.append(user_id)
print " ---> Guaranteed spammers: %s" % guaranteed_spammers
return users, guaranteed_spammers
@classmethod
def get_shared_stories_from_site(cls, feed_id, user_id, story_url, limit=3):
your_story = cls.objects.filter(story_feed_id=feed_id,
@ -2166,12 +2201,12 @@ class MSharedStory(mongo.Document):
return image_sizes
def fetch_original_text(self, force=False, request=None):
def fetch_original_text(self, force=False, request=None, debug=False):
original_text_z = self.original_text_z
feed = Feed.get_by_id(self.story_feed_id)
if not original_text_z or force:
ti = TextImporter(self, feed, request=request)
ti = TextImporter(self, feed=feed, request=request, debug=False)
original_text = ti.fetch()
else:
logging.user(request, "~FYFetching ~FGoriginal~FY story text, ~SBfound.")

View file

@ -542,6 +542,11 @@ def mark_story_as_shared(request):
'message': 'Could not find the original story and no copies could be found.'
})
if not request.user.profile.is_premium and MSharedStory.feed_quota(request.user.pk, feed_id):
return json.json_response(request, {
'code': -1,
'message': 'Only premium users can share multiple stories per day from the same site.'
})
shared_story = MSharedStory.objects.filter(user_id=request.user.pk,
story_feed_id=feed_id,
story_hash=story['story_hash']).limit(1).first()
@ -581,6 +586,16 @@ def mark_story_as_shared(request):
stories, profiles = MSharedStory.stories_with_comments_and_profiles([story], relative_user_id,
check_all=check_all)
story = stories[0]
starred_stories = MStarredStory.objects(user_id=request.user.pk,
story_feed_id=story['story_feed_id'],
story_hash=story['story_hash'])\
.only('story_hash', 'starred_date', 'user_tags').limit(1)
if starred_stories:
story['user_tags'] = starred_stories[0]['user_tags']
story['starred'] = True
starred_date = localtime_for_timezone(starred_stories[0]['starred_date'],
request.user.profile.timezone)
story['starred_date'] = format_story_link_date__long(starred_date, now)
story['shared_comments'] = strip_tags(shared_story['comments'] or "")
story['shared_by_user'] = True
story['shared'] = True

View file

@ -53,6 +53,7 @@ javascripts:
- media/js/vendor/jquery.tinysort.js
- media/js/vendor/jquery.fieldselection.js
- media/js/vendor/jquery.tipsy.js
- media/js/vendor/jquery.autosize.js
- media/js/vendor/jquery.chosen.js
- media/js/vendor/jquery.effects.core.js
- media/js/vendor/jquery.effects.slideOffscreen.js

View file

@ -41,14 +41,6 @@
android:noHistory="true"
android:label="@string/get_started" />
<activity
android:name=".activity.AddSites"
android:label="@string/add_sites" />
<activity
android:name=".activity.AddFollow"
android:label="@string/add_follow" />
<activity
android:name=".activity.AddTwitter"
android:label="@string/add_twitter" />
@ -60,10 +52,6 @@
<activity
android:name=".activity.AddSocial"
android:label="@string/add_friends" />
<activity
android:name=".activity.ImportFeeds"
android:label="@string/newsblur" />
<activity
android:name=".activity.Main"

View file

@ -0,0 +1,20 @@
body {
background-color: #1A1A1A;
color: #FFF;
}
a {
color: #319DC5;
}
a:visited {
color: #319DC5;
}
code {
background-color: #4C4C4C;
}
pre, blockquote {
background-color: #4C4C4C;
}

View file

@ -0,0 +1,20 @@
body {
background-color: #FFF;
}
a {
color: #405BA8;
}
a:visited {
color: #405BA8;
}
code {
background-color: #F2F2F2;
}
pre, blockquote {
background-color: #F2F2F2;
color: rgba(10, 12, 38, .8);
}

View file

@ -1,5 +1,4 @@
body {
background-color: #FFF;
overflow: hidden;
line-height: 1.5em;
width: 100%;
@ -36,23 +35,15 @@ img, video, embed, object, iframe, div, figure, dl, dt {
}
a {
color: #405BA8;
text-decoration: none;
}
a:visited {
color: #405BA8;
}
code {
background-color: #F2F2F2;
word-wrap: break-word !important;
}
pre, blockquote {
background-color: #F2F2F2;
border-left: 1px solid #C2C5BE;
color: rgba(10, 12, 38, .8);
padding: 0.6em;
margin: 0.6em;
word-wrap: break-word !important;

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/dark_gradient_background_default" />
</layer-list>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="@color/dark_item_header_border" />
<size android:height="1dp" />
</shape>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@color/dark_feed_background" />
</shape>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="rectangle">
<solid android:color="@color/dark_feed_background_selected_start"/>
</shape>
</item>
<item
android:top="0.5dp"
android:bottom="0.5dp">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/dark_feed_background_selected_end"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="90"
android:type="linear"
android:startColor="@color/dark_folder_background_start"
android:endColor="@color/dark_folder_background_end"/>
</shape>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="90"
android:type="linear"
android:startColor="@color/dark_folder_background_selected_start"
android:endColor="@color/dark_folder_background_selected_end"/>
</shape>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<gradient
android:angle= "90"
android:type= "linear"
android:startColor="@color/dark_folder_background_start"
android:endColor= "@color/dark_folder_background_end" />
</shape>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@color/black" />
</shape>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<gradient
android:id="@+id/row_item_feed_gradient"
android:angle= "270"
android:type= "linear"
android:startColor="@color/dark_feed_background_start"
android:endColor= "@color/dark_feed_background_end" />
</shape>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<gradient
android:id="@+id/row_item_header_gradient"
android:angle= "270"
android:type= "linear"
android:startColor="@color/dark_item_header_background_start"
android:endColor= "@color/dark_item_header_background_end" />
</shape>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="@drawable/dark_feed_background_highlight" />
<item android:drawable="@drawable/dark_feed_background_default" />
</selector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="@drawable/dark_folder_background_highlight" />
<item android:drawable="@drawable/dark_folder_background_default" />
</selector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/dark_story_background_highlight"/>
<item android:drawable="@drawable/dark_story_background_default"/>
</selector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/dark_story_background"/>
</shape>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="rectangle">
<solid android:color="@color/dark_story_background_start"/>
</shape>
</item>
<item
android:top="0.5dp"
android:bottom="0.5dp">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/dark_story_background_end"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/half_darkgray" />
<size android:height="1dp" />
</shape>
</item>
<item android:top="1dp">
<shape android:shape="rectangle">
<solid android:color="@color/darkgray" />
<size android:height="0.5dp" />
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="@color/tag_gray_text" />
</shape>
</item>
<item android:bottom="2px">
<shape android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="@color/tag_gray_text" />
</shape>
</item>
</layer-list>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/item_background" >
<FrameLayout
android:id="@+id/addfollow_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:gravity="center"
android:padding="30dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:id="@+id/addfollow_button_bar"
android:gravity="right"
android:padding="10dp">
<Button
android:id="@+id/login_addfollow_startreading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="Start Reading"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>

View file

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/item_background" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:id="@+id/addsites_button_bar"
android:gravity="right"
android:padding="10dp">
<Button
android:id="@+id/login_addsites_nextstep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="Next Step"
android:textSize="14sp" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/addsites_button_bar" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:gravity="center"
android:text="Start your collection of great sites to follow."
android:textSize="20sp" />
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="@drawable/divider_light" />
<FrameLayout
android:id="@+id/addsites_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="20dp" />
</LinearLayout>
</ScrollView>
</RelativeLayout>

View file

@ -25,7 +25,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="Skip this step"
android:text="Start Reading"
android:textSize="14sp" />
</LinearLayout>

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/list_background" >
style="?listBackground" >
<TextView

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/item_background"
style="?itemBackground"
android:orientation="vertical" >
<FrameLayout

View file

@ -69,4 +69,15 @@
</CheckBoxPreference>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/theme">
<ListPreference
android:key="theme"
android:title="@string/theme"
android:dialogTitle="@string/theme"
android:entries="@array/default_theme_entries"
android:entryValues="@array/default_theme_values"
android:defaultValue="@string/default_theme_value" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp" >
<TextView
android:id="@+id/addfollow_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="30dp"
android:text="@string/wonderful_things"
android:textColor="@color/darkgray"
android:textSize="16sp" />
<LinearLayout
android:id="@+id/addfollow_newsblur"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/addfollow_text"
android:layout_gravity="center_vertical"
android:layout_margin="20dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp" >
<TextView
android:id="@+id/addfollow_newsblur_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
android:text="@string/addfollow_add_newsblur"
android:textColor="@color/white"
android:textSize="16sp" />
<CheckBox
android:id="@+id/addfollow_newsblur_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right" />
</LinearLayout>
<LinearLayout
android:id="@+id/addfollow_popular"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/addfollow_newsblur"
android:layout_gravity="center_vertical"
android:layout_margin="20dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp" >
<TextView
android:id="@+id/addfollow_popular_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
android:text="@string/addfollow_add_popular"
android:textColor="@color/white"
android:textSize="16sp" />
<CheckBox
android:id="@+id/addfollow_popular_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right" />
</LinearLayout>
</RelativeLayout>

View file

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
android:orientation="vertical" >
<Button
android:id="@+id/login_add_reader_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_google_reader"
android:textSize="14sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="center_horizontal"
android:text="@string/login_add_sites_from_google_reader"
android:textColor="@color/darkgray"
android:textSize="12sp" />
<LinearLayout
android:id="@+id/login_categories_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ProgressBar
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="20dp"
android:id="@+id/login_categories_progress"
android:indeterminateOnly="true"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</LinearLayout>

View file

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<TextView
android:id="@+id/dialog_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minLines="3"
android:padding="10dp" />
<Button
android:id="@+id/dialog_button_okay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/dialog_message"
android:text="@string/alert_dialog_ok"
android:textSize="14sp" />
<Button
android:id="@+id/dialog_button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/dialog_message"
android:padding="10dp"
android:text="@string/alert_dialog_cancel"
android:textSize="14sp" />
</RelativeLayout>

View file

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<TextView
android:id="@+id/dialog_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp" />
<EditText
android:id="@+id/dialog_share_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/dialog_message"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:singleLine="false"
android:inputType="textCapSentences|textMultiLine"
android:hint="@string/share_comment_hint"
android:textSize="11sp" />
<Button
android:id="@+id/dialog_button_okay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/dialog_share_comment"
android:text="@string/alert_dialog_ok"
android:textSize="14sp" />
<Button
android:id="@+id/dialog_button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/dialog_share_comment"
android:padding="10dp"
android:text="@string/alert_dialog_close"
android:textSize="14sp" />
</RelativeLayout>

View file

@ -4,4 +4,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:background="@drawable/list_background" />
/>

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/actionbar_background"
style="?actionbarBackground"
android:gravity="center"
android:orientation="horizontal" >

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/item_background"
style="?itemBackground"
android:orientation="vertical" >
<TextView
@ -12,7 +12,7 @@
android:layout_centerInParent="true"
android:gravity="center"
android:text="@string/empty_list_view_loading"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="13dp"
android:textStyle="italic" />
@ -20,7 +20,7 @@
android:id="@+id/itemlistfragment_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@drawable/divider_light"
style="?divider"
android:dividerHeight="2dp" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/list_background"
style="?listBackground"
android:gravity="center"
android:orientation="vertical" >
@ -16,6 +16,6 @@
android:text="@string/loading"
android:textColor="@color/white"
android:textSize="20dp"
android:textStyle="bold" />
android:textStyle="bold"/>
</LinearLayout>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<TextView
android:id="@+id/dialog_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp" />
<Button
android:id="@+id/dialog_button_okay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/dialog_message"
android:text="@string/alert_dialog_ok"
android:textSize="14sp" />
<Button
android:id="@+id/dialog_button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/dialog_message"
android:padding="10dp"
android:text="@string/alert_dialog_cancel"
android:textSize="14sp" />
</RelativeLayout>

View file

@ -3,7 +3,7 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@color/item_background" >
style="?itemBackground" >
<TextView
android:layout_width="fill_parent"
@ -12,15 +12,14 @@
android:textColor="@color/white"
android:textSize="16dp"
android:textStyle="bold"
android:background="@drawable/list_background"
style="?listBackground"
android:text="@string/profile_recent_actvity" />
<ListView
android:id="@+id/profile_details_activitylist"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/item_background"
android:divider="@drawable/divider_light"
style="?profileActivityList"
android:dividerHeight="3dp" />
</LinearLayout>

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/item_background"
style="?itemBackground"
android:orientation="vertical" >
<LinearLayout

View file

@ -3,7 +3,7 @@
android:id="@+id/reading_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/item_background" >
style="?itemBackground" >
<LinearLayout
android:layout_width="match_parent"
@ -16,7 +16,7 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:background="@drawable/divider_item_header" />
style="?itemHeaderDivider" />
<include layout="@layout/include_reading_share_bar" />
@ -24,14 +24,14 @@
android:id="@+id/share_bar_underline"
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="@drawable/divider_light"
style="?divider"
android:visibility="gone" />
<com.newsblur.view.NewsblurWebview
android:id="@+id/reading_webview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/item_background"
style="?itemBackground"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="12dp"

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/item_background"
style="?itemBackground"
android:orientation="vertical" >
<RelativeLayout
@ -71,7 +71,7 @@
android:layout_marginRight="10dp"
android:layout_toLeftOf="@id/comment_reply_icon"
android:paddingBottom="3dp"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="12sp" />
<ImageView
@ -102,7 +102,7 @@
android:autoLink="web"
android:layout_marginBottom="4dp"
android:layout_toRightOf="@id/comment_user_image"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="14dp" />
<TextView

View file

@ -16,7 +16,7 @@
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:textColor="@color/half_darkgray"
style="?storyButtons"
android:textSize="12sp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
@ -32,7 +32,7 @@
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:textColor="@color/half_darkgray"
style="?storyButtons"
android:textSize="12sp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
@ -68,13 +68,12 @@
android:layout_height="wrap_content"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:textColor="@color/darkgray"
android:id="@+id/reading_friend_comment_total"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textStyle="bold"
android:textSize="10sp"
android:background="@drawable/gradient_background_default"
style="?commentsHeader"
/>
<View
@ -115,14 +114,13 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/darkgray"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textStyle="bold"
android:textSize="10sp"
android:background="@drawable/gradient_background_default"
style="?commentsHeader"
android:id="@+id/reading_public_comment_total" />
<View

View file

@ -8,7 +8,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:background="@drawable/row_item_header_background">
style="?rowItemHeaderBackground">
<RelativeLayout
android:id="@+id/row_item_feed_header"
@ -18,7 +18,7 @@
android:minHeight="6dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:background="@drawable/row_item_feed_header">
style="?rowItemFeedHeader">
<ImageView
android:id="@+id/reading_feed_icon"
@ -58,7 +58,7 @@
android:layout_marginTop="10dp"
android:layout_marginLeft="16dp"
android:layout_below="@id/item_feed_border"
android:textColor="@color/story_title_unread"
style="?storyTitleUnread"
android:textSize="17sp" />
<TextView
@ -69,7 +69,7 @@
android:layout_alignLeft="@id/reading_item_title"
android:layout_marginRight="12dp"
android:layout_marginTop="8dp"
android:textColor="@color/half_darkgray"
style="?readingItemMetadata"
android:textSize="12sp" />
<TextView
@ -80,7 +80,7 @@
android:layout_toRightOf="@id/reading_item_date"
android:maxLines="1"
android:minWidth="80dp"
android:textColor="@color/half_darkgray"
style="?readingItemMetadata"
android:textSize="12sp"
android:textStyle="bold"/>

View file

@ -7,7 +7,7 @@
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:visibility="gone"
android:background="@color/share_bar_background">
style="?shareBarBackground">
<View
android:id="@+id/center_filler"
@ -23,13 +23,9 @@
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="5dp"
android:textColor="@color/midgray"
style="?shareBarText"
android:textSize="11sp"
android:textStyle="bold"
android:shadowColor="@color/white"
android:shadowDx="0"
android:shadowDy="1"
android:shadowRadius="1" />
android:textStyle="bold" />
<TextView
android:id="@+id/shared_by"
@ -39,13 +35,9 @@
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:layout_marginRight="16dp"
android:textColor="@color/midgray"
style="?shareBarText"
android:textSize="11sp"
android:textStyle="bold"
android:shadowColor="@color/white"
android:shadowDx="0"
android:shadowDy="1"
android:shadowRadius="1" />
android:textStyle="bold" />
<com.newsblur.view.FlowLayout
android:id="@+id/reading_social_commentimages"

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/item_background"
style="?itemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="12dp"
@ -35,7 +35,7 @@
android:layout_alignParentRight="true"
android:layout_marginRight="26dp"
android:layout_marginTop="5dp"
android:textColor="@color/lightgray"
style="?defaultText"
android:textSize="12sp" />
<TextView
@ -57,7 +57,7 @@
android:layout_marginTop="5dp"
android:autoLink="web"
android:layout_toRightOf="@id/reply_user_image"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="14dp" />
</RelativeLayout>

View file

@ -15,10 +15,9 @@
android:layout_height="fill_parent"
android:layout_marginRight="1dp"
android:layout_weight="1"
android:background="@color/item_background"
style="?profileCount"
android:gravity="center_horizontal"
android:paddingTop="12dp"
android:textColor="@color/darkgray"
android:textSize="30dp"
android:textStyle="bold" />
@ -28,10 +27,9 @@
android:layout_height="fill_parent"
android:layout_marginRight="1dp"
android:layout_weight="1"
android:background="@color/item_background"
style="?profileCount"
android:gravity="center_horizontal"
android:paddingTop="12dp"
android:textColor="@color/darkgray"
android:textSize="30dp"
android:textStyle="bold" />
@ -41,10 +39,9 @@
android:layout_height="fill_parent"
android:layout_marginRight="1dp"
android:layout_weight="1"
android:background="@color/item_background"
style="?profileCount"
android:gravity="center_horizontal"
android:paddingTop="12dp"
android:textColor="@color/darkgray"
android:textSize="30dp"
android:textStyle="bold" />
@ -59,12 +56,11 @@
android:layout_height="fill_parent"
android:layout_marginRight="1dp"
android:layout_weight="1"
android:background="@color/item_background"
style="?profileCount"
android:gravity="center_horizontal"
android:paddingBottom="15dp"
android:paddingTop="3dp"
android:text="@string/profile_shared"
android:textColor="@color/darkgray"
android:textSize="11dp" />
<TextView
@ -72,12 +68,11 @@
android:layout_height="fill_parent"
android:layout_marginRight="1dp"
android:layout_weight="1"
android:background="@color/item_background"
style="?profileCount"
android:gravity="center_horizontal"
android:paddingBottom="15dp"
android:paddingTop="3dp"
android:text="@string/profile_following"
android:textColor="@color/darkgray"
android:textSize="11dp" />
<TextView
@ -85,12 +80,11 @@
android:layout_height="fill_parent"
android:layout_marginRight="1dp"
android:layout_weight="1"
android:background="@color/item_background"
style="?profileCount"
android:gravity="center_horizontal"
android:paddingBottom="15dp"
android:paddingTop="3dp"
android:text="@string/profile_followers"
android:textColor="@color/darkgray"
android:textSize="11dp" />
</TableRow>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<EditText
android:id="@+id/reply_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:singleLine="false"
android:inputType="textCapSentences|textMultiLine" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/item_background"
style="?itemBackground"
android:paddingBottom="10dp"
android:paddingTop="10dp" >
@ -23,19 +23,18 @@
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="10dp"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="10dp" />
<TextView
android:id="@+id/row_activity_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColorLink="@color/linkblue"
android:layout_alignParentTop="true"
android:layout_marginRight="10dp"
android:layout_toLeftOf="@id/row_activity_time"
android:layout_toRightOf="@id/row_activity_icon"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="13dp" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_folder_background" >
style="?selectorFolderBackground" >
<ImageView
android:id="@+id/row_everything_icon"
@ -80,7 +80,7 @@
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="@string/all_shared_stories"
android:textColor="@color/folder_text"
style="?selectorRowFeedName"
android:textSize="14dp"
android:textStyle="bold" />
@ -88,11 +88,11 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentTop="true"
android:background="@color/folder_border_top" />
style="?folderBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@color/folder_border_bottom" />
style="?folderBorderBottom" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_folder_background" >
style="?selectorFolderBackground" >
<ImageView
android:id="@+id/row_everything_icon"
@ -24,7 +24,7 @@
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="@string/all_stories_row_title"
android:textColor="@color/folder_text"
style="?selectorRowFeedName"
android:textSize="14dp"
android:textStyle="bold" />
@ -79,11 +79,11 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentTop="true"
android:background="@color/folder_border_top" />
style="?folderBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@color/folder_border_bottom" />
style="?folderBorderBottom" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_feed_background"
style="?selectorFeedBackground"
android:orientation="vertical" >
<LinearLayout
@ -68,7 +68,7 @@
android:layout_toRightOf="@id/row_feedfavicon"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/folder_text"
style="?selectorRowFeedName"
android:textSize="14sp"
android:textStyle="bold" />

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/item_background"
style="?itemBackground"
android:focusable="false">
<RelativeLayout
@ -42,7 +42,7 @@
android:ellipsize="end"
android:singleLine="true"
android:textStyle="bold"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="15sp" />
<TextView
@ -53,7 +53,7 @@
android:layout_below="@id/row_result_feedicon"
android:layout_marginRight="8dp"
android:paddingTop="8dp"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="20sp" />
<TextView
@ -63,7 +63,7 @@
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:paddingTop="8dp"
android:textColor="@color/darkgray"
style="?defaultText"
android:textSize="15sp" />
<TextView
@ -75,8 +75,7 @@
android:layout_marginRight="8dp"
android:paddingTop="8dp"
android:paddingBottom="12dp"
android:textColor="@color/darkgray"
android:textColorLink="@color/linkblue"
style="?defaultText"
android:textSize="13sp" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_folder_background"
style="?selectorFolderBackground"
android:addStatesFromChildren="true" >
<ImageView
@ -78,12 +78,11 @@
android:layout_centerVertical="true"
android:layout_toRightOf="@id/row_folder_icon"
android:layout_toLeftOf="@+id/row_foldersums"
android:textColor="@color/folder_text"
style="?selectorRowFolderName"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:textSize="13sp"
android:textStyle="bold"
android:shadowColor="@color/white"
android:shadowDy="1"
android:shadowRadius="1"
android:maxLines="1"
@ -91,13 +90,13 @@
<View
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="@color/folder_border_top"
android:layout_width="match_parent"
style="?folderBorderTop"
android:layout_alignParentTop="true" />
<View
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="@color/folder_border_bottom"
android:layout_width="match_parent"
style="?folderBorderBottom"
android:layout_alignParentBottom="true" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_story_background"
style="?selectorStoryBackground"
android:orientation="horizontal" >
<RelativeLayout

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_story_background"
style="?selectorStoryBackground"
android:orientation="horizontal" >
<RelativeLayout

View file

@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_folder_background" >
style="?selectorFolderBackground" >
<ImageView
android:id="@+id/row_saved_icon"
@ -24,7 +24,7 @@
android:paddingBottom="9dp"
android:paddingTop="9dp"
android:text="@string/saved_stories_row_title"
android:textColor="@color/folder_text"
style="?selectorRowFeedName"
android:textSize="13dp"
android:textStyle="bold" />
@ -52,11 +52,11 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentTop="true"
android:background="@color/folder_border_top" />
style="?folderBorderTop" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@color/folder_border_bottom" />
style="?folderBorderBottom" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_story_background"
style="?selectorStoryBackground"
android:orientation="horizontal" >
<RelativeLayout

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<EditText
android:id="@+id/comment_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:singleLine="false"
android:inputType="textCapSentences|textMultiLine"
android:hint="@string/share_comment_hint"/>
</RelativeLayout>

View file

@ -3,9 +3,8 @@
android:id="@+id/tag_text"
android:layout_width="60dp"
android:layout_height="15dp"
android:background="@drawable/tag_background_neutral"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="1dp"
android:textColor="@color/tag_gray_text"
style="?tag"
android:textSize="11sp" />

View file

@ -2,6 +2,30 @@
<resources>
<attr name="flow" format="string" />
<attr name="defaultImageSize" format="integer" />
<attr name="selectorFolderBackground" format="string" />
<attr name="selectorFeedBackground" format="string" />
<attr name="selectorRowFolderName" format="string" />
<attr name="selectorRowFeedName" format="string" />
<attr name="actionbarBackground" format="string" />
<attr name="listBackground" format="string" />
<attr name="itemBackground" format="string" />
<attr name="defaultText" format="string" />
<attr name="selectorStoryBackground" format="string" />
<attr name="rowItemHeaderBackground" format="string" />
<attr name="rowItemFeedHeader" format="string" />
<attr name="storyTitleUnread" format="string" />
<attr name="readingItemMetadata" format="string" />
<attr name="tag" format="string" />
<attr name="storyButtons" format="string" />
<attr name="shareBarBackground" format="string" />
<attr name="shareBarText" format="string" />
<attr name="commentsHeader" format="string" />
<attr name="folderBorderTop" format="string" />
<attr name="folderBorderBottom" format="string" />
<attr name="divider" format="string" />
<attr name="profileCount" format="string" />
<attr name="profileActivityList" format="string" />
<attr name="itemHeaderDivider" format="string" />
<declare-styleable name="FlowLayout">
<attr name="flow" />

View file

@ -5,32 +5,52 @@
<color name="darkgray">#434343</color>
<color name="midgray">#898989</color>
<color name="lightgray">#ccc</color>
<color name="black">#000000</color>
<color name="folder_background_end">#E9EBE4</color>
<color name="folder_background_start">#DDE0D7</color>
<color name="dark_folder_background_end">#000000</color>
<color name="dark_folder_background_start">#7000</color>
<color name="folder_background_selected_end">#D9DBD4</color>
<color name="folder_background_selected_start">#CDD0C7</color>
<color name="dark_folder_background_selected_end">#4C4C4C</color>
<color name="dark_folder_background_selected_start">#1A1A1A</color>
<color name="folder_text">#4C4C4C</color>
<color name="dark_folder_text">#FDFDFD</color>
<color name="folder_border_top">#FDFDFD</color>
<color name="folder_border_bottom">#B7BBAA</color>
<color name="dark_folder_border_top">#434343</color>
<color name="dark_folder_border_bottom">#3B3B3B</color>
<color name="feed_background">#F7F8F5</color>
<color name="dark_feed_background">#1A1A1A</color>
<color name="feed_background_end">#303030</color>
<color name="feed_background_start">#505050</color>
<color name="dark_feed_background_end">#303030</color>
<color name="dark_feed_background_start">#505050</color>
<color name="feed_background_selected_end">#FFFFD2</color>
<color name="feed_background_selected_start">#E3D0AE</color>
<color name="dark_feed_background_selected_end">#4C4C4C</color>
<color name="dark_feed_background_selected_start">#1A1A1A</color>
<color name="story_background">#F7F8F5</color>
<color name="story_background_end">#FFFDEF</color>
<color name="story_background_start">#DFDDCF</color>
<color name="dark_story_background">#1A1A1A</color>
<color name="dark_story_background_end">#4C4C4C</color>
<color name="dark_story_background_start">#1A1A1A</color>
<color name="story_title_unread">#333333</color>
<color name="dark_story_title_unread">#FFFDEF</color>
<color name="story_title_read">#808080</color>
<color name="story_content_unread">#404040</color>
<color name="dark_story_content_unread">#F7F8F5</color>
<color name="story_content_read">#909090</color>
<color name="story_feed_unread">#606060</color>
<color name="dark_story_feed_unread">#F7F8F5</color>
<color name="story_feed_read">#A0A0A0</color>
<color name="story_author_unread">#959595</color>
<color name="story_author_read">#C0C0C0</color>
<color name="story_date_unread">#262C6C</color>
<color name="dark_story_date_unread">#DFDDCF</color>
<color name="story_date_read">#BABDD1</color>
<color name="story_comment_divider">#F0F0F0</color>
@ -39,9 +59,14 @@
<color name="item_header_background_start">#FEFEFE</color>
<color name="item_header_background_end">#F3F4EF</color>
<color name="dark_item_header_background_start">#505050</color>
<color name="dark_item_header_background_end">#303030</color>
<color name="item_header_border">#C2C5BE</color>
<color name="dark_item_header_border">#42453E</color>
<color name="item_background">#FFF</color>
<color name="dark_item_background">#1A1A1A</color>
<color name="share_bar_background">#F5F5EF</color>
<color name="dark_share_bar_background">#303030</color>
<color name="half_black">#7000</color>
@ -59,6 +84,7 @@
<color name="saved_drop_shadow">#0E366f</color>
<color name="linkblue">#405BA8</color>
<color name="dark_linkblue">#319DC5</color>
<color name="negative">#CC2A2E</color>
@ -80,6 +106,8 @@
<color name="status_overlay_text">#DD111111</color>
<color name="status_overlay_background">#AA777777</color>
<color name="story_buttons_dark">#90928b</color>
<!-- To use a selector on a bg color, the options must be drawables, not colors. -->
<drawable name="toggle_bg_selected">#fdfdfd</drawable>
<drawable name="toggle_bg_normal">#dfe1dd</drawable>

View file

@ -141,8 +141,6 @@
<string name="empty_list_view_no_stories">No stories to read</string>
<string name="login_registration_register">Register</string>
<string name="login_google_reader">Google Reader</string>
<string name="login_add_sites_from_google_reader">Import your sites from Google Reader</string>
<string name="add_sites">Add some sites</string>
<string name="get_started">Let\'s get started</string>
<string name="add_friends">Add your friends</string>
@ -234,4 +232,17 @@
<string name="story">Story</string>
<string name="text">Text</string>
<string name="theme">Theme</string>
<string name="light">Light</string>
<string name="dark">Dark</string>
<string-array name="default_theme_entries">
<item>@string/light</item>
<item>@string/dark</item>
</string-array>
<string-array name="default_theme_values">
<item>light</item>
<item>dark</item>
</string-array>
<string name="default_theme_value">light</string>
</resources>

View file

@ -1,15 +1,244 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="dialog" parent="@android:style/Theme.Dialog">
<style name="classifyDialog" parent="@android:style/Theme.Dialog">
<item name="android:background">@drawable/actionbar_background</item>
<item name="android:textColor">@color/darkgray</item>
<item name="android:textSize">15dp</item>
<item name="android:padding">10dp</item>
</style>
<style name="darkClassifyDialog" parent="@android:style/Theme.Dialog">
<item name="android:background">@drawable/dark_actionbar_background</item>
<item name="android:textColor">@color/lightgray</item>
<item name="android:textSize">15dp</item>
<item name="android:padding">10dp</item>
</style>
<style name="actionbar" parent="@android:style/Widget.Holo.Light.ActionBar">
<item name="android:background">@drawable/actionbar_background</item>
</style>
<style name="actionbar.dark" parent="@android:style/Widget.Holo.ActionBar">
<item name="android:background">@drawable/dark_actionbar_background</item>
</style>
<style name="expandableListView" parent="@android:style/Widget.Holo.Light.ExpandableListView">
<item name="android:background">@drawable/list_background</item>
</style>
<style name="expandableListView.dark" parent="@android:style/Widget.Holo.ExpandableListView">
<item name="android:background">@drawable/dark_list_background</item>
</style>
<style name="selectorFolderBackground">
<item name="android:background">@drawable/selector_folder_background</item>
</style>
<style name="selectorFolderBackground.dark">
<item name="android:background">@drawable/dark_selector_folder_background</item>
</style>
<style name="selectorFeedBackground">
<item name="android:background">@drawable/selector_feed_background</item>
</style>
<style name="selectorFeedBackground.dark">
<item name="android:background">@drawable/dark_selector_feed_background</item>
</style>
<style name="selectorRowFolderName">
<item name="android:textColor">@color/folder_text</item>
<item name="android:shadowColor">@color/white</item>
</style>
<style name="selectorRowFolderName.dark">
<item name="android:textColor">@color/dark_folder_text</item>
<item name="android:shadowColor">@color/white</item>
</style>
<style name="selectorRowFeedName">
<item name="android:textColor">@color/folder_text</item>
</style>
<style name="selectorRowFeedName.dark">
<item name="android:textColor">@color/dark_folder_text</item>
</style>
<style name="actionbarBackground">
<item name="android:background">@drawable/actionbar_background</item>
</style>
<style name="actionbarBackground.dark">
<item name="android:background">@drawable/dark_actionbar_background</item>
</style>
<style name="listBackground">
<item name="android:background">@drawable/list_background</item>
</style>
<style name="listBackground.dark">
<item name="android:background">@drawable/dark_list_background</item>
</style>
<style name="itemBackground">
<item name="android:background">@color/item_background</item>
</style>
<style name="itemBackground.dark">
<item name="android:background">@color/dark_item_background</item>
</style>
<style name="defaultText">
<item name="android:textColorLink">@color/linkblue</item>
<item name="android:textColor">@color/darkgray</item>
</style>
<style name="defaultText.dark">
<item name="android:textColorLink">@color/dark_linkblue</item>
<item name="android:textColor">@color/white</item>
</style>
<style name="selectorStoryBackground">
<item name="android:background">@drawable/selector_story_background</item>
</style>
<style name="selectorStoryBackground.dark">
<item name="android:background">@drawable/dark_selector_story_background</item>
</style>
<style name="rowItemHeaderBackground">
<item name="android:background">@drawable/row_item_header_background</item>
</style>
<style name="rowItemHeaderBackground.dark">
<item name="android:background">@drawable/dark_row_item_header_background</item>
</style>
<style name="rowItemFeedHeader">
<item name="android:background">@drawable/row_item_feed_header</item>
</style>
<style name="rowItemFeedHeader.dark">
<item name="android:background">@drawable/dark_row_item_feed_header</item>
</style>
<style name="storyTitleUnread">
<item name="android:textColor">@color/story_title_unread</item>
</style>
<style name="storyTitleUnread.dark">
<item name="android:textColor">@color/dark_story_title_unread</item>
</style>
<style name="readingItemMetadata">
<item name="android:textColor">@color/half_darkgray</item>
</style>
<style name="readingItemMetadata.dark">
<item name="android:textColor">@color/half_white</item>
</style>
<style name="tag">
<item name="android:textColor">@color/tag_gray_text</item>
<item name="android:background">@drawable/tag_background_neutral</item>
</style>
<style name="tag.dark">
<item name="android:textColor">@color/tag_gray_shadow</item>
<item name="android:background">@drawable/tag_background_dark</item>
</style>
<style name="storyButtons">
<item name="android:textColor">@color/half_darkgray</item>
</style>
<style name="storyButtons.dark">
<item name="android:textColor">@color/story_buttons_dark</item>
</style>
<style name="shareBarBackground">
<item name="android:background">@color/share_bar_background</item>
</style>
<style name="shareBarBackground.dark">
<item name="android:background">@color/dark_share_bar_background</item>
</style>
<style name="shareBarText">
<item name="android:textColor">@color/midgray</item>
<item name="android:shadowColor">@color/white</item>
<item name="android:shadowDx">0</item>
<item name="android:shadowDy">1</item>
<item name="android:shadowRadius">1</item>
</style>
<style name="shareBarText.dark">
<item name="android:textColor">@color/midgray</item>
<item name="android:shadowDx">0</item>
<item name="android:shadowDy">0</item>
<item name="android:shadowRadius">0</item>
</style>
<style name="commentsHeader">
<item name="android:background">@drawable/gradient_background_default</item>
<item name="android:textColor">@color/darkgray</item>
</style>
<style name="commentsHeader.dark">
<item name="android:background">@drawable/dark_gradient_background_default</item>
<item name="android:textColor">@color/midgray</item>
</style>
<style name="folderBorderTop">
<item name="android:background">@color/folder_border_top</item>
</style>
<style name="folderBorderTop.dark">
<item name="android:background">@color/dark_folder_border_top</item>
</style>
<style name="folderBorderBottom">
<item name="android:background">@color/folder_border_bottom</item>
</style>
<style name="folderBorderBottom.dark">
<item name="android:background">@color/dark_folder_border_bottom</item>
</style>
<style name="divider">
<item name="android:divider">@drawable/divider_light</item>
</style>
<style name="divider.dark">
<item name="android:divider">@drawable/divider_dark</item>
</style>
<style name="profileCount">
<item name="android:background">@color/item_background</item>
<item name="android:textColor">@color/darkgray</item>
</style>
<style name="profileCount.dark">
<item name="android:background">@color/dark_item_background</item>
<item name="android:textColor">@color/white</item>
</style>
<style name="profileActivityList">
<item name="android:background">@color/item_background</item>
<item name="android:divider">@drawable/divider_light</item>
</style>
<style name="profileActivityList.dark">
<item name="android:background">@color/dark_item_background</item>
<item name="android:divider">@drawable/divider_dark</item>
</style>
<style name="itemHeaderDivider">
<item name="android:background">@drawable/divider_item_header</item>
</style>
<style name="itemHeaderDivider.dark">
<item name="android:background">@drawable/dark_divider_item_header</item>
</style>
</resources>

View file

@ -2,5 +2,59 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="NewsBlurTheme" parent="@android:style/Theme.Holo.Light" >
<item name="android:actionBarStyle">@style/actionbar</item>
<item name="android:expandableListViewStyle">@style/expandableListView</item>
<item name="selectorFolderBackground">@style/selectorFolderBackground</item>
<item name="selectorFeedBackground">@style/selectorFeedBackground</item>
<item name="selectorRowFolderName">@style/selectorRowFolderName</item>
<item name="selectorRowFeedName">@style/selectorRowFeedName</item>
<item name="actionbarBackground">@style/actionbarBackground</item>
<item name="listBackground">@style/listBackground</item>
<item name="itemBackground">@style/itemBackground</item>
<item name="defaultText">@style/defaultText</item>
<item name="selectorStoryBackground">@style/selectorStoryBackground</item>
<item name="rowItemHeaderBackground">@style/rowItemHeaderBackground</item>
<item name="rowItemFeedHeader">@style/rowItemFeedHeader</item>
<item name="storyTitleUnread">@style/storyTitleUnread</item>
<item name="readingItemMetadata">@style/readingItemMetadata</item>
<item name="tag">@style/tag</item>
<item name="storyButtons">@style/storyButtons</item>
<item name="shareBarBackground">@style/shareBarBackground</item>
<item name="shareBarText">@style/shareBarText</item>
<item name="commentsHeader">@style/commentsHeader</item>
<item name="folderBorderTop">@style/folderBorderTop</item>
<item name="folderBorderBottom">@style/folderBorderBottom</item>
<item name="divider">@style/divider</item>
<item name="profileCount">@style/profileCount</item>
<item name="profileActivityList">@style/profileActivityList</item>
<item name="itemHeaderDivider">@style/itemHeaderDivider</item>
</style>
<style name="NewsBlurDarkTheme" parent="@android:style/Theme.Holo" >
<item name="android:actionBarStyle">@style/actionbar.dark</item>
<item name="android:expandableListViewStyle">@style/expandableListView.dark</item>
<item name="selectorFolderBackground">@style/selectorFolderBackground.dark</item>
<item name="selectorFeedBackground">@style/selectorFeedBackground.dark</item>
<item name="selectorRowFolderName">@style/selectorRowFolderName.dark</item>
<item name="selectorRowFeedName">@style/selectorRowFeedName.dark</item>
<item name="actionbarBackground">@style/actionbarBackground.dark</item>
<item name="listBackground">@style/listBackground.dark</item>
<item name="itemBackground">@style/itemBackground.dark</item>
<item name="defaultText">@style/defaultText.dark</item>
<item name="selectorStoryBackground">@style/selectorStoryBackground.dark</item>
<item name="rowItemHeaderBackground">@style/rowItemHeaderBackground.dark</item>
<item name="rowItemFeedHeader">@style/rowItemFeedHeader.dark</item>
<item name="storyTitleUnread">@style/storyTitleUnread.dark</item>
<item name="readingItemMetadata">@style/readingItemMetadata.dark</item>
<item name="tag">@style/tag.dark</item>
<item name="storyButtons">@style/storyButtons.dark</item>
<item name="shareBarBackground">@style/shareBarBackground.dark</item>
<item name="shareBarText">@style/shareBarText.dark</item>
<item name="commentsHeader">@style/commentsHeader.dark</item>
<item name="folderBorderTop">@style/folderBorderTop.dark</item>
<item name="folderBorderBottom">@style/folderBorderBottom.dark</item>
<item name="divider">@style/divider.dark</item>
<item name="profileCount">@style/profileCount.dark</item>
<item name="profileActivityList">@style/profileActivityList.dark</item>
<item name="itemHeaderDivider">@style/itemHeaderDivider.dark</item>
</style>
</resources>

View file

@ -1,44 +0,0 @@
package com.newsblur.activity;
import android.content.Intent;
import android.os.Bundle;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.newsblur.R;
import com.newsblur.fragment.AddFollowFragment;
public class AddFollow extends NbActivity {
private FragmentManager fragmentManager;
private String currentTag = "addFollowFragment";
private AddFollowFragment addFollowFragment;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_addfollow);
fragmentManager = getFragmentManager();
if (fragmentManager.findFragmentByTag(currentTag ) == null) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
addFollowFragment = new AddFollowFragment();
transaction.add(R.id.addfollow_container, addFollowFragment, currentTag);
transaction.commit();
}
Button startReading = (Button) findViewById(R.id.login_addfollow_startreading);
startReading.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(AddFollow.this, Main.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
});
};
}

View file

@ -1,69 +0,0 @@
package com.newsblur.activity;
import java.util.ArrayList;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.newsblur.R;
import com.newsblur.fragment.AddSitesListFragment;
import com.newsblur.network.APIManager;
public class AddSites extends NbActivity {
private FragmentManager fragmentManager;
private String currentTag = "addsitesFragment";
private AddSitesListFragment sitesList;
private APIManager apiManager;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity_addsites);
apiManager = new APIManager(this);
fragmentManager = getFragmentManager();
if (fragmentManager.findFragmentByTag(currentTag ) == null) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
sitesList = new AddSitesListFragment();
transaction.add(R.id.addsites_container, sitesList, currentTag);
transaction.commit();
}
Button nextStep = (Button) findViewById(R.id.login_addsites_nextstep);
nextStep.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
final ArrayList<String> categories = sitesList.getSelectedCategories();
apiManager.addCategories(categories);
return null;
}
}.execute();
Intent i = new Intent(AddSites.this, AddSocial.class);
startActivity(i);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent i) {
if ((resultCode == RESULT_OK) && (sitesList != null)) {
sitesList.setGoogleReaderImported();
}
}
}

View file

@ -35,8 +35,9 @@ public class AddSocial extends NbActivity {
nextStep.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent i = new Intent(AddSocial.this, AddFollow.class);
startActivity(i);
Intent i = new Intent(AddSocial.this, Main.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
});

View file

@ -25,7 +25,8 @@ public class AllSharedStoriesReading extends Reading {
feedIds = getIntent().getStringArrayExtra(Reading.EXTRA_FEED_IDS);
setTitle(getResources().getString(R.string.all_shared_stories));
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView);
// No sourceUserId since this is all shared stories. The sourceUsedId for each story will be used.
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView, null);
getLoaderManager().initLoader(0, null, this);
}

View file

@ -24,7 +24,7 @@ public class AllStoriesReading extends Reading {
feedIds = getIntent().getStringArrayExtra(Reading.EXTRA_FEED_IDS);
setTitle(getResources().getString(R.string.all_stories_row_title));
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView);
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView, null);
getLoaderManager().initLoader(0, null, this);
}

View file

@ -24,7 +24,7 @@ public class FolderReading extends Reading {
folderName = getIntent().getStringExtra(Reading.EXTRA_FOLDERNAME);
setTitle(folderName);
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView);
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView, null);
getLoaderManager().initLoader(0, null, this);
}

View file

@ -1,39 +0,0 @@
package com.newsblur.activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.newsblur.R;
import com.newsblur.network.APIConstants;
public class ImportFeeds extends NbActivity {
private WebView webContainer;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_webcontainer);
webContainer = (WebView) findViewById(R.id.webcontainer);
webContainer.getSettings().setJavaScriptEnabled(true);
webContainer.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url){
if (TextUtils.equals(url, APIConstants.NEWSBLUR_URL + "/")) {
ImportFeeds.this.setResult(RESULT_OK);
ImportFeeds.this.finish();
return true;
}
view.loadUrl(url);
return false;
}
});
webContainer.loadUrl(APIConstants.URL_IMPORT_AUTHORIZATION);
}
}

View file

@ -12,6 +12,7 @@ import android.view.Window;
import com.newsblur.R;
import com.newsblur.fragment.LoginRegisterFragment;
import com.newsblur.util.PrefConstants;
import com.newsblur.util.PrefsUtils;
public class Login extends Activity {
@ -20,6 +21,8 @@ public class Login extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
PrefsUtils.applyThemePreference(this);
super.onCreate(savedInstanceState);
preferenceCheck();
requestWindowFeature(Window.FEATURE_NO_TITLE);

View file

@ -9,6 +9,7 @@ import android.view.Window;
import com.newsblur.R;
import com.newsblur.fragment.LoginProgressFragment;
import com.newsblur.util.PrefsUtils;
public class LoginProgress extends Activity {
@ -18,6 +19,8 @@ public class LoginProgress extends Activity {
@Override
protected void onCreate(Bundle bundle) {
PrefsUtils.applyThemePreference(this);
super.onCreate(bundle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_loginprogress);

View file

@ -6,7 +6,6 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@ -20,6 +19,8 @@ import com.newsblur.fragment.LogoutDialogFragment;
import com.newsblur.service.BootReceiver;
import com.newsblur.service.NBSyncService;
import com.newsblur.util.FeedUtils;
import com.newsblur.util.PrefsUtils;
import com.newsblur.util.UIUtils;
import com.newsblur.view.StateToggleButton.StateChangedListener;
public class Main extends NbActivity implements StateChangedListener {
@ -29,12 +30,15 @@ public class Main extends NbActivity implements StateChangedListener {
private FragmentManager fragmentManager;
private Menu menu;
private TextView overlayStatusText;
private boolean isLightTheme;
@Override
public void onCreate(Bundle savedInstanceState) {
PreferenceManager.setDefaultValues(this, R.layout.activity_settings, false);
isLightTheme = PrefsUtils.isLightThemeSelected(this);
requestWindowFeature(Window.FEATURE_PROGRESS);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.onCreate(savedInstanceState);
@ -59,6 +63,10 @@ public class Main extends NbActivity implements StateChangedListener {
// this view doesn't show stories, it is safe to perform cleanup
NBSyncService.holdStories(false);
triggerSync();
if (PrefsUtils.isLightThemeSelected(this) != isLightTheme) {
UIUtils.restartActivity(this);
}
}
private void setupActionBar() {

View file

@ -30,6 +30,9 @@ public class NbActivity extends Activity {
@Override
protected void onCreate(Bundle bundle) {
if (AppConstants.VERBOSE_LOG) Log.d(this.getClass().getName(), "onCreate");
PrefsUtils.applyThemePreference(this);
super.onCreate(bundle);
if (bundle != null) {

View file

@ -288,7 +288,7 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
startActivity(i);
return true;
} else if (item.getItemId() == R.id.menu_reading_sharenewsblur) {
DialogFragment newFragment = ShareDialogFragment.newInstance(getReadingFragment(), story, getReadingFragment().previouslySavedShareText);
DialogFragment newFragment = ShareDialogFragment.newInstance(getReadingFragment(), story, getReadingFragment().previouslySavedShareText, readingAdapter.getSourceUserId());
newFragment.show(getFragmentManager(), "dialog");
return true;
} else if (item.getItemId() == R.id.menu_shared) {

View file

@ -14,10 +14,12 @@ public abstract class ReadingAdapter extends FragmentStatePagerAdapter {
protected Cursor stories;
protected DefaultFeedView defaultFeedView;
protected String sourceUserId;
public ReadingAdapter(FragmentManager fm, DefaultFeedView defaultFeedView) {
public ReadingAdapter(FragmentManager fm, DefaultFeedView defaultFeedView, String sourceUserId) {
super(fm);
this.defaultFeedView = defaultFeedView;
this.sourceUserId = sourceUserId;
}
@Override
@ -74,4 +76,7 @@ public abstract class ReadingAdapter extends FragmentStatePagerAdapter {
}
}
public String getSourceUserId() {
return sourceUserId;
}
}

View file

@ -7,6 +7,7 @@ import android.app.FragmentTransaction;
import com.newsblur.R;
import com.newsblur.fragment.RegisterProgressFragment;
import com.newsblur.util.PrefsUtils;
/**
* Show progress screen while registering request is being processed. This
@ -20,6 +21,8 @@ public class RegisterProgress extends Activity {
@Override
protected void onCreate(Bundle bundle) {
PrefsUtils.applyThemePreference(this);
super.onCreate(bundle);
setContentView(R.layout.activity_loginprogress);

View file

@ -18,7 +18,7 @@ public class SavedStoriesReading extends Reading {
super.onCreate(savedInstanceBundle);
setTitle(getResources().getString(R.string.saved_stories_title));
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView);
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView, null);
getLoaderManager().initLoader(0, null, this);
}

View file

@ -2,20 +2,29 @@ package com.newsblur.activity;
import com.newsblur.R;
import com.newsblur.util.PrefConstants;
import com.newsblur.util.PrefsUtils;
import com.newsblur.util.UIUtils;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.view.MenuItem;
public class Settings extends PreferenceActivity {
public class Settings extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
PrefsUtils.applyThemePreference(this);
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
super.getPreferenceManager().setSharedPreferencesName(PrefConstants.PREFERENCES);
PreferenceManager preferenceManager = super.getPreferenceManager();
preferenceManager.setSharedPreferencesName(PrefConstants.PREFERENCES);
SharedPreferences prefs = getSharedPreferences(PrefConstants.PREFERENCES, 0);
prefs.registerOnSharedPreferenceChangeListener(this);
addPreferencesFromResource(R.layout.activity_settings);
// Remove the reading category of references on pre-4.4 devices as it only contains
@ -26,6 +35,14 @@ public class Settings extends PreferenceActivity {
}
}
@Override
protected void onDestroy() {
super.onDestroy();
SharedPreferences prefs = getSharedPreferences(PrefConstants.PREFERENCES, 0);
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@ -36,4 +53,11 @@ public class Settings extends PreferenceActivity {
return super.onOptionsItemSelected(item);
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(PrefConstants.THEME)) {
UIUtils.restartActivity(this);
}
}
}

View file

@ -27,7 +27,7 @@ public class SocialFeedReading extends Reading {
setTitle(getIntent().getStringExtra(EXTRA_USERNAME));
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView);
readingAdapter = new MixedFeedsReadingAdapter(getFragmentManager(), getContentResolver(), defaultFeedView, userId);
getLoaderManager().initLoader(0, null, this);
}

View file

@ -7,7 +7,6 @@ import android.content.Context;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Typeface;
import android.widget.SimpleCursorAdapter;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
@ -16,6 +15,7 @@ import com.newsblur.R;
import com.newsblur.domain.Feed;
import com.newsblur.domain.Story;
import com.newsblur.util.PrefsUtils;
import com.newsblur.util.ThemeUtils;
public class FeedItemsAdapter extends StoryItemsAdapter {
@ -28,14 +28,14 @@ public class FeedItemsAdapter extends StoryItemsAdapter {
this.feed = feed;
this.cursor = c;
storyTitleUnread = context.getResources().getColor(R.color.story_title_unread);
storyTitleRead = context.getResources().getColor(R.color.story_title_read);
storyContentUnread = context.getResources().getColor(R.color.story_content_unread);
storyContentRead = context.getResources().getColor(R.color.story_content_read);
storyAuthorUnread = context.getResources().getColor(R.color.story_author_unread);
storyAuthorRead = context.getResources().getColor(R.color.story_author_read);
storyDateUnread = context.getResources().getColor(R.color.story_date_unread);
storyDateRead = context.getResources().getColor(R.color.story_date_read);
storyTitleUnread = ThemeUtils.getStoryTitleUnreadColor(context);
storyTitleRead = ThemeUtils.getStoryTitleReadColor(context);
storyContentUnread = ThemeUtils.getStoryContentUnreadColor(context);
storyContentRead = ThemeUtils.getStoryContentReadColor(context);
storyAuthorUnread = ThemeUtils.getStoryAuthorUnreadColor(context);
storyAuthorRead = ThemeUtils.getStoryAuthorReadColor(context);
storyDateUnread = ThemeUtils.getStoryDateUnreadColor(context);
storyDateRead = ThemeUtils.getStoryDateReadColor(context);
}
@Override

View file

@ -16,7 +16,8 @@ public class FeedReadingAdapter extends ReadingAdapter {
private Classifier classifier;
public FeedReadingAdapter(FragmentManager fm, Feed feed, Classifier classifier, DefaultFeedView defaultFeedView) {
super(fm, defaultFeedView);
// sourceUserId not required for feed reading
super(fm, defaultFeedView, null);
this.feed = feed;
this.classifier = classifier;
}
@ -24,7 +25,7 @@ public class FeedReadingAdapter extends ReadingAdapter {
@Override
protected synchronized Fragment getReadingItemFragment(int position) {
stories.moveToPosition(position);
return ReadingItemFragment.newInstance(Story.fromCursor(stories), feed.title, feed.faviconColor, feed.faviconFade, feed.faviconBorder, feed.faviconText, feed.faviconUrl, classifier, false, defaultFeedView);
return ReadingItemFragment.newInstance(Story.fromCursor(stories), feed.title, feed.faviconColor, feed.faviconFade, feed.faviconBorder, feed.faviconText, feed.faviconUrl, classifier, false, defaultFeedView, sourceUserId);
}
}

Some files were not shown because too many files have changed in this diff Show more