Merge remote-tracking branch 'upstream/master'

Conflicts:
	clients/android/NewsBlur/res/layout/activity_addsites.xml
This commit is contained in:
Mark Anderson 2014-06-27 21:40:26 +01:00
commit 1c084c2817
97 changed files with 1463 additions and 610 deletions

View file

@ -334,7 +334,7 @@ def api_saved_tag_list(request):
tags = []
for tag in starred_counts:
if tag['tag'] == "": continue
if not tag['tag'] or tag['tag'] == "": continue
tags.append(dict(label="%s (%s %s)" % (tag['tag'], tag['count'],
'story' if tag['count'] == 1 else 'stories'),
value=tag['tag']))
@ -380,7 +380,10 @@ def api_unread_story(request, trigger_slug=None):
if isinstance(feed_or_folder, int) or feed_or_folder.isdigit():
feed_id = int(feed_or_folder)
usersub = UserSubscription.objects.get(user=user, feed_id=feed_id)
try:
usersub = UserSubscription.objects.get(user=user, feed_id=feed_id)
except UserSubscription.DoesNotExist:
return dict(data=[])
found_feed_ids = [feed_id]
found_trained_feed_ids = [feed_id] if usersub.is_trained else []
stories = usersub.get_stories(order="newest", read_filter="unread",

View file

@ -567,11 +567,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:
@ -587,7 +587,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
@ -608,7 +608,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
@ -877,7 +877,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:
@ -903,6 +904,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):
@ -941,17 +948,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):

View file

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

View file

@ -751,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."
@ -771,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 = []
@ -780,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)
@ -909,6 +912,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

View file

@ -2103,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) |
@ -2113,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

View file

@ -1119,7 +1119,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)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,6 +2,29 @@
<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" />
<declare-styleable name="FlowLayout">
<attr name="flow" />

View file

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

View file

@ -208,4 +208,17 @@
<string name="story">Story</string>
<string name="text">Text</string>
<string name="theme">Theme</string>
<string name="light">Light</string>
<string name="dark">Dark</string>
<string-array name="default_theme_entries">
<item>@string/light</item>
<item>@string/dark</item>
</string-array>
<string-array name="default_theme_values">
<item>light</item>
<item>dark</item>
</string-array>
<string name="default_theme_value">light</string>
</resources>

View file

@ -1,15 +1,236 @@
<?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>
</resources>

View file

@ -2,5 +2,57 @@
<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>
</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>
</style>
</resources>

View file

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

View file

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

View file

@ -6,7 +6,6 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@ -19,6 +18,7 @@ import com.newsblur.fragment.SyncUpdateFragment;
import com.newsblur.service.SyncService;
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, SyncUpdateFragment.SyncUpdateFragmentInterface {
@ -29,6 +29,7 @@ public class Main extends NbActivity implements StateChangedListener, SyncUpdate
private SyncUpdateFragment syncFragment;
private static final String TAG = "MainActivity";
private Menu menu;
private boolean isLightTheme;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -36,6 +37,8 @@ public class Main extends NbActivity implements StateChangedListener, SyncUpdate
PrefsUtils.checkForUpgrade(this);
PreferenceManager.setDefaultValues(this, R.layout.activity_settings, false);
isLightTheme = PrefsUtils.isLightThemeSelected(this);
requestWindowFeature(Window.FEATURE_PROGRESS);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.onCreate(savedInstanceState);
@ -63,6 +66,11 @@ public class Main extends NbActivity implements StateChangedListener, SyncUpdate
@Override
protected void onResume() {
super.onResume();
if (PrefsUtils.isLightThemeSelected(this) != isLightTheme) {
UIUtils.restartActivity(this);
}
if (PrefsUtils.isTimeToAutoSync(this)) {
triggerRefresh();
}

View file

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

View file

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

View file

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

View file

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

View file

@ -17,6 +17,7 @@ import com.newsblur.activity.NewsBlurApplication;
import com.newsblur.domain.Story;
import com.newsblur.util.ImageLoader;
import com.newsblur.util.PrefsUtils;
import com.newsblur.util.ThemeUtils;
public class MultipleFeedItemsAdapter extends StoryItemsAdapter {
@ -30,16 +31,16 @@ public class MultipleFeedItemsAdapter extends StoryItemsAdapter {
imageLoader = ((NewsBlurApplication) context.getApplicationContext()).getImageLoader();
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);
storyFeedUnread = context.getResources().getColor(R.color.story_feed_unread);
storyFeedRead = context.getResources().getColor(R.color.story_feed_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);
storyFeedUnread = ThemeUtils.getStoryFeedUnreadColor(context);
storyFeedRead = ThemeUtils.getStoryFeedReadColor(context);
this.ignoreReadStatus = ignoreReadStatus;
}

View file

@ -1,14 +1,12 @@
package com.newsblur.fragment;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.newsblur.R;
@ -28,57 +26,45 @@ public class AddFeedFragment extends DialogFragment {
args.putString(FEED_NAME, feedName);
frag.setArguments(args);
return frag;
}
@Override
public void onCreate(Bundle savedInstanceState) {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.dialog);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
final String addFeedString = getResources().getString(R.string.add_feed_message);
apiManager = new APIManager(getActivity());
View v = inflater.inflate(R.layout.fragment_confirm_dialog, container, false);
final TextView message = (TextView) v.findViewById(R.id.dialog_message);
message.setText(String.format(addFeedString, getArguments().getString(FEED_NAME)));
Button okayButton = (Button) v.findViewById(R.id.dialog_button_okay);
okayButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
v.setEnabled(false);
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... arg) {
return apiManager.addFeed(getArguments().getString(FEED_ID), null);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
AddFeedFragment.this.dismiss();
AddFeedFragment.this.getActivity().finish();
} else {
AddFeedFragment.this.dismiss();
Toast.makeText(getActivity(), "Error adding feed", Toast.LENGTH_SHORT).show();
}
};
}.execute();
}
});
Button cancelButton = (Button) v.findViewById(R.id.dialog_button_cancel);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
AddFeedFragment.this.dismiss();
}
});
return v;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String addFeedString = getResources().getString(R.string.add_feed_message);
final Activity activity = getActivity();
apiManager = new APIManager(activity);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(String.format(addFeedString, getArguments().getString(FEED_NAME)));
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... arg) {
return apiManager.addFeed(getArguments().getString(FEED_ID), null);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
activity.finish();
AddFeedFragment.this.dismiss();
} else {
AddFeedFragment.this.dismiss();
Toast.makeText(activity, "Error adding feed", Toast.LENGTH_SHORT).show();
}
};
}.execute();
}
});
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
AddFeedFragment.this.dismiss();
}
});
return builder.create();
}
}

View file

@ -1,30 +1,34 @@
package com.newsblur.fragment;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.newsblur.R;
public class AlertDialogFragment extends DialogFragment {
private static final String MESSAGE = "message";
public String message = "";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE | DialogFragment.STYLE_NO_FRAME, R.style.dialog);
setCancelable(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_dialog, null);
TextView messageView = (TextView) v.findViewById(R.id.dialog_message);
messageView.setText(message);
return v;
}
public static AlertDialogFragment newAlertDialogFragment(String message) {
AlertDialogFragment fragment = new AlertDialogFragment();
Bundle args = new Bundle();
args.putString(MESSAGE, message);
fragment.setArguments(args);
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(getArguments().getString(MESSAGE));
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
AlertDialogFragment.this.dismiss();
}
});
return builder.create();
}
}

View file

@ -3,22 +3,19 @@ package com.newsblur.fragment;
import java.io.Serializable;
import java.util.Map;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.DialogFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.newsblur.R;
import com.newsblur.domain.Classifier;
import com.newsblur.network.APIManager;
import com.newsblur.util.FeedUtils;
import com.newsblur.util.PrefsUtils;
public class ClassifierDialogFragment extends DialogFragment {
@ -49,7 +46,12 @@ public class ClassifierDialogFragment extends DialogFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.dialog);
if (PrefsUtils.isLightThemeSelected(getActivity())) {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.classifyDialog);
} else {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.darkClassifyDialog);
}
feedId = getArguments().getString(FEED_ID);
key = getArguments().getString(KEY);
classifierType = getArguments().getInt(TYPE);

View file

@ -2,23 +2,15 @@ package com.newsblur.fragment;
import com.newsblur.R;
import com.newsblur.activity.Main;
import com.newsblur.database.FeedProvider;
import com.newsblur.network.APIManager;
import com.newsblur.util.FeedUtils;
import android.app.Activity;
import android.net.Uri;
import android.os.AsyncTask;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class DeleteFeedFragment extends DialogFragment {
private static final String FEED_ID = "feed_url";
@ -35,54 +27,31 @@ public class DeleteFeedFragment extends DialogFragment {
return frag;
}
private FragmentManager fragmentManager;
private SyncUpdateFragment syncFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.dialog);
super.onCreate(savedInstanceState);
fragmentManager = super.getFragmentManager();
syncFragment = (SyncUpdateFragment) fragmentManager.findFragmentByTag(SyncUpdateFragment.TAG);
if (syncFragment == null) {
syncFragment = new SyncUpdateFragment();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_confirm_dialog, null);
TextView messageView = (TextView) v.findViewById(R.id.dialog_message);
messageView.setText(String.format(getResources().getString(R.string.delete_feed_message), getArguments().getString(FEED_NAME)));
Button okayButton = (Button) v.findViewById(R.id.dialog_button_okay);
okayButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(String.format(getResources().getString(R.string.delete_feed_message), getArguments().getString(FEED_NAME)));
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
FeedUtils.deleteFeed(getArguments().getLong(FEED_ID), getArguments().getString(FOLDER_NAME), getActivity(), new APIManager(getActivity()));
// if called from main view then refresh otherwise it was
// called from the feed view so finish
Activity activity = DeleteFeedFragment.this.getActivity();
if (activity instanceof Main) {
((Main)activity).updateAfterSync();
((Main)activity).updateAfterSync();
} else {
activity.finish();
activity.finish();
}
DeleteFeedFragment.this.dismiss();
}
});
Button cancelButton = (Button) v.findViewById(R.id.dialog_button_cancel);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
DeleteFeedFragment.this.dismiss();
}
});
return v;
}
});
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
DeleteFeedFragment.this.dismiss();
}
});
return builder.create();
}
}

View file

@ -1,47 +1,33 @@
package com.newsblur.fragment;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.newsblur.R;
import com.newsblur.util.PrefsUtils;
public class LogoutDialogFragment extends DialogFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.dialog);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
View v = inflater.inflate(R.layout.fragment_logout_dialog, container, false);
final TextView message = (TextView) v.findViewById(R.id.dialog_message);
message.setText(getActivity().getResources().getString(R.string.logout_warning));
Button okayButton = (Button) v.findViewById(R.id.dialog_button_okay);
okayButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(getResources().getString(R.string.logout_warning));
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
PrefsUtils.logout(getActivity());
}
});
Button cancelButton = (Button) v.findViewById(R.id.dialog_button_cancel);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
LogoutDialogFragment.this.dismiss();
}
});
return v;
}
}
});
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
LogoutDialogFragment.this.dismiss();
}
});
return builder.create();
}
}

View file

@ -145,9 +145,7 @@ public class ProfileDetailsFragment extends Fragment implements OnClickListener
unfollowButton.setVisibility(View.VISIBLE);
} else {
FragmentManager fm = ProfileDetailsFragment.this.getFragmentManager();
AlertDialogFragment alertDialog = new AlertDialogFragment();
final String message = getResources().getString(R.string.follow_error);
alertDialog.message = message;
AlertDialogFragment alertDialog = AlertDialogFragment.newAlertDialogFragment(getResources().getString(R.string.follow_error));
alertDialog.show(fm, "fragment_edit_name");
}
}
@ -173,10 +171,8 @@ public class ProfileDetailsFragment extends Fragment implements OnClickListener
followButton.setVisibility(View.VISIBLE);
} else {
FragmentManager fm = ProfileDetailsFragment.this.getFragmentManager();
AlertDialogFragment alertDialog = new AlertDialogFragment();
final String message = getResources().getString(R.string.unfollow_error);
alertDialog.message = message;
alertDialog.show(fm, "fragment_edit_name");
AlertDialogFragment alertDialog = AlertDialogFragment.newAlertDialogFragment(getResources().getString(R.string.unfollow_error));
alertDialog.show(fm, "fragment_edit_name");
}
}
}

View file

@ -485,7 +485,13 @@ public class ReadingItemFragment extends Fragment implements ClassifierDialogFra
builder.append("<style style=\"text/css\">");
builder.append(String.format("body { font-size: %sem; } ", Float.toString(currentSize)));
builder.append("</style>");
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"reading.css\" /></head><body><div class=\"NB-story\">");
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"reading.css\" />");
if (PrefsUtils.isLightThemeSelected(getActivity())) {
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"light_reading.css\" />");
} else {
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"dark_reading.css\" />");
}
builder.append("</head><body><div class=\"NB-story\">");
builder.append(storyText);
builder.append("</div></body></html>");
web.loadDataWithBaseURL("file:///android_asset/", builder.toString(), "text/html", "UTF-8", null);

View file

@ -1,15 +1,15 @@
package com.newsblur.fragment;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.newsblur.R;
@ -37,67 +37,56 @@ public class ReplyDialogFragment extends DialogFragment {
frag.setArguments(args);
return frag;
}
@Override
public void onCreate(Bundle savedInstanceState) {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.dialog);
story = (Story) getArguments().getSerializable(STORY);
commentUserId = getArguments().getString(COMMENT_USER_ID);
commentUsername = getArguments().getString(COMMENT_USERNAME);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
final String shareString = getResources().getString(R.string.reply_to);
apiManager = new APIManager(getActivity());
View v = inflater.inflate(R.layout.fragment_dialog, container, false);
final TextView message = (TextView) v.findViewById(R.id.dialog_message);
final EditText reply = (EditText) v.findViewById(R.id.dialog_share_comment);
message.setText(String.format(shareString, getArguments().getString(COMMENT_USERNAME)));
Button okayButton = (Button) v.findViewById(R.id.dialog_button_okay);
okayButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
v.setEnabled(false);
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... arg) {
return apiManager.replyToComment(story.id, story.feedId, commentUserId, reply.getText().toString());
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
Toast.makeText(getActivity(), R.string.replied, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), R.string.error_replying, Toast.LENGTH_LONG).show();
}
v.setEnabled(true);
ReplyDialogFragment.this.dismiss();
};
}.execute();
}
});
Button cancelButton = (Button) v.findViewById(R.id.dialog_button_cancel);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ReplyDialogFragment.this.dismiss();
}
});
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return v;
}
story = (Story) getArguments().getSerializable(STORY);
public interface ReplyDialogCallback {
public void replyPosted(String reply);
}
commentUserId = getArguments().getString(COMMENT_USER_ID);
commentUsername = getArguments().getString(COMMENT_USERNAME);
final Activity activity = getActivity();
apiManager = new APIManager(activity);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final String shareString = getResources().getString(R.string.reply_to);
builder.setTitle(String.format(shareString, getArguments().getString(COMMENT_USERNAME)));
LayoutInflater layoutInflater = LayoutInflater.from(activity);
View replyView = layoutInflater.inflate(R.layout.reply_dialog, null);
builder.setView(replyView);
final EditText reply = (EditText) replyView.findViewById(R.id.reply_field);
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... arg) {
return apiManager.replyToComment(story.id, story.feedId, commentUserId, reply.getText().toString());
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
Toast.makeText(activity, R.string.replied, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, R.string.error_replying, Toast.LENGTH_LONG).show();
}
ReplyDialogFragment.this.dismiss();
};
}.execute();
}
});
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ReplyDialogFragment.this.dismiss();
}
});
return builder.create();
}
}

View file

@ -2,22 +2,20 @@ package com.newsblur.fragment;
import java.io.Serializable;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.DialogFragment;
import android.text.Editable;
import android.text.Html;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.newsblur.R;
@ -44,7 +42,7 @@ public class ShareDialogFragment extends DialogFragment {
private Comment previousComment;
private String previouslySavedShareText;
private boolean hasShared = false;
private EditText commentEditText;
private EditText commentEditText;
public static ShareDialogFragment newInstance(final SharedCallbackDialog sharedCallback, final Story story, final String previouslySavedShareText) {
ShareDialogFragment frag = new ShareDialogFragment();
@ -54,107 +52,85 @@ public class ShareDialogFragment extends DialogFragment {
args.putSerializable(CALLBACK, sharedCallback);
frag.setArguments(args);
return frag;
}
@Override
public void onCreate(Bundle savedInstanceState) {
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.dialog);
super.onCreate(savedInstanceState);
story = (Story) getArguments().getSerializable(STORY);
callback = (SharedCallbackDialog) getArguments().getSerializable(CALLBACK);
user = PrefsUtils.getUserDetails(getActivity());
previouslySavedShareText = getArguments().getString(PREVIOUSLY_SAVED_SHARE_TEXT);
apiManager = new APIManager(getActivity());
resolver = getActivity().getContentResolver();
for (String sharedUserId : story.sharedUserIds) {
if (TextUtils.equals(user.id, sharedUserId)) {
hasBeenShared = true;
break;
}
}
if (hasBeenShared) {
commentCursor = resolver.query(FeedProvider.COMMENTS_URI, null, null, new String[] { story.id, user.id }, null);
commentCursor.moveToFirst();
previousComment = Comment.fromCursor(commentCursor);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
final String shareString = getResources().getString(R.string.share_newsblur);
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_dialog, container, false);
final TextView message = (TextView) v.findViewById(R.id.dialog_message);
commentEditText = (EditText) v.findViewById(R.id.dialog_share_comment);
final Button shareButton = (Button) v.findViewById(R.id.dialog_button_okay);
shareButton.setText(R.string.share_this_story);
commentEditText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
if (editable.length() > 0) {
shareButton.setText(R.string.share_with_comments);
} else {
shareButton.setText(R.string.share_this_story);
}
}
final Activity activity = getActivity();
story = (Story) getArguments().getSerializable(STORY);
callback = (SharedCallbackDialog) getArguments().getSerializable(CALLBACK);
user = PrefsUtils.getUserDetails(activity);
previouslySavedShareText = getArguments().getString(PREVIOUSLY_SAVED_SHARE_TEXT);
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
apiManager = new APIManager(getActivity());
resolver = getActivity().getContentResolver();
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) { }
});
message.setText(String.format(shareString, Html.fromHtml(story.title)));
for (String sharedUserId : story.sharedUserIds) {
if (TextUtils.equals(user.id, sharedUserId)) {
hasBeenShared = true;
break;
}
}
if (hasBeenShared) {
shareButton.setText(R.string.edit);
commentEditText.setText(previousComment.commentText);
} else if (!TextUtils.isEmpty(previouslySavedShareText)) {
commentEditText.setText(previouslySavedShareText);
}
if (hasBeenShared) {
commentCursor = resolver.query(FeedProvider.COMMENTS_URI, null, null, new String[] { story.id, user.id }, null);
commentCursor.moveToFirst();
previousComment = Comment.fromCursor(commentCursor);
}
Button okayButton = (Button) v.findViewById(R.id.dialog_button_okay);
okayButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
final String shareComment = commentEditText.getText().toString();
v.setEnabled(false);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final String shareString = getResources().getString(R.string.share_newsblur);
builder.setTitle(String.format(shareString, Html.fromHtml(story.title)));
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... arg) {
return apiManager.shareStory(story.id, story.feedId, shareComment, story.sourceUserId);
}
LayoutInflater layoutInflater = LayoutInflater.from(activity);
View replyView = layoutInflater.inflate(R.layout.share_dialog, null);
builder.setView(replyView);
commentEditText = (EditText) replyView.findViewById(R.id.comment_field);
@Override
protected void onPostExecute(Boolean result) {
if (result) {
hasShared = true;
UIUtils.safeToast(getActivity(), R.string.shared, Toast.LENGTH_LONG);
callback.sharedCallback(shareComment, hasBeenShared);
} else {
UIUtils.safeToast(getActivity(), R.string.error_sharing, Toast.LENGTH_LONG);
}
v.setEnabled(true);
ShareDialogFragment.this.dismiss();
};
}.execute();
}
});
int positiveButtonText = R.string.share_this_story;
if (hasBeenShared) {
positiveButtonText = R.string.edit;
commentEditText.setText(previousComment.commentText);
} else if (!TextUtils.isEmpty(previouslySavedShareText)) {
commentEditText.setText(previouslySavedShareText);
}
Button cancelButton = (Button) v.findViewById(R.id.dialog_button_cancel);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ShareDialogFragment.this.dismiss();
}
});
builder.setPositiveButton(positiveButtonText, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
return v;
}
final String shareComment = commentEditText.getText().toString();
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... arg) {
return apiManager.shareStory(story.id, story.feedId, shareComment, story.sourceUserId);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
hasShared = true;
UIUtils.safeToast(activity, R.string.shared, Toast.LENGTH_LONG);
callback.sharedCallback(shareComment, hasBeenShared);
} else {
UIUtils.safeToast(activity, R.string.error_sharing, Toast.LENGTH_LONG);
}
ShareDialogFragment.this.dismiss();
};
}.execute();
}
});
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ShareDialogFragment.this.dismiss();
}
});
return builder.create();
}
@Override
public void onDestroy() {

View file

@ -46,4 +46,6 @@ public class PrefConstants {
public static final String READING_ENTER_IMMERSIVE_SINGLE_TAP = "immersive_enter_single_tap";
public static final String STORIES_SHOW_PREVIEWS = "pref_show_content_preview";
public static final String THEME = "theme";
}

View file

@ -8,6 +8,7 @@ import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -18,6 +19,7 @@ import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.newsblur.R;
import com.newsblur.activity.Login;
import com.newsblur.database.BlurDatabase;
import com.newsblur.domain.UserDetails;
@ -302,4 +304,20 @@ public class PrefsUtils {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
return prefs.getBoolean(PrefConstants.STORIES_SHOW_PREVIEWS, true);
}
public static void applyThemePreference(Activity activity) {
SharedPreferences prefs = activity.getSharedPreferences(PrefConstants.PREFERENCES, 0);
String theme = prefs.getString(PrefConstants.THEME, "light");
if (theme.equals("light")) {
activity.setTheme(R.style.NewsBlurTheme);
} else {
activity.setTheme(R.style.NewsBlurDarkTheme);
}
}
public static boolean isLightThemeSelected(Context context) {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
String theme = prefs.getString(PrefConstants.THEME, "light");
return theme.equals("light");
}
}

View file

@ -0,0 +1,95 @@
package com.newsblur.util;
import android.content.Context;
import com.newsblur.R;
/**
* Created by mark on 20/05/2014.
*/
public class ThemeUtils {
public static int getStoryTitleUnreadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_title_unread);
} else {
return getColor(context, R.color.dark_story_title_unread);
}
}
private static int getColor(Context context, int id) {
return context.getResources().getColor(id);
}
public static int getStoryTitleReadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_title_read);
} else {
return getColor(context, R.color.story_title_read);
}
}
public static int getStoryContentUnreadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_content_unread);
} else {
return getColor(context, R.color.dark_story_content_unread);
}
}
public static int getStoryContentReadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_content_read);
} else {
return getColor(context, R.color.story_content_read);
}
}
public static int getStoryAuthorUnreadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_author_unread);
} else {
return getColor(context, R.color.story_author_unread);
}
}
public static int getStoryAuthorReadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_author_read);
} else {
return getColor(context, R.color.story_author_read);
}
}
public static int getStoryDateUnreadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_date_unread);
} else {
return getColor(context, R.color.dark_story_date_unread);
}
}
public static int getStoryDateReadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_date_read);
} else {
return getColor(context, R.color.story_date_read);
}
}
public static int getStoryFeedUnreadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_feed_unread);
} else {
return getColor(context, R.color.dark_story_feed_unread);
}
}
public static int getStoryFeedReadColor(Context context) {
if (PrefsUtils.isLightThemeSelected(context)) {
return getColor(context, R.color.story_feed_read);
} else {
return getColor(context, R.color.story_feed_read);
}
}
}

View file

@ -3,13 +3,17 @@ package com.newsblur.util;
import static android.graphics.Bitmap.Config.ARGB_8888;
import static android.graphics.Color.WHITE;
import static android.graphics.PorterDuff.Mode.DST_IN;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.os.Handler;
import android.view.View;
import android.widget.Toast;
@ -106,4 +110,25 @@ public class UIUtils {
Toast.makeText(c, rid, duration).show();
}
}
/**
* Restart an activity. See http://stackoverflow.com/a/11651252/70795
* We post this on the Handler to allow onResume to finish before the activity restarts
* and avoid an exception.
*/
public static void restartActivity(final Activity activity) {
new Handler().post(new Runnable() {
@Override
public void run() {
Intent intent = activity.getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
activity.overridePendingTransition(0, 0);
activity.finish();
activity.overridePendingTransition(0, 0);
activity.startActivity(intent);
}
});
}
}

View file

@ -22,6 +22,7 @@ import com.newsblur.activity.Profile;
import com.newsblur.domain.UserDetails;
import com.newsblur.network.domain.ActivitiesResponse;
import com.newsblur.util.ImageLoader;
import com.newsblur.util.PrefsUtils;
public class ActivitiesAdapter extends ArrayAdapter<ActivitiesResponse> {
@ -52,9 +53,14 @@ public class ActivitiesAdapter extends ArrayAdapter<ActivitiesResponse> {
sharedStory = resources.getString(R.string.profile_shared_story);
withComment = resources.getString(R.string.profile_with_comment);
ago = resources.getString(R.string.profile_ago);
highlight = new ForegroundColorSpan(resources.getColor(R.color.linkblue));
darkgray = new ForegroundColorSpan(resources.getColor(R.color.darkgray));
if (PrefsUtils.isLightThemeSelected(context)) {
highlight = new ForegroundColorSpan(resources.getColor(R.color.linkblue));
darkgray = new ForegroundColorSpan(resources.getColor(R.color.darkgray));
} else {
highlight = new ForegroundColorSpan(resources.getColor(R.color.dark_linkblue));
darkgray = new ForegroundColorSpan(resources.getColor(R.color.white));
}
}
@Override

View file

@ -1401,6 +1401,15 @@ a img {
left: 12px;
top: 10px;
}
.NB-feedbar .NB-folder .NB-read-icon {
background: transparent url('/media/embed/icons/circular/g_icn_unread.png') no-repeat center center;
background-size: 8px;
width: 16px;
height: 16px;
position: absolute;
left: 12px;
top: 10px;
}
.NB-feedbar .folder ul.folder,
.NB-feedbar .folder .NB-feedlist-collapse-icon,
@ -3809,9 +3818,10 @@ body {
.NB-feeds-header-river-container .NB-feeds-header {
border-bottom: 1px solid #B7BBAA;
}
.NB-feeds-header-starred-container {
.NB-feeds-header-read-container.NB-feeds-header-container {
border-top: 1px solid #B7BBAA;
}
.NB-feeds-header-read.NB-feeds-header,
.NB-feeds-header-starred.NB-feeds-header {
border-bottom: 1px solid #B7BBAA;
}
@ -3850,6 +3860,25 @@ body {
display: none;
}
/* ========================= */
/* = Header - Read Stories = */
/* ========================= */
.NB-feeds-header-read-container.NB-block {
display: block;
}
.NB-feeds-header-read {
display: block;
}
.NB-feeds-header-read .NB-feeds-header-icon {
background: transparent url('/media/embed/icons/circular/g_icn_unread.png') no-repeat center center;
background-size: 8px;
}
.NB-feeds-header-read.NB-empty .NB-feeds-header-count {
display: none;
}
/* ===================== */
/* = Header - Try Feed = */
/* ===================== */

View file

@ -514,6 +514,10 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
}
if (feed_id == this.feed_id) {
if (data.feeds) {
var river = _.any(['river:', 'social:'], function(prefix) {
return _.isString(feed_id) && _.string.startsWith(feed_id, prefix);
});
if (river) _.each(data.feeds, function(feed) { feed.temp = true; });
this.feeds.add(data.feeds);
}
if (data.classifiers) {
@ -595,6 +599,7 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
this.make_request('/reader/starred_stories', {
page: page,
query: NEWSBLUR.reader.flags.search,
order: this.view_setting('starred', 'order'),
tag: tag,
v: 2
}, pre_callback, error_callback, {
@ -602,6 +607,32 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
'request_type': 'GET'
});
},
fetch_read_stories: function(page, callback, error_callback, first_load) {
var self = this;
var pre_callback = function(data) {
if (!NEWSBLUR.Globals.is_premium && NEWSBLUR.Globals.is_authenticated) {
if (first_load) {
data.stories = data.stories.splice(0, 3);
} else {
data.stories = [];
}
}
return self.load_feed_precallback(data, 'read', callback, first_load);
};
this.feed_id = 'read';
this.make_request('/reader/read_stories', {
page: page,
query: NEWSBLUR.reader.flags.search,
order: this.view_setting('read', 'order')
}, pre_callback, error_callback, {
'ajax_group': (page ? 'feed_page' : 'feed'),
'request_type': 'GET'
});
},
fetch_river_stories: function(feed_id, feeds, page, callback, error_callback, first_load) {
var self = this;
@ -609,7 +640,7 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
var pre_callback = function(data) {
if (!NEWSBLUR.Globals.is_premium && NEWSBLUR.Globals.is_authenticated) {
if (first_load) {
data.stories = data.stories.splice(0, 5);
data.stories = data.stories.splice(0, 3);
} else {
data.stories = [];
}

View file

@ -6,6 +6,7 @@ NEWSBLUR.Router = Backbone.Router.extend({
"site/:site_id/:slug": "site",
"site/:site_id/": "site",
"site/:site_id": "site",
"read": "read",
"saved": "starred",
"saved/:tag": "starred",
"folder/saved": "starred",
@ -44,8 +45,16 @@ NEWSBLUR.Router = Backbone.Router.extend({
}
},
read: function() {
var options = {
router: true
};
console.log(["read stories", options]);
NEWSBLUR.reader.open_read_stories(options);
},
starred: function(tag) {
options = {
var options = {
router: true,
tag: tag
};

View file

@ -43,6 +43,7 @@
$river_blurblogs_header: $('.NB-feeds-header-river-blurblogs'),
$river_global_header: $('.NB-feeds-header-river-global'),
$starred_header: $('.NB-feeds-header-starred'),
$read_header: $('.NB-feeds-header-read'),
$tryfeed_header: $('.NB-feeds-header-tryfeed'),
$taskbar: $('.NB-taskbar-view'),
$feed_floater: $('.NB-feed-story-view-floater'),
@ -1201,6 +1202,7 @@
this.model.flags['no_more_stories'] = false;
this.$s.$feed_scroll.scrollTop(0);
this.$s.$starred_header.removeClass('NB-selected');
this.$s.$read_header.removeClass('NB-selected');
this.$s.$river_sites_header.removeClass('NB-selected');
this.$s.$river_blurblogs_header.removeClass('NB-selected');
this.$s.$river_global_header.removeClass('NB-selected');
@ -1250,6 +1252,8 @@
this.open_starred_stories(options);
} else if (this.flags['starred_view']) {
this.open_starred_stories(options);
} else if (this.active_feed == 'read') {
this.open_read_stories(options);
} else if (this.flags['social_view'] &&
this.active_feed == 'river:blurblogs') {
this.open_river_blurblogs_stories();
@ -1485,7 +1489,7 @@
$list.removeClass('NB-active');
}
if (this.flags['starred_view']) {
if (_.contains(['starred', 'read'], feed_id)) {
$page_tab.addClass('NB-disabled');
}
@ -1539,9 +1543,9 @@
});
},
// ===============
// = Feed Header =
// ===============
// ===================
// = Starred Stories =
// ===================
update_starred_count: function() {
var starred_count = this.model.starred_count;
@ -1639,6 +1643,67 @@
this.flags['story_titles_loaded'] = true;
},
// =====================
// = Read Stories Feed =
// =====================
open_read_stories: function(options) {
options = options || {};
var $story_titles = this.$s.$story_titles;
this.reset_feed(options);
this.hide_splash_page();
this.active_feed = 'read';
if (options.story_id) {
this.flags['select_story_in_feed'] = options.story_id;
}
this.iframe_scroll = null;
this.$s.$read_header.addClass('NB-selected');
this.$s.$body.addClass('NB-view-river');
this.flags.river_view = true;
$('.task_view_page', this.$s.$taskbar).addClass('NB-disabled');
var explicit_view_setting = this.model.view_setting(this.active_feed, 'view');
if (!explicit_view_setting || explicit_view_setting == 'page') {
explicit_view_setting = 'feed';
}
this.set_correct_story_view_for_feed(this.active_feed, explicit_view_setting);
this.switch_taskbar_view(this.story_view);
this.setup_mousemove_on_views();
this.make_feed_title_in_stories();
if (NEWSBLUR.assets.preference('story_layout') == 'full') {
NEWSBLUR.app.story_list.show_loading(options);
} else {
NEWSBLUR.app.story_titles.show_loading(options);
}
NEWSBLUR.app.taskbar_info.hide_stories_error();
this.model.fetch_read_stories(1, _.bind(this.post_open_read_stories, this),
NEWSBLUR.app.taskbar_info.show_stories_error, true);
if (!options.silent) {
var url = "/read";
if (window.location.pathname != url) {
NEWSBLUR.router.navigate(url);
}
}
},
post_open_read_stories: function(data, first_load) {
if (this.active_feed == 'read') {
// NEWSBLUR.log(['post_open_read_stories', data.stories.length, first_load]);
this.flags['opening_feed'] = false;
if (this.counts['select_story_in_feed'] || this.flags['select_story_in_feed']) {
this.select_story_in_feed();
}
if (first_load) {
this.find_story_with_action_preference_on_open_feed();
}
// this.show_story_titles_above_intelligence_level({'animate': false});
this.flags['story_titles_loaded'] = true;
}
},
// =================
// = River of News =
// =================
@ -2388,6 +2453,9 @@
if (this.flags['starred_view']) {
this.model.fetch_starred_stories(this.counts['page'], this.flags['starred_tag'], _.bind(this.post_open_starred_stories, this),
NEWSBLUR.app.taskbar_info.show_stories_error, false);
} else if (this.active_feed == 'read') {
this.model.fetch_read_stories(this.counts['page'], _.bind(this.post_open_read_stories, this),
NEWSBLUR.app.taskbar_info.show_stories_error, false);
} else if (this.flags['social_view'] && _.contains(['river:blurblogs', 'river:global'], this.active_feed)) {
this.model.fetch_river_blurblogs_stories(this.active_feed,
this.counts['page'],
@ -4063,7 +4131,7 @@
feed_id = feed_id || this.active_feed;
var feed = this.model.get_feed(feed_id);
if (this.flags['starred_view']) {
if (_.contains(['starred', 'read'], feed_id)) {
// Umm, no. Not yet.
} else if (feed) {
return feed.unread_counts();

View file

@ -26,6 +26,7 @@ NEWSBLUR.Views.FeedList = Backbone.View.extend({
// TODO: Refactor this to load after both feeds and social feeds load.
this.load_router();
this.show_read_stories_header();
this.update_dashboard_count();
this.scroll_to_selected();
}, this));
@ -312,6 +313,8 @@ NEWSBLUR.Views.FeedList = Backbone.View.extend({
$selected_view = NEWSBLUR.reader.$s.$river_sites_header.closest(".NB-feeds-header-container");
} else if (!$selected_view && NEWSBLUR.reader.active_feed == 'starred') {
$selected_view = NEWSBLUR.reader.$s.$starred_header.closest(".NB-feeds-header-container");
} else if (!$selected_view && NEWSBLUR.reader.active_feed == 'read') {
$selected_view = NEWSBLUR.reader.$s.$read_header.closest(".NB-feeds-header-container");
}
if (!$selected_view) return;
@ -344,6 +347,11 @@ NEWSBLUR.Views.FeedList = Backbone.View.extend({
is_sorting: function() {
return this.options.sorting;
},
show_read_stories_header: function() {
NEWSBLUR.reader.$s.$read_header.closest('.NB-feeds-header-read-container')
.addClass('NB-block');
}
});

View file

@ -11,7 +11,9 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({
left: 0
},
'overlay_top': true,
'popover_class': 'NB-filter-popover-container'
'popover_class': 'NB-filter-popover-container',
'show_readfilter': true,
'show_order': true
},
events: {
@ -22,6 +24,13 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({
initialize: function(options) {
this.options = _.extend({}, this.options, options);
if (NEWSBLUR.reader.active_feed == "read") {
this.options['show_readfilter'] = false;
}
if (NEWSBLUR.reader.flags['starred_view']) {
this.options.feed_id = "starred"; // Ignore tags
this.options['show_readfilter'] = false;
}
NEWSBLUR.ReaderPopover.prototype.initialize.call(this, this.options);
this.model = NEWSBLUR.assets;
this.render();
@ -43,14 +52,14 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({
$.make('div', { className: 'NB-popover-section' }, [
(feed && $.make('div', { className: 'NB-section-icon NB-filter-popover-filter-icon' })),
$.make('div', { className: 'NB-popover-section-title' }, 'Filter Options'),
$.make('ul', { className: 'segmented-control NB-menu-manage-view-setting-readfilter' }, [
(this.options.show_readfilter && $.make('ul', { className: 'segmented-control NB-menu-manage-view-setting-readfilter' }, [
$.make('li', { className: 'NB-view-setting-option NB-view-setting-readfilter-all NB-active' }, 'All stories'),
$.make('li', { className: 'NB-view-setting-option NB-view-setting-readfilter-unread' }, 'Unread only')
]),
$.make('ul', { className: 'segmented-control NB-menu-manage-view-setting-order' }, [
])),
(this.options.show_order && $.make('ul', { className: 'segmented-control NB-menu-manage-view-setting-order' }, [
$.make('li', { className: 'NB-view-setting-option NB-view-setting-order-newest NB-active' }, 'Newest first'),
$.make('li', { className: 'NB-view-setting-option NB-view-setting-order-oldest' }, 'Oldest')
])
]))
]),
(feed && $.make('div', { className: 'NB-popover-section' }, [
$.make('div', { className: 'NB-section-icon NB-filter-popover-stats-icon' }),

View file

@ -43,6 +43,7 @@ NEWSBLUR.Views.FeedSearchView = Backbone.View.extend({
tipsy.disable();
tipsy.hide();
}
NEWSBLUR.reader.$s.$story_titles_header.removeClass("NB-searching");
Backbone.View.prototype.remove.call(this);
},
@ -120,7 +121,7 @@ NEWSBLUR.Views.FeedSearchView = Backbone.View.extend({
NEWSBLUR.reader.flags.searching = true;
NEWSBLUR.reader.flags.search = "";
}
this.feedbar_view.$el.addClass("NB-searching");
NEWSBLUR.reader.$s.$story_titles_header.addClass("NB-searching");
},
blur_search: function() {
@ -129,7 +130,7 @@ NEWSBLUR.Views.FeedSearchView = Backbone.View.extend({
if (query.length == 0) {
NEWSBLUR.reader.flags.searching = false;
this.feedbar_view.$el.removeClass("NB-searching");
NEWSBLUR.reader.$s.$story_titles_header.removeClass("NB-searching");
if (NEWSBLUR.reader.flags.search) {
this.close_search();
}

View file

@ -5,6 +5,7 @@ NEWSBLUR.Views.Sidebar = Backbone.View.extend({
events: {
"click .NB-feeds-header-starred .NB-feedlist-collapse-icon": "collapse_starred_stories",
"click .NB-feeds-header-starred": "open_starred_stories",
"click .NB-feeds-header-read": "open_read_stories",
"click .NB-feeds-header-river-sites": "open_river_stories",
"click .NB-feeds-header-river-blurblogs .NB-feedlist-collapse-icon": "collapse_river_blurblog",
"click .NB-feeds-header-river-blurblogs": "open_river_blurblogs_stories",
@ -134,6 +135,10 @@ NEWSBLUR.Views.Sidebar = Backbone.View.extend({
return NEWSBLUR.reader.open_starred_stories();
},
open_read_stories: function() {
return NEWSBLUR.reader.open_read_stories();
},
open_river_stories: function() {
return NEWSBLUR.reader.open_river_stories();
},

View file

@ -403,6 +403,14 @@ NEWSBLUR.Views.StoryListView = Backbone.View.extend({
'.'
];
}
if (NEWSBLUR.reader.active_feed == "read") {
message = [
'This read stories list is a ',
$.make('a', { href: '#', className: 'NB-splash-link' }, 'premium feature'),
'.'
];
}
var $notice = $.make('div', { className: 'NB-feed-story-premium-only' }, [
$.make('div', { className: 'NB-feed-story-premium-only-text'}, message)
]);

View file

@ -36,6 +36,12 @@ NEWSBLUR.Views.StoryTitlesHeader = Backbone.View.extend({
$view = $(_.template('\
<div class="NB-folder NB-no-hover">\
<div class="NB-search-container"></div>\
<div class="NB-feedbar-options-container">\
<span class="NB-feedbar-options">\
<div class="NB-icon"></div>\
<%= NEWSBLUR.assets.view_setting("starred", "order") %>\
</span>\
</div>\
<div class="NB-starred-icon"></div>\
<div class="NB-feedlist-manage-icon"></div>\
<span class="folder_title_text">Saved Stories<% if (tag) { %> - <%= tag %><% } %></span>\
@ -48,6 +54,20 @@ NEWSBLUR.Views.StoryTitlesHeader = Backbone.View.extend({
}).render();
this.search_view.blur_search();
$(".NB-search-container", $view).html(this.search_view.$el);
} else if (NEWSBLUR.reader.active_feed == "read") {
$view = $(_.template('\
<div class="NB-folder NB-no-hover">\
<div class="NB-feedbar-options-container">\
<span class="NB-feedbar-options">\
<div class="NB-icon"></div>\
<%= NEWSBLUR.assets.view_setting("read", "order") %>\
</span>\
</div>\
<div class="NB-read-icon"></div>\
<div class="NB-feedlist-manage-icon"></div>\
<div class="folder_title_text">Read Stories</div>\
</div>\
', {}));
} else if (this.showing_fake_folder) {
$view = $(_.template('\
<div class="NB-folder NB-no-hover">\
@ -207,7 +227,9 @@ NEWSBLUR.Views.StoryTitlesHeader = Backbone.View.extend({
},
open_options_popover: function(e) {
if (!this.showing_fake_folder) return;
if (!(this.showing_fake_folder ||
NEWSBLUR.reader.active_feed == "read" ||
NEWSBLUR.reader.flags['starred_view'])) return;
NEWSBLUR.FeedOptionsPopover.create({
anchor: this.$(".NB-feedbar-options"),

View file

@ -79,6 +79,13 @@ NEWSBLUR.Views.StoryTitlesView = Backbone.View.extend({
'.'
];
}
if (NEWSBLUR.reader.active_feed == "read") {
message = [
'This read stories list is a ',
$.make('a', { href: '#', className: 'NB-splash-link' }, 'premium feature'),
'.'
];
}
var $notice = $.make('div', { className: 'NB-feed-story-premium-only' }, [
$.make('div', { className: 'NB-feed-story-premium-only-text'}, message)
]);

View file

@ -81,6 +81,14 @@
<ul class="folder NB-feedlist" id="feed_list"></ul>
<div class="NB-feeds-header-container NB-feeds-header-read-container NB-hidden">
<div class="NB-feeds-header NB-feeds-header-read">
<div class="NB-feeds-header-icon"></div>
<div class="NB-feeds-header-title">
Read Stories
</div>
</div>
</div>
<div class="NB-feeds-header-container NB-feeds-header-starred-container">
<div class="NB-feeds-header NB-feeds-header-starred NB-empty">
<div class="NB-feeds-header-count feed_counts_floater unread_count"></div>

View file

@ -16,7 +16,8 @@ urlpatterns = patterns('',
(r'^site/(?P<feed_id>\d+)?', reader_views.index),
(r'^folder/(?P<folder_name>\d+)?', reader_views.index),
url(r'^saved/(?P<tag_name>\d+)?', reader_views.index, name='saved-stories-tag'),
(r'^saved/?', reader_views.index),
(r'^saved/?', reader_views.index),
(r'^read/?', reader_views.index),
(r'^social/\d+/.*?', reader_views.index),
(r'^user/.*?', reader_views.index),
(r'^null/.*?', reader_views.index),