mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
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:
commit
7ec3a93531
216 changed files with 3183 additions and 1863 deletions
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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.'})
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
20
clients/android/NewsBlur/assets/dark_reading.css
Normal file
20
clients/android/NewsBlur/assets/dark_reading.css
Normal 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;
|
||||
}
|
20
clients/android/NewsBlur/assets/light_reading.css
Normal file
20
clients/android/NewsBlur/assets/light_reading.css
Normal 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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
15
clients/android/NewsBlur/res/drawable/divider_dark.xml
Normal file
15
clients/android/NewsBlur/res/drawable/divider_dark.xml
Normal 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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -4,4 +4,4 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@null"
|
||||
android:background="@drawable/list_background" />
|
||||
/>
|
|
@ -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" >
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"/>
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
17
clients/android/NewsBlur/res/layout/reply_dialog.xml
Normal file
17
clients/android/NewsBlur/res/layout/reply_dialog.xml
Normal 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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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" />
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
18
clients/android/NewsBlur/res/layout/share_dialog.xml
Normal file
18
clients/android/NewsBlur/res/layout/share_dialog.xml
Normal 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>
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue