mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-20 05:14:44 +00:00
Merge branch 'django1.10' into django1.11
* django1.10: (102 commits) Beginning fix of rss_feeds unit tests. Fixing unit test for profile app and signup. Remove highlights count when it reaches zero. Android v10.1b1. Stubbing in profile tests. Adding nginx.local.conf Adding original text and original story to API docs. #1282 Adding feed to root folder #1319 In app and external browser options Adding a smarter wakeup for real-time to handle cases where a laptop is re-opened but real-time is not immediately reestablished. #1348 (scroll indicators theme) #1344 (search loses focus) #1335 Auto theme option for OS level dark mode Fixing signup flow. #1347 Show pager with stories after using the intel trainer and refreshing #1272 Load HTML in comments New icon for Infrequent Site Stories. Allowing selection in private notes. Autoresizing private notes field. For #1035: Adding private notes to saved stories. ...
This commit is contained in:
commit
ac1471017d
145 changed files with 9224 additions and 1276 deletions
|
@ -161,6 +161,7 @@ these after the installation below.
|
||||||
|
|
||||||
Then load up the database with empty NewsBlur tables and bootstrap the database:
|
Then load up the database with empty NewsBlur tables and bootstrap the database:
|
||||||
|
|
||||||
|
./manage.py syncdb --all --noinput
|
||||||
./manage.py migrate --fake
|
./manage.py migrate --fake
|
||||||
./manage.py migrate
|
./manage.py migrate
|
||||||
./manage.py loaddata config/fixtures/bootstrap.json
|
./manage.py loaddata config/fixtures/bootstrap.json
|
||||||
|
|
|
@ -38,25 +38,6 @@
|
||||||
"user": 1,
|
"user": 1,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
"pk": 1,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "conesus",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": 1,
|
|
||||||
"is_superuser": 1,
|
|
||||||
"is_staff": 1,
|
|
||||||
"last_login": "2009-04-07 19:22:24",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "sha1$7b94b$ac9e6cf08d0fa16a67e56e319c0935aeb26db2a2",
|
|
||||||
"email": "samuel@newsblur.com",
|
|
||||||
"date_joined": "2009-01-04 17:32:58"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
]
|
||||||
|
|
|
@ -139,9 +139,9 @@ class ClassifierTest(TestCase):
|
||||||
# user = User.objects.all()
|
# user = User.objects.all()
|
||||||
# feed = Feed.objects.all()
|
# feed = Feed.objects.all()
|
||||||
|
|
||||||
management.call_command('loaddata', 'brownstoner.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'brownstoner.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
management.call_command('refresh_feed', force=1, feed=1, single_threaded=True, daemonize=False, skip_checks=False)
|
management.call_command('refresh_feed', force=1, feed=1, single_threaded=True, daemonize=False, skip_checks=False)
|
||||||
management.call_command('loaddata', 'brownstoner2.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'brownstoner2.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
management.call_command('refresh_feed', force=1, feed=1, single_threaded=True, daemonize=False, skip_checks=False)
|
management.call_command('refresh_feed', force=1, feed=1, single_threaded=True, daemonize=False, skip_checks=False)
|
||||||
|
|
||||||
stories = MStory.objects(story_feed_id=1)[:53]
|
stories = MStory.objects(story_feed_id=1)[:53]
|
||||||
|
|
|
@ -10,5 +10,6 @@ urlpatterns = [
|
||||||
url(r'^add_site/?$', views.add_site_authed, name='api-add-site-authed'),
|
url(r'^add_site/?$', views.add_site_authed, name='api-add-site-authed'),
|
||||||
url(r'^check_share_on_site/(?P<token>\w+)', views.check_share_on_site, name='api-check-share-on-site'),
|
url(r'^check_share_on_site/(?P<token>\w+)', views.check_share_on_site, name='api-check-share-on-site'),
|
||||||
url(r'^share_story/(?P<token>\w+)', views.share_story, name='api-share-story'),
|
url(r'^share_story/(?P<token>\w+)', views.share_story, name='api-share-story'),
|
||||||
|
url(r'^save_story/(?P<token>\w+)', views.save_story, name='api-save-story'),
|
||||||
url(r'^share_story/?$', views.share_story),
|
url(r'^share_story/?$', views.share_story),
|
||||||
]
|
]
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.contrib.auth import logout as logout_user
|
||||||
from apps.reader.forms import SignupForm, LoginForm
|
from apps.reader.forms import SignupForm, LoginForm
|
||||||
from apps.profile.models import Profile
|
from apps.profile.models import Profile
|
||||||
from apps.social.models import MSocialProfile, MSharedStory, MSocialSubscription
|
from apps.social.models import MSocialProfile, MSharedStory, MSocialSubscription
|
||||||
from apps.rss_feeds.models import Feed
|
from apps.rss_feeds.models import Feed, MStarredStoryCounts, MStarredStory
|
||||||
from apps.rss_feeds.text_importer import TextImporter
|
from apps.rss_feeds.text_importer import TextImporter
|
||||||
from apps.reader.models import UserSubscription, UserSubscriptionFolders, RUserStory
|
from apps.reader.models import UserSubscription, UserSubscriptionFolders, RUserStory
|
||||||
from utils import json_functions as json
|
from utils import json_functions as json
|
||||||
|
@ -80,8 +80,10 @@ def logout(request):
|
||||||
def add_site_load_script(request, token):
|
def add_site_load_script(request, token):
|
||||||
code = 0
|
code = 0
|
||||||
usf = None
|
usf = None
|
||||||
profile = None;
|
profile = None
|
||||||
user_profile = None;
|
user_profile = None
|
||||||
|
starred_counts = {}
|
||||||
|
|
||||||
def image_base64(image_name, path='icons/circular/'):
|
def image_base64(image_name, path='icons/circular/'):
|
||||||
image_file = open(os.path.join(settings.MEDIA_ROOT, 'img/%s%s' % (path, image_name)))
|
image_file = open(os.path.join(settings.MEDIA_ROOT, 'img/%s%s' % (path, image_name)))
|
||||||
return base64.b64encode(image_file.read())
|
return base64.b64encode(image_file.read())
|
||||||
|
@ -99,6 +101,7 @@ def add_site_load_script(request, token):
|
||||||
user=profile.user
|
user=profile.user
|
||||||
)
|
)
|
||||||
user_profile = MSocialProfile.get_user(user_id=profile.user.pk)
|
user_profile = MSocialProfile.get_user(user_id=profile.user.pk)
|
||||||
|
starred_counts = MStarredStoryCounts.user_counts(profile.user.pk)
|
||||||
else:
|
else:
|
||||||
code = -1
|
code = -1
|
||||||
except Profile.DoesNotExist:
|
except Profile.DoesNotExist:
|
||||||
|
@ -112,6 +115,7 @@ def add_site_load_script(request, token):
|
||||||
'folders': (usf and usf.folders) or [],
|
'folders': (usf and usf.folders) or [],
|
||||||
'user': profile and profile.user or {},
|
'user': profile and profile.user or {},
|
||||||
'user_profile': user_profile and json.encode(user_profile.canonical()) or {},
|
'user_profile': user_profile and json.encode(user_profile.canonical()) or {},
|
||||||
|
'starred_counts': json.encode(starred_counts),
|
||||||
'accept_image': accept_image,
|
'accept_image': accept_image,
|
||||||
'error_image': error_image,
|
'error_image': error_image,
|
||||||
'add_image': add_image,
|
'add_image': add_image,
|
||||||
|
@ -300,7 +304,6 @@ def share_story(request, token=None):
|
||||||
message = "Not authenticated, couldn't find user by token."
|
message = "Not authenticated, couldn't find user by token."
|
||||||
else:
|
else:
|
||||||
message = "Not authenticated, no token supplied and not authenticated."
|
message = "Not authenticated, no token supplied and not authenticated."
|
||||||
|
|
||||||
|
|
||||||
if not profile:
|
if not profile:
|
||||||
return HttpResponse(json.encode({
|
return HttpResponse(json.encode({
|
||||||
|
@ -391,3 +394,106 @@ def share_story(request, token=None):
|
||||||
response['Access-Control-Allow-Methods'] = 'POST'
|
response['Access-Control-Allow-Methods'] = 'POST'
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@required_params('story_url', 'title')
|
||||||
|
def save_story(request, token=None):
|
||||||
|
code = 0
|
||||||
|
story_url = request.POST['story_url']
|
||||||
|
user_tags = request.POST.getlist('user_tags') or request.REQUEST.getlist('user_tags[]') or []
|
||||||
|
add_user_tag = request.POST.get('add_user_tag', None)
|
||||||
|
title = request.POST['title']
|
||||||
|
content = request.POST.get('content', None)
|
||||||
|
rss_url = request.POST.get('rss_url', None)
|
||||||
|
user_notes = request.POST.get('user_notes', None)
|
||||||
|
feed_id = request.POST.get('feed_id', None) or 0
|
||||||
|
feed = None
|
||||||
|
message = None
|
||||||
|
profile = None
|
||||||
|
|
||||||
|
if request.user.is_authenticated():
|
||||||
|
profile = request.user.profile
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
profile = Profile.objects.get(secret_token=token)
|
||||||
|
except Profile.DoesNotExist:
|
||||||
|
code = -1
|
||||||
|
if token:
|
||||||
|
message = "Not authenticated, couldn't find user by token."
|
||||||
|
else:
|
||||||
|
message = "Not authenticated, no token supplied and not authenticated."
|
||||||
|
|
||||||
|
if not profile:
|
||||||
|
return HttpResponse(json.encode({
|
||||||
|
'code': code,
|
||||||
|
'message': message,
|
||||||
|
'story': None,
|
||||||
|
}), mimetype='text/plain')
|
||||||
|
|
||||||
|
if feed_id:
|
||||||
|
feed = Feed.get_by_id(feed_id)
|
||||||
|
else:
|
||||||
|
if rss_url:
|
||||||
|
logging.user(request.user, "~FBFinding feed (save_story): %s" % rss_url)
|
||||||
|
feed = Feed.get_feed_from_url(rss_url, create=True, fetch=True)
|
||||||
|
if not feed:
|
||||||
|
logging.user(request.user, "~FBFinding feed (save_story): %s" % story_url)
|
||||||
|
feed = Feed.get_feed_from_url(story_url, create=True, fetch=True)
|
||||||
|
if feed:
|
||||||
|
feed_id = feed.pk
|
||||||
|
|
||||||
|
if content:
|
||||||
|
content = lxml.html.fromstring(content)
|
||||||
|
content.make_links_absolute(story_url)
|
||||||
|
content = lxml.html.tostring(content)
|
||||||
|
else:
|
||||||
|
importer = TextImporter(story=None, story_url=story_url, request=request, debug=settings.DEBUG)
|
||||||
|
document = importer.fetch(skip_save=True, return_document=True)
|
||||||
|
content = document['content']
|
||||||
|
if not title:
|
||||||
|
title = document['title']
|
||||||
|
|
||||||
|
if add_user_tag:
|
||||||
|
user_tags = user_tags + [tag for tag in add_user_tag.split(',')]
|
||||||
|
|
||||||
|
starred_story = MStarredStory.objects.filter(user_id=profile.user.pk,
|
||||||
|
story_feed_id=feed_id,
|
||||||
|
story_guid=story_url).limit(1).first()
|
||||||
|
if not starred_story:
|
||||||
|
story_db = {
|
||||||
|
"story_guid": story_url,
|
||||||
|
"story_permalink": story_url,
|
||||||
|
"story_title": title,
|
||||||
|
"story_feed_id": feed_id,
|
||||||
|
"story_content": content,
|
||||||
|
"story_date": datetime.datetime.now(),
|
||||||
|
"starred_date": datetime.datetime.now(),
|
||||||
|
"user_id": profile.user.pk,
|
||||||
|
"user_tags": user_tags,
|
||||||
|
"user_notes": user_notes,
|
||||||
|
}
|
||||||
|
starred_story = MStarredStory.objects.create(**story_db)
|
||||||
|
logging.user(profile.user, "~BM~FCStarring story from site: ~SB%s: %s" % (story_url, user_tags))
|
||||||
|
message = "Saving story from site: %s: %s" % (story_url, user_tags)
|
||||||
|
else:
|
||||||
|
starred_story.story_content = content
|
||||||
|
starred_story.story_title = title
|
||||||
|
starred_story.user_tags = user_tags
|
||||||
|
starred_story.story_permalink = story_url
|
||||||
|
starred_story.story_guid = story_url
|
||||||
|
starred_story.story_feed_id = feed_id
|
||||||
|
starred_story.user_notes = user_notes
|
||||||
|
starred_story.save()
|
||||||
|
logging.user(profile.user, "~BM~FC~SBUpdating~SN starred story from site: ~SB%s: %s" % (story_url, user_tags))
|
||||||
|
message = "Updating saved story from site: %s: %s" % (story_url, user_tags)
|
||||||
|
|
||||||
|
MStarredStoryCounts.schedule_count_tags_for_user(request.user.pk)
|
||||||
|
|
||||||
|
response = HttpResponse(json.encode({
|
||||||
|
'code': code,
|
||||||
|
'message': message,
|
||||||
|
'story': starred_story,
|
||||||
|
}), mimetype='text/plain')
|
||||||
|
response['Access-Control-Allow-Origin'] = '*'
|
||||||
|
response['Access-Control-Allow-Methods'] = 'POST'
|
||||||
|
|
||||||
|
return response
|
|
@ -1,30 +1,4 @@
|
||||||
[
|
[
|
||||||
{
|
|
||||||
"pk": 2,
|
|
||||||
"model": "sites.site",
|
|
||||||
"fields": {
|
|
||||||
"domain": "testserver",
|
|
||||||
"name": "testserver"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pk": 1,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "conesus",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": 1,
|
|
||||||
"is_superuser": 1,
|
|
||||||
"is_staff": 1,
|
|
||||||
"last_login": "2009-04-07 19:22:24",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "sha1$7b94b$ac9e6cf08d0fa16a67e56e319c0935aeb26db2a2",
|
|
||||||
"email": "samuel@newsblur.com",
|
|
||||||
"date_joined": "2009-01-04 17:32:58"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
"model": "reader.usersubscriptionfolders",
|
"model": "reader.usersubscriptionfolders",
|
||||||
|
@ -33,4 +7,4 @@
|
||||||
"user": 1
|
"user": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from mongoengine.queryset import OperationError
|
from mongoengine.queryset import OperationError
|
||||||
import vendor.opml as opml
|
import vendor.opml as opml
|
||||||
from apps.rss_feeds.models import Feed, DuplicateFeed, MStarredStory
|
from apps.rss_feeds.models import Feed, DuplicateFeed
|
||||||
from apps.reader.models import UserSubscription, UserSubscriptionFolders
|
from apps.reader.models import UserSubscription, UserSubscriptionFolders
|
||||||
from utils import json_functions as json, urlnorm
|
from utils import json_functions as json, urlnorm
|
||||||
from utils import log as logging
|
from utils import log as logging
|
||||||
|
|
|
@ -2,7 +2,6 @@ from celery.task import Task
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from apps.feed_import.models import UploadedOPML, OPMLImporter
|
from apps.feed_import.models import UploadedOPML, OPMLImporter
|
||||||
from apps.reader.models import UserSubscription
|
from apps.reader.models import UserSubscription
|
||||||
from apps.rss_feeds.models import MStarredStory
|
|
||||||
from utils import log as logging
|
from utils import log as logging
|
||||||
|
|
||||||
|
|
||||||
|
|
37
apps/profile/tests.py
Normal file
37
apps/profile/tests.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
from utils import json_functions as json
|
||||||
|
from django.test.client import Client
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.conf import settings
|
||||||
|
from mongoengine.connection import connect, disconnect
|
||||||
|
|
||||||
|
class ProfileTest(TestCase):
|
||||||
|
fixtures = [
|
||||||
|
'subscriptions.json',
|
||||||
|
'rss_feeds.json',
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
disconnect()
|
||||||
|
settings.MONGODB = connect('test_newsblur')
|
||||||
|
self.client = Client(HTTP_USER_AGENT='Mozilla/5.0')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
settings.MONGODB.drop_database('test_newsblur')
|
||||||
|
|
||||||
|
def test_create_account(self):
|
||||||
|
resp = self.client.get(reverse('load-feeds'))
|
||||||
|
response = json.decode(resp.content)
|
||||||
|
self.assertEquals(response['authenticated'], False)
|
||||||
|
|
||||||
|
response = self.client.post(reverse('welcome-signup'), {
|
||||||
|
'signup-username': 'test',
|
||||||
|
'signup-password': 'password',
|
||||||
|
'signup-email': 'test@newsblur.com',
|
||||||
|
})
|
||||||
|
self.assertEquals(response.status_code, 302)
|
||||||
|
|
||||||
|
resp = self.client.get(reverse('load-feeds'))
|
||||||
|
response = json.decode(resp.content)
|
||||||
|
self.assertEquals(response['authenticated'], True)
|
||||||
|
|
|
@ -366,7 +366,7 @@ class PSHBUpdateTestCase(PSHBTestBase, TestCase):
|
||||||
self.assertEquals(self.requests[0][0],
|
self.assertEquals(self.requests[0][0],
|
||||||
'http://myhub.example.com/endpoint')
|
'http://myhub.example.com/endpoint')
|
||||||
self.assertEquals(self.requests[0][1]['callback'],
|
self.assertEquals(self.requests[0][1]['callback'],
|
||||||
'http://testserver/1/')
|
'http://test.nb.local.com/1/')
|
||||||
self.assert_((self.requests[0][1]['lease_seconds'] - 86400) < 5)
|
self.assert_((self.requests[0][1]['lease_seconds'] - 86400) < 5)
|
||||||
|
|
||||||
def test_update_with_changed_self(self):
|
def test_update_with_changed_self(self):
|
||||||
|
@ -414,7 +414,7 @@ class PSHBUpdateTestCase(PSHBTestBase, TestCase):
|
||||||
self.assertEquals(self.requests[0][0],
|
self.assertEquals(self.requests[0][0],
|
||||||
'http://myhub.example.com/endpoint')
|
'http://myhub.example.com/endpoint')
|
||||||
self.assertEquals(self.requests[0][1]['callback'],
|
self.assertEquals(self.requests[0][1]['callback'],
|
||||||
'http://testserver/1/')
|
'http://test.nb.local.com/1/')
|
||||||
self.assert_((self.requests[0][1]['lease_seconds'] - 86400) < 5)
|
self.assert_((self.requests[0][1]['lease_seconds'] - 86400) < 5)
|
||||||
|
|
||||||
def test_update_with_changed_hub_and_self(self):
|
def test_update_with_changed_hub_and_self(self):
|
||||||
|
@ -463,5 +463,5 @@ class PSHBUpdateTestCase(PSHBTestBase, TestCase):
|
||||||
self.assertEquals(self.requests[0][0],
|
self.assertEquals(self.requests[0][0],
|
||||||
'http://myhub.example.com/endpoint')
|
'http://myhub.example.com/endpoint')
|
||||||
self.assertEquals(self.requests[0][1]['callback'],
|
self.assertEquals(self.requests[0][1]['callback'],
|
||||||
'http://testserver/1/')
|
'http://test.nb.local.com/1/')
|
||||||
self.assert_((self.requests[0][1]['lease_seconds'] - 86400) < 5)
|
self.assert_((self.requests[0][1]['lease_seconds'] - 86400) < 5)
|
||||||
|
|
|
@ -1,18 +1,4 @@
|
||||||
[
|
[
|
||||||
{
|
|
||||||
"pk": 1,
|
|
||||||
"model": "reader.usersubscription",
|
|
||||||
"fields": {
|
|
||||||
"feed": 1,
|
|
||||||
"unread_count_updated": "2009-08-01 00:23:42",
|
|
||||||
"mark_read_date": "2009-07-28 23:17:27",
|
|
||||||
"unread_count_neutral": 0,
|
|
||||||
"unread_count_positive": 0,
|
|
||||||
"unread_count_negative": 0,
|
|
||||||
"user": 1,
|
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
"model": "reader.usersubscriptionfolders",
|
"model": "reader.usersubscriptionfolders",
|
||||||
|
@ -26,7 +12,7 @@
|
||||||
"model": "reader.usersubscriptionfolders",
|
"model": "reader.usersubscriptionfolders",
|
||||||
"fields": {
|
"fields": {
|
||||||
"folders": "[5299728, 644144, 1187026, {\"Brainiacs & Opinion\": [569, 38, 3581, 183139, 1186180, 15]}, {\"Science & Technology\": [731503, 140145, 1272495, 76, 161, 39, {\"Hacker\": [5985150, 3323431]}]}, {\"Humor\": [212379, 3530, 5994357]}, {\"Videos\": [3240, 5168]}]",
|
"folders": "[5299728, 644144, 1187026, {\"Brainiacs & Opinion\": [569, 38, 3581, 183139, 1186180, 15]}, {\"Science & Technology\": [731503, 140145, 1272495, 76, 161, 39, {\"Hacker\": [5985150, 3323431]}]}, {\"Humor\": [212379, 3530, 5994357]}, {\"Videos\": [3240, 5168]}]",
|
||||||
"user": 2
|
"user": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -40,7 +26,7 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -54,7 +40,7 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -68,7 +54,7 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -82,7 +68,7 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -96,7 +82,7 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -110,7 +96,7 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -124,7 +110,7 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -138,22 +124,13 @@
|
||||||
"unread_count_neutral": 0,
|
"unread_count_neutral": 0,
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"unread_count_negative": 0,
|
"unread_count_negative": 0,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2009-07-28 23:17:27"
|
"last_read_date": "2009-07-28 23:17:27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"pk": 2,
|
"pk": 3,
|
||||||
"model": "sites.site",
|
|
||||||
"fields": {
|
|
||||||
"domain": "testserver",
|
|
||||||
"name": "testserver"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"pk": 1,
|
|
||||||
"model": "auth.user",
|
"model": "auth.user",
|
||||||
"fields": {
|
"fields": {
|
||||||
"username": "conesus",
|
"username": "conesus",
|
||||||
|
@ -171,7 +148,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pk": 2,
|
"pk": 4,
|
||||||
"model": "auth.user",
|
"model": "auth.user",
|
||||||
"fields": {
|
"fields": {
|
||||||
"username": "Dejal",
|
"username": "Dejal",
|
||||||
|
@ -198,9 +175,9 @@
|
||||||
"unread_count_positive": 0,
|
"unread_count_positive": 0,
|
||||||
"mark_read_date": "2010-06-28 19:36:44",
|
"mark_read_date": "2010-06-28 19:36:44",
|
||||||
"unread_count_negative": 3,
|
"unread_count_negative": 3,
|
||||||
"user": 1,
|
"user": 3,
|
||||||
"last_read_date": "2010-06-15 19:30:35",
|
"last_read_date": "2010-06-15 19:30:35",
|
||||||
"unread_count_neutral": 0
|
"unread_count_neutral": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -626,7 +626,9 @@ class UserSubscription(models.Model):
|
||||||
if cutoff_date:
|
if cutoff_date:
|
||||||
cutoff_date = cutoff_date + datetime.timedelta(seconds=1)
|
cutoff_date = cutoff_date + datetime.timedelta(seconds=1)
|
||||||
else:
|
else:
|
||||||
latest_story = MStory.objects(story_feed_id=self.feed.pk)\
|
now = datetime.datetime.now()
|
||||||
|
latest_story = MStory.objects(story_feed_id=self.feed.pk,
|
||||||
|
story_date__lte=now)\
|
||||||
.order_by('-story_date').only('story_date').limit(1)
|
.order_by('-story_date').only('story_date').limit(1)
|
||||||
if latest_story and len(latest_story) >= 1:
|
if latest_story and len(latest_story) >= 1:
|
||||||
cutoff_date = (latest_story[0]['story_date']
|
cutoff_date = (latest_story[0]['story_date']
|
||||||
|
|
|
@ -199,6 +199,8 @@ def signup(request):
|
||||||
url = "https://%s%s" % (Site.objects.get_current().domain,
|
url = "https://%s%s" % (Site.objects.get_current().domain,
|
||||||
reverse('stripe-form'))
|
reverse('stripe-form'))
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
else:
|
||||||
|
return HttpResponseRedirect(reverse('index'))
|
||||||
|
|
||||||
return index(request)
|
return index(request)
|
||||||
|
|
||||||
|
@ -695,8 +697,7 @@ def load_single_feed(request, feed_id):
|
||||||
starred_stories = MStarredStory.objects(user_id=user.pk,
|
starred_stories = MStarredStory.objects(user_id=user.pk,
|
||||||
story_feed_id=feed.pk,
|
story_feed_id=feed.pk,
|
||||||
story_hash__in=story_hashes)\
|
story_hash__in=story_hashes)\
|
||||||
.hint([('user_id', 1), ('story_hash', 1)])\
|
.hint([('user_id', 1), ('story_hash', 1)])
|
||||||
.only('story_hash', 'starred_date', 'user_tags')
|
|
||||||
shared_story_hashes = MSharedStory.check_shared_story_hashes(user.pk, story_hashes)
|
shared_story_hashes = MSharedStory.check_shared_story_hashes(user.pk, story_hashes)
|
||||||
shared_stories = []
|
shared_stories = []
|
||||||
if shared_story_hashes:
|
if shared_story_hashes:
|
||||||
|
@ -704,8 +705,7 @@ def load_single_feed(request, feed_id):
|
||||||
story_hash__in=shared_story_hashes)\
|
story_hash__in=shared_story_hashes)\
|
||||||
.hint([('story_hash', 1)])\
|
.hint([('story_hash', 1)])\
|
||||||
.only('story_hash', 'shared_date', 'comments')
|
.only('story_hash', 'shared_date', 'comments')
|
||||||
starred_stories = dict([(story.story_hash, dict(starred_date=story.starred_date,
|
starred_stories = dict([(story.story_hash, story)
|
||||||
user_tags=story.user_tags))
|
|
||||||
for story in starred_stories])
|
for story in starred_stories])
|
||||||
shared_stories = dict([(story.story_hash, dict(shared_date=story.shared_date,
|
shared_stories = dict([(story.story_hash, dict(shared_date=story.shared_date,
|
||||||
comments=story.comments))
|
comments=story.comments))
|
||||||
|
@ -730,11 +730,14 @@ def load_single_feed(request, feed_id):
|
||||||
story['read_status'] = 0
|
story['read_status'] = 0
|
||||||
if story['story_hash'] in starred_stories:
|
if story['story_hash'] in starred_stories:
|
||||||
story['starred'] = True
|
story['starred'] = True
|
||||||
starred_date = localtime_for_timezone(starred_stories[story['story_hash']]['starred_date'],
|
starred_story = Feed.format_story(starred_stories[story['story_hash']])
|
||||||
|
starred_date = localtime_for_timezone(starred_story['starred_date'],
|
||||||
user.profile.timezone)
|
user.profile.timezone)
|
||||||
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
||||||
story['starred_timestamp'] = starred_date.strftime('%s')
|
story['starred_timestamp'] = starred_date.strftime('%s')
|
||||||
story['user_tags'] = starred_stories[story['story_hash']]['user_tags']
|
story['user_tags'] = starred_story['user_tags']
|
||||||
|
story['user_notes'] = starred_story['user_notes']
|
||||||
|
story['highlights'] = starred_story['highlights']
|
||||||
if story['story_hash'] in shared_stories:
|
if story['story_hash'] in shared_stories:
|
||||||
story['shared'] = True
|
story['shared'] = True
|
||||||
shared_date = localtime_for_timezone(shared_stories[story['story_hash']]['shared_date'],
|
shared_date = localtime_for_timezone(shared_stories[story['story_hash']]['shared_date'],
|
||||||
|
@ -885,6 +888,7 @@ def load_starred_stories(request):
|
||||||
query = request.GET.get('query', '').strip()
|
query = request.GET.get('query', '').strip()
|
||||||
order = request.GET.get('order', 'newest')
|
order = request.GET.get('order', 'newest')
|
||||||
tag = request.GET.get('tag')
|
tag = request.GET.get('tag')
|
||||||
|
highlights = is_true(request.GET.get('highlights', False))
|
||||||
story_hashes = request.GET.getlist('h') or request.GET.getlist('h[]')
|
story_hashes = request.GET.getlist('h') or request.GET.getlist('h[]')
|
||||||
story_hashes = story_hashes[:100]
|
story_hashes = story_hashes[:100]
|
||||||
version = int(request.GET.get('v', 1))
|
version = int(request.GET.get('v', 1))
|
||||||
|
@ -902,6 +906,17 @@ def load_starred_stories(request):
|
||||||
else:
|
else:
|
||||||
stories = []
|
stories = []
|
||||||
message = "You must be a premium subscriber to search."
|
message = "You must be a premium subscriber to search."
|
||||||
|
elif highlights:
|
||||||
|
if user.profile.is_premium:
|
||||||
|
mstories = MStarredStory.objects(
|
||||||
|
user_id=user.pk,
|
||||||
|
highlights__exists=True,
|
||||||
|
__raw__={"$where": "this.highlights.length > 0"}
|
||||||
|
).order_by('%sstarred_date' % order_by)[offset:offset+limit]
|
||||||
|
stories = Feed.format_stories(mstories)
|
||||||
|
else:
|
||||||
|
stories = []
|
||||||
|
message = "You must be a premium subscriber to read through saved story highlights."
|
||||||
elif tag:
|
elif tag:
|
||||||
if user.profile.is_premium:
|
if user.profile.is_premium:
|
||||||
mstories = MStarredStory.objects(
|
mstories = MStarredStory.objects(
|
||||||
|
@ -1048,6 +1063,12 @@ def starred_stories_rss_feed(request, user_id, secret_token, tag_slug):
|
||||||
starred_stories = MStarredStory.objects(
|
starred_stories = MStarredStory.objects(
|
||||||
user_id=user.pk
|
user_id=user.pk
|
||||||
).order_by('-starred_date').limit(25)
|
).order_by('-starred_date').limit(25)
|
||||||
|
elif tag_counts.is_highlights:
|
||||||
|
starred_stories = MStarredStory.objects(
|
||||||
|
user_id=user.pk,
|
||||||
|
highlights__exists=True,
|
||||||
|
__raw__={"$where": "this.highlights.length > 0"}
|
||||||
|
).order_by('-starred_date').limit(25)
|
||||||
else:
|
else:
|
||||||
starred_stories = MStarredStory.objects(
|
starred_stories = MStarredStory.objects(
|
||||||
user_id=user.pk,
|
user_id=user.pk,
|
||||||
|
@ -1247,9 +1268,8 @@ def load_read_stories(request):
|
||||||
for story in shared_stories])
|
for story in shared_stories])
|
||||||
starred_stories = MStarredStory.objects(user_id=user.pk,
|
starred_stories = MStarredStory.objects(user_id=user.pk,
|
||||||
story_hash__in=story_hashes)\
|
story_hash__in=story_hashes)\
|
||||||
.hint([('user_id', 1), ('story_hash', 1)])\
|
.hint([('user_id', 1), ('story_hash', 1)])
|
||||||
.only('story_hash', 'starred_date')
|
starred_stories = dict([(story.story_hash, story)
|
||||||
starred_stories = dict([(story.story_hash, story.starred_date)
|
|
||||||
for story in starred_stories])
|
for story in starred_stories])
|
||||||
|
|
||||||
nowtz = localtime_for_timezone(now, user.profile.timezone)
|
nowtz = localtime_for_timezone(now, user.profile.timezone)
|
||||||
|
@ -1266,7 +1286,8 @@ def load_read_stories(request):
|
||||||
}
|
}
|
||||||
if story['story_hash'] in starred_stories:
|
if story['story_hash'] in starred_stories:
|
||||||
story['starred'] = True
|
story['starred'] = True
|
||||||
starred_date = localtime_for_timezone(starred_stories[story['story_hash']],
|
starred_story = Feed.format_story(starred_stories[story['story_hash']])
|
||||||
|
starred_date = localtime_for_timezone(starred_story['starred_date'],
|
||||||
user.profile.timezone)
|
user.profile.timezone)
|
||||||
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
||||||
story['starred_timestamp'] = starred_date.strftime('%s')
|
story['starred_timestamp'] = starred_date.strftime('%s')
|
||||||
|
@ -1394,10 +1415,11 @@ def load_river_stories__redis(request):
|
||||||
story_hashes = [s['story_hash'] for s in stories]
|
story_hashes = [s['story_hash'] for s in stories]
|
||||||
starred_stories = MStarredStory.objects(
|
starred_stories = MStarredStory.objects(
|
||||||
user_id=user.pk,
|
user_id=user.pk,
|
||||||
story_hash__in=story_hashes
|
story_hash__in=story_hashes)
|
||||||
).only('story_hash', 'starred_date', 'user_tags')
|
|
||||||
starred_stories = dict([(story.story_hash, dict(starred_date=story.starred_date,
|
starred_stories = dict([(story.story_hash, dict(starred_date=story.starred_date,
|
||||||
user_tags=story.user_tags))
|
user_tags=story.user_tags,
|
||||||
|
highlights=story.highlights,
|
||||||
|
user_notes=story.user_notes))
|
||||||
for story in starred_stories])
|
for story in starred_stories])
|
||||||
else:
|
else:
|
||||||
starred_stories = {}
|
starred_stories = {}
|
||||||
|
@ -1445,6 +1467,8 @@ def load_river_stories__redis(request):
|
||||||
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
||||||
story['starred_timestamp'] = starred_date.strftime('%s')
|
story['starred_timestamp'] = starred_date.strftime('%s')
|
||||||
story['user_tags'] = starred_stories[story['story_hash']]['user_tags']
|
story['user_tags'] = starred_stories[story['story_hash']]['user_tags']
|
||||||
|
story['user_notes'] = starred_stories[story['story_hash']]['user_notes']
|
||||||
|
story['highlights'] = starred_stories[story['story_hash']]['highlights']
|
||||||
story['intelligence'] = {
|
story['intelligence'] = {
|
||||||
'feed': apply_classifier_feeds(classifier_feeds, story['story_feed_id']),
|
'feed': apply_classifier_feeds(classifier_feeds, story['story_feed_id']),
|
||||||
'author': apply_classifier_authors(classifier_authors, story),
|
'author': apply_classifier_authors(classifier_authors, story),
|
||||||
|
@ -2393,6 +2417,8 @@ def _mark_story_as_starred(request):
|
||||||
story_id = request.POST.get('story_id', None)
|
story_id = request.POST.get('story_id', None)
|
||||||
story_hash = request.POST.get('story_hash', None)
|
story_hash = request.POST.get('story_hash', None)
|
||||||
user_tags = request.POST.getlist('user_tags') or request.POST.getlist('user_tags[]')
|
user_tags = request.POST.getlist('user_tags') or request.POST.getlist('user_tags[]')
|
||||||
|
user_notes = request.POST.get('user_notes', None)
|
||||||
|
highlights = request.POST.getlist('highlights') or request.POST.getlist('highlights[]') or []
|
||||||
message = ""
|
message = ""
|
||||||
if story_hash:
|
if story_hash:
|
||||||
story, _ = MStory.find_story(story_hash=story_hash)
|
story, _ = MStory.find_story(story_hash=story_hash)
|
||||||
|
@ -2405,16 +2431,23 @@ def _mark_story_as_starred(request):
|
||||||
|
|
||||||
story_db = dict([(k, v) for k, v in story._data.items()
|
story_db = dict([(k, v) for k, v in story._data.items()
|
||||||
if k is not None and v is not None])
|
if k is not None and v is not None])
|
||||||
|
# Pop all existing user-specific fields because we don't want to reuse them from the found story
|
||||||
|
# in case MStory.find_story uses somebody else's saved/shared story (because the original is deleted)
|
||||||
story_db.pop('user_id', None)
|
story_db.pop('user_id', None)
|
||||||
story_db.pop('starred_date', None)
|
story_db.pop('starred_date', None)
|
||||||
story_db.pop('id', None)
|
story_db.pop('id', None)
|
||||||
story_db.pop('user_tags', None)
|
story_db.pop('user_tags', None)
|
||||||
|
story_db.pop('highlights', None)
|
||||||
|
story_db.pop('user_notes', None)
|
||||||
|
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
story_values = dict(starred_date=now, user_tags=user_tags, **story_db)
|
story_values = dict(starred_date=now, user_tags=user_tags, highlights=highlights, user_notes=user_notes, **story_db)
|
||||||
params = dict(story_guid=story.story_guid, user_id=request.user.pk)
|
params = dict(story_guid=story.story_guid, user_id=request.user.pk)
|
||||||
starred_story = MStarredStory.objects(**params).limit(1)
|
starred_story = MStarredStory.objects(**params).limit(1)
|
||||||
created = False
|
created = False
|
||||||
|
changed_user_notes = False
|
||||||
removed_user_tags = []
|
removed_user_tags = []
|
||||||
|
removed_highlights = []
|
||||||
if not starred_story:
|
if not starred_story:
|
||||||
params.update(story_values)
|
params.update(story_values)
|
||||||
if params.has_key('story_latest_content_z'):
|
if params.has_key('story_latest_content_z'):
|
||||||
|
@ -2431,14 +2464,26 @@ def _mark_story_as_starred(request):
|
||||||
story_feed_id=feed_id,
|
story_feed_id=feed_id,
|
||||||
story_id=starred_story.story_guid)
|
story_id=starred_story.story_guid)
|
||||||
new_user_tags = user_tags
|
new_user_tags = user_tags
|
||||||
|
new_highlights = highlights
|
||||||
|
changed_user_notes = bool(user_notes)
|
||||||
MStarredStoryCounts.adjust_count(request.user.pk, feed_id=feed_id, amount=1)
|
MStarredStoryCounts.adjust_count(request.user.pk, feed_id=feed_id, amount=1)
|
||||||
else:
|
else:
|
||||||
starred_story = starred_story[0]
|
starred_story = starred_story[0]
|
||||||
new_user_tags = list(set(user_tags) - set(starred_story.user_tags or []))
|
new_user_tags = list(set(user_tags) - set(starred_story.user_tags or []))
|
||||||
removed_user_tags = list(set(starred_story.user_tags or []) - set(user_tags))
|
removed_user_tags = list(set(starred_story.user_tags or []) - set(user_tags))
|
||||||
|
new_highlights = list(set(highlights) - set(starred_story.highlights or []))
|
||||||
|
removed_highlights = list(set(starred_story.highlights or []) - set(highlights))
|
||||||
|
changed_user_notes = bool(user_notes != starred_story.user_notes)
|
||||||
starred_story.user_tags = user_tags
|
starred_story.user_tags = user_tags
|
||||||
|
starred_story.highlights = highlights
|
||||||
|
starred_story.user_notes = user_notes
|
||||||
starred_story.save()
|
starred_story.save()
|
||||||
|
|
||||||
|
if len(highlights) == 1 and len(new_highlights) == 1:
|
||||||
|
MStarredStoryCounts.adjust_count(request.user.pk, highlights=True, amount=1)
|
||||||
|
elif len(highlights) == 0 and len(removed_highlights):
|
||||||
|
MStarredStoryCounts.adjust_count(request.user.pk, highlights=True, amount=-1)
|
||||||
|
|
||||||
for tag in new_user_tags:
|
for tag in new_user_tags:
|
||||||
MStarredStoryCounts.adjust_count(request.user.pk, tag=tag, amount=1)
|
MStarredStoryCounts.adjust_count(request.user.pk, tag=tag, amount=1)
|
||||||
for tag in removed_user_tags:
|
for tag in removed_user_tags:
|
||||||
|
@ -2451,13 +2496,14 @@ def _mark_story_as_starred(request):
|
||||||
if not starred_count and len(starred_counts):
|
if not starred_count and len(starred_counts):
|
||||||
starred_count = MStarredStory.objects(user_id=request.user.pk).count()
|
starred_count = MStarredStory.objects(user_id=request.user.pk).count()
|
||||||
|
|
||||||
r = redis.Redis(connection_pool=settings.REDIS_PUBSUB_POOL)
|
if not changed_user_notes:
|
||||||
r.publish(request.user.username, 'story:starred:%s' % story.story_hash)
|
r = redis.Redis(connection_pool=settings.REDIS_PUBSUB_POOL)
|
||||||
|
r.publish(request.user.username, 'story:starred:%s' % story.story_hash)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
logging.user(request, "~FCStarring: ~SB%s (~FM~SB%s~FC~SN)" % (story.story_title[:32], starred_story.user_tags))
|
logging.user(request, "~FCStarring: ~SB%s (~FM~SB%s~FC~SN)" % (story.story_title[:32], starred_story.user_tags))
|
||||||
else:
|
else:
|
||||||
logging.user(request, "~FCUpdating starred:~SN~FC ~SB%s~SN (~FM~SB%s~FC~SN)" % (story.story_title[:32], starred_story.user_tags))
|
logging.user(request, "~FCUpdating starred:~SN~FC ~SB%s~SN (~FM~SB%s~FC~SN/~FM%s~FC)" % (story.story_title[:32], starred_story.user_tags, starred_story.user_notes))
|
||||||
|
|
||||||
return {'code': code, 'message': message, 'starred_count': starred_count, 'starred_counts': starred_counts}
|
return {'code': code, 'message': message, 'starred_count': starred_count, 'starred_counts': starred_counts}
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"pk": 2,
|
|
||||||
"model": "sites.site",
|
|
||||||
"fields": {
|
|
||||||
"domain": "testserver",
|
|
||||||
"name": "testserver"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "newsblur_test",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false,
|
|
||||||
"is_staff": true,
|
|
||||||
"last_login": "2011-07-18 00:23:49",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "sha1$d5473$d07ce4495b088ff0f41a62d5113d0189ce8f0096",
|
|
||||||
"email": "samuel@newsblur.com",
|
|
||||||
"date_joined": "2011-07-18 00:23:49"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,22 +1,46 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"pk": 6,
|
"pk": 16,
|
||||||
"model": "rss_feeds.feed",
|
"model": "rss_feeds.feed",
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"premium_subscribers": -1,
|
||||||
|
"creation": "2011-08-27",
|
||||||
|
"exception_code": 0,
|
||||||
|
"last_load_time": 0,
|
||||||
|
"active_subscribers": 1,
|
||||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/brokelyn.xml",
|
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/brokelyn.xml",
|
||||||
"days_to_trim": 90,
|
|
||||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/brokelyn.html",
|
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/brokelyn.html",
|
||||||
|
"hash_address_and_link": "16",
|
||||||
"feed_link_locked": true,
|
"feed_link_locked": true,
|
||||||
"num_subscribers": 0,
|
"last_update": "2011-08-27 02:45:21",
|
||||||
"creation": "2009-01-12",
|
"etag": null,
|
||||||
"feed_title": "Brokelyn",
|
"average_stories_per_month": 0,
|
||||||
"last_update": "2009-07-06 22:30:03",
|
"feed_title": "Brokelyn",
|
||||||
"next_scheduled_update": "2009-07-06 22:30:03",
|
"last_modified": null,
|
||||||
"last_story_date": "2009-07-06 22:30:03",
|
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||||
"min_to_decay": 1,
|
"favicon_color": null,
|
||||||
"etag": "",
|
"stories_last_month": 0,
|
||||||
"last_modified": "2009-07-06 22:30:03",
|
"active": true,
|
||||||
"active": 1
|
"favicon_not_found": false,
|
||||||
|
"has_page_exception": false,
|
||||||
|
"fetched_once": false,
|
||||||
|
"days_to_trim": 90,
|
||||||
|
"num_subscribers": 1,
|
||||||
|
"last_story_date": "2011-08-28 00:03:50",
|
||||||
|
"min_to_decay": 720,
|
||||||
|
"has_feed_exception": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 16,
|
||||||
|
"model": "rss_feeds.feeddata",
|
||||||
|
"fields": {
|
||||||
|
"feed": 16,
|
||||||
|
"feed_classifier_counts": null,
|
||||||
|
"feed_tagline": "Visual feed reading with intelligence.",
|
||||||
|
"popular_tags": "[]",
|
||||||
|
"story_count_history": null,
|
||||||
|
"popular_authors": "[]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"pk": 1,
|
"pk": 10,
|
||||||
"model": "rss_feeds.feed",
|
"model": "rss_feeds.feed",
|
||||||
"fields": {
|
"fields": {
|
||||||
"premium_subscribers": -1,
|
"premium_subscribers": -1,
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
"active_subscribers": 1,
|
"active_subscribers": 1,
|
||||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker1.xml",
|
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker1.xml",
|
||||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker1.html",
|
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker1.html",
|
||||||
|
"hash_address_and_link": "10",
|
||||||
"feed_link_locked": true,
|
"feed_link_locked": true,
|
||||||
"last_update": "2011-08-27 02:45:21",
|
"last_update": "2011-08-27 02:45:21",
|
||||||
"etag": null,
|
"etag": null,
|
||||||
|
@ -30,4 +31,4 @@
|
||||||
"has_feed_exception": false
|
"has_feed_exception": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
1
apps/rss_feeds/fixtures/initial_data.json
Symbolic link
1
apps/rss_feeds/fixtures/initial_data.json
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../../config/fixtures/bootstrap.json
|
|
@ -110,34 +110,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
"pk": 2,
|
|
||||||
"model": "sites.site",
|
|
||||||
"fields": {
|
|
||||||
"domain": "testserver",
|
|
||||||
"name": "testserver"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
"pk": 1,
|
|
||||||
"model": "auth.user",
|
|
||||||
"fields": {
|
|
||||||
"username": "conesus",
|
|
||||||
"first_name": "",
|
|
||||||
"last_name": "",
|
|
||||||
"is_active": 1,
|
|
||||||
"is_superuser": 1,
|
|
||||||
"is_staff": 1,
|
|
||||||
"last_login": "2009-07-06 22:30:03",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": [],
|
|
||||||
"password": "sha1$7b94b$ac9e6cf08d0fa16a67e56e319c0935aeb26db2a2",
|
|
||||||
"email": "samuel@newsblur.com",
|
|
||||||
"date_joined": "2009-01-04 17:32:58"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"pk": 2,
|
"pk": 2,
|
||||||
|
@ -467,4 +439,4 @@
|
||||||
"has_feed_exception": false
|
"has_feed_exception": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1881,7 +1881,7 @@ class Feed(models.Model):
|
||||||
story_title = strip_tags(story_content)
|
story_title = strip_tags(story_content)
|
||||||
if not story_title and story_db.story_permalink:
|
if not story_title and story_db.story_permalink:
|
||||||
story_title = story_db.story_permalink
|
story_title = story_db.story_permalink
|
||||||
if len(story_title) > 80:
|
if story_title and len(story_title) > 80:
|
||||||
story_title = story_title[:80] + '...'
|
story_title = story_title[:80] + '...'
|
||||||
|
|
||||||
story = {}
|
story = {}
|
||||||
|
@ -1912,6 +1912,10 @@ class Feed(models.Model):
|
||||||
story['starred_date'] = story_db.starred_date
|
story['starred_date'] = story_db.starred_date
|
||||||
if hasattr(story_db, 'user_tags'):
|
if hasattr(story_db, 'user_tags'):
|
||||||
story['user_tags'] = story_db.user_tags
|
story['user_tags'] = story_db.user_tags
|
||||||
|
if hasattr(story_db, 'user_notes'):
|
||||||
|
story['user_notes'] = story_db.user_notes
|
||||||
|
if hasattr(story_db, 'highlights'):
|
||||||
|
story['highlights'] = story_db.highlights
|
||||||
if hasattr(story_db, 'shared_date'):
|
if hasattr(story_db, 'shared_date'):
|
||||||
story['shared_date'] = story_db.shared_date
|
story['shared_date'] = story_db.shared_date
|
||||||
if hasattr(story_db, 'comments'):
|
if hasattr(story_db, 'comments'):
|
||||||
|
@ -2844,7 +2848,9 @@ class MStarredStory(mongo.DynamicDocument):
|
||||||
story_guid = mongo.StringField()
|
story_guid = mongo.StringField()
|
||||||
story_hash = mongo.StringField()
|
story_hash = mongo.StringField()
|
||||||
story_tags = mongo.ListField(mongo.StringField(max_length=250))
|
story_tags = mongo.ListField(mongo.StringField(max_length=250))
|
||||||
|
user_notes = mongo.StringField()
|
||||||
user_tags = mongo.ListField(mongo.StringField(max_length=128))
|
user_tags = mongo.ListField(mongo.StringField(max_length=128))
|
||||||
|
highlights = mongo.ListField(mongo.StringField(max_length=1024))
|
||||||
image_urls = mongo.ListField(mongo.StringField(max_length=1024))
|
image_urls = mongo.ListField(mongo.StringField(max_length=1024))
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
|
@ -2855,6 +2861,16 @@ class MStarredStory(mongo.DynamicDocument):
|
||||||
'allow_inheritance': False,
|
'allow_inheritance': False,
|
||||||
'strict': False,
|
'strict': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
try:
|
||||||
|
user = User.objects.get(pk=self.user_id)
|
||||||
|
username = user.username
|
||||||
|
except User.DoesNotExist:
|
||||||
|
username = '[deleted]'
|
||||||
|
return "%s: %s (%s)" % (username,
|
||||||
|
self.story_title[:20],
|
||||||
|
self.story_feed_id)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.story_content:
|
if self.story_content:
|
||||||
|
@ -2964,6 +2980,7 @@ class MStarredStoryCounts(mongo.Document):
|
||||||
user_id = mongo.IntField()
|
user_id = mongo.IntField()
|
||||||
tag = mongo.StringField(max_length=128)
|
tag = mongo.StringField(max_length=128)
|
||||||
feed_id = mongo.IntField()
|
feed_id = mongo.IntField()
|
||||||
|
is_highlights = mongo.BooleanField()
|
||||||
slug = mongo.StringField(max_length=128)
|
slug = mongo.StringField(max_length=128)
|
||||||
count = mongo.IntField(default=0)
|
count = mongo.IntField(default=0)
|
||||||
|
|
||||||
|
@ -2973,6 +2990,16 @@ class MStarredStoryCounts(mongo.Document):
|
||||||
'ordering': ['tag'],
|
'ordering': ['tag'],
|
||||||
'allow_inheritance': False,
|
'allow_inheritance': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
if self.tag:
|
||||||
|
return "Tag: %s (%s)" % (self.tag, self.count)
|
||||||
|
elif self.feed_id:
|
||||||
|
return "Feed: %s (%s)" % (self.feed_id, self.count)
|
||||||
|
elif self.is_highlights:
|
||||||
|
return "Highlights: %s (%s)" % (self.is_highlights, self.count)
|
||||||
|
|
||||||
|
return "%s/%s/%s" % (self.tag, self.feed_id, self.is_highlights)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rss_url(self, secret_token=None):
|
def rss_url(self, secret_token=None):
|
||||||
|
@ -2992,6 +3019,7 @@ class MStarredStoryCounts(mongo.Document):
|
||||||
counts = cls.objects.filter(user_id=user_id)
|
counts = cls.objects.filter(user_id=user_id)
|
||||||
counts = sorted([{'tag': c.tag,
|
counts = sorted([{'tag': c.tag,
|
||||||
'count': c.count,
|
'count': c.count,
|
||||||
|
'is_highlights': c.is_highlights,
|
||||||
'feed_address': c.rss_url,
|
'feed_address': c.rss_url,
|
||||||
'feed_id': c.feed_id}
|
'feed_id': c.feed_id}
|
||||||
for c in counts],
|
for c in counts],
|
||||||
|
@ -3000,7 +3028,7 @@ class MStarredStoryCounts(mongo.Document):
|
||||||
total = 0
|
total = 0
|
||||||
feed_total = 0
|
feed_total = 0
|
||||||
for c in counts:
|
for c in counts:
|
||||||
if not c['tag'] and not c['feed_id']:
|
if not c['tag'] and not c['feed_id'] and not c['is_highlights']:
|
||||||
total = c['count']
|
total = c['count']
|
||||||
if c['feed_id']:
|
if c['feed_id']:
|
||||||
feed_total += c['count']
|
feed_total += c['count']
|
||||||
|
@ -3025,20 +3053,22 @@ class MStarredStoryCounts(mongo.Document):
|
||||||
def count_for_user(cls, user_id, total_only=False):
|
def count_for_user(cls, user_id, total_only=False):
|
||||||
user_tags = []
|
user_tags = []
|
||||||
user_feeds = []
|
user_feeds = []
|
||||||
|
highlights = 0
|
||||||
|
|
||||||
if not total_only:
|
if not total_only:
|
||||||
cls.objects(user_id=user_id).delete()
|
cls.objects(user_id=user_id).delete()
|
||||||
try:
|
try:
|
||||||
user_tags = cls.count_tags_for_user(user_id)
|
user_tags = cls.count_tags_for_user(user_id)
|
||||||
|
highlights = cls.count_highlights_for_user(user_id)
|
||||||
user_feeds = cls.count_feeds_for_user(user_id)
|
user_feeds = cls.count_feeds_for_user(user_id)
|
||||||
except pymongo.errors.OperationFailure, e:
|
except pymongo.errors.OperationFailure, e:
|
||||||
logging.debug(" ---> ~FBOperationError on mongo: ~SB%s" % e)
|
logging.debug(" ---> ~FBOperationError on mongo: ~SB%s" % e)
|
||||||
|
|
||||||
total_stories_count = MStarredStory.objects(user_id=user_id).count()
|
total_stories_count = MStarredStory.objects(user_id=user_id).count()
|
||||||
cls.objects(user_id=user_id, tag=None, feed_id=None).update_one(set__count=total_stories_count,
|
cls.objects(user_id=user_id, tag=None, feed_id=None, is_highlights=None).update_one(set__count=total_stories_count,
|
||||||
upsert=True)
|
upsert=True)
|
||||||
|
|
||||||
return dict(total=total_stories_count, tags=user_tags, feeds=user_feeds)
|
return dict(total=total_stories_count, tags=user_tags, feeds=user_feeds, highlights=highlights)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def count_tags_for_user(cls, user_id):
|
def count_tags_for_user(cls, user_id):
|
||||||
|
@ -3051,9 +3081,24 @@ class MStarredStoryCounts(mongo.Document):
|
||||||
for tag, count in dict(user_tags).items():
|
for tag, count in dict(user_tags).items():
|
||||||
cls.objects(user_id=user_id, tag=tag, slug=slugify(tag)).update_one(set__count=count,
|
cls.objects(user_id=user_id, tag=tag, slug=slugify(tag)).update_one(set__count=count,
|
||||||
upsert=True)
|
upsert=True)
|
||||||
|
|
||||||
return user_tags
|
return user_tags
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def count_highlights_for_user(cls, user_id):
|
||||||
|
highlighted_count = MStarredStory.objects(user_id=user_id,
|
||||||
|
highlights__exists=True,
|
||||||
|
__raw__={"$where": "this.highlights.length > 0"}).count()
|
||||||
|
if highlighted_count > 0:
|
||||||
|
cls.objects(user_id=user_id,
|
||||||
|
is_highlights=True,
|
||||||
|
slug="highlights"
|
||||||
|
).update_one(set__count=highlighted_count, upsert=True)
|
||||||
|
else:
|
||||||
|
cls.objects(user_id=user_id, is_highlights=True, slug="highlights").delete()
|
||||||
|
|
||||||
|
return highlighted_count
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def count_feeds_for_user(cls, user_id):
|
def count_feeds_for_user(cls, user_id):
|
||||||
all_feeds = MStarredStory.objects(user_id=user_id).item_frequencies('story_feed_id')
|
all_feeds = MStarredStory.objects(user_id=user_id).item_frequencies('story_feed_id')
|
||||||
|
@ -3079,12 +3124,14 @@ class MStarredStoryCounts(mongo.Document):
|
||||||
return user_feeds
|
return user_feeds
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def adjust_count(cls, user_id, feed_id=None, tag=None, amount=0):
|
def adjust_count(cls, user_id, feed_id=None, tag=None, highlights=None, amount=0):
|
||||||
params = dict(user_id=user_id)
|
params = dict(user_id=user_id)
|
||||||
if feed_id:
|
if feed_id:
|
||||||
params['feed_id'] = feed_id
|
params['feed_id'] = feed_id
|
||||||
if tag:
|
if tag:
|
||||||
params['tag'] = tag
|
params['tag'] = tag
|
||||||
|
if highlights:
|
||||||
|
params['is_highlights'] = True
|
||||||
|
|
||||||
cls.objects(**params).update_one(inc__count=amount, upsert=True)
|
cls.objects(**params).update_one(inc__count=amount, upsert=True)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -16,7 +16,7 @@ class FeedTest(TestCase):
|
||||||
disconnect()
|
disconnect()
|
||||||
settings.MONGODB = connect('test_newsblur')
|
settings.MONGODB = connect('test_newsblur')
|
||||||
settings.REDIS_STORY_HASH_POOL = redis.ConnectionPool(host=settings.REDIS_STORY['host'], port=6379, db=10)
|
settings.REDIS_STORY_HASH_POOL = redis.ConnectionPool(host=settings.REDIS_STORY['host'], port=6379, db=10)
|
||||||
settings.REDIS_FEED_READ_POOL = redis.ConnectionPool(host=settings.SESSION_REDIS_HOST, port=6379, db=10)
|
settings.REDIS_FEED_READ_POOL = redis.ConnectionPool(host=settings.REDIS_SESSIONS['host'], port=6379, db=10)
|
||||||
|
|
||||||
r = redis.Redis(connection_pool=settings.REDIS_STORY_HASH_POOL)
|
r = redis.Redis(connection_pool=settings.REDIS_STORY_HASH_POOL)
|
||||||
r.delete('RS:1')
|
r.delete('RS:1')
|
||||||
|
@ -33,9 +33,9 @@ class FeedTest(TestCase):
|
||||||
def test_load_feeds__gawker(self):
|
def test_load_feeds__gawker(self):
|
||||||
self.client.login(username='conesus', password='test')
|
self.client.login(username='conesus', password='test')
|
||||||
|
|
||||||
management.call_command('loaddata', 'gawker1.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'gawker1.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
|
|
||||||
feed = Feed.objects.get(feed_link__contains='gawker')
|
feed = Feed.objects.get(pk=10)
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
self.assertEquals(stories.count(), 0)
|
self.assertEquals(stories.count(), 0)
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class FeedTest(TestCase):
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
self.assertEquals(stories.count(), 38)
|
self.assertEquals(stories.count(), 38)
|
||||||
|
|
||||||
management.call_command('loaddata', 'gawker2.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'gawker2.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
|
|
||||||
feed.update(force=True)
|
feed.update(force=True)
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ class FeedTest(TestCase):
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
self.assertEquals(stories.count(), 38)
|
self.assertEquals(stories.count(), 38)
|
||||||
|
|
||||||
url = reverse('load-single-feed', kwargs=dict(feed_id=1))
|
url = reverse('load-single-feed', kwargs=dict(feed_id=10))
|
||||||
response = self.client.get(url)
|
response = self.client.get(url)
|
||||||
feed = json.decode(response.content)
|
feed = json.decode(response.content)
|
||||||
self.assertEquals(len(feed['stories']), 6)
|
self.assertEquals(len(feed['stories']), 6)
|
||||||
|
@ -60,7 +60,7 @@ class FeedTest(TestCase):
|
||||||
def test_load_feeds__gothamist(self):
|
def test_load_feeds__gothamist(self):
|
||||||
self.client.login(username='conesus', password='test')
|
self.client.login(username='conesus', password='test')
|
||||||
|
|
||||||
management.call_command('loaddata', 'gothamist_aug_2009_1.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'gothamist_aug_2009_1.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
feed = Feed.objects.get(feed_link__contains='gothamist')
|
feed = Feed.objects.get(feed_link__contains='gothamist')
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
self.assertEquals(stories.count(), 0)
|
self.assertEquals(stories.count(), 0)
|
||||||
|
@ -75,7 +75,7 @@ class FeedTest(TestCase):
|
||||||
content = json.decode(response.content)
|
content = json.decode(response.content)
|
||||||
self.assertEquals(len(content['stories']), 6)
|
self.assertEquals(len(content['stories']), 6)
|
||||||
|
|
||||||
management.call_command('loaddata', 'gothamist_aug_2009_2.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'gothamist_aug_2009_2.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
feed.update(force=True)
|
feed.update(force=True)
|
||||||
|
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
|
@ -93,7 +93,7 @@ class FeedTest(TestCase):
|
||||||
|
|
||||||
old_story_guid = "tag:google.com,2005:reader/item/4528442633bc7b2b"
|
old_story_guid = "tag:google.com,2005:reader/item/4528442633bc7b2b"
|
||||||
|
|
||||||
management.call_command('loaddata', 'slashdot1.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'slashdot1.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
|
|
||||||
feed = Feed.objects.get(feed_link__contains='slashdot')
|
feed = Feed.objects.get(feed_link__contains='slashdot')
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
|
@ -114,7 +114,7 @@ class FeedTest(TestCase):
|
||||||
content = json.decode(response.content)
|
content = json.decode(response.content)
|
||||||
self.assertEquals(content['feeds']['5']['nt'], 37)
|
self.assertEquals(content['feeds']['5']['nt'], 37)
|
||||||
|
|
||||||
management.call_command('loaddata', 'slashdot2.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'slashdot2.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
management.call_command('refresh_feed', force=1, feed=5, single_threaded=True, daemonize=False, skip_checks=False)
|
management.call_command('refresh_feed', force=1, feed=5, single_threaded=True, daemonize=False, skip_checks=False)
|
||||||
|
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
|
@ -136,7 +136,7 @@ class FeedTest(TestCase):
|
||||||
def test_load_feeds__motherjones(self):
|
def test_load_feeds__motherjones(self):
|
||||||
self.client.login(username='conesus', password='test')
|
self.client.login(username='conesus', password='test')
|
||||||
|
|
||||||
management.call_command('loaddata', 'motherjones1.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'motherjones1.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
|
|
||||||
feed = Feed.objects.get(feed_link__contains='motherjones')
|
feed = Feed.objects.get(feed_link__contains='motherjones')
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
|
@ -157,7 +157,7 @@ class FeedTest(TestCase):
|
||||||
content = json.decode(response.content)
|
content = json.decode(response.content)
|
||||||
self.assertEquals(content['feeds'][str(feed.pk)]['nt'], 9)
|
self.assertEquals(content['feeds'][str(feed.pk)]['nt'], 9)
|
||||||
|
|
||||||
management.call_command('loaddata', 'motherjones2.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'motherjones2.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
management.call_command('refresh_feed', force=1, feed=feed.pk, single_threaded=True, daemonize=False, skip_checks=False)
|
management.call_command('refresh_feed', force=1, feed=feed.pk, single_threaded=True, daemonize=False, skip_checks=False)
|
||||||
|
|
||||||
stories = MStory.objects(story_feed_id=feed.pk)
|
stories = MStory.objects(story_feed_id=feed.pk)
|
||||||
|
@ -225,19 +225,23 @@ class FeedTest(TestCase):
|
||||||
self.assertEquals(content['feeds']['766']['nt'], 19)
|
self.assertEquals(content['feeds']['766']['nt'], 19)
|
||||||
|
|
||||||
def test_load_feeds__brokelyn__invalid_xml(self):
|
def test_load_feeds__brokelyn__invalid_xml(self):
|
||||||
|
BROKELYN_FEED_ID = 16
|
||||||
self.client.login(username='conesus', password='test')
|
self.client.login(username='conesus', password='test')
|
||||||
|
management.call_command('loaddata', 'brokelyn.json', verbosity=0, commit=False)
|
||||||
|
self.assertEquals(Feed.objects.get(pk=BROKELYN_FEED_ID).pk, BROKELYN_FEED_ID)
|
||||||
|
management.call_command('refresh_feed', force=1, feed=BROKELYN_FEED_ID, single_threaded=True, daemonize=False)
|
||||||
|
|
||||||
management.call_command('loaddata', 'brokelyn.json', verbosity=0, skip_checks=False)
|
management.call_command('loaddata', 'brokelyn.json', verbosity=0, commit=False, skip_checks=False)
|
||||||
management.call_command('refresh_feed', force=1, feed=6, single_threaded=True, daemonize=False, skip_checks=False)
|
management.call_command('refresh_feed', force=1, feed=6, single_threaded=True, daemonize=False, skip_checks=False)
|
||||||
|
|
||||||
url = reverse('load-single-feed', kwargs=dict(feed_id=6))
|
url = reverse('load-single-feed', kwargs=dict(feed_id=BROKELYN_FEED_ID))
|
||||||
response = self.client.get(url)
|
response = self.client.get(url)
|
||||||
|
|
||||||
# pprint([c['story_title'] for c in json.decode(response.content)])
|
# pprint([c['story_title'] for c in json.decode(response.content)])
|
||||||
feed = json.decode(response.content)
|
feed = json.decode(response.content)
|
||||||
|
|
||||||
# Test: 1 changed char in title
|
# Test: 1 changed char in title
|
||||||
self.assertEquals(len(feed['stories']), 6)
|
self.assertEquals(len(feed['stories']), 0)
|
||||||
|
|
||||||
def test_all_feeds(self):
|
def test_all_feeds(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1255,8 +1255,10 @@ class MSocialSubscription(mongo.Document):
|
||||||
cutoff_date = cutoff_date + datetime.timedelta(seconds=1)
|
cutoff_date = cutoff_date + datetime.timedelta(seconds=1)
|
||||||
else:
|
else:
|
||||||
# Use the latest story to get last read time.
|
# Use the latest story to get last read time.
|
||||||
|
now = datetime.datetime.now()
|
||||||
latest_shared_story = MSharedStory.objects(user_id=self.subscription_user_id,
|
latest_shared_story = MSharedStory.objects(user_id=self.subscription_user_id,
|
||||||
shared_date__gte=user_profile.unread_cutoff
|
shared_date__gte=user_profile.unread_cutoff,
|
||||||
|
story_date__lte=now
|
||||||
).order_by('-shared_date').only('shared_date').first()
|
).order_by('-shared_date').only('shared_date').first()
|
||||||
if latest_shared_story:
|
if latest_shared_story:
|
||||||
cutoff_date = latest_shared_story['shared_date'] + datetime.timedelta(seconds=1)
|
cutoff_date = latest_shared_story['shared_date'] + datetime.timedelta(seconds=1)
|
||||||
|
|
|
@ -1304,6 +1304,7 @@ def shared_stories_rss_feed_noid(request):
|
||||||
|
|
||||||
return index
|
return index
|
||||||
|
|
||||||
|
@ratelimit(minutes=1, requests=5)
|
||||||
def shared_stories_rss_feed(request, user_id, username):
|
def shared_stories_rss_feed(request, user_id, username):
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(pk=user_id)
|
user = User.objects.get(pk=user_id)
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.newsblur"
|
package="com.newsblur">
|
||||||
android:versionCode="167"
|
|
||||||
android:versionName="10.0" >
|
|
||||||
|
|
||||||
<uses-sdk
|
|
||||||
android:minSdkVersion="21"
|
|
||||||
android:targetSdkVersion="28" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
@ -131,6 +125,9 @@
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.FolderReading"/>
|
android:name=".activity.FolderReading"/>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".activity.InAppBrowser" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.SearchForFeeds" android:launchMode="singleTop" >
|
android:name=".activity.SearchForFeeds" android:launchMode="singleTop" >
|
||||||
|
|
|
@ -8,7 +8,7 @@ buildscript {
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,27 +22,29 @@ repositories {
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'checkstyle'
|
apply plugin: 'checkstyle'
|
||||||
apply plugin: 'findbugs'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-core-utils:27.1.1'
|
implementation 'com.android.support:support-core-utils:28.0.0'
|
||||||
compile 'com.android.support:support-fragment:27.1.1'
|
implementation 'com.android.support:support-fragment:28.0.0'
|
||||||
compile 'com.android.support:support-core-ui:27.1.1'
|
implementation 'com.android.support:support-core-ui:28.0.0'
|
||||||
compile 'com.jakewharton:butterknife:7.0.1'
|
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
|
||||||
compile 'com.squareup.okhttp3:okhttp:3.8.1'
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
compile 'com.google.code.gson:gson:2.8.2'
|
implementation 'com.android.support:recyclerview-v7:28.0.0'
|
||||||
compile 'com.android.support:recyclerview-v7:27.1.1'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 28
|
||||||
buildToolsVersion '27.0.3'
|
defaultConfig {
|
||||||
|
applicationId "com.newsblur"
|
||||||
|
minSdkVersion 21
|
||||||
|
targetSdkVersion 28
|
||||||
|
versionCode 168
|
||||||
|
versionName "10.1"
|
||||||
|
}
|
||||||
compileOptions.with {
|
compileOptions.with {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_7
|
sourceCompatibility = JavaVersion.VERSION_1_7
|
||||||
}
|
}
|
||||||
|
viewBinding.enabled = true
|
||||||
// force old processing behaviour that butterknife 7 depends on, until we can afford to upgrade
|
|
||||||
android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
|
|
|
@ -11,16 +11,6 @@
|
||||||
-dontwarn okhttp3.**
|
-dontwarn okhttp3.**
|
||||||
-dontnote okhttp3.**
|
-dontnote okhttp3.**
|
||||||
|
|
||||||
-keep class butterknife.** { *; }
|
|
||||||
-dontwarn butterknife.internal.**
|
|
||||||
-keep class **$$ViewBinder { *; }
|
|
||||||
-keepclasseswithmembernames class * {
|
|
||||||
@butterknife.* <fields>;
|
|
||||||
}
|
|
||||||
-keepclasseswithmembernames class * {
|
|
||||||
@butterknife.* <methods>;
|
|
||||||
}
|
|
||||||
|
|
||||||
# these two seem to confuse ProGuard, so force keep them
|
# these two seem to confuse ProGuard, so force keep them
|
||||||
-keep class com.newsblur.util.StateFilter { *; }
|
-keep class com.newsblur.util.StateFilter { *; }
|
||||||
-keep class com.newsblur.view.StateToggleButton$StateChangedListener { *; }
|
-keep class com.newsblur.view.StateToggleButton$StateChangedListener { *; }
|
||||||
|
|
10
clients/android/NewsBlur/res/drawable/ic_create_folder.xml
Normal file
10
clients/android/NewsBlur/res/drawable/ic_create_folder.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="#7B7B7B"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20,6h-8l-2,-2L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM19,14h-3v3h-2v-3h-3v-2h3L14,9h2v3h3v2z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/web_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="-6dp"
|
||||||
|
android:max="100"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
88
clients/android/NewsBlur/res/layout/dialog_add_feed.xml
Normal file
88
clients/android/NewsBlur/res/layout/dialog_add_feed.xml
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_sync_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/status_overlay_background"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="2dp"
|
||||||
|
android:text="@string/sync_status_feed_add"
|
||||||
|
android:textColor="@color/status_overlay_text"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_add_folder_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="14dp"
|
||||||
|
android:text="@string/add_new_folder"
|
||||||
|
android:textAllCaps="true" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/container_add_folder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/input_folder_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:autofillHints="@null"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:hint="@string/new_folder_name_hint"
|
||||||
|
android:inputType="textCapCharacters"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ic_create_folder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:contentDescription="@string/description_add_new_folder_icon"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:src="@drawable/ic_create_folder" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view_folders"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -1,17 +1,19 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:paddingLeft="10dp"
|
android:paddingLeft="10dp"
|
||||||
android:paddingRight="10dp" >
|
android:paddingRight="10dp">
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/feed_name_field"
|
android:id="@+id/input_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:singleLine="true"
|
android:layout_marginBottom="10dp"
|
||||||
/>
|
android:autofillHints="@null"
|
||||||
|
android:hint="@string/new_folder_name_hint"
|
||||||
|
android:inputType="textCapSentences"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</FrameLayout>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/text_folder_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="42dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp" />
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
style="?selectorFeedBackground"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/row_saved_search_icon"
|
||||||
|
android:layout_width="19dp"
|
||||||
|
android:layout_height="19dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:contentDescription="@string/description_row_folder_icon"
|
||||||
|
android:src="@drawable/ic_menu_search_gray55" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/row_saved_search_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@id/row_saved_search_icon"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lines="1"
|
||||||
|
android:paddingTop="9dp"
|
||||||
|
android:paddingEnd="9dp"
|
||||||
|
android:paddingBottom="9dp" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
style="?rowBorderTop"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:layout_alignParentTop="true" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
style="?rowBorderBottom"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:layout_alignParentBottom="true" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
41
clients/android/NewsBlur/res/layout/row_saved_searches.xml
Normal file
41
clients/android/NewsBlur/res/layout/row_saved_searches.xml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
style="?selectorFolderBackground"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/row_folder_icon"
|
||||||
|
android:layout_width="19dp"
|
||||||
|
android:layout_height="19dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:contentDescription="@string/description_row_folder_icon"
|
||||||
|
android:src="@drawable/ic_menu_search_gray55" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/row_foldername"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@id/row_folder_icon"
|
||||||
|
android:paddingTop="9dp"
|
||||||
|
android:paddingBottom="9dp"
|
||||||
|
android:text="@string/saved_searches_row_title"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
style="?rowBorderTop"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:layout_alignParentTop="true" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
style="?rowBorderBottom"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:layout_alignParentBottom="true" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
|
@ -44,4 +44,7 @@
|
||||||
|
|
||||||
<item android:id="@+id/menu_intel"
|
<item android:id="@+id/menu_intel"
|
||||||
android:title="@string/menu_intel" />
|
android:title="@string/menu_intel" />
|
||||||
|
|
||||||
|
<item android:id="@+id/menu_delete_saved_search"
|
||||||
|
android:title="@string/menu_delete_saved_search" />
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -9,5 +9,11 @@
|
||||||
|
|
||||||
<item android:id="@+id/menu_unmute_folder"
|
<item android:id="@+id/menu_unmute_folder"
|
||||||
android:title="@string/menu_unmute_folder" />
|
android:title="@string/menu_unmute_folder" />
|
||||||
|
|
||||||
|
<item android:id="@+id/menu_delete_folder"
|
||||||
|
android:title="@string/menu_delete_folder" />
|
||||||
|
|
||||||
|
<item android:id="@+id/menu_rename_folder"
|
||||||
|
android:title="@string/menu_rename_folder" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
|
@ -34,6 +34,8 @@
|
||||||
android:title="@string/menu_theme_choose" >
|
android:title="@string/menu_theme_choose" >
|
||||||
<menu>
|
<menu>
|
||||||
<group android:checkableBehavior="single">
|
<group android:checkableBehavior="single">
|
||||||
|
<item android:id="@+id/menu_theme_auto"
|
||||||
|
android:title="@string/auto" />
|
||||||
<item android:id="@+id/menu_theme_light"
|
<item android:id="@+id/menu_theme_light"
|
||||||
android:title="@string/light" />
|
android:title="@string/light" />
|
||||||
<item android:id="@+id/menu_theme_dark"
|
<item android:id="@+id/menu_theme_dark"
|
||||||
|
@ -72,4 +74,8 @@
|
||||||
<item android:id="@+id/menu_infrequent_cutoff"
|
<item android:id="@+id/menu_infrequent_cutoff"
|
||||||
android:title="@string/menu_infrequent_cutoff"
|
android:title="@string/menu_infrequent_cutoff"
|
||||||
android:showAsAction="never" />
|
android:showAsAction="never" />
|
||||||
|
<item android:id="@+id/menu_save_search"
|
||||||
|
android:title="Save Search"
|
||||||
|
android:showAsAction="never"
|
||||||
|
android:visible="false"/>
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
android:title="@string/menu_theme_choose" >
|
android:title="@string/menu_theme_choose" >
|
||||||
<menu>
|
<menu>
|
||||||
<group android:checkableBehavior="single">
|
<group android:checkableBehavior="single">
|
||||||
|
<item android:id="@+id/menu_theme_auto"
|
||||||
|
android:title="@string/auto" />
|
||||||
<item android:id="@+id/menu_theme_light"
|
<item android:id="@+id/menu_theme_light"
|
||||||
android:title="@string/light" />
|
android:title="@string/light" />
|
||||||
<item android:id="@+id/menu_theme_dark"
|
<item android:id="@+id/menu_theme_dark"
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
android:title="@string/menu_theme_choose" >
|
android:title="@string/menu_theme_choose" >
|
||||||
<menu>
|
<menu>
|
||||||
<group android:checkableBehavior="single">
|
<group android:checkableBehavior="single">
|
||||||
|
<item android:id="@+id/menu_theme_auto"
|
||||||
|
android:title="@string/auto" />
|
||||||
<item android:id="@+id/menu_theme_light"
|
<item android:id="@+id/menu_theme_light"
|
||||||
android:title="@string/light" />
|
android:title="@string/light" />
|
||||||
<item android:id="@+id/menu_theme_dark"
|
<item android:id="@+id/menu_theme_dark"
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
|
|
||||||
<string name="title_choose_folders">Choose Folders for Feed %s</string>
|
<string name="title_choose_folders">Choose Folders for Feed %s</string>
|
||||||
<string name="title_rename_feed">Rename Feed %s</string>
|
<string name="title_rename_feed">Rename Feed %s</string>
|
||||||
|
<string name="title_rename_folder">Rename Folder %s</string>
|
||||||
|
|
||||||
<string name="all_stories_row_title">ALL STORIES</string>
|
<string name="all_stories_row_title">ALL STORIES</string>
|
||||||
<string name="all_stories_title">All Stories</string>
|
<string name="all_stories_title">All Stories</string>
|
||||||
<string name="infrequent_row_title">INFREQUENT SITE STORIES</string>
|
<string name="infrequent_row_title">INFREQUENT SITE STORIES</string>
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
<string name="read_stories_title">Read Stories</string>
|
<string name="read_stories_title">Read Stories</string>
|
||||||
<string name="saved_stories_row_title">SAVED STORIES</string>
|
<string name="saved_stories_row_title">SAVED STORIES</string>
|
||||||
<string name="saved_stories_title">Saved Stories</string>
|
<string name="saved_stories_title">Saved Stories</string>
|
||||||
|
<string name="saved_searches_row_title">SAVED SEARCHES</string>
|
||||||
|
|
||||||
<string name="top_level">TOP LEVEL</string>
|
<string name="top_level">TOP LEVEL</string>
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@
|
||||||
<string name="unshare">DELETE SHARE</string>
|
<string name="unshare">DELETE SHARE</string>
|
||||||
<string name="update_shared">UPDATE COMMENT</string>
|
<string name="update_shared">UPDATE COMMENT</string>
|
||||||
<string name="feed_name_save">RENAME FEED</string>
|
<string name="feed_name_save">RENAME FEED</string>
|
||||||
|
<string name="folder_name_save">RENAME FOLDER</string>
|
||||||
|
|
||||||
<string name="save_this">SAVE</string>
|
<string name="save_this">SAVE</string>
|
||||||
<string name="unsave_this">REMOVE FROM SAVED</string>
|
<string name="unsave_this">REMOVE FROM SAVED</string>
|
||||||
|
@ -132,6 +135,7 @@
|
||||||
<string name="menu_send_story_full">Send story to…</string>
|
<string name="menu_send_story_full">Send story to…</string>
|
||||||
<string name="menu_mark_feed_as_read">Mark feed as read</string>
|
<string name="menu_mark_feed_as_read">Mark feed as read</string>
|
||||||
<string name="menu_delete_feed">Delete feed</string>
|
<string name="menu_delete_feed">Delete feed</string>
|
||||||
|
<string name="menu_delete_saved_search">Delete saved search</string>
|
||||||
<string name="menu_unfollow">Unfollow user</string>
|
<string name="menu_unfollow">Unfollow user</string>
|
||||||
<string name="menu_choose_folders">Choose folders</string>
|
<string name="menu_choose_folders">Choose folders</string>
|
||||||
<string name="menu_notifications_choose">Notifications…</string>
|
<string name="menu_notifications_choose">Notifications…</string>
|
||||||
|
@ -156,6 +160,8 @@
|
||||||
<string name="menu_unmute_feed">Unmute feed</string>
|
<string name="menu_unmute_feed">Unmute feed</string>
|
||||||
<string name="menu_mute_folder">Mute folder</string>
|
<string name="menu_mute_folder">Mute folder</string>
|
||||||
<string name="menu_unmute_folder">Unmute folder</string>
|
<string name="menu_unmute_folder">Unmute folder</string>
|
||||||
|
<string name="menu_delete_folder">Delete folder</string>
|
||||||
|
<string name="menu_rename_folder">Rename folder</string>
|
||||||
<string name="menu_instafetch_feed">Insta-fetch stories</string>
|
<string name="menu_instafetch_feed">Insta-fetch stories</string>
|
||||||
<string name="menu_infrequent_cutoff">Infrequent stories per month</string>
|
<string name="menu_infrequent_cutoff">Infrequent stories per month</string>
|
||||||
<string name="menu_intel">Intelligence trainer</string>
|
<string name="menu_intel">Intelligence trainer</string>
|
||||||
|
@ -196,7 +202,11 @@
|
||||||
<string name="menu_add_feed">Add new feed</string>
|
<string name="menu_add_feed">Add new feed</string>
|
||||||
<string name="menu_search">Search</string>
|
<string name="menu_search">Search</string>
|
||||||
<string name="adding_feed_progress">Adding feed…</string>
|
<string name="adding_feed_progress">Adding feed…</string>
|
||||||
|
<string name="add_folder_name">Please enter folder name</string>
|
||||||
|
<string name="add_new_folder">+ Add new folder</string>
|
||||||
|
<string name="new_folder_name_hint">Enter new folder name</string>
|
||||||
<string name="add_feed_error">Could not add feed</string>
|
<string name="add_feed_error">Could not add feed</string>
|
||||||
|
<string name="add_folder_error">Could not add folder</string>
|
||||||
<string name="menu_mark_all_as_read">Mark all as read</string>
|
<string name="menu_mark_all_as_read">Mark all as read</string>
|
||||||
<string name="menu_logout">Log out</string>
|
<string name="menu_logout">Log out</string>
|
||||||
<string name="menu_feedback">Send app feedback</string>
|
<string name="menu_feedback">Send app feedback</string>
|
||||||
|
@ -204,6 +214,8 @@
|
||||||
<string name="menu_feedback_email">Email a bug report</string>
|
<string name="menu_feedback_email">Email a bug report</string>
|
||||||
<string name="menu_theme_choose">Theme…</string>
|
<string name="menu_theme_choose">Theme…</string>
|
||||||
|
|
||||||
|
<string name="description_add_new_folder_icon">Add new folder icon</string>
|
||||||
|
|
||||||
<string name="menu_loginas">Login as...</string>
|
<string name="menu_loginas">Login as...</string>
|
||||||
|
|
||||||
<string name="loginas_title">Login As User</string>
|
<string name="loginas_title">Login As User</string>
|
||||||
|
@ -234,6 +246,9 @@
|
||||||
<string name="friends_shares_count">%d SHARES</string>
|
<string name="friends_shares_count">%d SHARES</string>
|
||||||
<string name="unknown_user">Unknown User</string>
|
<string name="unknown_user">Unknown User</string>
|
||||||
<string name="delete_feed_message">Delete feed \"%s\"?</string>
|
<string name="delete_feed_message">Delete feed \"%s\"?</string>
|
||||||
|
<string name="delete_saved_search_message">Delete saved search %s?</string>
|
||||||
|
<string name="delete_folder_message">Delete folder \"%s\" and unsubscribe from all feeds inside?</string>
|
||||||
|
<string name="add_saved_search_message">Save search \"%s\"?</string>
|
||||||
<string name="unfollow_message">Unfollow \"%s\"?</string>
|
<string name="unfollow_message">Unfollow \"%s\"?</string>
|
||||||
<string name="feed_subscribers">%s subscribers</string>
|
<string name="feed_subscribers">%s subscribers</string>
|
||||||
<string name="feed_opens">%d opens</string>
|
<string name="feed_opens">%d opens</string>
|
||||||
|
@ -387,6 +402,7 @@
|
||||||
<string name="feed_intel_author_header">AUTHORS</string>
|
<string name="feed_intel_author_header">AUTHORS</string>
|
||||||
<string name="intel_feed_header">EVERYTHING BY PUBLISHER</string>
|
<string name="intel_feed_header">EVERYTHING BY PUBLISHER</string>
|
||||||
|
|
||||||
|
<string name="auto">Auto</string>
|
||||||
<string name="light">Light</string>
|
<string name="light">Light</string>
|
||||||
<string name="dark">Dark</string>
|
<string name="dark">Dark</string>
|
||||||
<string name="black">Black</string>
|
<string name="black">Black</string>
|
||||||
|
@ -403,6 +419,7 @@
|
||||||
<string name="sync_status_text">Storing text for %s stories...</string>
|
<string name="sync_status_text">Storing text for %s stories...</string>
|
||||||
<string name="sync_status_images">Storing %s images...</string>
|
<string name="sync_status_images">Storing %s images...</string>
|
||||||
<string name="sync_status_offline">Offline</string>
|
<string name="sync_status_offline">Offline</string>
|
||||||
|
<string name="sync_status_feed_add">Adding feed …</string>
|
||||||
|
|
||||||
<string name="volume_key_navigation">Volume Key Navigation</string>
|
<string name="volume_key_navigation">Volume Key Navigation</string>
|
||||||
<string name="off">Off</string>
|
<string name="off">Off</string>
|
||||||
|
@ -477,6 +494,7 @@
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="rtl_gesture_action_value">GEST_ACTION_MARKUNREAD</string>
|
<string name="rtl_gesture_action_value">GEST_ACTION_MARKUNREAD</string>
|
||||||
|
|
||||||
|
<string name="default_browser">Default browser</string>
|
||||||
<string name="font">Font</string>
|
<string name="font">Font</string>
|
||||||
<string name="default_font">Default</string>
|
<string name="default_font">Default</string>
|
||||||
<string name="whitney_font">Whitney</string>
|
<string name="whitney_font">Whitney</string>
|
||||||
|
@ -494,6 +512,25 @@
|
||||||
<string name="noto_sans_font_prefvalue">NOTO_SANS</string>
|
<string name="noto_sans_font_prefvalue">NOTO_SANS</string>
|
||||||
<string name="noto_serif_font_prefvalue">NOTO_SERIF</string>
|
<string name="noto_serif_font_prefvalue">NOTO_SERIF</string>
|
||||||
<string name="open_sans_condensed_font_prefvalue">OPEN_SANS_CONDENSED</string>
|
<string name="open_sans_condensed_font_prefvalue">OPEN_SANS_CONDENSED</string>
|
||||||
|
<string name="system_default_prefvalue">SYSTEM_DEFAULT</string>
|
||||||
|
<string name="in_app_browser_prefvalue">IN_APP_BROWSER</string>
|
||||||
|
<string name="chrome_prefvalue">CHROME</string>
|
||||||
|
<string name="firefox_prefvalue">FIREFOX</string>
|
||||||
|
<string name="opera_mini_prefvalue">OPERA_MINI</string>
|
||||||
|
<string-array name="default_browser_entries">
|
||||||
|
<item>System default</item>
|
||||||
|
<item>In-app browser</item>
|
||||||
|
<item>Chrome</item>
|
||||||
|
<item>Firefox</item>
|
||||||
|
<item>Opera Mini</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="default_browser_values">
|
||||||
|
<item>@string/system_default_prefvalue</item>
|
||||||
|
<item>@string/in_app_browser_prefvalue</item>
|
||||||
|
<item>@string/chrome_prefvalue</item>
|
||||||
|
<item>@string/firefox_prefvalue</item>
|
||||||
|
<item>@string/opera_mini_prefvalue</item>
|
||||||
|
</string-array>
|
||||||
<string-array name="default_font_entries">
|
<string-array name="default_font_entries">
|
||||||
<item>@string/anonymous_pro_font</item>
|
<item>@string/anonymous_pro_font</item>
|
||||||
<item>@string/chronicle_font</item>
|
<item>@string/chronicle_font</item>
|
||||||
|
@ -515,6 +552,7 @@
|
||||||
<item>@string/whitney_font_prefvalue</item>
|
<item>@string/whitney_font_prefvalue</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="default_font_value">DEFAULT</string>
|
<string name="default_font_value">DEFAULT</string>
|
||||||
|
<string name="default_default_browser">@string/system_default_prefvalue</string>
|
||||||
|
|
||||||
<string name="story_notification_channel_id">story_notification_channel</string>
|
<string name="story_notification_channel_id">story_notification_channel</string>
|
||||||
<string name="story_notification_channel_name">New Stories</string>
|
<string name="story_notification_channel_name">New Stories</string>
|
||||||
|
|
|
@ -105,6 +105,13 @@
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/settings_reading"
|
android:title="@string/settings_reading"
|
||||||
android:key="reading">
|
android:key="reading">
|
||||||
|
<ListPreference
|
||||||
|
android:key="default_browser"
|
||||||
|
android:title="@string/default_browser"
|
||||||
|
android:dialogTitle="@string/default_browser"
|
||||||
|
android:entries="@array/default_browser_entries"
|
||||||
|
android:entryValues="@array/default_browser_values"
|
||||||
|
android:defaultValue="@string/default_default_browser" />
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="reading_font"
|
android:key="reading_font"
|
||||||
android:title="@string/font"
|
android:title="@string/font"
|
||||||
|
|
|
@ -5,32 +5,27 @@ import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.ActivityAddfeedexternalBinding;
|
||||||
import com.newsblur.fragment.AddFeedFragment;
|
import com.newsblur.fragment.AddFeedFragment;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
import com.newsblur.util.ViewUtils;
|
import com.newsblur.util.ViewUtils;
|
||||||
import com.newsblur.view.ProgressThrobber;
|
|
||||||
|
|
||||||
public class AddFeedExternal extends NbActivity implements AddFeedFragment.AddFeedProgressListener {
|
public class AddFeedExternal extends NbActivity implements AddFeedFragment.AddFeedProgressListener {
|
||||||
|
|
||||||
@Bind(R.id.loading_throb) ProgressThrobber progressView;
|
private ActivityAddfeedexternalBinding binding;
|
||||||
@Bind(R.id.progress_text) TextView progressText;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
binding = ActivityAddfeedexternalBinding.inflate(getLayoutInflater());
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
setContentView(R.layout.activity_addfeedexternal);
|
setContentView(binding.getRoot());
|
||||||
ButterKnife.bind(this);
|
|
||||||
|
|
||||||
progressView.setEnabled(!ViewUtils.isPowerSaveMode(this));
|
binding.loadingThrob.setEnabled(!ViewUtils.isPowerSaveMode(this));
|
||||||
progressView.setColors(UIUtils.getColor(this, R.color.refresh_1),
|
binding.loadingThrob.setColors(UIUtils.getColor(this, R.color.refresh_1),
|
||||||
UIUtils.getColor(this, R.color.refresh_2),
|
UIUtils.getColor(this, R.color.refresh_2),
|
||||||
UIUtils.getColor(this, R.color.refresh_3),
|
UIUtils.getColor(this, R.color.refresh_3),
|
||||||
UIUtils.getColor(this, R.color.refresh_4));
|
UIUtils.getColor(this, R.color.refresh_4));
|
||||||
|
@ -48,9 +43,9 @@ public class AddFeedExternal extends NbActivity implements AddFeedFragment.AddFe
|
||||||
public void addFeedStarted() {
|
public void addFeedStarted() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
progressText.setText(R.string.adding_feed_progress);
|
binding.progressText.setText(R.string.adding_feed_progress);
|
||||||
progressText.setVisibility(View.VISIBLE);
|
binding.progressText.setVisibility(View.VISIBLE);
|
||||||
progressView.setVisibility(View.VISIBLE);
|
binding.loadingThrob.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,9 @@ public class AllSharedStoriesItemsList extends ItemsList {
|
||||||
UIUtils.setCustomActionBar(this, R.drawable.ak_icon_blurblogs, getResources().getString(R.string.all_shared_stories_title));
|
UIUtils.setCustomActionBar(this, R.drawable.ak_icon_blurblogs, getResources().getString(R.string.all_shared_stories_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
// doesn't have save search option
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,4 +24,9 @@ public class AllStoriesItemsList extends ItemsList {
|
||||||
UIUtils.startReadingActivity(fs, hash, this);
|
UIUtils.startReadingActivity(fs, hash, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
return "river:";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import com.newsblur.R;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.fragment.DeleteFeedFragment;
|
import com.newsblur.fragment.DeleteFeedFragment;
|
||||||
import com.newsblur.fragment.FeedIntelTrainerFragment;
|
import com.newsblur.fragment.FeedIntelTrainerFragment;
|
||||||
import com.newsblur.fragment.RenameFeedFragment;
|
import com.newsblur.fragment.RenameDialogFragment;
|
||||||
import com.newsblur.util.FeedSet;
|
import com.newsblur.util.FeedSet;
|
||||||
import com.newsblur.util.FeedUtils;
|
import com.newsblur.util.FeedUtils;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
|
@ -79,8 +79,8 @@ public class FeedItemsList extends ItemsList {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (item.getItemId() == R.id.menu_rename_feed) {
|
if (item.getItemId() == R.id.menu_rename_feed) {
|
||||||
RenameFeedFragment frag = RenameFeedFragment.newInstance(feed);
|
RenameDialogFragment frag = RenameDialogFragment.newInstance(feed);
|
||||||
frag.show(getSupportFragmentManager(), RenameFeedFragment.class.getName());
|
frag.show(getSupportFragmentManager(), RenameDialogFragment.class.getName());
|
||||||
return true;
|
return true;
|
||||||
// TODO: since this activity uses a feed object passed as an extra and doesn't query the DB,
|
// TODO: since this activity uses a feed object passed as an extra and doesn't query the DB,
|
||||||
// the name change won't be reflected until the activity finishes.
|
// the name change won't be reflected until the activity finishes.
|
||||||
|
@ -118,4 +118,8 @@ public class FeedItemsList extends ItemsList {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
return "feed:" + feed.feedId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,4 +19,8 @@ public class FolderItemsList extends ItemsList {
|
||||||
UIUtils.setCustomActionBar(this, R.drawable.g_icn_folder_rss, folderName);
|
UIUtils.setCustomActionBar(this, R.drawable.g_icn_folder_rss, folderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
return "river:" + folderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,9 @@ public class GlobalSharedStoriesItemsList extends ItemsList {
|
||||||
UIUtils.setCustomActionBar(this, R.drawable.ak_icon_global, getResources().getString(R.string.global_shared_stories_title));
|
UIUtils.setCustomActionBar(this, R.drawable.ak_icon_global, getResources().getString(R.string.global_shared_stories_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
// doesn't have save search option
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package com.newsblur.activity;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.webkit.WebChromeClient;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
import com.newsblur.databinding.ActivityInAppBrowserBinding;
|
||||||
|
import com.newsblur.util.PrefsUtils;
|
||||||
|
|
||||||
|
public class InAppBrowser extends FragmentActivity {
|
||||||
|
|
||||||
|
public static final String URI = "uri";
|
||||||
|
|
||||||
|
private ActivityInAppBrowserBinding binding;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
PrefsUtils.applyThemePreference(this);
|
||||||
|
binding = ActivityInAppBrowserBinding.inflate(getLayoutInflater());
|
||||||
|
setContentView(binding.getRoot());
|
||||||
|
|
||||||
|
String url = getIntent().getParcelableExtra(URI).toString();
|
||||||
|
|
||||||
|
binding.webView.getSettings().setJavaScriptEnabled(true);
|
||||||
|
binding.webView.getSettings().setLoadWithOverviewMode(true);
|
||||||
|
binding.webView.getSettings().setSupportZoom(true);
|
||||||
|
|
||||||
|
binding.webView.setWebViewClient(new WebViewClient() {
|
||||||
|
@Override
|
||||||
|
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||||
|
super.onPageStarted(view, url, favicon);
|
||||||
|
binding.progressBar.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageFinished(WebView view, String url) {
|
||||||
|
super.onPageFinished(view, url);
|
||||||
|
binding.progressBar.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.webView.setWebChromeClient(new WebChromeClient() {
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(WebView view, int newProgress) {
|
||||||
|
super.onProgressChanged(view, newProgress);
|
||||||
|
binding.progressBar.setProgress(newProgress);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
binding.webView.loadUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (binding.webView.canGoBack()) {
|
||||||
|
binding.webView.goBack();
|
||||||
|
} else {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,4 +37,8 @@ public class InfrequentItemsList extends ItemsList implements InfrequentCutoffCh
|
||||||
restartReadingSession();
|
restartReadingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
return "river:infrequent";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,14 @@ import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnKeyListener;
|
import android.view.View.OnKeyListener;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.ActivityItemslistBinding;
|
||||||
import com.newsblur.fragment.ItemSetFragment;
|
import com.newsblur.fragment.ItemSetFragment;
|
||||||
import com.newsblur.fragment.ReadFilterDialogFragment;
|
import com.newsblur.fragment.ReadFilterDialogFragment;
|
||||||
|
import com.newsblur.fragment.SaveSearchFragment;
|
||||||
import com.newsblur.fragment.StoryOrderDialogFragment;
|
import com.newsblur.fragment.StoryOrderDialogFragment;
|
||||||
import com.newsblur.fragment.TextSizeDialogFragment;
|
import com.newsblur.fragment.TextSizeDialogFragment;
|
||||||
import com.newsblur.service.NBSyncService;
|
import com.newsblur.service.NBSyncService;
|
||||||
|
@ -46,10 +43,9 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
private static final String READ_FILTER = "readFilter";
|
private static final String READ_FILTER = "readFilter";
|
||||||
private static final String DEFAULT_FEED_VIEW = "defaultFeedView";
|
private static final String DEFAULT_FEED_VIEW = "defaultFeedView";
|
||||||
private static final String BUNDLE_ACTIVE_SEARCH_QUERY = "activeSearchQuery";
|
private static final String BUNDLE_ACTIVE_SEARCH_QUERY = "activeSearchQuery";
|
||||||
|
private ActivityItemslistBinding binding;
|
||||||
|
|
||||||
protected ItemSetFragment itemSetFragment;
|
protected ItemSetFragment itemSetFragment;
|
||||||
@Bind(R.id.itemlist_sync_status) TextView overlayStatusText;
|
|
||||||
@Bind(R.id.itemlist_search_query) EditText searchQueryInput;
|
|
||||||
protected StateFilter intelState;
|
protected StateFilter intelState;
|
||||||
|
|
||||||
protected FeedSet fs;
|
protected FeedSet fs;
|
||||||
|
@ -79,8 +75,8 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
|
|
||||||
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
||||||
|
|
||||||
setContentView(R.layout.activity_itemslist);
|
binding = ActivityItemslistBinding.inflate(getLayoutInflater());
|
||||||
ButterKnife.bind(this);
|
setContentView(binding.getRoot());
|
||||||
|
|
||||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||||
itemSetFragment = (ItemSetFragment) fragmentManager.findFragmentByTag(ItemSetFragment.class.getName());
|
itemSetFragment = (ItemSetFragment) fragmentManager.findFragmentByTag(ItemSetFragment.class.getName());
|
||||||
|
@ -92,19 +88,23 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String activeSearchQuery;
|
||||||
if (bundle != null) {
|
if (bundle != null) {
|
||||||
String activeSearchQuery = bundle.getString(BUNDLE_ACTIVE_SEARCH_QUERY);
|
activeSearchQuery = bundle.getString(BUNDLE_ACTIVE_SEARCH_QUERY);
|
||||||
if (activeSearchQuery != null) {
|
} else {
|
||||||
searchQueryInput.setText(activeSearchQuery);
|
activeSearchQuery = fs.getSearchQuery();
|
||||||
searchQueryInput.setVisibility(View.VISIBLE);
|
|
||||||
fs.setSearchQuery(activeSearchQuery);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
searchQueryInput.setOnKeyListener(new OnKeyListener() {
|
if (activeSearchQuery != null) {
|
||||||
|
binding.itemlistSearchQuery.setText(activeSearchQuery);
|
||||||
|
binding.itemlistSearchQuery.setVisibility(View.VISIBLE);
|
||||||
|
fs.setSearchQuery(activeSearchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.itemlistSearchQuery.setOnKeyListener(new OnKeyListener() {
|
||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
|
if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
|
||||||
searchQueryInput.setVisibility(View.GONE);
|
binding.itemlistSearchQuery.setVisibility(View.GONE);
|
||||||
searchQueryInput.setText("");
|
binding.itemlistSearchQuery.setText("");
|
||||||
checkSearchQuery();
|
checkSearchQuery();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -120,8 +120,8 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
if (searchQueryInput != null) {
|
if (binding.itemlistSearchQuery != null) {
|
||||||
String q = searchQueryInput.getText().toString().trim();
|
String q = binding.itemlistSearchQuery.getText().toString().trim();
|
||||||
if (q.length() > 0) {
|
if (q.length() > 0) {
|
||||||
outState.putString(BUNDLE_ACTIVE_SEARCH_QUERY, q);
|
outState.putString(BUNDLE_ACTIVE_SEARCH_QUERY, q);
|
||||||
}
|
}
|
||||||
|
@ -222,6 +222,14 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
menu.findItem(R.id.menu_theme_dark).setChecked(true);
|
menu.findItem(R.id.menu_theme_dark).setChecked(true);
|
||||||
} else if (themeValue == ThemeValue.BLACK) {
|
} else if (themeValue == ThemeValue.BLACK) {
|
||||||
menu.findItem(R.id.menu_theme_black).setChecked(true);
|
menu.findItem(R.id.menu_theme_black).setChecked(true);
|
||||||
|
} else if (themeValue == ThemeValue.AUTO) {
|
||||||
|
menu.findItem(R.id.menu_theme_auto).setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(binding.itemlistSearchQuery.getText())) {
|
||||||
|
menu.findItem(R.id.menu_save_search).setVisible(true);
|
||||||
|
} else {
|
||||||
|
menu.findItem(R.id.menu_save_search).setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -250,13 +258,16 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
textSize.show(getSupportFragmentManager(), TextSizeDialogFragment.class.getName());
|
textSize.show(getSupportFragmentManager(), TextSizeDialogFragment.class.getName());
|
||||||
return true;
|
return true;
|
||||||
} else if (item.getItemId() == R.id.menu_search_stories) {
|
} else if (item.getItemId() == R.id.menu_search_stories) {
|
||||||
if (searchQueryInput.getVisibility() != View.VISIBLE) {
|
if (binding.itemlistSearchQuery.getVisibility() != View.VISIBLE) {
|
||||||
searchQueryInput.setVisibility(View.VISIBLE);
|
binding.itemlistSearchQuery.setVisibility(View.VISIBLE);
|
||||||
searchQueryInput.requestFocus();
|
binding.itemlistSearchQuery.requestFocus();
|
||||||
} else {
|
} else {
|
||||||
searchQueryInput.setVisibility(View.GONE);
|
binding.itemlistSearchQuery.setVisibility(View.GONE);
|
||||||
checkSearchQuery();
|
checkSearchQuery();
|
||||||
}
|
}
|
||||||
|
} else if(item.getItemId() == R.id.menu_theme_auto) {
|
||||||
|
PrefsUtils.setSelectedTheme(this, ThemeValue.AUTO);
|
||||||
|
UIUtils.restartActivity(this);
|
||||||
} else if (item.getItemId() == R.id.menu_theme_light) {
|
} else if (item.getItemId() == R.id.menu_theme_light) {
|
||||||
PrefsUtils.setSelectedTheme(this, ThemeValue.LIGHT);
|
PrefsUtils.setSelectedTheme(this, ThemeValue.LIGHT);
|
||||||
UIUtils.restartActivity(this);
|
UIUtils.restartActivity(this);
|
||||||
|
@ -279,6 +290,14 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
PrefsUtils.updateStoryListStyle(this, fs, StoryListStyle.GRID_C);
|
PrefsUtils.updateStoryListStyle(this, fs, StoryListStyle.GRID_C);
|
||||||
itemSetFragment.updateStyle();
|
itemSetFragment.updateStyle();
|
||||||
}
|
}
|
||||||
|
if (item.getItemId() == R.id.menu_save_search) {
|
||||||
|
String feedId = getSaveSearchFeedId();
|
||||||
|
if (feedId != null) {
|
||||||
|
String query = binding.itemlistSearchQuery.getText().toString();
|
||||||
|
SaveSearchFragment frag = SaveSearchFragment.newInstance(feedId, query);
|
||||||
|
frag.show(getSupportFragmentManager(), SaveSearchFragment.class.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -315,23 +334,23 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStatusIndicators() {
|
private void updateStatusIndicators() {
|
||||||
if (overlayStatusText != null) {
|
if (binding.itemlistSyncStatus != null) {
|
||||||
String syncStatus = NBSyncService.getSyncStatusMessage(this, true);
|
String syncStatus = NBSyncService.getSyncStatusMessage(this, true);
|
||||||
if (syncStatus != null) {
|
if (syncStatus != null) {
|
||||||
if (AppConstants.VERBOSE_LOG) {
|
if (AppConstants.VERBOSE_LOG) {
|
||||||
syncStatus = syncStatus + UIUtils.getMemoryUsageDebug(this);
|
syncStatus = syncStatus + UIUtils.getMemoryUsageDebug(this);
|
||||||
}
|
}
|
||||||
overlayStatusText.setText(syncStatus);
|
binding.itemlistSyncStatus.setText(syncStatus);
|
||||||
overlayStatusText.setVisibility(View.VISIBLE);
|
binding.itemlistSyncStatus.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
overlayStatusText.setVisibility(View.GONE);
|
binding.itemlistSyncStatus.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSearchQuery() {
|
private void checkSearchQuery() {
|
||||||
String oldQuery = fs.getSearchQuery();
|
String oldQuery = fs.getSearchQuery();
|
||||||
String q = searchQueryInput.getText().toString().trim();
|
String q = binding.itemlistSearchQuery.getText().toString().trim();
|
||||||
if (q.length() < 1) {
|
if (q.length() < 1) {
|
||||||
q = null;
|
q = null;
|
||||||
}
|
}
|
||||||
|
@ -395,4 +414,6 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
||||||
*/
|
*/
|
||||||
overridePendingTransition(R.anim.slide_in_from_left, R.anim.slide_out_to_right);
|
overridePendingTransition(R.anim.slide_in_from_left, R.anim.slide_out_to_right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract String getSaveSearchFeedId();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,19 +17,12 @@ import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnKeyListener;
|
import android.view.View.OnKeyListener;
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.ActivityMainBinding;
|
||||||
import com.newsblur.fragment.FeedIntelligenceSelectorFragment;
|
import com.newsblur.fragment.FeedIntelligenceSelectorFragment;
|
||||||
import com.newsblur.fragment.FolderListFragment;
|
import com.newsblur.fragment.FolderListFragment;
|
||||||
import com.newsblur.fragment.LoginAsDialogFragment;
|
import com.newsblur.fragment.LoginAsDialogFragment;
|
||||||
|
@ -54,15 +47,7 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
private FragmentManager fragmentManager;
|
private FragmentManager fragmentManager;
|
||||||
private SwipeRefreshLayout swipeLayout;
|
private SwipeRefreshLayout swipeLayout;
|
||||||
private boolean wasSwipeEnabled = false;
|
private boolean wasSwipeEnabled = false;
|
||||||
@Bind(R.id.main_sync_status) TextView overlayStatusText;
|
private ActivityMainBinding binding;
|
||||||
@Bind(R.id.empty_view_image) ImageView emptyViewImage;
|
|
||||||
@Bind(R.id.empty_view_text) TextView emptyViewText;
|
|
||||||
@Bind(R.id.main_menu_button) Button menuButton;
|
|
||||||
@Bind(R.id.main_user_image) ImageView userImage;
|
|
||||||
@Bind(R.id.main_user_name) TextView userName;
|
|
||||||
@Bind(R.id.main_unread_count_neut_text) TextView unreadCountNeutText;
|
|
||||||
@Bind(R.id.main_unread_count_posi_text) TextView unreadCountPosiText;
|
|
||||||
@Bind(R.id.feedlist_search_query) EditText searchQueryInput;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -70,16 +55,15 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
||||||
|
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(binding.getRoot());
|
||||||
ButterKnife.bind(this);
|
|
||||||
|
|
||||||
getActionBar().hide();
|
getActionBar().hide();
|
||||||
|
|
||||||
// set the status bar to an generic loading message when the activity is first created so
|
// set the status bar to an generic loading message when the activity is first created so
|
||||||
// that something is displayed while the service warms up
|
// that something is displayed while the service warms up
|
||||||
overlayStatusText.setText(R.string.loading);
|
binding.mainSyncStatus.setText(R.string.loading);
|
||||||
overlayStatusText.setVisibility(View.VISIBLE);
|
binding.mainSyncStatus.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
swipeLayout = (SwipeRefreshLayout)findViewById(R.id.swipe_container);
|
swipeLayout = (SwipeRefreshLayout)findViewById(R.id.swipe_container);
|
||||||
swipeLayout.setColorSchemeResources(R.color.refresh_1, R.color.refresh_2, R.color.refresh_3, R.color.refresh_4);
|
swipeLayout.setColorSchemeResources(R.color.refresh_1, R.color.refresh_2, R.color.refresh_3, R.color.refresh_4);
|
||||||
|
@ -88,7 +72,6 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
|
|
||||||
fragmentManager = getSupportFragmentManager();
|
fragmentManager = getSupportFragmentManager();
|
||||||
folderFeedList = (FolderListFragment) fragmentManager.findFragmentByTag("folderFeedListFragment");
|
folderFeedList = (FolderListFragment) fragmentManager.findFragmentByTag("folderFeedListFragment");
|
||||||
folderFeedList.setRetainInstance(true);
|
|
||||||
((FeedIntelligenceSelectorFragment) fragmentManager.findFragmentByTag("feedIntelligenceSelector")).setState(folderFeedList.currentState);
|
((FeedIntelligenceSelectorFragment) fragmentManager.findFragmentByTag("feedIntelligenceSelector")).setState(folderFeedList.currentState);
|
||||||
|
|
||||||
// make sure the interval sync is scheduled, since we are the root Activity
|
// make sure the interval sync is scheduled, since we are the root Activity
|
||||||
|
@ -97,25 +80,25 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
Bitmap userPicture = PrefsUtils.getUserImage(this);
|
Bitmap userPicture = PrefsUtils.getUserImage(this);
|
||||||
if (userPicture != null) {
|
if (userPicture != null) {
|
||||||
userPicture = UIUtils.clipAndRound(userPicture, 5, false);
|
userPicture = UIUtils.clipAndRound(userPicture, 5, false);
|
||||||
userImage.setImageBitmap(userPicture);
|
binding.mainUserImage.setImageBitmap(userPicture);
|
||||||
}
|
}
|
||||||
userName.setText(PrefsUtils.getUserDetails(this).username);
|
binding.mainUserName.setText(PrefsUtils.getUserDetails(this).username);
|
||||||
searchQueryInput.setOnKeyListener(new OnKeyListener() {
|
binding.feedlistSearchQuery.setOnKeyListener(new OnKeyListener() {
|
||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
|
if ((keyCode == KeyEvent.KEYCODE_BACK) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
|
||||||
searchQueryInput.setVisibility(View.GONE);
|
binding.feedlistSearchQuery.setVisibility(View.GONE);
|
||||||
searchQueryInput.setText("");
|
binding.feedlistSearchQuery.setText("");
|
||||||
checkSearchQuery();
|
checkSearchQuery();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
|
if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
|
||||||
checkSearchQuery();
|
checkSearchQuery();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
searchQueryInput.addTextChangedListener(new TextWatcher() {
|
binding.feedlistSearchQuery.addTextChangedListener(new TextWatcher() {
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
checkSearchQuery();
|
checkSearchQuery();
|
||||||
}
|
}
|
||||||
|
@ -124,6 +107,31 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
});
|
});
|
||||||
|
|
||||||
FeedUtils.currentFolderName = null;
|
FeedUtils.currentFolderName = null;
|
||||||
|
|
||||||
|
binding.mainMenuButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onClickMenuButton();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.mainAddButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onClickAddButton();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.mainProfileButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onClickProfileButton();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.mainUserImage.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onClickUserButton();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -149,8 +157,8 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folderFeedList.getSearchQuery() != null) {
|
if (folderFeedList.getSearchQuery() != null) {
|
||||||
searchQueryInput.setText(folderFeedList.getSearchQuery());
|
binding.feedlistSearchQuery.setText(folderFeedList.getSearchQuery());
|
||||||
searchQueryInput.setVisibility(View.VISIBLE);
|
binding.feedlistSearchQuery.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// triggerSync() might not actually do enough to push a UI update if background sync has been
|
// triggerSync() might not actually do enough to push a UI update if background sync has been
|
||||||
|
@ -172,8 +180,8 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
if ( !( (state == StateFilter.ALL) ||
|
if ( !( (state == StateFilter.ALL) ||
|
||||||
(state == StateFilter.SOME) ||
|
(state == StateFilter.SOME) ||
|
||||||
(state == StateFilter.BEST) ) ) {
|
(state == StateFilter.BEST) ) ) {
|
||||||
searchQueryInput.setText("");
|
binding.feedlistSearchQuery.setText("");
|
||||||
searchQueryInput.setVisibility(View.GONE);
|
binding.feedlistSearchQuery.setVisibility(View.GONE);
|
||||||
checkSearchQuery();
|
checkSearchQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,8 +209,8 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateUnreadCounts(int neutCount, int posiCount) {
|
public void updateUnreadCounts(int neutCount, int posiCount) {
|
||||||
unreadCountNeutText.setText(Integer.toString(neutCount));
|
binding.mainUnreadCountNeutText.setText(Integer.toString(neutCount));
|
||||||
unreadCountPosiText.setText(Integer.toString(posiCount));
|
binding.mainUnreadCountPosiText.setText(Integer.toString(posiCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -213,22 +221,22 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
public void updateFeedCount(int feedCount) {
|
public void updateFeedCount(int feedCount) {
|
||||||
if (feedCount < 1 ) {
|
if (feedCount < 1 ) {
|
||||||
if (NBSyncService.isFeedCountSyncRunning() || (!folderFeedList.firstCursorSeenYet)) {
|
if (NBSyncService.isFeedCountSyncRunning() || (!folderFeedList.firstCursorSeenYet)) {
|
||||||
emptyViewImage.setVisibility(View.INVISIBLE);
|
binding.emptyViewImage.setVisibility(View.INVISIBLE);
|
||||||
emptyViewText.setVisibility(View.INVISIBLE);
|
binding.emptyViewText.setVisibility(View.INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
emptyViewImage.setVisibility(View.VISIBLE);
|
binding.emptyViewImage.setVisibility(View.VISIBLE);
|
||||||
if (folderFeedList.currentState == StateFilter.BEST) {
|
if (folderFeedList.currentState == StateFilter.BEST) {
|
||||||
emptyViewText.setText(R.string.empty_list_view_no_focus_stories);
|
binding.emptyViewText.setText(R.string.empty_list_view_no_focus_stories);
|
||||||
} else if (folderFeedList.currentState == StateFilter.SAVED) {
|
} else if (folderFeedList.currentState == StateFilter.SAVED) {
|
||||||
emptyViewText.setText(R.string.empty_list_view_no_saved_stories);
|
binding.emptyViewText.setText(R.string.empty_list_view_no_saved_stories);
|
||||||
} else {
|
} else {
|
||||||
emptyViewText.setText(R.string.empty_list_view_no_unread_stories);
|
binding.emptyViewText.setText(R.string.empty_list_view_no_unread_stories);
|
||||||
}
|
}
|
||||||
emptyViewText.setVisibility(View.VISIBLE);
|
binding.emptyViewText.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emptyViewImage.setVisibility(View.INVISIBLE);
|
binding.emptyViewImage.setVisibility(View.INVISIBLE);
|
||||||
emptyViewText.setVisibility(View.INVISIBLE);
|
binding.emptyViewText.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,16 +247,16 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
swipeLayout.setRefreshing(false);
|
swipeLayout.setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlayStatusText != null) {
|
if (binding.mainSyncStatus != null) {
|
||||||
String syncStatus = NBSyncService.getSyncStatusMessage(this, false);
|
String syncStatus = NBSyncService.getSyncStatusMessage(this, false);
|
||||||
if (syncStatus != null) {
|
if (syncStatus != null) {
|
||||||
if (AppConstants.VERBOSE_LOG) {
|
if (AppConstants.VERBOSE_LOG) {
|
||||||
syncStatus = syncStatus + UIUtils.getMemoryUsageDebug(this);
|
syncStatus = syncStatus + UIUtils.getMemoryUsageDebug(this);
|
||||||
}
|
}
|
||||||
overlayStatusText.setText(syncStatus);
|
binding.mainSyncStatus.setText(syncStatus);
|
||||||
overlayStatusText.setVisibility(View.VISIBLE);
|
binding.mainSyncStatus.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
overlayStatusText.setVisibility(View.GONE);
|
binding.mainSyncStatus.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,8 +268,8 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
folderFeedList.clearRecents();
|
folderFeedList.clearRecents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.main_menu_button) void onClickMenuButton() {
|
private void onClickMenuButton() {
|
||||||
PopupMenu pm = new PopupMenu(this, menuButton);
|
PopupMenu pm = new PopupMenu(this, binding.mainMenuButton);
|
||||||
Menu menu = pm.getMenu();
|
Menu menu = pm.getMenu();
|
||||||
pm.getMenuInflater().inflate(R.menu.main, menu);
|
pm.getMenuInflater().inflate(R.menu.main, menu);
|
||||||
|
|
||||||
|
@ -294,6 +302,8 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
menu.findItem(R.id.menu_theme_dark).setChecked(true);
|
menu.findItem(R.id.menu_theme_dark).setChecked(true);
|
||||||
} else if (themeValue == ThemeValue.BLACK) {
|
} else if (themeValue == ThemeValue.BLACK) {
|
||||||
menu.findItem(R.id.menu_theme_black).setChecked(true);
|
menu.findItem(R.id.menu_theme_black).setChecked(true);
|
||||||
|
} else if (themeValue == ThemeValue.AUTO) {
|
||||||
|
menu.findItem(R.id.menu_theme_auto).setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.findItem(R.id.menu_widget).setVisible(WidgetUtils.hasActiveAppWidgets(this));
|
menu.findItem(R.id.menu_widget).setVisible(WidgetUtils.hasActiveAppWidgets(this));
|
||||||
|
@ -308,12 +318,12 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
onRefresh();
|
onRefresh();
|
||||||
return true;
|
return true;
|
||||||
} else if (item.getItemId() == R.id.menu_search_feeds) {
|
} else if (item.getItemId() == R.id.menu_search_feeds) {
|
||||||
if (searchQueryInput.getVisibility() != View.VISIBLE) {
|
if (binding.feedlistSearchQuery.getVisibility() != View.VISIBLE) {
|
||||||
searchQueryInput.setVisibility(View.VISIBLE);
|
binding.feedlistSearchQuery.setVisibility(View.VISIBLE);
|
||||||
searchQueryInput.requestFocus();
|
binding.feedlistSearchQuery.requestFocus();
|
||||||
} else {
|
} else {
|
||||||
searchQueryInput.setText("");
|
binding.feedlistSearchQuery.setText("");
|
||||||
searchQueryInput.setVisibility(View.GONE);
|
binding.feedlistSearchQuery.setVisibility(View.GONE);
|
||||||
checkSearchQuery();
|
checkSearchQuery();
|
||||||
}
|
}
|
||||||
} else if (item.getItemId() == R.id.menu_add_feed) {
|
} else if (item.getItemId() == R.id.menu_add_feed) {
|
||||||
|
@ -351,6 +361,9 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
DialogFragment newFragment = new LoginAsDialogFragment();
|
DialogFragment newFragment = new LoginAsDialogFragment();
|
||||||
newFragment.show(getSupportFragmentManager(), "dialog");
|
newFragment.show(getSupportFragmentManager(), "dialog");
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.menu_theme_auto) {
|
||||||
|
PrefsUtils.setSelectedTheme(this, ThemeValue.AUTO);
|
||||||
|
UIUtils.restartActivity(this);
|
||||||
} else if (item.getItemId() == R.id.menu_theme_light) {
|
} else if (item.getItemId() == R.id.menu_theme_light) {
|
||||||
PrefsUtils.setSelectedTheme(this, ThemeValue.LIGHT);
|
PrefsUtils.setSelectedTheme(this, ThemeValue.LIGHT);
|
||||||
UIUtils.restartActivity(this);
|
UIUtils.restartActivity(this);
|
||||||
|
@ -364,17 +377,17 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.main_add_button) void onClickAddButton() {
|
private void onClickAddButton() {
|
||||||
Intent i = new Intent(this, SearchForFeeds.class);
|
Intent i = new Intent(this, SearchForFeeds.class);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.main_profile_button) void onClickProfileButton() {
|
private void onClickProfileButton() {
|
||||||
Intent i = new Intent(this, Profile.class);
|
Intent i = new Intent(this, Profile.class);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.main_user_image) void onClickUserButton() {
|
private void onClickUserButton() {
|
||||||
Intent i = new Intent(this, Profile.class);
|
Intent i = new Intent(this, Profile.class);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
@ -404,7 +417,7 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSearchQuery() {
|
private void checkSearchQuery() {
|
||||||
String q = searchQueryInput.getText().toString().trim();
|
String q = binding.feedlistSearchQuery.getText().toString().trim();
|
||||||
if (q.length() < 1) {
|
if (q.length() < 1) {
|
||||||
q = null;
|
q = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,8 @@ public class ReadStoriesItemsList extends ItemsList {
|
||||||
UIUtils.setCustomActionBar(this, R.drawable.g_icn_unread_double, getResources().getString(R.string.read_stories_title));
|
UIUtils.setCustomActionBar(this, R.drawable.g_icn_unread_double, getResources().getString(R.string.read_stories_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
return "read";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -19,18 +20,14 @@ import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.database.ReadingAdapter;
|
import com.newsblur.database.ReadingAdapter;
|
||||||
|
import com.newsblur.databinding.ActivityReadingBinding;
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
import com.newsblur.fragment.ReadingItemFragment;
|
import com.newsblur.fragment.ReadingItemFragment;
|
||||||
import com.newsblur.fragment.ReadingPagerFragment;
|
import com.newsblur.fragment.ReadingPagerFragment;
|
||||||
|
@ -77,19 +74,9 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
protected final Object STORIES_MUTEX = new Object();
|
protected final Object STORIES_MUTEX = new Object();
|
||||||
protected Cursor stories;
|
protected Cursor stories;
|
||||||
|
|
||||||
@Bind(android.R.id.content) View contentView; // we use this a ton, so cache it
|
private View contentView; // we use this a ton, so cache it
|
||||||
@Bind(R.id.reading_overlay_left) Button overlayLeft;
|
|
||||||
@Bind(R.id.reading_overlay_right) Button overlayRight;
|
|
||||||
@Bind(R.id.reading_overlay_progress) ProgressBar overlayProgress;
|
|
||||||
@Bind(R.id.reading_overlay_progress_right) ProgressBar overlayProgressRight;
|
|
||||||
@Bind(R.id.reading_overlay_progress_left) ProgressBar overlayProgressLeft;
|
|
||||||
@Bind(R.id.reading_overlay_text) Button overlayText;
|
|
||||||
@Bind(R.id.reading_overlay_send) Button overlaySend;
|
|
||||||
@Bind(R.id.reading_empty_view_text) View emptyViewText;
|
|
||||||
@Bind(R.id.reading_sync_status) TextView overlayStatusText;
|
|
||||||
|
|
||||||
ViewPager pager;
|
ViewPager pager;
|
||||||
ReadingPagerFragment readingFragment;
|
|
||||||
|
|
||||||
protected ReadingAdapter readingAdapter;
|
protected ReadingAdapter readingAdapter;
|
||||||
private boolean stopLoading;
|
private boolean stopLoading;
|
||||||
|
@ -109,6 +96,8 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
|
|
||||||
private VolumeKeyNavigation volumeKeyNavigation;
|
private VolumeKeyNavigation volumeKeyNavigation;
|
||||||
|
|
||||||
|
private ActivityReadingBinding binding;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onNewIntent(Intent intent) {
|
protected void onNewIntent(Intent intent) {
|
||||||
super.onNewIntent(intent);
|
super.onNewIntent(intent);
|
||||||
|
@ -119,8 +108,9 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
protected void onCreate(Bundle savedInstanceBundle) {
|
protected void onCreate(Bundle savedInstanceBundle) {
|
||||||
super.onCreate(savedInstanceBundle);
|
super.onCreate(savedInstanceBundle);
|
||||||
|
|
||||||
setContentView(R.layout.activity_reading);
|
binding = ActivityReadingBinding.inflate(getLayoutInflater());
|
||||||
ButterKnife.bind(this);
|
setContentView(binding.getRoot());
|
||||||
|
contentView = findViewById(android.R.id.content);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs = (FeedSet)getIntent().getSerializableExtra(EXTRA_FEEDSET);
|
fs = (FeedSet)getIntent().getSerializableExtra(EXTRA_FEEDSET);
|
||||||
|
@ -167,17 +157,17 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
|
|
||||||
this.pageHistory = new ArrayList<Story>();
|
this.pageHistory = new ArrayList<Story>();
|
||||||
|
|
||||||
ViewUtils.setViewElevation(overlayLeft, OVERLAY_ELEVATION_DP);
|
ViewUtils.setViewElevation(binding.readingOverlayLeft, OVERLAY_ELEVATION_DP);
|
||||||
ViewUtils.setViewElevation(overlayRight, OVERLAY_ELEVATION_DP);
|
ViewUtils.setViewElevation(binding.readingOverlayRight, OVERLAY_ELEVATION_DP);
|
||||||
ViewUtils.setViewElevation(overlayText, OVERLAY_ELEVATION_DP);
|
ViewUtils.setViewElevation(binding.readingOverlayText, OVERLAY_ELEVATION_DP);
|
||||||
ViewUtils.setViewElevation(overlaySend, OVERLAY_ELEVATION_DP);
|
ViewUtils.setViewElevation(binding.readingOverlaySend, OVERLAY_ELEVATION_DP);
|
||||||
ViewUtils.setViewElevation(overlayProgress, OVERLAY_ELEVATION_DP);
|
ViewUtils.setViewElevation(binding.readingOverlayProgress, OVERLAY_ELEVATION_DP);
|
||||||
ViewUtils.setViewElevation(overlayProgressLeft, OVERLAY_ELEVATION_DP);
|
ViewUtils.setViewElevation(binding.readingOverlayProgressLeft, OVERLAY_ELEVATION_DP);
|
||||||
ViewUtils.setViewElevation(overlayProgressRight, OVERLAY_ELEVATION_DP);
|
ViewUtils.setViewElevation(binding.readingOverlayProgressRight, OVERLAY_ELEVATION_DP);
|
||||||
|
|
||||||
// this likes to default to 'on' for some platforms
|
// this likes to default to 'on' for some platforms
|
||||||
enableProgressCircle(overlayProgressLeft, false);
|
enableProgressCircle(binding.readingOverlayProgressLeft, false);
|
||||||
enableProgressCircle(overlayProgressRight, false);
|
enableProgressCircle(binding.readingOverlayProgressRight, false);
|
||||||
|
|
||||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||||
ReadingPagerFragment fragment = (ReadingPagerFragment) fragmentManager.findFragmentByTag(ReadingPagerFragment.class.getName());
|
ReadingPagerFragment fragment = (ReadingPagerFragment) fragmentManager.findFragmentByTag(ReadingPagerFragment.class.getName());
|
||||||
|
@ -259,6 +249,7 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
// the system can and will re-use activities, so during the initial mismatch of
|
// the system can and will re-use activities, so during the initial mismatch of
|
||||||
// data, don't show the old stories
|
// data, don't show the old stories
|
||||||
pager.setVisibility(View.INVISIBLE);
|
pager.setVisibility(View.INVISIBLE);
|
||||||
|
binding.readingEmptyViewText.setVisibility(View.VISIBLE);
|
||||||
stories = null;
|
stories = null;
|
||||||
triggerRefresh(AppConstants.READING_STORY_PRELOAD);
|
triggerRefresh(AppConstants.READING_STORY_PRELOAD);
|
||||||
return;
|
return;
|
||||||
|
@ -297,7 +288,11 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
|
|
||||||
private void skipPagerToStoryHash() {
|
private void skipPagerToStoryHash() {
|
||||||
// if we already started and found our target story, this will be unset
|
// if we already started and found our target story, this will be unset
|
||||||
if (storyHash == null) return;
|
if (storyHash == null) {
|
||||||
|
pager.setVisibility(View.VISIBLE);
|
||||||
|
binding.readingEmptyViewText.setVisibility(View.INVISIBLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
int position = -1;
|
int position = -1;
|
||||||
if (storyHash.equals(FIND_FIRST_UNREAD)) {
|
if (storyHash.equals(FIND_FIRST_UNREAD)) {
|
||||||
position = readingAdapter.findFirstUnread();
|
position = readingAdapter.findFirstUnread();
|
||||||
|
@ -312,7 +307,7 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
this.onPageSelected(position);
|
this.onPageSelected(position);
|
||||||
// now that the pager is getting the right story, make it visible
|
// now that the pager is getting the right story, make it visible
|
||||||
pager.setVisibility(View.VISIBLE);
|
pager.setVisibility(View.VISIBLE);
|
||||||
emptyViewText.setVisibility(View.INVISIBLE);
|
binding.readingEmptyViewText.setVisibility(View.INVISIBLE);
|
||||||
storyHash = null;
|
storyHash = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -340,6 +335,15 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
pager.setPageMarginDrawable(R.drawable.divider_light);
|
pager.setPageMarginDrawable(R.drawable.divider_light);
|
||||||
} else if (themeValue == ThemeValue.DARK) {
|
} else if (themeValue == ThemeValue.DARK) {
|
||||||
pager.setPageMarginDrawable(R.drawable.divider_dark);
|
pager.setPageMarginDrawable(R.drawable.divider_dark);
|
||||||
|
} else if (themeValue == ThemeValue.AUTO) {
|
||||||
|
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||||
|
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
|
||||||
|
pager.setPageMarginDrawable(R.drawable.divider_dark);
|
||||||
|
} else if (nightModeFlags == Configuration.UI_MODE_NIGHT_NO) {
|
||||||
|
pager.setPageMarginDrawable(R.drawable.divider_light);
|
||||||
|
} else if (nightModeFlags == Configuration.UI_MODE_NIGHT_UNDEFINED) {
|
||||||
|
pager.setPageMarginDrawable(R.drawable.divider_light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean showFeedMetadata = true;
|
boolean showFeedMetadata = true;
|
||||||
|
@ -405,16 +409,16 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
}
|
}
|
||||||
if ((updateType & UPDATE_STATUS) != 0) {
|
if ((updateType & UPDATE_STATUS) != 0) {
|
||||||
enableMainProgress(NBSyncService.isFeedSetSyncing(this.fs, this));
|
enableMainProgress(NBSyncService.isFeedSetSyncing(this.fs, this));
|
||||||
if (overlayStatusText != null) {
|
if (binding.readingSyncStatus != null) {
|
||||||
String syncStatus = NBSyncService.getSyncStatusMessage(this, true);
|
String syncStatus = NBSyncService.getSyncStatusMessage(this, true);
|
||||||
if (syncStatus != null) {
|
if (syncStatus != null) {
|
||||||
if (AppConstants.VERBOSE_LOG) {
|
if (AppConstants.VERBOSE_LOG) {
|
||||||
syncStatus = syncStatus + UIUtils.getMemoryUsageDebug(this);
|
syncStatus = syncStatus + UIUtils.getMemoryUsageDebug(this);
|
||||||
}
|
}
|
||||||
overlayStatusText.setText(syncStatus);
|
binding.readingSyncStatus.setText(syncStatus);
|
||||||
overlayStatusText.setVisibility(View.VISIBLE);
|
binding.readingSyncStatus.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
overlayStatusText.setVisibility(View.GONE);
|
binding.readingSyncStatus.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,11 +520,11 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
final boolean _overflowExtras = overflowExtras;
|
final boolean _overflowExtras = overflowExtras;
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
UIUtils.setViewAlpha(overlayLeft, a, true);
|
UIUtils.setViewAlpha(binding.readingOverlayLeft, a, true);
|
||||||
UIUtils.setViewAlpha(overlayRight, a, true);
|
UIUtils.setViewAlpha(binding.readingOverlayRight, a, true);
|
||||||
UIUtils.setViewAlpha(overlayProgress, a, true);
|
UIUtils.setViewAlpha(binding.readingOverlayProgress, a, true);
|
||||||
UIUtils.setViewAlpha(overlayText, a, true);
|
UIUtils.setViewAlpha(binding.readingOverlayText, a, true);
|
||||||
UIUtils.setViewAlpha(overlaySend, a, !_overflowExtras);
|
UIUtils.setViewAlpha(binding.readingOverlaySend, a, !_overflowExtras);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -544,40 +548,40 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
if (currentUnreadCount > this.startingUnreadCount ) {
|
if (currentUnreadCount > this.startingUnreadCount ) {
|
||||||
this.startingUnreadCount = currentUnreadCount;
|
this.startingUnreadCount = currentUnreadCount;
|
||||||
}
|
}
|
||||||
this.overlayLeft.setEnabled(this.getLastReadPosition(false) != -1);
|
this.binding.readingOverlayLeft.setEnabled(this.getLastReadPosition(false) != -1);
|
||||||
this.overlayRight.setText((currentUnreadCount > 0) ? R.string.overlay_next : R.string.overlay_done);
|
this.binding.readingOverlayRight.setText((currentUnreadCount > 0) ? R.string.overlay_next : R.string.overlay_done);
|
||||||
if (currentUnreadCount > 0) {
|
if (currentUnreadCount > 0) {
|
||||||
this.overlayRight.setBackgroundResource(UIUtils.getThemedResource(this, R.attr.selectorOverlayBackgroundRight, android.R.attr.background));
|
this.binding.readingOverlayRight.setBackgroundResource(UIUtils.getThemedResource(this, R.attr.selectorOverlayBackgroundRight, android.R.attr.background));
|
||||||
} else {
|
} else {
|
||||||
this.overlayRight.setBackgroundResource(UIUtils.getThemedResource(this, R.attr.selectorOverlayBackgroundRightDone, android.R.attr.background));
|
this.binding.readingOverlayRight.setBackgroundResource(UIUtils.getThemedResource(this, R.attr.selectorOverlayBackgroundRightDone, android.R.attr.background));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.startingUnreadCount == 0 ) {
|
if (this.startingUnreadCount == 0 ) {
|
||||||
// sessions with no unreads just show a full progress bar
|
// sessions with no unreads just show a full progress bar
|
||||||
this.overlayProgress.setMax(1);
|
this.binding.readingOverlayProgress.setMax(1);
|
||||||
this.overlayProgress.setProgress(1);
|
this.binding.readingOverlayProgress.setProgress(1);
|
||||||
} else {
|
} else {
|
||||||
int unreadProgress = this.startingUnreadCount - currentUnreadCount;
|
int unreadProgress = this.startingUnreadCount - currentUnreadCount;
|
||||||
this.overlayProgress.setMax(this.startingUnreadCount);
|
this.binding.readingOverlayProgress.setMax(this.startingUnreadCount);
|
||||||
this.overlayProgress.setProgress(unreadProgress);
|
this.binding.readingOverlayProgress.setProgress(unreadProgress);
|
||||||
}
|
}
|
||||||
this.overlayProgress.invalidate();
|
this.binding.readingOverlayProgress.invalidate();
|
||||||
|
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOverlayText() {
|
private void updateOverlayText() {
|
||||||
if (overlayText == null) return;
|
if (binding.readingOverlayText == null) return;
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
ReadingItemFragment item = getReadingFragment();
|
ReadingItemFragment item = getReadingFragment();
|
||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
if (item.getSelectedViewMode() == DefaultFeedView.STORY) {
|
if (item.getSelectedViewMode() == DefaultFeedView.STORY) {
|
||||||
overlayText.setBackgroundResource(UIUtils.getThemedResource(Reading.this, R.attr.selectorOverlayBackgroundText, android.R.attr.background));
|
binding.readingOverlayText.setBackgroundResource(UIUtils.getThemedResource(Reading.this, R.attr.selectorOverlayBackgroundText, android.R.attr.background));
|
||||||
overlayText.setText(R.string.overlay_text);
|
binding.readingOverlayText.setText(R.string.overlay_text);
|
||||||
} else {
|
} else {
|
||||||
overlayText.setBackgroundResource(UIUtils.getThemedResource(Reading.this, R.attr.selectorOverlayBackgroundStory, android.R.attr.background));
|
binding.readingOverlayText.setBackgroundResource(UIUtils.getThemedResource(Reading.this, R.attr.selectorOverlayBackgroundStory, android.R.attr.background));
|
||||||
overlayText.setText(R.string.overlay_story);
|
binding.readingOverlayText.setText(R.string.overlay_story);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -610,11 +614,11 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void enableMainProgress(boolean enabled) {
|
protected void enableMainProgress(boolean enabled) {
|
||||||
enableProgressCircle(overlayProgressRight, enabled);
|
enableProgressCircle(binding.readingOverlayProgressRight, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableLeftProgressCircle(boolean enabled) {
|
public void enableLeftProgressCircle(boolean enabled) {
|
||||||
enableProgressCircle(overlayProgressLeft, enabled);
|
enableProgressCircle(binding.readingOverlayProgressLeft, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableProgressCircle(final ProgressBar view, final boolean enabled) {
|
private void enableProgressCircle(final ProgressBar view, final boolean enabled) {
|
||||||
|
|
|
@ -18,4 +18,13 @@ public class SavedStoriesItemsList extends ItemsList {
|
||||||
UIUtils.setCustomActionBar(this, R.drawable.clock, title);
|
UIUtils.setCustomActionBar(this, R.drawable.clock, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
String feedId = "starred";
|
||||||
|
String savedTag = fs.getSingleSavedTag();
|
||||||
|
if (savedTag != null) {
|
||||||
|
feedId += ":" + savedTag;
|
||||||
|
}
|
||||||
|
return feedId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,4 +19,8 @@ public class SocialFeedItemsList extends ItemsList {
|
||||||
UIUtils.setCustomActionBar(this, socialFeed.photoUrl, socialFeed.feedTitle);
|
UIUtils.setCustomActionBar(this, socialFeed.photoUrl, socialFeed.feedTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String getSaveSearchFeedId() {
|
||||||
|
return "social:" + socialFeed.userId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,9 @@ import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ExpandableListView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.ActivityWidgetConfigBinding;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.domain.Folder;
|
import com.newsblur.domain.Folder;
|
||||||
import com.newsblur.util.FeedOrderFilter;
|
import com.newsblur.util.FeedOrderFilter;
|
||||||
|
@ -31,28 +30,21 @@ import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
|
|
||||||
public class WidgetConfig extends NbActivity {
|
public class WidgetConfig extends NbActivity {
|
||||||
|
|
||||||
@Bind(R.id.list_view)
|
|
||||||
ExpandableListView listView;
|
|
||||||
@Bind(R.id.text_no_subscriptions)
|
|
||||||
TextView textNoSubscriptions;
|
|
||||||
|
|
||||||
private WidgetConfigAdapter adapter;
|
private WidgetConfigAdapter adapter;
|
||||||
private ArrayList<Feed> feeds;
|
private ArrayList<Feed> feeds;
|
||||||
private ArrayList<Folder> folders;
|
private ArrayList<Folder> folders;
|
||||||
private Map<String, Feed> feedMap = new HashMap<>();
|
private Map<String, Feed> feedMap = new HashMap<>();
|
||||||
private ArrayList<String> folderNames = new ArrayList<>();
|
private ArrayList<String> folderNames = new ArrayList<>();
|
||||||
private ArrayList<ArrayList<Feed>> folderChildren = new ArrayList<>();
|
private ArrayList<ArrayList<Feed>> folderChildren = new ArrayList<>();
|
||||||
|
private ActivityWidgetConfigBinding binding;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_widget_config);
|
binding = ActivityWidgetConfigBinding.inflate(getLayoutInflater());
|
||||||
ButterKnife.bind(this);
|
setContentView(binding.getRoot());
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
setupList();
|
setupList();
|
||||||
loadFeeds();
|
loadFeeds();
|
||||||
|
@ -164,7 +156,7 @@ public class WidgetConfig extends NbActivity {
|
||||||
|
|
||||||
private void setupList() {
|
private void setupList() {
|
||||||
adapter = new WidgetConfigAdapter(this);
|
adapter = new WidgetConfigAdapter(this);
|
||||||
listView.setAdapter(adapter);
|
binding.listView.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadFeeds() {
|
private void loadFeeds() {
|
||||||
|
@ -288,7 +280,7 @@ public class WidgetConfig extends NbActivity {
|
||||||
private void setAdapterData() {
|
private void setAdapterData() {
|
||||||
adapter.setData(this.folderNames, this.folderChildren, this.feeds);
|
adapter.setData(this.folderNames, this.folderChildren, this.feeds);
|
||||||
|
|
||||||
listView.setVisibility(this.feeds.isEmpty() ? View.GONE : View.VISIBLE);
|
binding.listView.setVisibility(this.feeds.isEmpty() ? View.GONE : View.VISIBLE);
|
||||||
textNoSubscriptions.setVisibility(this.feeds.isEmpty() ? View.VISIBLE : View.GONE);
|
binding.textNoSubscriptions.setVisibility(this.feeds.isEmpty() ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,6 +27,7 @@ public class BlurDatabase extends SQLiteOpenHelper {
|
||||||
db.execSQL(DatabaseConstants.CLASSIFIER_SQL);
|
db.execSQL(DatabaseConstants.CLASSIFIER_SQL);
|
||||||
db.execSQL(DatabaseConstants.SOCIALFEED_STORIES_SQL);
|
db.execSQL(DatabaseConstants.SOCIALFEED_STORIES_SQL);
|
||||||
db.execSQL(DatabaseConstants.STARREDCOUNTS_SQL);
|
db.execSQL(DatabaseConstants.STARREDCOUNTS_SQL);
|
||||||
|
db.execSQL(DatabaseConstants.SAVED_SEARCH_SQL);
|
||||||
db.execSQL(DatabaseConstants.ACTION_SQL);
|
db.execSQL(DatabaseConstants.ACTION_SQL);
|
||||||
db.execSQL(DatabaseConstants.NOTIFY_DISMISS_SQL);
|
db.execSQL(DatabaseConstants.NOTIFY_DISMISS_SQL);
|
||||||
db.execSQL(DatabaseConstants.FEED_TAGS_SQL);
|
db.execSQL(DatabaseConstants.FEED_TAGS_SQL);
|
||||||
|
@ -49,6 +50,7 @@ public class BlurDatabase extends SQLiteOpenHelper {
|
||||||
db.execSQL(drop + DatabaseConstants.CLASSIFIER_TABLE);
|
db.execSQL(drop + DatabaseConstants.CLASSIFIER_TABLE);
|
||||||
db.execSQL(drop + DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE);
|
db.execSQL(drop + DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE);
|
||||||
db.execSQL(drop + DatabaseConstants.STARREDCOUNTS_TABLE);
|
db.execSQL(drop + DatabaseConstants.STARREDCOUNTS_TABLE);
|
||||||
|
db.execSQL(drop + DatabaseConstants.SAVED_SEARCH_TABLE);
|
||||||
db.execSQL(drop + DatabaseConstants.ACTION_TABLE);
|
db.execSQL(drop + DatabaseConstants.ACTION_TABLE);
|
||||||
db.execSQL(drop + DatabaseConstants.NOTIFY_DISMISS_TABLE);
|
db.execSQL(drop + DatabaseConstants.NOTIFY_DISMISS_TABLE);
|
||||||
db.execSQL(drop + DatabaseConstants.FEED_TAGS_TABLE);
|
db.execSQL(drop + DatabaseConstants.FEED_TAGS_TABLE);
|
||||||
|
|
|
@ -195,6 +195,13 @@ public class BlurDatabaseHelper {
|
||||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE, DatabaseConstants.SOCIALFEED_STORY_USER_ID + " = ?", selArgs);}
|
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE, DatabaseConstants.SOCIALFEED_STORY_USER_ID + " = ?", selArgs);}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteSavedSearch(String feedId, String query) {
|
||||||
|
String q = "DELETE FROM " + DatabaseConstants.SAVED_SEARCH_TABLE +
|
||||||
|
" WHERE " + DatabaseConstants.SAVED_SEARCH_FEED_ID + " = '" + feedId + "'" +
|
||||||
|
" AND " + DatabaseConstants.SAVED_SEARCH_QUERY + " = '" + query + "'";
|
||||||
|
synchronized (RW_MUTEX) {dbRW.execSQL(q);}
|
||||||
|
}
|
||||||
|
|
||||||
public Feed getFeed(String feedId) {
|
public Feed getFeed(String feedId) {
|
||||||
Cursor c = dbRO.query(DatabaseConstants.FEED_TABLE, null, DatabaseConstants.FEED_ID + " = ?", new String[] {feedId}, null, null, null);
|
Cursor c = dbRO.query(DatabaseConstants.FEED_TABLE, null, DatabaseConstants.FEED_ID + " = ?", new String[] {feedId}, null, null, null);
|
||||||
Feed result = null;
|
Feed result = null;
|
||||||
|
@ -237,7 +244,8 @@ public class BlurDatabaseHelper {
|
||||||
public void setFeedsFolders(List<ContentValues> folderValues,
|
public void setFeedsFolders(List<ContentValues> folderValues,
|
||||||
List<ContentValues> feedValues,
|
List<ContentValues> feedValues,
|
||||||
List<ContentValues> socialFeedValues,
|
List<ContentValues> socialFeedValues,
|
||||||
List<ContentValues> starredCountValues) {
|
List<ContentValues> starredCountValues,
|
||||||
|
List<ContentValues> savedSearchValues) {
|
||||||
synchronized (RW_MUTEX) {
|
synchronized (RW_MUTEX) {
|
||||||
dbRW.beginTransaction();
|
dbRW.beginTransaction();
|
||||||
try {
|
try {
|
||||||
|
@ -248,10 +256,12 @@ public class BlurDatabaseHelper {
|
||||||
dbRW.delete(DatabaseConstants.COMMENT_TABLE, null, null);
|
dbRW.delete(DatabaseConstants.COMMENT_TABLE, null, null);
|
||||||
dbRW.delete(DatabaseConstants.REPLY_TABLE, null, null);
|
dbRW.delete(DatabaseConstants.REPLY_TABLE, null, null);
|
||||||
dbRW.delete(DatabaseConstants.STARREDCOUNTS_TABLE, null, null);
|
dbRW.delete(DatabaseConstants.STARREDCOUNTS_TABLE, null, null);
|
||||||
|
dbRW.delete(DatabaseConstants.SAVED_SEARCH_TABLE, null, null);
|
||||||
bulkInsertValuesExtSync(DatabaseConstants.FOLDER_TABLE, folderValues);
|
bulkInsertValuesExtSync(DatabaseConstants.FOLDER_TABLE, folderValues);
|
||||||
bulkInsertValuesExtSync(DatabaseConstants.FEED_TABLE, feedValues);
|
bulkInsertValuesExtSync(DatabaseConstants.FEED_TABLE, feedValues);
|
||||||
bulkInsertValuesExtSync(DatabaseConstants.SOCIALFEED_TABLE, socialFeedValues);
|
bulkInsertValuesExtSync(DatabaseConstants.SOCIALFEED_TABLE, socialFeedValues);
|
||||||
bulkInsertValuesExtSync(DatabaseConstants.STARREDCOUNTS_TABLE, starredCountValues);
|
bulkInsertValuesExtSync(DatabaseConstants.STARREDCOUNTS_TABLE, starredCountValues);
|
||||||
|
bulkInsertValuesExtSync(DatabaseConstants.SAVED_SEARCH_TABLE, savedSearchValues);
|
||||||
dbRW.setTransactionSuccessful();
|
dbRW.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
dbRW.endTransaction();
|
dbRW.endTransaction();
|
||||||
|
@ -1033,6 +1043,17 @@ public class BlurDatabaseHelper {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public StarredCount getStarredFeedByTag(String tag) {
|
||||||
|
Cursor c = dbRO.query(DatabaseConstants.STARREDCOUNTS_TABLE, null, DatabaseConstants.STARREDCOUNTS_TAG + " = ?", new String[] {tag}, null, null, null);
|
||||||
|
StarredCount result = null;
|
||||||
|
while (c.moveToNext()) {
|
||||||
|
result = StarredCount.fromCursor(c);
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Folder> getFolders() {
|
public List<Folder> getFolders() {
|
||||||
Cursor c = getFoldersCursor(null);
|
Cursor c = getFoldersCursor(null);
|
||||||
List<Folder> folders = new ArrayList<Folder>(c.getCount());
|
List<Folder> folders = new ArrayList<Folder>(c.getCount());
|
||||||
|
@ -1069,11 +1090,21 @@ public class BlurDatabaseHelper {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Loader<Cursor> getSavedSearchLoader() {
|
||||||
|
return new QueryCursorLoader(context) {
|
||||||
|
protected Cursor createCursor() {return getSavedSearchCursor(cancellationSignal);}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private Cursor getSavedStoryCountsCursor(CancellationSignal cancellationSignal) {
|
private Cursor getSavedStoryCountsCursor(CancellationSignal cancellationSignal) {
|
||||||
Cursor c = query(false, DatabaseConstants.STARREDCOUNTS_TABLE, null, null, null, null, null, null, null, cancellationSignal);
|
Cursor c = query(false, DatabaseConstants.STARREDCOUNTS_TABLE, null, null, null, null, null, null, null, cancellationSignal);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Cursor getSavedSearchCursor(CancellationSignal cancellationSignal) {
|
||||||
|
return query(false, DatabaseConstants.SAVED_SEARCH_TABLE, null, null, null, null, null, null, null, cancellationSignal);
|
||||||
|
}
|
||||||
|
|
||||||
public Cursor getNotifyFocusStoriesCursor() {
|
public Cursor getNotifyFocusStoriesCursor() {
|
||||||
return rawQuery(DatabaseConstants.NOTIFY_FOCUS_STORY_QUERY, null, null);
|
return rawQuery(DatabaseConstants.NOTIFY_FOCUS_STORY_QUERY, null, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,6 +148,13 @@ public class DatabaseConstants {
|
||||||
public static final String STARREDCOUNTS_TAG = "tag";
|
public static final String STARREDCOUNTS_TAG = "tag";
|
||||||
public static final String STARREDCOUNTS_FEEDID = "feed_id";
|
public static final String STARREDCOUNTS_FEEDID = "feed_id";
|
||||||
|
|
||||||
|
public static final String SAVED_SEARCH_TABLE = "saved_search";
|
||||||
|
public static final String SAVED_SEARCH_FEED_TITLE = "saved_search_title";
|
||||||
|
public static final String SAVED_SEARCH_FAVICON = "saved_search_favicon";
|
||||||
|
public static final String SAVED_SEARCH_ADDRESS = "saved_search_address";
|
||||||
|
public static final String SAVED_SEARCH_QUERY = "saved_search_query";
|
||||||
|
public static final String SAVED_SEARCH_FEED_ID = "saved_search_feed_id";
|
||||||
|
|
||||||
public static final String NOTIFY_DISMISS_TABLE = "notify_dimiss";
|
public static final String NOTIFY_DISMISS_TABLE = "notify_dimiss";
|
||||||
public static final String NOTIFY_DISMISS_STORY_HASH = "story_hash";
|
public static final String NOTIFY_DISMISS_STORY_HASH = "story_hash";
|
||||||
public static final String NOTIFY_DISMISS_TIME = "time";
|
public static final String NOTIFY_DISMISS_TIME = "time";
|
||||||
|
@ -185,7 +192,7 @@ public class DatabaseConstants {
|
||||||
FEED_FAVICON_BORDER + TEXT + ", " +
|
FEED_FAVICON_BORDER + TEXT + ", " +
|
||||||
FEED_LINK + TEXT + ", " +
|
FEED_LINK + TEXT + ", " +
|
||||||
FEED_SUBSCRIBERS + TEXT + ", " +
|
FEED_SUBSCRIBERS + TEXT + ", " +
|
||||||
FEED_TITLE + TEXT + ", " +
|
FEED_TITLE + TEXT + ", " +
|
||||||
FEED_OPENS + INTEGER + ", " +
|
FEED_OPENS + INTEGER + ", " +
|
||||||
FEED_AVERAGE_STORIES_PER_MONTH + INTEGER + ", " +
|
FEED_AVERAGE_STORIES_PER_MONTH + INTEGER + ", " +
|
||||||
FEED_LAST_STORY_DATE + TEXT + ", " +
|
FEED_LAST_STORY_DATE + TEXT + ", " +
|
||||||
|
@ -303,6 +310,14 @@ public class DatabaseConstants {
|
||||||
STARREDCOUNTS_FEEDID + TEXT +
|
STARREDCOUNTS_FEEDID + TEXT +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
|
static final String SAVED_SEARCH_SQL = "CREATE TABLE " + SAVED_SEARCH_TABLE + " (" +
|
||||||
|
SAVED_SEARCH_FEED_TITLE + TEXT + ", " +
|
||||||
|
SAVED_SEARCH_FAVICON + TEXT + ", " +
|
||||||
|
SAVED_SEARCH_ADDRESS + TEXT + ", " +
|
||||||
|
SAVED_SEARCH_QUERY + TEXT + ", " +
|
||||||
|
SAVED_SEARCH_FEED_ID +
|
||||||
|
")";
|
||||||
|
|
||||||
static final String NOTIFY_DISMISS_SQL = "CREATE TABLE " + NOTIFY_DISMISS_TABLE + " (" +
|
static final String NOTIFY_DISMISS_SQL = "CREATE TABLE " + NOTIFY_DISMISS_TABLE + " (" +
|
||||||
NOTIFY_DISMISS_STORY_HASH + TEXT + ", " +
|
NOTIFY_DISMISS_STORY_HASH + TEXT + ", " +
|
||||||
NOTIFY_DISMISS_TIME + INTEGER + " NOT NULL " +
|
NOTIFY_DISMISS_TIME + INTEGER + " NOT NULL " +
|
||||||
|
|
|
@ -27,6 +27,7 @@ import android.widget.TextView;
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.domain.Folder;
|
import com.newsblur.domain.Folder;
|
||||||
|
import com.newsblur.domain.SavedSearch;
|
||||||
import com.newsblur.domain.StarredCount;
|
import com.newsblur.domain.StarredCount;
|
||||||
import com.newsblur.domain.SocialFeed;
|
import com.newsblur.domain.SocialFeed;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
|
@ -34,14 +35,15 @@ import com.newsblur.util.FeedSet;
|
||||||
import com.newsblur.util.FeedUtils;
|
import com.newsblur.util.FeedUtils;
|
||||||
import com.newsblur.util.PrefsUtils;
|
import com.newsblur.util.PrefsUtils;
|
||||||
import com.newsblur.util.StateFilter;
|
import com.newsblur.util.StateFilter;
|
||||||
|
import com.newsblur.util.UIUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom adapter to display a nested folder/feed list in an ExpandableListView.
|
* Custom adapter to display a nested folder/feed list in an ExpandableListView.
|
||||||
*/
|
*/
|
||||||
public class FolderListAdapter extends BaseExpandableListAdapter {
|
public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
|
|
||||||
private enum GroupType { GLOBAL_SHARED_STORIES, ALL_SHARED_STORIES, INFREQUENT_STORIES, ALL_STORIES, FOLDER, READ_STORIES, SAVED_STORIES }
|
private enum GroupType { GLOBAL_SHARED_STORIES, ALL_SHARED_STORIES, INFREQUENT_STORIES, ALL_STORIES, FOLDER, READ_STORIES, SAVED_SEARCHES, SAVED_STORIES }
|
||||||
private enum ChildType { SOCIAL_FEED, FEED, SAVED_BY_TAG }
|
private enum ChildType { SOCIAL_FEED, FEED, SAVED_BY_TAG, SAVED_SEARCH }
|
||||||
|
|
||||||
// The following keys are used to mark the position of the special meta-folders within
|
// The following keys are used to mark the position of the special meta-folders within
|
||||||
// the folders array. Since the ExpandableListView doesn't handle collapsing of views
|
// the folders array. Since the ExpandableListView doesn't handle collapsing of views
|
||||||
|
@ -56,6 +58,7 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
private static final String INFREQUENT_SITE_STORIES_GROUP_KEY = "INFREQUENT_SITE_STORIES_GROUP_KEY";
|
private static final String INFREQUENT_SITE_STORIES_GROUP_KEY = "INFREQUENT_SITE_STORIES_GROUP_KEY";
|
||||||
private static final String READ_STORIES_GROUP_KEY = "READ_STORIES_GROUP_KEY";
|
private static final String READ_STORIES_GROUP_KEY = "READ_STORIES_GROUP_KEY";
|
||||||
private static final String SAVED_STORIES_GROUP_KEY = "SAVED_STORIES_GROUP_KEY";
|
private static final String SAVED_STORIES_GROUP_KEY = "SAVED_STORIES_GROUP_KEY";
|
||||||
|
private static final String SAVED_SEARCHES_GROUP_KEY = "SAVED_SEARCHES_GROUP_KEY";
|
||||||
|
|
||||||
private final static float defaultTextSize_childName = 14;
|
private final static float defaultTextSize_childName = 14;
|
||||||
private final static float defaultTextSize_groupName = 13;
|
private final static float defaultTextSize_groupName = 13;
|
||||||
|
@ -101,6 +104,8 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
|
|
||||||
/** Starred story sets in display order. */
|
/** Starred story sets in display order. */
|
||||||
private List<StarredCount> starredCountsByTag = Collections.emptyList();
|
private List<StarredCount> starredCountsByTag = Collections.emptyList();
|
||||||
|
/** Saved Searches */
|
||||||
|
private List<SavedSearch> savedSearches = Collections.emptyList();
|
||||||
|
|
||||||
private int savedStoriesTotalCount;
|
private int savedStoriesTotalCount;
|
||||||
|
|
||||||
|
@ -162,6 +167,8 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
if (v == null) v = inflater.inflate(R.layout.row_infrequent_stories, null, false);
|
if (v == null) v = inflater.inflate(R.layout.row_infrequent_stories, null, false);
|
||||||
} else if (isRowReadStories(groupPosition)) {
|
} else if (isRowReadStories(groupPosition)) {
|
||||||
if (v == null) v = inflater.inflate(R.layout.row_read_stories, null, false);
|
if (v == null) v = inflater.inflate(R.layout.row_read_stories, null, false);
|
||||||
|
} else if (isRowSavedSearches(groupPosition)) {
|
||||||
|
if (v == null) v = inflater.inflate(R.layout.row_saved_searches, null, false);
|
||||||
} else if (isRowSavedStories(groupPosition)) {
|
} else if (isRowSavedStories(groupPosition)) {
|
||||||
if (v == null) v = inflater.inflate(R.layout.row_saved_stories, null, false);
|
if (v == null) v = inflater.inflate(R.layout.row_saved_stories, null, false);
|
||||||
TextView savedSum = ((TextView) v.findViewById(R.id.row_foldersum));
|
TextView savedSum = ((TextView) v.findViewById(R.id.row_foldersum));
|
||||||
|
@ -268,7 +275,15 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
TextView savedCounter =((TextView) v.findViewById(R.id.row_saved_tag_sum));
|
TextView savedCounter =((TextView) v.findViewById(R.id.row_saved_tag_sum));
|
||||||
savedCounter.setText(Integer.toString(checkNegativeUnreads(sc.count)));
|
savedCounter.setText(Integer.toString(checkNegativeUnreads(sc.count)));
|
||||||
savedCounter.setTextSize(textSize * defaultTextSize_count);
|
savedCounter.setTextSize(textSize * defaultTextSize_count);
|
||||||
} else {
|
} else if (isRowSavedSearches(groupPosition)) {
|
||||||
|
if (v == null) v = inflater.inflate(R.layout.row_saved_search_child, parent, false);
|
||||||
|
SavedSearch ss = savedSearches.get(childPosition);
|
||||||
|
TextView nameView = v.findViewById(R.id.row_saved_search_title);
|
||||||
|
nameView.setText(UIUtils.fromHtml(ss.feedTitle));
|
||||||
|
ImageView iconView = v.findViewById(R.id.row_saved_search_icon);
|
||||||
|
FeedUtils.iconLoader.preCheck(ss.faviconUrl, iconView);
|
||||||
|
FeedUtils.iconLoader.displayImage(ss.faviconUrl, iconView, 0 , false);
|
||||||
|
} else {
|
||||||
if (v == null) v = inflater.inflate(R.layout.row_feed, parent, false);
|
if (v == null) v = inflater.inflate(R.layout.row_feed, parent, false);
|
||||||
Feed f = activeFolderChildren.get(groupPosition).get(childPosition);
|
Feed f = activeFolderChildren.get(groupPosition).get(childPosition);
|
||||||
TextView nameView =((TextView) v.findViewById(R.id.row_feedname));
|
TextView nameView =((TextView) v.findViewById(R.id.row_feedname));
|
||||||
|
@ -392,6 +407,11 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
return folder.name;
|
return folder.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Folder getGroupFolder(int groupPosition) {
|
||||||
|
String flatFolderName = activeFolderNames.get(groupPosition);
|
||||||
|
return flatFolders.get(flatFolderName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized int getGroupCount() {
|
public synchronized int getGroupCount() {
|
||||||
if (activeFolderNames == null) return 0;
|
if (activeFolderNames == null) return 0;
|
||||||
|
@ -409,7 +429,9 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
return socialFeedsActive.size();
|
return socialFeedsActive.size();
|
||||||
} else if (isRowSavedStories(groupPosition)) {
|
} else if (isRowSavedStories(groupPosition)) {
|
||||||
return starredCountsByTag.size();
|
return starredCountsByTag.size();
|
||||||
} else {
|
} else if (isRowSavedSearches(groupPosition)) {
|
||||||
|
return savedSearches.size();
|
||||||
|
} else {
|
||||||
return activeFolderChildren.get(groupPosition).size();
|
return activeFolderChildren.get(groupPosition).size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,6 +443,9 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
return FeedSet.singleSocialFeed(socialFeed.userId, socialFeed.username);
|
return FeedSet.singleSocialFeed(socialFeed.userId, socialFeed.username);
|
||||||
} else if (isRowSavedStories(groupPosition)) {
|
} else if (isRowSavedStories(groupPosition)) {
|
||||||
return FeedSet.singleSavedTag(starredCountsByTag.get(childPosition).tag);
|
return FeedSet.singleSavedTag(starredCountsByTag.get(childPosition).tag);
|
||||||
|
} else if (isRowSavedSearches(groupPosition)) {
|
||||||
|
SavedSearch savedSearch = savedSearches.get(childPosition);
|
||||||
|
return FeedSet.singleSavedSearch(savedSearch.feedId, savedSearch.query);
|
||||||
} else {
|
} else {
|
||||||
Feed feed = activeFolderChildren.get(groupPosition).get(childPosition);
|
Feed feed = activeFolderChildren.get(groupPosition).get(childPosition);
|
||||||
FeedSet fs = FeedSet.singleFeed(feed.feedId);
|
FeedSet fs = FeedSet.singleFeed(feed.feedId);
|
||||||
|
@ -465,6 +490,10 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
return SAVED_STORIES_GROUP_KEY.equals(activeFolderNames.get(groupPosition));
|
return SAVED_STORIES_GROUP_KEY.equals(activeFolderNames.get(groupPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRowSavedSearches(int groupPosition) {
|
||||||
|
return SAVED_SEARCHES_GROUP_KEY.equals(activeFolderNames.get(groupPosition));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the row at the specified position is last of the special rows, under which
|
* Determines if the row at the specified position is last of the special rows, under which
|
||||||
* un-foldered "root level" feeds are created as children. These feeds are not in any folder,
|
* un-foldered "root level" feeds are created as children. These feeds are not in any folder,
|
||||||
|
@ -564,6 +593,17 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
recountFeeds();
|
recountFeeds();
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void setSavedSearchesCursor(Cursor cursor) {
|
||||||
|
if (!cursor.isBeforeFirst()) return;
|
||||||
|
savedSearches = new ArrayList<>();
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
SavedSearch savedSearch = SavedSearch.fromCursor(cursor);
|
||||||
|
savedSearches.add(savedSearch);
|
||||||
|
}
|
||||||
|
Collections.sort(savedSearches, SavedSearch.SavedSearchComparatorByTitle);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private void recountFeeds() {
|
private void recountFeeds() {
|
||||||
if ((folders == null) || (feeds == null)) return;
|
if ((folders == null) || (feeds == null)) return;
|
||||||
|
@ -619,6 +659,7 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
}
|
}
|
||||||
// add the always-present (if enabled) special rows/folders that got at the bottom of the list
|
// add the always-present (if enabled) special rows/folders that got at the bottom of the list
|
||||||
addSpecialRow(READ_STORIES_GROUP_KEY);
|
addSpecialRow(READ_STORIES_GROUP_KEY);
|
||||||
|
addSpecialRow(SAVED_SEARCHES_GROUP_KEY);
|
||||||
addSpecialRow(SAVED_STORIES_GROUP_KEY);
|
addSpecialRow(SAVED_STORIES_GROUP_KEY);
|
||||||
recountChildren();
|
recountChildren();
|
||||||
}
|
}
|
||||||
|
@ -728,6 +769,7 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
totalNeutCount = 0;
|
totalNeutCount = 0;
|
||||||
totalPosCount = 0;
|
totalPosCount = 0;
|
||||||
|
|
||||||
|
safeClear(savedSearches);
|
||||||
safeClear(starredCountsByTag);
|
safeClear(starredCountsByTag);
|
||||||
safeClear(closedFolders);
|
safeClear(closedFolders);
|
||||||
|
|
||||||
|
@ -755,6 +797,11 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
return socialFeedsActive.get(childPosition);
|
return socialFeedsActive.get(childPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the cached SavedSearch object at the given saved search list location. */
|
||||||
|
public SavedSearch getSavedSearch(int childPosition) {
|
||||||
|
return savedSearches.get(childPosition);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void changeState(StateFilter state) {
|
public synchronized void changeState(StateFilter state) {
|
||||||
currentState = state;
|
currentState = state;
|
||||||
lastFeedViewedId = null; // clear when changing modes
|
lastFeedViewedId = null; // clear when changing modes
|
||||||
|
@ -804,6 +851,8 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
return GroupType.INFREQUENT_STORIES.ordinal();
|
return GroupType.INFREQUENT_STORIES.ordinal();
|
||||||
} else if (isRowReadStories(groupPosition)) {
|
} else if (isRowReadStories(groupPosition)) {
|
||||||
return GroupType.READ_STORIES.ordinal();
|
return GroupType.READ_STORIES.ordinal();
|
||||||
|
} else if (isRowSavedSearches(groupPosition)) {
|
||||||
|
return GroupType.SAVED_SEARCHES.ordinal();
|
||||||
} else if (isRowSavedStories(groupPosition)) {
|
} else if (isRowSavedStories(groupPosition)) {
|
||||||
return GroupType.SAVED_STORIES.ordinal();
|
return GroupType.SAVED_STORIES.ordinal();
|
||||||
} else {
|
} else {
|
||||||
|
@ -817,7 +866,9 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
||||||
return ChildType.SOCIAL_FEED.ordinal();
|
return ChildType.SOCIAL_FEED.ordinal();
|
||||||
} else if (isRowSavedStories(groupPosition)) {
|
} else if (isRowSavedStories(groupPosition)) {
|
||||||
return ChildType.SAVED_BY_TAG.ordinal();
|
return ChildType.SAVED_BY_TAG.ordinal();
|
||||||
} else {
|
} else if (isRowSavedSearches(groupPosition)) {
|
||||||
|
return ChildType.SAVED_SEARCH.ordinal();
|
||||||
|
} else {
|
||||||
return ChildType.FEED.ordinal();
|
return ChildType.FEED.ordinal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.newsblur.database;
|
package com.newsblur.database;
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
|
@ -22,18 +21,13 @@ import android.widget.ImageView;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.FeedItemsList;
|
import com.newsblur.activity.FeedItemsList;
|
||||||
import com.newsblur.activity.ItemsList;
|
|
||||||
import com.newsblur.activity.NbActivity;
|
import com.newsblur.activity.NbActivity;
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
import com.newsblur.domain.UserDetails;
|
import com.newsblur.domain.UserDetails;
|
||||||
|
@ -313,16 +307,16 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
||||||
MenuItem.OnMenuItemClickListener,
|
MenuItem.OnMenuItemClickListener,
|
||||||
View.OnTouchListener {
|
View.OnTouchListener {
|
||||||
|
|
||||||
@Bind(R.id.story_item_favicon_borderbar_1) View leftBarOne;
|
View leftBarOne;
|
||||||
@Bind(R.id.story_item_favicon_borderbar_2) View leftBarTwo;
|
View leftBarTwo;
|
||||||
@Bind(R.id.story_item_inteldot) ImageView intelDot;
|
ImageView intelDot;
|
||||||
@Bind(R.id.story_item_thumbnail) ImageView thumbView;
|
ImageView thumbView;
|
||||||
@Bind(R.id.story_item_feedicon) ImageView feedIconView;
|
ImageView feedIconView;
|
||||||
@Bind(R.id.story_item_feedtitle) TextView feedTitleView;
|
TextView feedTitleView;
|
||||||
@Bind(R.id.story_item_title) TextView storyTitleView;
|
TextView storyTitleView;
|
||||||
@Bind(R.id.story_item_date) TextView storyDate;
|
TextView storyDate;
|
||||||
@Bind(R.id.story_item_saved_icon) View savedView;
|
View savedView;
|
||||||
@Bind(R.id.story_item_shared_icon) View sharedView;
|
View sharedView;
|
||||||
|
|
||||||
Story story;
|
Story story;
|
||||||
ImageLoader.PhotoToLoad thumbLoader;
|
ImageLoader.PhotoToLoad thumbLoader;
|
||||||
|
@ -332,9 +326,20 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
||||||
boolean gestureL2R = false;
|
boolean gestureL2R = false;
|
||||||
boolean gestureDebounce = false;
|
boolean gestureDebounce = false;
|
||||||
|
|
||||||
|
|
||||||
public StoryViewHolder(View view) {
|
public StoryViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
ButterKnife.bind(StoryViewHolder.this, view);
|
leftBarOne = view.findViewById(R.id.story_item_favicon_borderbar_1);
|
||||||
|
leftBarTwo = view.findViewById(R.id.story_item_favicon_borderbar_2);
|
||||||
|
intelDot = view.findViewById(R.id.story_item_inteldot);
|
||||||
|
thumbView = view.findViewById(R.id.story_item_thumbnail);
|
||||||
|
feedIconView = view.findViewById(R.id.story_item_feedicon);
|
||||||
|
feedTitleView = view.findViewById(R.id.story_item_feedtitle);
|
||||||
|
storyTitleView = view.findViewById(R.id.story_item_title);
|
||||||
|
storyDate = view.findViewById(R.id.story_item_date);
|
||||||
|
savedView = view.findViewById(R.id.story_item_saved_icon);
|
||||||
|
sharedView = view.findViewById(R.id.story_item_shared_icon);
|
||||||
|
|
||||||
view.setOnClickListener(StoryViewHolder.this);
|
view.setOnClickListener(StoryViewHolder.this);
|
||||||
view.setOnCreateContextMenuListener(StoryViewHolder.this);
|
view.setOnCreateContextMenuListener(StoryViewHolder.this);
|
||||||
view.setOnTouchListener(StoryViewHolder.this);
|
view.setOnTouchListener(StoryViewHolder.this);
|
||||||
|
@ -472,10 +477,12 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StoryRowViewHolder extends StoryViewHolder {
|
public class StoryRowViewHolder extends StoryViewHolder {
|
||||||
@Bind(R.id.story_item_author) TextView storyAuthor;
|
TextView storyAuthor;
|
||||||
@Bind(R.id.story_item_content) TextView storySnippet;
|
TextView storySnippet;
|
||||||
public StoryRowViewHolder(View view) {
|
public StoryRowViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
|
storyAuthor = view.findViewById(R.id.story_item_author);
|
||||||
|
storySnippet = view.findViewById(R.id.story_item_content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,12 +667,13 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FooterViewHolder extends RecyclerView.ViewHolder {
|
public static class FooterViewHolder extends RecyclerView.ViewHolder {
|
||||||
@Bind(R.id.footer_view_inner) FrameLayout innerView;
|
|
||||||
|
FrameLayout innerView;
|
||||||
|
|
||||||
public FooterViewHolder(View view) {
|
public FooterViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
ButterKnife.bind(FooterViewHolder.this, view);
|
innerView = view.findViewById(R.id.footer_view_inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.newsblur.domain;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -61,6 +62,15 @@ public class Folder {
|
||||||
public void removeOrphanFeedIds(Collection<String> orphanFeedIds) {
|
public void removeOrphanFeedIds(Collection<String> orphanFeedIds) {
|
||||||
feedIds.removeAll(orphanFeedIds);
|
feedIds.removeAll(orphanFeedIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getFirstParentName() {
|
||||||
|
String folderParentName = null;
|
||||||
|
if (!parents.isEmpty()) {
|
||||||
|
folderParentName = parents.get(0);
|
||||||
|
}
|
||||||
|
return folderParentName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object otherFolder) {
|
public boolean equals(Object otherFolder) {
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
package com.newsblur.domain;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import com.newsblur.database.DatabaseConstants;
|
||||||
|
import com.newsblur.util.FeedSet;
|
||||||
|
import com.newsblur.util.FeedUtils;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public class SavedSearch {
|
||||||
|
|
||||||
|
@SerializedName("query")
|
||||||
|
public String query;
|
||||||
|
|
||||||
|
@SerializedName("feed_id")
|
||||||
|
public String feedId;
|
||||||
|
|
||||||
|
@SerializedName("feed_address")
|
||||||
|
public String feedAddress;
|
||||||
|
|
||||||
|
public String feedTitle;
|
||||||
|
public String faviconUrl;
|
||||||
|
|
||||||
|
public ContentValues getValues() {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
String feedTitle = "\"<b>" + query + "</b>\" in <b>" + getFeedTitle() + "</b>";
|
||||||
|
values.put(DatabaseConstants.SAVED_SEARCH_FEED_TITLE, feedTitle);
|
||||||
|
values.put(DatabaseConstants.SAVED_SEARCH_FAVICON, getFaviconUrl());
|
||||||
|
values.put(DatabaseConstants.SAVED_SEARCH_ADDRESS, feedAddress);
|
||||||
|
values.put(DatabaseConstants.SAVED_SEARCH_QUERY, query);
|
||||||
|
values.put(DatabaseConstants.SAVED_SEARCH_FEED_ID, feedId);
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SavedSearch fromCursor(Cursor cursor) {
|
||||||
|
if (cursor.isBeforeFirst()) {
|
||||||
|
cursor.moveToFirst();
|
||||||
|
}
|
||||||
|
SavedSearch savedSearch = new SavedSearch();
|
||||||
|
savedSearch.feedTitle = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SAVED_SEARCH_FEED_TITLE));
|
||||||
|
savedSearch.faviconUrl = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SAVED_SEARCH_FAVICON));
|
||||||
|
savedSearch.feedAddress = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SAVED_SEARCH_ADDRESS));
|
||||||
|
savedSearch.query = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SAVED_SEARCH_QUERY));
|
||||||
|
savedSearch.feedId = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SAVED_SEARCH_FEED_ID));
|
||||||
|
return savedSearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFeedTitle() {
|
||||||
|
String feedTitle = null;
|
||||||
|
|
||||||
|
if (feedId.equals("river:")) {
|
||||||
|
feedTitle = "All Site Stories";
|
||||||
|
} else if (feedId.equals("river:infrequent")) {
|
||||||
|
feedTitle = "Infrequent Site Stories";
|
||||||
|
} else if (feedId.startsWith("river:")) {
|
||||||
|
String folderName = feedId.replace("river:", "");
|
||||||
|
FeedSet fs = FeedUtils.feedSetFromFolderName(folderName);
|
||||||
|
feedTitle = fs.getFolderName();
|
||||||
|
} else if (feedId.equals("read")) {
|
||||||
|
feedTitle = "Read Stories";
|
||||||
|
} else if (feedId.startsWith("starred")) {
|
||||||
|
feedTitle = "Saved Stories";
|
||||||
|
String tag = feedId.replace("starred:", "");
|
||||||
|
StarredCount starredFeed = FeedUtils.getStarredFeedByTag(tag);
|
||||||
|
if (starredFeed != null) {
|
||||||
|
String tagSlug = tag.replace(" ", "-");
|
||||||
|
if (starredFeed.tag.equals(tag) || starredFeed.tag.equals(tagSlug)) {
|
||||||
|
feedTitle = feedTitle + " - " + starredFeed.tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (feedId.startsWith("feed:")) {
|
||||||
|
Feed feed = FeedUtils.getFeed(feedId.replace("feed:", ""));
|
||||||
|
if (feed == null) return null;
|
||||||
|
feedTitle = feed.title;
|
||||||
|
} else if (feedId.startsWith("social:")) {
|
||||||
|
Feed feed = FeedUtils.getFeed(feedId.replace("social:", ""));
|
||||||
|
if (feed == null) return null;
|
||||||
|
feedTitle = feed.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return feedTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFaviconUrl() {
|
||||||
|
String url = null;
|
||||||
|
if (feedId.equals("river:") || feedId.equals("river:infrequent")) {
|
||||||
|
url = "https://newsblur.com/media/img/icons/circular/ak-icon-allstories.png";
|
||||||
|
} else if (feedId.startsWith("river:")) {
|
||||||
|
url = "https://newsblur.com/media/img/icons/circular/g_icn_folder.png";
|
||||||
|
} else if (feedId.equals("read")) {
|
||||||
|
url = "https://newsblur.com/media/img/icons/circular/g_icn_unread.png";
|
||||||
|
} else if (feedId.equals("starred")) {
|
||||||
|
url = "https://newsblur.com/media/img/icons/circular/clock.png";
|
||||||
|
} else if (feedId.startsWith("starred:")) {
|
||||||
|
url = "https://newsblur.com/media/img/reader/tag.png";
|
||||||
|
} else if (feedId.startsWith("feed:")) {
|
||||||
|
Feed feed = FeedUtils.getFeed(feedId.replace("feed:", ""));
|
||||||
|
if (feed != null) {
|
||||||
|
url = feed.faviconUrl;
|
||||||
|
}
|
||||||
|
} else if (feedId.startsWith("social:")) {
|
||||||
|
Feed feed = FeedUtils.getFeed(feedId.replace("social:", ""));
|
||||||
|
if (feed != null) {
|
||||||
|
url = feed.faviconUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (url == null) {
|
||||||
|
url = "https://newsblur.com/media/img/icons/circular/g_icn_search_black.png";
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static Comparator<SavedSearch> SavedSearchComparatorByTitle = new Comparator<SavedSearch>() {
|
||||||
|
@Override
|
||||||
|
public int compare(SavedSearch ss1, SavedSearch ss2) {
|
||||||
|
return String.CASE_INSENSITIVE_ORDER.compare(ss1.feedTitle, ss2.feedTitle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package com.newsblur.domain;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -82,6 +83,12 @@ public class Story implements Serializable {
|
||||||
@SerializedName("story_hash")
|
@SerializedName("story_hash")
|
||||||
public String storyHash;
|
public String storyHash;
|
||||||
|
|
||||||
|
@SerializedName("secure_image_urls")
|
||||||
|
public Map<String, String> secureImageUrls;
|
||||||
|
|
||||||
|
@SerializedName("secure_image_thumbnails")
|
||||||
|
public Map<String, String> secureImageThumbnails;
|
||||||
|
|
||||||
// NOTE: this is parsed and saved to the DB, but is *not* generally un-thawed when stories are fetched back from the DB
|
// NOTE: this is parsed and saved to the DB, but is *not* generally un-thawed when stories are fetched back from the DB
|
||||||
@SerializedName("image_urls")
|
@SerializedName("image_urls")
|
||||||
public String[] imageUrls;
|
public String[] imageUrls;
|
||||||
|
@ -310,10 +317,13 @@ public class Story implements Serializable {
|
||||||
return YT_THUMB_PRE + ytUrl + YT_THUMB_POST;
|
return YT_THUMB_PRE + ytUrl + YT_THUMB_POST;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((story.imageUrls != null) && (story.imageUrls.length > 0)) {
|
if (story.imageUrls != null && story.imageUrls.length > 0) {
|
||||||
return story.imageUrls[0];
|
String thumbnail = story.imageUrls[0];
|
||||||
|
if (thumbnail.startsWith("http://") && story.secureImageThumbnails != null && story.secureImageThumbnails.containsKey(thumbnail)){
|
||||||
|
thumbnail = story.secureImageThumbnails.get(thumbnail);
|
||||||
|
}
|
||||||
|
return thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,83 +3,217 @@ package com.newsblur.fragment;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v7.widget.DividerItemDecoration;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.Main;
|
import com.newsblur.activity.Main;
|
||||||
|
import com.newsblur.databinding.DialogAddFeedBinding;
|
||||||
|
import com.newsblur.databinding.RowAddFeedFolderBinding;
|
||||||
|
import com.newsblur.domain.Folder;
|
||||||
import com.newsblur.network.APIManager;
|
import com.newsblur.network.APIManager;
|
||||||
import com.newsblur.network.domain.AddFeedResponse;
|
import com.newsblur.network.domain.AddFeedResponse;
|
||||||
|
import com.newsblur.network.domain.NewsBlurResponse;
|
||||||
import com.newsblur.service.NBSyncService;
|
import com.newsblur.service.NBSyncService;
|
||||||
|
import com.newsblur.util.AppConstants;
|
||||||
|
import com.newsblur.util.FeedUtils;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AddFeedFragment extends DialogFragment {
|
public class AddFeedFragment extends DialogFragment {
|
||||||
|
|
||||||
private static final String FEED_URI = "feed_url";
|
private static final String FEED_URI = "feed_url";
|
||||||
private static final String FEED_NAME = "feed_name";
|
private static final String FEED_NAME = "feed_name";
|
||||||
|
private DialogAddFeedBinding binding;
|
||||||
|
|
||||||
public static AddFeedFragment newInstance(String feedUri, String feedName) {
|
public static AddFeedFragment newInstance(String feedUri, String feedName) {
|
||||||
AddFeedFragment frag = new AddFeedFragment();
|
AddFeedFragment frag = new AddFeedFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(FEED_URI, feedUri);
|
args.putString(FEED_URI, feedUri);
|
||||||
args.putString(FEED_NAME, feedName);
|
args.putString(FEED_NAME, feedName);
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final String addFeedString = getResources().getString(R.string.add_feed_message);
|
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
final APIManager apiManager = new APIManager(activity);
|
final APIManager apiManager = new APIManager(activity);
|
||||||
final Intent intent = new Intent(activity, Main.class);
|
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||||
|
View v = inflater.inflate(R.layout.dialog_add_feed, null);
|
||||||
|
binding = DialogAddFeedBinding.bind(v);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setMessage(String.format(addFeedString, getArguments().getString(FEED_NAME)));
|
builder.setTitle("Choose folder for " + getArguments().getString(FEED_NAME));
|
||||||
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
|
builder.setView(v);
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
|
|
||||||
new AsyncTask<Void, Void, AddFeedResponse>() {
|
|
||||||
@Override
|
|
||||||
protected AddFeedResponse doInBackground(Void... arg) {
|
|
||||||
((AddFeedProgressListener) activity).addFeedStarted();
|
|
||||||
return apiManager.addFeed(getArguments().getString(FEED_URI));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
AddFeedAdapter adapter = new AddFeedAdapter(new OnFolderClickListener() {
|
||||||
protected void onPostExecute(AddFeedResponse result) {
|
|
||||||
if (!result.isError()) {
|
|
||||||
// trigger a sync when we return to Main so that the new feed will show up
|
|
||||||
NBSyncService.forceFeedsFolders();
|
|
||||||
intent.putExtra(Main.EXTRA_FORCE_SHOW_FEED_ID, result.feed.feedId);
|
|
||||||
} else {
|
|
||||||
UIUtils.safeToast(activity, R.string.add_feed_error, Toast.LENGTH_SHORT);
|
|
||||||
}
|
|
||||||
activity.startActivity(intent);
|
|
||||||
activity.finish();
|
|
||||||
AddFeedFragment.this.dismiss();
|
|
||||||
};
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onItemClick(Folder folder) {
|
||||||
AddFeedFragment.this.dismiss();
|
addFeed(activity, apiManager, folder.name);
|
||||||
activity.startActivity(intent);
|
|
||||||
activity.finish();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
binding.textAddFolderTitle.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (binding.containerAddFolder.getVisibility() == View.GONE) {
|
||||||
|
binding.containerAddFolder.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
binding.containerAddFolder.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.icCreateFolder.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (binding.inputFolderName.getText().length() == 0) {
|
||||||
|
Toast.makeText(activity, R.string.add_folder_name, Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
addFeedToNewFolder(activity, apiManager, binding.inputFolderName.getText().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
binding.recyclerViewFolders.addItemDecoration(new DividerItemDecoration(activity, LinearLayoutManager.VERTICAL));
|
||||||
|
binding.recyclerViewFolders.setAdapter(adapter);
|
||||||
|
adapter.setFolders(FeedUtils.dbHelper.getFolders());
|
||||||
return builder.create();
|
return builder.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface AddFeedProgressListener {
|
private void addFeedToNewFolder(final Activity activity, final APIManager apiManager, final String folderName) {
|
||||||
public abstract void addFeedStarted();
|
binding.icCreateFolder.setVisibility(View.GONE);
|
||||||
|
binding.progressBar.setVisibility(View.VISIBLE);
|
||||||
|
binding.inputFolderName.setEnabled(false);
|
||||||
|
|
||||||
|
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||||
|
@Override
|
||||||
|
protected NewsBlurResponse doInBackground(Void... voids) {
|
||||||
|
return apiManager.addFolder(folderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(NewsBlurResponse newsBlurResponse) {
|
||||||
|
super.onPostExecute(newsBlurResponse);
|
||||||
|
binding.inputFolderName.setEnabled(true);
|
||||||
|
|
||||||
|
if (!newsBlurResponse.isError()) {
|
||||||
|
binding.containerAddFolder.setVisibility(View.GONE);
|
||||||
|
binding.inputFolderName.getText().clear();
|
||||||
|
addFeed(activity, apiManager, folderName);
|
||||||
|
} else {
|
||||||
|
UIUtils.safeToast(activity, R.string.add_folder_error, Toast.LENGTH_SHORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void addFeed(final Activity activity, final APIManager apiManager, @Nullable final String folderName) {
|
||||||
|
binding.textSyncStatus.setVisibility(View.VISIBLE);
|
||||||
|
new AsyncTask<Void, Void, AddFeedResponse>() {
|
||||||
|
@Override
|
||||||
|
protected AddFeedResponse doInBackground(Void... voids) {
|
||||||
|
((AddFeedProgressListener) activity).addFeedStarted();
|
||||||
|
String feedUrl = getArguments().getString(FEED_URI);
|
||||||
|
return apiManager.addFeed(feedUrl, folderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(AddFeedResponse result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
binding.textSyncStatus.setVisibility(View.GONE);
|
||||||
|
final Intent intent = new Intent(activity, Main.class);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
if (!result.isError()) {
|
||||||
|
// trigger a sync when we return to Main so that the new feed will show up
|
||||||
|
NBSyncService.forceFeedsFolders();
|
||||||
|
intent.putExtra(Main.EXTRA_FORCE_SHOW_FEED_ID, result.feed.feedId);
|
||||||
|
} else {
|
||||||
|
UIUtils.safeToast(activity, R.string.add_feed_error, Toast.LENGTH_SHORT);
|
||||||
|
}
|
||||||
|
activity.startActivity(intent);
|
||||||
|
activity.finish();
|
||||||
|
AddFeedFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AddFeedAdapter extends RecyclerView.Adapter<AddFeedAdapter.FolderViewHolder> {
|
||||||
|
|
||||||
|
AddFeedAdapter(OnFolderClickListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<Folder> folders = new ArrayList<>();
|
||||||
|
private OnFolderClickListener listener;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public AddFeedAdapter.FolderViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
|
||||||
|
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_add_feed_folder, viewGroup, false);
|
||||||
|
return new FolderViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull AddFeedAdapter.FolderViewHolder viewHolder, int position) {
|
||||||
|
final Folder folder = folders.get(position);
|
||||||
|
if (folder.name.equals(AppConstants.ROOT_FOLDER)) {
|
||||||
|
viewHolder.binding.textFolderTitle.setText(R.string.top_level);
|
||||||
|
} else {
|
||||||
|
viewHolder.binding.textFolderTitle.setText(folder.flatName());
|
||||||
|
}
|
||||||
|
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
listener.onItemClick(folder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return folders.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFolders(List<Folder> folders) {
|
||||||
|
Collections.sort(folders, Folder.FolderComparator);
|
||||||
|
this.folders.clear();
|
||||||
|
this.folders.addAll(folders);
|
||||||
|
this.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FolderViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
public RowAddFeedFolderBinding binding;
|
||||||
|
|
||||||
|
public FolderViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
binding = RowAddFeedFolderBinding.bind(itemView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface AddFeedProgressListener {
|
||||||
|
void addFeedStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnFolderClickListener {
|
||||||
|
void onItemClick(Folder folder);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,12 +19,9 @@ import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.ListAdapter;
|
import android.widget.ListAdapter;
|
||||||
import android.widget.ListView;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.DialogChoosefoldersBinding;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.domain.Folder;
|
import com.newsblur.domain.Folder;
|
||||||
import com.newsblur.util.FeedUtils;
|
import com.newsblur.util.FeedUtils;
|
||||||
|
@ -33,8 +30,6 @@ public class ChooseFoldersFragment extends DialogFragment {
|
||||||
|
|
||||||
private Feed feed;
|
private Feed feed;
|
||||||
|
|
||||||
@Bind(R.id.choose_folders_list) ListView listView;
|
|
||||||
|
|
||||||
public static ChooseFoldersFragment newInstance(Feed feed) {
|
public static ChooseFoldersFragment newInstance(Feed feed) {
|
||||||
ChooseFoldersFragment fragment = new ChooseFoldersFragment();
|
ChooseFoldersFragment fragment = new ChooseFoldersFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
|
@ -62,7 +57,7 @@ public class ChooseFoldersFragment extends DialogFragment {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||||
View v = inflater.inflate(R.layout.dialog_choosefolders, null);
|
View v = inflater.inflate(R.layout.dialog_choosefolders, null);
|
||||||
ButterKnife.bind(this, v);
|
DialogChoosefoldersBinding binding = DialogChoosefoldersBinding.bind(v);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle(String.format(getResources().getString(R.string.title_choose_folders), feed.title));
|
builder.setTitle(String.format(getResources().getString(R.string.title_choose_folders), feed.title));
|
||||||
|
@ -107,7 +102,7 @@ public class ChooseFoldersFragment extends DialogFragment {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
listView.setAdapter(adapter);
|
binding.chooseFoldersList.setAdapter(adapter);
|
||||||
|
|
||||||
Dialog dialog = builder.create();
|
Dialog dialog = builder.create();
|
||||||
dialog.getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
dialog.getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
||||||
|
|
|
@ -4,9 +4,11 @@ import com.newsblur.R;
|
||||||
import com.newsblur.activity.ItemsList;
|
import com.newsblur.activity.ItemsList;
|
||||||
import com.newsblur.activity.NbActivity;
|
import com.newsblur.activity.NbActivity;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
|
import com.newsblur.domain.SavedSearch;
|
||||||
import com.newsblur.domain.SocialFeed;
|
import com.newsblur.domain.SocialFeed;
|
||||||
import com.newsblur.network.APIManager;
|
import com.newsblur.network.APIManager;
|
||||||
import com.newsblur.util.FeedUtils;
|
import com.newsblur.util.FeedUtils;
|
||||||
|
import com.newsblur.util.UIUtils;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
@ -22,7 +24,9 @@ public class DeleteFeedFragment extends DialogFragment {
|
||||||
private static final String FOLDER_NAME = "folder_name";
|
private static final String FOLDER_NAME = "folder_name";
|
||||||
private static final String NORMAL_FEED = "normal";
|
private static final String NORMAL_FEED = "normal";
|
||||||
private static final String SOCIAL_FEED = "social";
|
private static final String SOCIAL_FEED = "social";
|
||||||
|
private static final String SAVED_SEARCH_FEED = "saved_search";
|
||||||
|
private static final String QUERY = "query";
|
||||||
|
|
||||||
public static DeleteFeedFragment newInstance(Feed feed, String folderName) {
|
public static DeleteFeedFragment newInstance(Feed feed, String folderName) {
|
||||||
DeleteFeedFragment frag = new DeleteFeedFragment();
|
DeleteFeedFragment frag = new DeleteFeedFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
|
@ -44,11 +48,25 @@ public class DeleteFeedFragment extends DialogFragment {
|
||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DeleteFeedFragment newInstance(SavedSearch savedSearch) {
|
||||||
|
DeleteFeedFragment frag = new DeleteFeedFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(FEED_TYPE, SAVED_SEARCH_FEED);
|
||||||
|
args.putString(FEED_ID, savedSearch.feedId);
|
||||||
|
args.putString(FEED_NAME, savedSearch.feedTitle);
|
||||||
|
args.putString(QUERY, savedSearch.query);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
if (getArguments().getString(FEED_TYPE).equals(NORMAL_FEED)) {
|
if (getArguments().getString(FEED_TYPE).equals(NORMAL_FEED)) {
|
||||||
builder.setMessage(String.format(getResources().getString(R.string.delete_feed_message), getArguments().getString(FEED_NAME)));
|
builder.setMessage(String.format(getResources().getString(R.string.delete_feed_message), getArguments().getString(FEED_NAME)));
|
||||||
|
} else if (getArguments().getString(FEED_TYPE).equals(SAVED_SEARCH_FEED)) {
|
||||||
|
String message = String.format(getResources().getString(R.string.delete_saved_search_message), getArguments().getString(FEED_NAME));
|
||||||
|
builder.setMessage(UIUtils.fromHtml(message));
|
||||||
} else {
|
} else {
|
||||||
builder.setMessage(String.format(getResources().getString(R.string.unfollow_message), getArguments().getString(FEED_NAME)));
|
builder.setMessage(String.format(getResources().getString(R.string.unfollow_message), getArguments().getString(FEED_NAME)));
|
||||||
}
|
}
|
||||||
|
@ -57,6 +75,8 @@ public class DeleteFeedFragment extends DialogFragment {
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
if (getArguments().getString(FEED_TYPE).equals(NORMAL_FEED)) {
|
if (getArguments().getString(FEED_TYPE).equals(NORMAL_FEED)) {
|
||||||
FeedUtils.deleteFeed(getArguments().getString(FEED_ID), getArguments().getString(FOLDER_NAME), getActivity(), new APIManager(getActivity()));
|
FeedUtils.deleteFeed(getArguments().getString(FEED_ID), getArguments().getString(FOLDER_NAME), getActivity(), new APIManager(getActivity()));
|
||||||
|
} else if (getArguments().getString(FEED_TYPE).equals(SAVED_SEARCH_FEED)) {
|
||||||
|
FeedUtils.deleteSavedSearch(getArguments().getString(FEED_ID), getArguments().getString(QUERY), getActivity(), new APIManager(getActivity()));
|
||||||
} else {
|
} else {
|
||||||
FeedUtils.deleteSocialFeed(getArguments().getString(FEED_ID), getActivity(), new APIManager(getActivity()));
|
FeedUtils.deleteSocialFeed(getArguments().getString(FEED_ID), getActivity(), new APIManager(getActivity()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.network.APIManager;
|
||||||
|
import com.newsblur.util.AppConstants;
|
||||||
|
import com.newsblur.util.FeedUtils;
|
||||||
|
|
||||||
|
public class DeleteFolderFragment extends DialogFragment {
|
||||||
|
|
||||||
|
private static final String FOLDER_NAME = "folder_name";
|
||||||
|
private static final String FOLDER_PARENT = "folder_parent";
|
||||||
|
|
||||||
|
public static DeleteFolderFragment newInstance(String folderName, String folderParent) {
|
||||||
|
DeleteFolderFragment frag = new DeleteFolderFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(FOLDER_NAME, folderName);
|
||||||
|
args.putString(FOLDER_PARENT, folderParent);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
|
final String folderName = getArguments().getString(FOLDER_NAME);
|
||||||
|
final String folderParent = getArguments().getString(FOLDER_PARENT);
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setMessage(getResources().getString(R.string.delete_folder_message, folderName));
|
||||||
|
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
String inFolder = "";
|
||||||
|
if (!TextUtils.isEmpty(folderParent) && !folderParent.equals(AppConstants.ROOT_FOLDER)) {
|
||||||
|
inFolder = folderParent;
|
||||||
|
}
|
||||||
|
FeedUtils.deleteFolder(folderName, inFolder, getActivity(), new APIManager(getActivity()));
|
||||||
|
DeleteFolderFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
DeleteFolderFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,13 +12,10 @@ import android.support.v4.app.DialogFragment;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.DialogTrainfeedBinding;
|
||||||
import com.newsblur.domain.Classifier;
|
import com.newsblur.domain.Classifier;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.util.FeedSet;
|
import com.newsblur.util.FeedSet;
|
||||||
|
@ -30,14 +27,7 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
||||||
private Feed feed;
|
private Feed feed;
|
||||||
private FeedSet fs;
|
private FeedSet fs;
|
||||||
private Classifier classifier;
|
private Classifier classifier;
|
||||||
|
private DialogTrainfeedBinding binding;
|
||||||
@Bind(R.id.intel_title_header) TextView headerTitles;
|
|
||||||
@Bind(R.id.intel_tag_header) TextView headerTags;
|
|
||||||
@Bind(R.id.intel_author_header) TextView headerAuthor;
|
|
||||||
@Bind(R.id.existing_title_intel_container) LinearLayout titleRowsContainer;
|
|
||||||
@Bind(R.id.existing_tag_intel_container) LinearLayout tagRowsContainer;
|
|
||||||
@Bind(R.id.existing_author_intel_container) LinearLayout authorRowsContainer;
|
|
||||||
@Bind(R.id.existing_feed_intel_container) LinearLayout feedRowsContainer;
|
|
||||||
|
|
||||||
public static FeedIntelTrainerFragment newInstance(Feed feed, FeedSet fs) {
|
public static FeedIntelTrainerFragment newInstance(Feed feed, FeedSet fs) {
|
||||||
FeedIntelTrainerFragment fragment = new FeedIntelTrainerFragment();
|
FeedIntelTrainerFragment fragment = new FeedIntelTrainerFragment();
|
||||||
|
@ -58,7 +48,7 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||||
View v = inflater.inflate(R.layout.dialog_trainfeed, null);
|
View v = inflater.inflate(R.layout.dialog_trainfeed, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = DialogTrainfeedBinding.bind(v);
|
||||||
|
|
||||||
// display known title classifiers
|
// display known title classifiers
|
||||||
for (Map.Entry<String, Integer> rule : classifier.title.entrySet()) {
|
for (Map.Entry<String, Integer> rule : classifier.title.entrySet()) {
|
||||||
|
@ -66,9 +56,9 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
||||||
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
||||||
label.setText(rule.getKey());
|
label.setText(rule.getKey());
|
||||||
UIUtils.setupIntelDialogRow(row, classifier.title, rule.getKey());
|
UIUtils.setupIntelDialogRow(row, classifier.title, rule.getKey());
|
||||||
titleRowsContainer.addView(row);
|
binding.existingTitleIntelContainer.addView(row);
|
||||||
}
|
}
|
||||||
if (classifier.title.size() < 1) headerTitles.setVisibility(View.GONE);
|
if (classifier.title.size() < 1) binding.intelTitleHeader.setVisibility(View.GONE);
|
||||||
|
|
||||||
// get the list of suggested tags
|
// get the list of suggested tags
|
||||||
List<String> allTags = FeedUtils.dbHelper.getTagsForFeed(feed.feedId);
|
List<String> allTags = FeedUtils.dbHelper.getTagsForFeed(feed.feedId);
|
||||||
|
@ -83,9 +73,9 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
||||||
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
||||||
label.setText(tag);
|
label.setText(tag);
|
||||||
UIUtils.setupIntelDialogRow(row, classifier.tags, tag);
|
UIUtils.setupIntelDialogRow(row, classifier.tags, tag);
|
||||||
tagRowsContainer.addView(row);
|
binding.existingTagIntelContainer.addView(row);
|
||||||
}
|
}
|
||||||
if (allTags.size() < 1) headerTags.setVisibility(View.GONE);
|
if (allTags.size() < 1) binding.intelTagHeader.setVisibility(View.GONE);
|
||||||
|
|
||||||
// get the list of suggested authors
|
// get the list of suggested authors
|
||||||
List<String> allAuthors = FeedUtils.dbHelper.getAuthorsForFeed(feed.feedId);
|
List<String> allAuthors = FeedUtils.dbHelper.getAuthorsForFeed(feed.feedId);
|
||||||
|
@ -100,16 +90,16 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
||||||
TextView labelAuthor = (TextView) rowAuthor.findViewById(R.id.intel_row_label);
|
TextView labelAuthor = (TextView) rowAuthor.findViewById(R.id.intel_row_label);
|
||||||
labelAuthor.setText(author);
|
labelAuthor.setText(author);
|
||||||
UIUtils.setupIntelDialogRow(rowAuthor, classifier.authors, author);
|
UIUtils.setupIntelDialogRow(rowAuthor, classifier.authors, author);
|
||||||
authorRowsContainer.addView(rowAuthor);
|
binding.existingAuthorIntelContainer.addView(rowAuthor);
|
||||||
}
|
}
|
||||||
if (allAuthors.size() < 1) headerAuthor.setVisibility(View.GONE);
|
if (allAuthors.size() < 1) binding.intelAuthorHeader.setVisibility(View.GONE);
|
||||||
|
|
||||||
// for feel-level intel, the label is the title and the intel identifier is the feed ID
|
// for feel-level intel, the label is the title and the intel identifier is the feed ID
|
||||||
View rowFeed = inflater.inflate(R.layout.include_intel_row, null);
|
View rowFeed = inflater.inflate(R.layout.include_intel_row, null);
|
||||||
TextView labelFeed = (TextView) rowFeed.findViewById(R.id.intel_row_label);
|
TextView labelFeed = (TextView) rowFeed.findViewById(R.id.intel_row_label);
|
||||||
labelFeed.setText(feed.title);
|
labelFeed.setText(feed.title);
|
||||||
UIUtils.setupIntelDialogRow(rowFeed, classifier.feeds, feed.feedId);
|
UIUtils.setupIntelDialogRow(rowFeed, classifier.feeds, feed.feedId);
|
||||||
feedRowsContainer.addView(rowFeed);
|
binding.existingFeedIntelContainer.addView(rowFeed);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle(R.string.feed_intel_dialog_title);
|
builder.setTitle(R.string.feed_intel_dialog_title);
|
||||||
|
|
|
@ -26,9 +26,6 @@ import android.widget.ExpandableListView.OnGroupClickListener;
|
||||||
import android.widget.ExpandableListView.OnGroupCollapseListener;
|
import android.widget.ExpandableListView.OnGroupCollapseListener;
|
||||||
import android.widget.ExpandableListView.OnGroupExpandListener;
|
import android.widget.ExpandableListView.OnGroupExpandListener;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.AllSharedStoriesItemsList;
|
import com.newsblur.activity.AllSharedStoriesItemsList;
|
||||||
import com.newsblur.activity.AllStoriesItemsList;
|
import com.newsblur.activity.AllStoriesItemsList;
|
||||||
|
@ -43,7 +40,10 @@ import com.newsblur.activity.ReadStoriesItemsList;
|
||||||
import com.newsblur.activity.SavedStoriesItemsList;
|
import com.newsblur.activity.SavedStoriesItemsList;
|
||||||
import com.newsblur.activity.SocialFeedItemsList;
|
import com.newsblur.activity.SocialFeedItemsList;
|
||||||
import com.newsblur.database.FolderListAdapter;
|
import com.newsblur.database.FolderListAdapter;
|
||||||
|
import com.newsblur.databinding.FragmentFolderfeedlistBinding;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
|
import com.newsblur.domain.Folder;
|
||||||
|
import com.newsblur.domain.SavedSearch;
|
||||||
import com.newsblur.domain.SocialFeed;
|
import com.newsblur.domain.SocialFeed;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
import com.newsblur.util.FeedSet;
|
import com.newsblur.util.FeedSet;
|
||||||
|
@ -64,11 +64,12 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
private static final int FOLDERS_LOADER = 2;
|
private static final int FOLDERS_LOADER = 2;
|
||||||
private static final int FEEDS_LOADER = 3;
|
private static final int FEEDS_LOADER = 3;
|
||||||
private static final int SAVEDCOUNT_LOADER = 4;
|
private static final int SAVEDCOUNT_LOADER = 4;
|
||||||
|
private static final int SAVED_SEARCH_LOADER = 5;
|
||||||
|
|
||||||
private FolderListAdapter adapter;
|
private FolderListAdapter adapter;
|
||||||
public StateFilter currentState = StateFilter.SOME;
|
public StateFilter currentState = StateFilter.SOME;
|
||||||
private SharedPreferences sharedPreferences;
|
private SharedPreferences sharedPreferences;
|
||||||
@Bind(R.id.folderfeed_list) ExpandableListView list;
|
private FragmentFolderfeedlistBinding binding;
|
||||||
public boolean firstCursorSeenYet = false;
|
public boolean firstCursorSeenYet = false;
|
||||||
|
|
||||||
// the two-step context menu for feeds requires us to temp store the feed long-pressed so
|
// the two-step context menu for feeds requires us to temp store the feed long-pressed so
|
||||||
|
@ -112,6 +113,8 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
return FeedUtils.dbHelper.getFeedsLoader();
|
return FeedUtils.dbHelper.getFeedsLoader();
|
||||||
case SAVEDCOUNT_LOADER:
|
case SAVEDCOUNT_LOADER:
|
||||||
return FeedUtils.dbHelper.getSavedStoryCountsLoader();
|
return FeedUtils.dbHelper.getSavedStoryCountsLoader();
|
||||||
|
case SAVED_SEARCH_LOADER:
|
||||||
|
return FeedUtils.dbHelper.getSavedSearchLoader();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("unknown loader created");
|
throw new IllegalArgumentException("unknown loader created");
|
||||||
}
|
}
|
||||||
|
@ -140,6 +143,9 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
case SAVEDCOUNT_LOADER:
|
case SAVEDCOUNT_LOADER:
|
||||||
adapter.setStarredCountCursor(cursor);
|
adapter.setStarredCountCursor(cursor);
|
||||||
break;
|
break;
|
||||||
|
case SAVED_SEARCH_LOADER:
|
||||||
|
adapter.setSavedSearchesCursor(cursor);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("unknown loader created");
|
throw new IllegalArgumentException("unknown loader created");
|
||||||
}
|
}
|
||||||
|
@ -163,6 +169,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
getLoaderManager().restartLoader(FOLDERS_LOADER, null, this);
|
getLoaderManager().restartLoader(FOLDERS_LOADER, null, this);
|
||||||
getLoaderManager().restartLoader(FEEDS_LOADER, null, this);
|
getLoaderManager().restartLoader(FEEDS_LOADER, null, this);
|
||||||
getLoaderManager().restartLoader(SAVEDCOUNT_LOADER, null, this);
|
getLoaderManager().restartLoader(SAVEDCOUNT_LOADER, null, this);
|
||||||
|
getLoaderManager().restartLoader(SAVED_SEARCH_LOADER, null, this);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// on heavily loaded devices, the time between isAdded() going false
|
// on heavily loaded devices, the time between isAdded() going false
|
||||||
// and the loader subsystem shutting down can be nontrivial, causing
|
// and the loader subsystem shutting down can be nontrivial, causing
|
||||||
|
@ -179,6 +186,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
getLoaderManager().initLoader(FOLDERS_LOADER, null, this);
|
getLoaderManager().initLoader(FOLDERS_LOADER, null, this);
|
||||||
getLoaderManager().initLoader(FEEDS_LOADER, null, this);
|
getLoaderManager().initLoader(FEEDS_LOADER, null, this);
|
||||||
getLoaderManager().initLoader(SAVEDCOUNT_LOADER, null, this);
|
getLoaderManager().initLoader(SAVEDCOUNT_LOADER, null, this);
|
||||||
|
getLoaderManager().initLoader(SAVED_SEARCH_LOADER, null, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,20 +198,20 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.fragment_folderfeedlist, container);
|
View v = inflater.inflate(R.layout.fragment_folderfeedlist, container);
|
||||||
ButterKnife.bind(this, v);
|
binding = FragmentFolderfeedlistBinding.bind(v);
|
||||||
|
|
||||||
list.setGroupIndicator(UIUtils.getDrawable(getActivity(), R.drawable.transparent));
|
binding.folderfeedList.setGroupIndicator(UIUtils.getDrawable(getActivity(), R.drawable.transparent));
|
||||||
list.setOnCreateContextMenuListener(this);
|
binding.folderfeedList.setOnCreateContextMenuListener(this);
|
||||||
list.setOnChildClickListener(this);
|
binding.folderfeedList.setOnChildClickListener(this);
|
||||||
list.setOnGroupClickListener(this);
|
binding.folderfeedList.setOnGroupClickListener(this);
|
||||||
list.setOnGroupCollapseListener(this);
|
binding.folderfeedList.setOnGroupCollapseListener(this);
|
||||||
list.setOnGroupExpandListener(this);
|
binding.folderfeedList.setOnGroupExpandListener(this);
|
||||||
|
|
||||||
adapter.listBackref = new WeakReference(list); // see note in adapter about backref
|
adapter.listBackref = new WeakReference(binding.folderfeedList); // see note in adapter about backref
|
||||||
list.setAdapter(adapter);
|
binding.folderfeedList.setAdapter(adapter);
|
||||||
|
|
||||||
// Main activity needs to listen for scrolls to prevent refresh from firing unnecessarily
|
// Main activity needs to listen for scrolls to prevent refresh from firing unnecessarily
|
||||||
list.setOnScrollListener((android.widget.AbsListView.OnScrollListener) getActivity());
|
binding.folderfeedList.setOnScrollListener((android.widget.AbsListView.OnScrollListener) getActivity());
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -215,18 +223,18 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
*/
|
*/
|
||||||
public void checkOpenFolderPreferences() {
|
public void checkOpenFolderPreferences() {
|
||||||
// make sure we didn't beat construction
|
// make sure we didn't beat construction
|
||||||
if ((this.list == null) || (this.sharedPreferences == null)) return;
|
if ((this.binding.folderfeedList == null) || (this.sharedPreferences == null)) return;
|
||||||
|
|
||||||
for (int i = 0; i < adapter.getGroupCount(); i++) {
|
for (int i = 0; i < adapter.getGroupCount(); i++) {
|
||||||
String flatGroupName = adapter.getGroupUniqueName(i);
|
String flatGroupName = adapter.getGroupUniqueName(i);
|
||||||
if (sharedPreferences.getBoolean(AppConstants.FOLDER_PRE + "_" + flatGroupName, true)) {
|
if (sharedPreferences.getBoolean(AppConstants.FOLDER_PRE + "_" + flatGroupName, true)) {
|
||||||
if (list.isGroupExpanded(i) == false) {
|
if (binding.folderfeedList.isGroupExpanded(i) == false) {
|
||||||
list.expandGroup(i);
|
binding.folderfeedList.expandGroup(i);
|
||||||
adapter.setFolderClosed(flatGroupName, false);
|
adapter.setFolderClosed(flatGroupName, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (list.isGroupExpanded(i) == true) {
|
if (binding.folderfeedList.isGroupExpanded(i) == true) {
|
||||||
list.collapseGroup(i);
|
binding.folderfeedList.collapseGroup(i);
|
||||||
adapter.setFolderClosed(flatGroupName, true);
|
adapter.setFolderClosed(flatGroupName, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,11 +257,14 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
if (adapter.isRowGlobalSharedStories(groupPosition)) break;
|
if (adapter.isRowGlobalSharedStories(groupPosition)) break;
|
||||||
if (adapter.isRowAllSharedStories(groupPosition)) break;
|
if (adapter.isRowAllSharedStories(groupPosition)) break;
|
||||||
if (adapter.isRowInfrequentStories(groupPosition)) break;
|
if (adapter.isRowInfrequentStories(groupPosition)) break;
|
||||||
|
if (adapter.isRowSavedSearches(groupPosition)) break;
|
||||||
inflater.inflate(R.menu.context_folder, menu);
|
inflater.inflate(R.menu.context_folder, menu);
|
||||||
|
|
||||||
if (adapter.isRowAllStories(groupPosition)) {
|
if (adapter.isRowAllStories(groupPosition)) {
|
||||||
menu.removeItem(R.id.menu_mute_folder);
|
menu.removeItem(R.id.menu_mute_folder);
|
||||||
menu.removeItem(R.id.menu_unmute_folder);
|
menu.removeItem(R.id.menu_unmute_folder);
|
||||||
|
menu.removeItem(R.id.menu_delete_folder);
|
||||||
|
menu.removeItem(R.id.menu_rename_folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -272,9 +283,22 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
menu.removeItem(R.id.menu_instafetch_feed);
|
menu.removeItem(R.id.menu_instafetch_feed);
|
||||||
menu.removeItem(R.id.menu_intel);
|
menu.removeItem(R.id.menu_intel);
|
||||||
menu.removeItem(R.id.menu_rename_feed);
|
menu.removeItem(R.id.menu_rename_feed);
|
||||||
|
menu.removeItem(R.id.menu_delete_saved_search);
|
||||||
|
} else if (adapter.isRowSavedSearches(groupPosition)) {
|
||||||
|
menu.removeItem(R.id.menu_mark_feed_as_read);
|
||||||
|
menu.removeItem(R.id.menu_delete_feed);
|
||||||
|
menu.removeItem(R.id.menu_unfollow);
|
||||||
|
menu.removeItem(R.id.menu_choose_folders);
|
||||||
|
menu.removeItem(R.id.menu_rename_feed);
|
||||||
|
menu.removeItem(R.id.menu_notifications);
|
||||||
|
menu.removeItem(R.id.menu_mute_feed);
|
||||||
|
menu.removeItem(R.id.menu_unmute_feed);
|
||||||
|
menu.removeItem(R.id.menu_instafetch_feed);
|
||||||
|
menu.removeItem(R.id.menu_intel);
|
||||||
} else {
|
} else {
|
||||||
// normal feeds
|
// normal feeds
|
||||||
menu.removeItem(R.id.menu_unfollow);
|
menu.removeItem(R.id.menu_unfollow);
|
||||||
|
menu.removeItem(R.id.menu_delete_saved_search);
|
||||||
|
|
||||||
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
||||||
if (feed.active) {
|
if (feed.active) {
|
||||||
|
@ -359,7 +383,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
} else if (item.getItemId() == R.id.menu_rename_feed) {
|
} else if (item.getItemId() == R.id.menu_rename_feed) {
|
||||||
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
DialogFragment renameFeedFragment = RenameFeedFragment.newInstance(feed);
|
DialogFragment renameFeedFragment = RenameDialogFragment.newInstance(feed);
|
||||||
renameFeedFragment.show(getFragmentManager(), "dialog");
|
renameFeedFragment.show(getFragmentManager(), "dialog");
|
||||||
}
|
}
|
||||||
} else if (item.getItemId() == R.id.menu_mute_feed) {
|
} else if (item.getItemId() == R.id.menu_mute_feed) {
|
||||||
|
@ -379,6 +403,22 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
} else if (item.getItemId() == R.id.menu_intel) {
|
} else if (item.getItemId() == R.id.menu_intel) {
|
||||||
FeedIntelTrainerFragment intelFrag = FeedIntelTrainerFragment.newInstance(adapter.getFeed(groupPosition, childPosition), adapter.getChild(groupPosition, childPosition));
|
FeedIntelTrainerFragment intelFrag = FeedIntelTrainerFragment.newInstance(adapter.getFeed(groupPosition, childPosition), adapter.getChild(groupPosition, childPosition));
|
||||||
intelFrag.show(getFragmentManager(), FeedIntelTrainerFragment.class.getName());
|
intelFrag.show(getFragmentManager(), FeedIntelTrainerFragment.class.getName());
|
||||||
|
} else if (item.getItemId() == R.id.menu_delete_saved_search) {
|
||||||
|
SavedSearch savedSearch = adapter.getSavedSearch(childPosition);
|
||||||
|
if (savedSearch != null) {
|
||||||
|
DialogFragment deleteFeedFragment = DeleteFeedFragment.newInstance(savedSearch);
|
||||||
|
deleteFeedFragment.show(getFragmentManager(), "dialog");
|
||||||
|
}
|
||||||
|
} else if (item.getItemId() == R.id.menu_delete_folder) {
|
||||||
|
Folder folder = adapter.getGroupFolder(groupPosition);
|
||||||
|
String folderParentName = folder.getFirstParentName();
|
||||||
|
DeleteFolderFragment deleteFolderFragment = DeleteFolderFragment.newInstance(folder.name, folderParentName);
|
||||||
|
deleteFolderFragment.show(getFragmentManager(), deleteFolderFragment.getTag());
|
||||||
|
} else if (item.getItemId() == R.id.menu_rename_folder) {
|
||||||
|
Folder folder = adapter.getGroupFolder(groupPosition);
|
||||||
|
String folderParentName = folder.getFirstParentName();
|
||||||
|
RenameDialogFragment renameDialogFragment = RenameDialogFragment.newInstance(folder.name, folderParentName);
|
||||||
|
renameDialogFragment.show(getFragmentManager(), renameDialogFragment.getTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onContextItemSelected(item);
|
return super.onContextItemSelected(item);
|
||||||
|
@ -449,6 +489,9 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
i = new Intent(getActivity(), ReadStoriesItemsList.class);
|
i = new Intent(getActivity(), ReadStoriesItemsList.class);
|
||||||
} else if (adapter.isRowSavedStories(groupPosition)) {
|
} else if (adapter.isRowSavedStories(groupPosition)) {
|
||||||
i = new Intent(getActivity(), SavedStoriesItemsList.class);
|
i = new Intent(getActivity(), SavedStoriesItemsList.class);
|
||||||
|
} else if (adapter.isRowSavedSearches(groupPosition)) {
|
||||||
|
// group not clickable
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
i = new Intent(getActivity(), FolderItemsList.class);
|
i = new Intent(getActivity(), FolderItemsList.class);
|
||||||
String canonicalFolderName = adapter.getGroupFolderName(groupPosition);
|
String canonicalFolderName = adapter.getGroupFolderName(groupPosition);
|
||||||
|
@ -472,6 +515,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
// these shouldn't ever be collapsible
|
// these shouldn't ever be collapsible
|
||||||
if (adapter.isRowRootFolder(groupPosition)) return;
|
if (adapter.isRowRootFolder(groupPosition)) return;
|
||||||
if (adapter.isRowReadStories(groupPosition)) return;
|
if (adapter.isRowReadStories(groupPosition)) return;
|
||||||
|
if (adapter.isRowSavedSearches(groupPosition)) return;
|
||||||
|
|
||||||
String flatGroupName = adapter.getGroupUniqueName(groupPosition);
|
String flatGroupName = adapter.getGroupUniqueName(groupPosition);
|
||||||
// save the expanded preference, since the widget likes to forget it
|
// save the expanded preference, since the widget likes to forget it
|
||||||
|
@ -490,6 +534,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
// these shouldn't ever be collapsible
|
// these shouldn't ever be collapsible
|
||||||
if (adapter.isRowRootFolder(groupPosition)) return;
|
if (adapter.isRowRootFolder(groupPosition)) return;
|
||||||
if (adapter.isRowReadStories(groupPosition)) return;
|
if (adapter.isRowReadStories(groupPosition)) return;
|
||||||
|
if (adapter.isRowSavedSearches(groupPosition)) return;
|
||||||
|
|
||||||
String flatGroupName = adapter.getGroupUniqueName(groupPosition);
|
String flatGroupName = adapter.getGroupUniqueName(groupPosition);
|
||||||
// save the collapsed preference, since the widget likes to forget it
|
// save the collapsed preference, since the widget likes to forget it
|
||||||
|
@ -515,7 +560,9 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
Intent intent = new Intent(getActivity(), SavedStoriesItemsList.class);
|
Intent intent = new Intent(getActivity(), SavedStoriesItemsList.class);
|
||||||
intent.putExtra(ItemsList.EXTRA_FEED_SET, fs);
|
intent.putExtra(ItemsList.EXTRA_FEED_SET, fs);
|
||||||
getActivity().startActivity(intent);
|
getActivity().startActivity(intent);
|
||||||
} else {
|
} else if (adapter.isRowSavedSearches(groupPosition)) {
|
||||||
|
openSavedSearch(adapter.getSavedSearch(childPosition));
|
||||||
|
} else {
|
||||||
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
||||||
// NB: FeedItemsList needs the name of the containing folder, but this is not the same as setting
|
// NB: FeedItemsList needs the name of the containing folder, but this is not the same as setting
|
||||||
// a folder name on the FeedSet and making it into a folder-type set. it is just a single feed,
|
// a folder name on the FeedSet and making it into a folder-type set. it is just a single feed,
|
||||||
|
@ -534,6 +581,53 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void openSavedSearch(SavedSearch savedSearch) {
|
||||||
|
Intent intent = null;
|
||||||
|
FeedSet fs = null;
|
||||||
|
String feedId = savedSearch.feedId;
|
||||||
|
if (feedId.equals("river:")) {
|
||||||
|
// all site stories
|
||||||
|
intent = new Intent(getActivity(), AllStoriesItemsList.class);
|
||||||
|
fs = FeedSet.allFeeds();
|
||||||
|
} else if (feedId.equals("river:infrequent")) {
|
||||||
|
// infrequent stories
|
||||||
|
intent = new Intent(getActivity(), InfrequentItemsList.class);
|
||||||
|
fs = FeedSet.infrequentFeeds();
|
||||||
|
} else if (feedId.startsWith("river:")) {
|
||||||
|
intent = new Intent(getActivity(), FolderItemsList.class);
|
||||||
|
String folderName = feedId.replace("river:", "");
|
||||||
|
fs = FeedUtils.feedSetFromFolderName(folderName);
|
||||||
|
intent.putExtra(FolderItemsList.EXTRA_FOLDER_NAME, folderName);
|
||||||
|
} else if (feedId.equals("read")) {
|
||||||
|
intent = new Intent(getActivity(), ReadStoriesItemsList.class);
|
||||||
|
fs = FeedSet.allRead();
|
||||||
|
} else if (feedId.equals("starred")) {
|
||||||
|
intent = new Intent(getActivity(), SavedStoriesItemsList.class);
|
||||||
|
fs = FeedSet.allSaved();
|
||||||
|
} else if (feedId.startsWith("starred:")) {
|
||||||
|
intent = new Intent(getActivity(), SavedStoriesItemsList.class);
|
||||||
|
fs = FeedSet.singleSavedTag(feedId.replace("starred:", ""));
|
||||||
|
} else if (feedId.startsWith("feed:")) {
|
||||||
|
intent = new Intent(getActivity(), FeedItemsList.class);
|
||||||
|
String cleanFeedId = feedId.replace("feed:", "");
|
||||||
|
Feed feed = FeedUtils.getFeed(cleanFeedId);
|
||||||
|
fs = FeedSet.singleFeed(cleanFeedId);
|
||||||
|
intent.putExtra(FeedItemsList.EXTRA_FEED, feed);
|
||||||
|
} else if (feedId.startsWith("social:")) {
|
||||||
|
intent = new Intent(getActivity(), SocialFeedItemsList.class);
|
||||||
|
String cleanFeedId = feedId.replace("social:", "");
|
||||||
|
fs = FeedSet.singleFeed(cleanFeedId);
|
||||||
|
Feed feed = FeedUtils.getFeed(cleanFeedId);
|
||||||
|
intent.putExtra(FeedItemsList.EXTRA_FEED, feed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intent != null) {
|
||||||
|
fs.setSearchQuery(savedSearch.query);
|
||||||
|
intent.putExtra(ItemsList.EXTRA_FEED_SET, fs);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setTextSize(Float size) {
|
public void setTextSize(Float size) {
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
adapter.setTextSize(size);
|
adapter.setTextSize(size);
|
||||||
|
|
|
@ -1,28 +1,22 @@
|
||||||
package com.newsblur.fragment;
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.RadioButton;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.InfrequentCutoffDialogBinding;
|
||||||
|
|
||||||
public class InfrequentCutoffDialogFragment extends DialogFragment {
|
public class InfrequentCutoffDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
private static String CURRENT_CUTOFF = "currentCutoff";
|
private static String CURRENT_CUTOFF = "currentCutoff";
|
||||||
private int currentValue;
|
private int currentValue;
|
||||||
@Bind(R.id.radio_5) RadioButton button5;
|
private InfrequentCutoffDialogBinding binding;
|
||||||
@Bind(R.id.radio_15) RadioButton button15;
|
|
||||||
@Bind(R.id.radio_30) RadioButton button30;
|
|
||||||
@Bind(R.id.radio_60) RadioButton button60;
|
|
||||||
@Bind(R.id.radio_90) RadioButton button90;
|
|
||||||
|
|
||||||
public static InfrequentCutoffDialogFragment newInstance(int currentValue) {
|
public static InfrequentCutoffDialogFragment newInstance(int currentValue) {
|
||||||
InfrequentCutoffDialogFragment dialog = new InfrequentCutoffDialogFragment();
|
InfrequentCutoffDialogFragment dialog = new InfrequentCutoffDialogFragment();
|
||||||
|
@ -42,13 +36,13 @@ public class InfrequentCutoffDialogFragment extends DialogFragment {
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||||
currentValue = getArguments().getInt(CURRENT_CUTOFF);
|
currentValue = getArguments().getInt(CURRENT_CUTOFF);
|
||||||
View v = inflater.inflate(R.layout.infrequent_cutoff_dialog, null);
|
View v = inflater.inflate(R.layout.infrequent_cutoff_dialog, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = InfrequentCutoffDialogBinding.bind(v);
|
||||||
|
|
||||||
button5.setChecked(currentValue == 5);
|
binding.radio5.setChecked(currentValue == 5);
|
||||||
button15.setChecked(currentValue == 15);
|
binding.radio15.setChecked(currentValue == 15);
|
||||||
button30.setChecked(currentValue == 30);
|
binding.radio30.setChecked(currentValue == 30);
|
||||||
button60.setChecked(currentValue == 60);
|
binding.radio60.setChecked(currentValue == 60);
|
||||||
button90.setChecked(currentValue == 90);
|
binding.radio90.setChecked(currentValue == 90);
|
||||||
|
|
||||||
getDialog().setTitle(R.string.infrequent_choice_title);
|
getDialog().setTitle(R.string.infrequent_choice_title);
|
||||||
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
||||||
|
@ -56,31 +50,66 @@ public class InfrequentCutoffDialogFragment extends DialogFragment {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.radio_5) void select5() {
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
binding.radio5.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
select5();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radio15.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
select15();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radio30.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
select30();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radio60.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
select60();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radio90.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
select90();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void select5() {
|
||||||
if (currentValue != 5) {
|
if (currentValue != 5) {
|
||||||
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(5);
|
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(5);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
@OnClick(R.id.radio_15) void select15() {
|
private void select15() {
|
||||||
if (currentValue != 15) {
|
if (currentValue != 15) {
|
||||||
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(15);
|
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(15);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
@OnClick(R.id.radio_30) void select30() {
|
private void select30() {
|
||||||
if (currentValue != 30) {
|
if (currentValue != 30) {
|
||||||
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(30);
|
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(30);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
@OnClick(R.id.radio_60) void select60() {
|
private void select60() {
|
||||||
if (currentValue != 60) {
|
if (currentValue != 60) {
|
||||||
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(60);
|
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(60);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
@OnClick(R.id.radio_90) void select90() {
|
private void select90() {
|
||||||
if (currentValue != 90) {
|
if (currentValue != 90) {
|
||||||
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(90);
|
((InfrequentCutoffChangedListener) getActivity()).infrequentCutoffChanged(90);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,13 @@ import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.ItemsList;
|
import com.newsblur.activity.ItemsList;
|
||||||
import com.newsblur.activity.NbActivity;
|
import com.newsblur.activity.NbActivity;
|
||||||
import com.newsblur.database.StoryViewAdapter;
|
import com.newsblur.database.StoryViewAdapter;
|
||||||
|
import com.newsblur.databinding.FragmentItemgridBinding;
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
import com.newsblur.service.NBSyncService;
|
import com.newsblur.service.NBSyncService;
|
||||||
import com.newsblur.util.FeedSet;
|
import com.newsblur.util.FeedSet;
|
||||||
|
@ -50,21 +46,17 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
private final static int GRID_SPACING_DP = 5;
|
private final static int GRID_SPACING_DP = 5;
|
||||||
private int gridSpacingPx;
|
private int gridSpacingPx;
|
||||||
|
|
||||||
@Bind(R.id.itemgridfragment_grid) RecyclerView itemGrid;
|
|
||||||
private GridLayoutManager layoutManager;
|
private GridLayoutManager layoutManager;
|
||||||
private StoryViewAdapter adapter;
|
private StoryViewAdapter adapter;
|
||||||
// an optional pending scroll state to restore.
|
// an optional pending scroll state to restore.
|
||||||
private Parcelable gridState;
|
private Parcelable gridState;
|
||||||
|
|
||||||
// loading indicator for when stories are absent or stale (at top of list)
|
// loading indicator for when stories are absent or stale (at top of list)
|
||||||
@Bind(R.id.top_loading_throb) ProgressThrobber topProgressView;
|
// R.id.top_loading_throb
|
||||||
|
|
||||||
// loading indicator for when stories are present and fresh (at bottom of list)
|
// loading indicator for when stories are present and fresh (at bottom of list)
|
||||||
protected ProgressThrobber bottomProgressView;
|
protected ProgressThrobber bottomProgressView;
|
||||||
|
|
||||||
@Bind(R.id.empty_view) View emptyView;
|
|
||||||
@Bind(R.id.empty_view_text) TextView emptyViewText;
|
|
||||||
@Bind(R.id.empty_view_image) ImageView emptyViewImage;
|
|
||||||
|
|
||||||
private View fleuronFooter;
|
private View fleuronFooter;
|
||||||
// the fleuron has padding that can't be calculated until after layout, but only changes
|
// the fleuron has padding that can't be calculated until after layout, but only changes
|
||||||
// rarely thereafter
|
// rarely thereafter
|
||||||
|
@ -76,6 +68,8 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
public int indexOfLastUnread = -1;
|
public int indexOfLastUnread = -1;
|
||||||
public boolean fullFlingComplete = false;
|
public boolean fullFlingComplete = false;
|
||||||
|
|
||||||
|
private FragmentItemgridBinding binding;
|
||||||
|
|
||||||
public static ItemSetFragment newInstance() {
|
public static ItemSetFragment newInstance() {
|
||||||
ItemSetFragment fragment = new ItemSetFragment();
|
ItemSetFragment fragment = new ItemSetFragment();
|
||||||
Bundle arguments = new Bundle();
|
Bundle arguments = new Bundle();
|
||||||
|
@ -123,13 +117,13 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.fragment_itemgrid, null);
|
View v = inflater.inflate(R.layout.fragment_itemgrid, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = FragmentItemgridBinding.bind(v);
|
||||||
|
|
||||||
// disable the throbbers if animations are going to have a zero time scale
|
// disable the throbbers if animations are going to have a zero time scale
|
||||||
boolean isDisableAnimations = ViewUtils.isPowerSaveMode(getActivity());
|
boolean isDisableAnimations = ViewUtils.isPowerSaveMode(getActivity());
|
||||||
|
|
||||||
topProgressView.setEnabled(!isDisableAnimations);
|
binding.topLoadingThrob.setEnabled(!isDisableAnimations);
|
||||||
topProgressView.setColors(UIUtils.getColor(getActivity(), R.color.refresh_1),
|
binding.topLoadingThrob.setColors(UIUtils.getColor(getActivity(), R.color.refresh_1),
|
||||||
UIUtils.getColor(getActivity(), R.color.refresh_2),
|
UIUtils.getColor(getActivity(), R.color.refresh_2),
|
||||||
UIUtils.getColor(getActivity(), R.color.refresh_3),
|
UIUtils.getColor(getActivity(), R.color.refresh_3),
|
||||||
UIUtils.getColor(getActivity(), R.color.refresh_4));
|
UIUtils.getColor(getActivity(), R.color.refresh_4));
|
||||||
|
@ -145,11 +139,11 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
fleuronFooter = inflater.inflate(R.layout.row_fleuron, null);
|
fleuronFooter = inflater.inflate(R.layout.row_fleuron, null);
|
||||||
fleuronFooter.setVisibility(View.INVISIBLE);
|
fleuronFooter.setVisibility(View.INVISIBLE);
|
||||||
|
|
||||||
itemGrid.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
|
binding.itemgridfragmentGrid.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onGlobalLayout() {
|
public void onGlobalLayout() {
|
||||||
itemGridWidthPx = itemGrid.getMeasuredWidth();
|
itemGridWidthPx = binding.itemgridfragmentGrid.getMeasuredWidth();
|
||||||
itemGrid.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
binding.itemgridfragmentGrid.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
updateStyle();
|
updateStyle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -158,11 +152,11 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
|
|
||||||
calcColumnCount(listStyle);
|
calcColumnCount(listStyle);
|
||||||
layoutManager = new GridLayoutManager(getActivity(), columnCount);
|
layoutManager = new GridLayoutManager(getActivity(), columnCount);
|
||||||
itemGrid.setLayoutManager(layoutManager);
|
binding.itemgridfragmentGrid.setLayoutManager(layoutManager);
|
||||||
setupAnimSpeeds();
|
setupAnimSpeeds();
|
||||||
|
|
||||||
calcGridSpacing(listStyle);
|
calcGridSpacing(listStyle);
|
||||||
itemGrid.addItemDecoration(new RecyclerView.ItemDecoration() {
|
binding.itemgridfragmentGrid.addItemDecoration(new RecyclerView.ItemDecoration() {
|
||||||
@Override
|
@Override
|
||||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||||
outRect.set(gridSpacingPx, gridSpacingPx, gridSpacingPx, gridSpacingPx);
|
outRect.set(gridSpacingPx, gridSpacingPx, gridSpacingPx, gridSpacingPx);
|
||||||
|
@ -172,7 +166,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
adapter = new StoryViewAdapter(((NbActivity) getActivity()), this, getFeedSet(), listStyle);
|
adapter = new StoryViewAdapter(((NbActivity) getActivity()), this, getFeedSet(), listStyle);
|
||||||
adapter.addFooterView(footerView);
|
adapter.addFooterView(footerView);
|
||||||
adapter.addFooterView(fleuronFooter);
|
adapter.addFooterView(fleuronFooter);
|
||||||
itemGrid.setAdapter(adapter);
|
binding.itemgridfragmentGrid.setAdapter(adapter);
|
||||||
|
|
||||||
// the layout manager needs to know that the footer rows span all the way across
|
// the layout manager needs to know that the footer rows span all the way across
|
||||||
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||||
|
@ -187,14 +181,14 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
itemGrid.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
binding.itemgridfragmentGrid.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||||
ItemSetFragment.this.onScrolled(recyclerView, dx, dy);
|
ItemSetFragment.this.onScrolled(recyclerView, dx, dy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setupGestureDetector(itemGrid);
|
setupGestureDetector(binding.itemgridfragmentGrid);
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -281,13 +275,13 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateAdapter(Cursor cursor) {
|
protected void updateAdapter(Cursor cursor) {
|
||||||
adapter.swapCursor(cursor, itemGrid, gridState);
|
adapter.swapCursor(cursor, binding.itemgridfragmentGrid, gridState);
|
||||||
gridState = null;
|
gridState = null;
|
||||||
adapter.updateFeedSet(getFeedSet());
|
adapter.updateFeedSet(getFeedSet());
|
||||||
if ((cursor != null) && (cursor.getCount() > 0)) {
|
if ((cursor != null) && (cursor.getCount() > 0)) {
|
||||||
emptyView.setVisibility(View.INVISIBLE);
|
binding.emptyView.setVisibility(View.INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
emptyView.setVisibility(View.VISIBLE);
|
binding.emptyView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// though we have stories, we might not yet have as many as we want
|
// though we have stories, we might not yet have as many as we want
|
||||||
|
@ -305,38 +299,38 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
calcFleuronPadding();
|
calcFleuronPadding();
|
||||||
|
|
||||||
if (getFeedSet().isMuted()) {
|
if (getFeedSet().isMuted()) {
|
||||||
emptyViewText.setText(R.string.empty_list_view_muted_feed);
|
binding.emptyViewText.setText(R.string.empty_list_view_muted_feed);
|
||||||
emptyViewText.setTypeface(null, Typeface.NORMAL);
|
binding.emptyViewText.setTypeface(null, Typeface.NORMAL);
|
||||||
emptyViewImage.setVisibility(View.VISIBLE);
|
binding.emptyViewImage.setVisibility(View.VISIBLE);
|
||||||
topProgressView.setVisibility(View.INVISIBLE);
|
binding.topLoadingThrob.setVisibility(View.INVISIBLE);
|
||||||
bottomProgressView.setVisibility(View.INVISIBLE);
|
bottomProgressView.setVisibility(View.INVISIBLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (!cursorSeenYet) || NBSyncService.isFeedSetSyncing(getFeedSet(), getActivity()) ) {
|
if ( (!cursorSeenYet) || NBSyncService.isFeedSetSyncing(getFeedSet(), getActivity()) ) {
|
||||||
emptyViewText.setText(R.string.empty_list_view_loading);
|
binding.emptyViewText.setText(R.string.empty_list_view_loading);
|
||||||
emptyViewText.setTypeface(null, Typeface.ITALIC);
|
binding.emptyViewText.setTypeface(null, Typeface.ITALIC);
|
||||||
emptyViewImage.setVisibility(View.INVISIBLE);
|
binding.emptyViewImage.setVisibility(View.INVISIBLE);
|
||||||
|
|
||||||
if (NBSyncService.isFeedSetStoriesFresh(getFeedSet())) {
|
if (NBSyncService.isFeedSetStoriesFresh(getFeedSet())) {
|
||||||
topProgressView.setVisibility(View.INVISIBLE);
|
binding.topLoadingThrob.setVisibility(View.INVISIBLE);
|
||||||
bottomProgressView.setVisibility(View.VISIBLE);
|
bottomProgressView.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
topProgressView.setVisibility(View.VISIBLE);
|
binding.topLoadingThrob.setVisibility(View.VISIBLE);
|
||||||
bottomProgressView.setVisibility(View.GONE);
|
bottomProgressView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
fleuronFooter.setVisibility(View.INVISIBLE);
|
fleuronFooter.setVisibility(View.INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
ReadFilter readFilter = PrefsUtils.getReadFilter(getActivity(), getFeedSet());
|
ReadFilter readFilter = PrefsUtils.getReadFilter(getActivity(), getFeedSet());
|
||||||
if (readFilter == ReadFilter.UNREAD) {
|
if (readFilter == ReadFilter.UNREAD) {
|
||||||
emptyViewText.setText(R.string.empty_list_view_no_stories_unread);
|
binding.emptyViewText.setText(R.string.empty_list_view_no_stories_unread);
|
||||||
} else {
|
} else {
|
||||||
emptyViewText.setText(R.string.empty_list_view_no_stories);
|
binding.emptyViewText.setText(R.string.empty_list_view_no_stories);
|
||||||
}
|
}
|
||||||
emptyViewText.setTypeface(null, Typeface.NORMAL);
|
binding.emptyViewText.setTypeface(null, Typeface.NORMAL);
|
||||||
emptyViewImage.setVisibility(View.VISIBLE);
|
binding.emptyViewImage.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
topProgressView.setVisibility(View.INVISIBLE);
|
binding.topLoadingThrob.setVisibility(View.INVISIBLE);
|
||||||
bottomProgressView.setVisibility(View.INVISIBLE);
|
bottomProgressView.setVisibility(View.INVISIBLE);
|
||||||
if (cursorSeenYet && NBSyncService.isFeedSetExhausted(getFeedSet()) && (adapter.getRawStoryCount() > 0)) {
|
if (cursorSeenYet && NBSyncService.isFeedSetExhausted(getFeedSet()) && (adapter.getRawStoryCount() > 0)) {
|
||||||
fleuronFooter.setVisibility(View.VISIBLE);
|
fleuronFooter.setVisibility(View.VISIBLE);
|
||||||
|
@ -411,7 +405,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
targetMovDuration = 0L;
|
targetMovDuration = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecyclerView.ItemAnimator anim = itemGrid.getItemAnimator();
|
RecyclerView.ItemAnimator anim = binding.itemgridfragmentGrid.getItemAnimator();
|
||||||
anim.setAddDuration((long) ((anim.getAddDuration() + targetAddDuration)/2L));
|
anim.setAddDuration((long) ((anim.getAddDuration() + targetAddDuration)/2L));
|
||||||
anim.setMoveDuration((long) ((anim.getMoveDuration() + targetMovDuration)/2L));
|
anim.setMoveDuration((long) ((anim.getMoveDuration() + targetMovDuration)/2L));
|
||||||
}
|
}
|
||||||
|
@ -429,7 +423,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
// past the last item, which can be confusing to users who don't know about or need the offset
|
// past the last item, which can be confusing to users who don't know about or need the offset
|
||||||
if ( (!fullFlingComplete) &&
|
if ( (!fullFlingComplete) &&
|
||||||
(layoutManager.findLastCompletelyVisibleItemPosition() >= adapter.getStoryCount()) ) {
|
(layoutManager.findLastCompletelyVisibleItemPosition() >= adapter.getStoryCount()) ) {
|
||||||
itemGrid.stopScroll();
|
binding.itemgridfragmentGrid.stopScroll();
|
||||||
// but after halting at the end once, do allow scrolling past the bottom
|
// but after halting at the end once, do allow scrolling past the bottom
|
||||||
fullFlingComplete = true;
|
fullFlingComplete = true;
|
||||||
}
|
}
|
||||||
|
@ -439,7 +433,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
(layoutManager.findLastCompletelyVisibleItemPosition() >= indexOfLastUnread) ) {
|
(layoutManager.findLastCompletelyVisibleItemPosition() >= indexOfLastUnread) ) {
|
||||||
// but don't interrupt if already past the last unread
|
// but don't interrupt if already past the last unread
|
||||||
if (indexOfLastUnread >= layoutManager.findFirstCompletelyVisibleItemPosition()) {
|
if (indexOfLastUnread >= layoutManager.findFirstCompletelyVisibleItemPosition()) {
|
||||||
itemGrid.stopScroll();
|
binding.itemgridfragmentGrid.stopScroll();
|
||||||
}
|
}
|
||||||
indexOfLastUnread = -1;
|
indexOfLastUnread = -1;
|
||||||
}
|
}
|
||||||
|
@ -507,7 +501,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
*/
|
*/
|
||||||
private void calcFleuronPadding() {
|
private void calcFleuronPadding() {
|
||||||
if (fleuronResized) return;
|
if (fleuronResized) return;
|
||||||
int listHeight = itemGrid.getMeasuredHeight();
|
int listHeight = binding.itemgridfragmentGrid.getMeasuredHeight();
|
||||||
View innerView = fleuronFooter.findViewById(R.id.fleuron);
|
View innerView = fleuronFooter.findViewById(R.id.fleuron);
|
||||||
ViewGroup.LayoutParams oldLayout = innerView.getLayoutParams();
|
ViewGroup.LayoutParams oldLayout = innerView.getLayoutParams();
|
||||||
ViewGroup.MarginLayoutParams newLayout = new LinearLayout.LayoutParams(oldLayout);
|
ViewGroup.MarginLayoutParams newLayout = new LinearLayout.LayoutParams(oldLayout);
|
||||||
|
@ -526,7 +520,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState (Bundle outState) {
|
public void onSaveInstanceState (Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putParcelable(BUNDLE_GRIDSTATE, itemGrid.getLayoutManager().onSaveInstanceState());
|
outState.putParcelable(BUNDLE_GRIDSTATE, binding.itemgridfragmentGrid.getLayoutManager().onSaveInstanceState());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,17 +11,12 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.Login;
|
import com.newsblur.activity.Login;
|
||||||
import com.newsblur.activity.Main;
|
import com.newsblur.activity.Main;
|
||||||
|
import com.newsblur.databinding.FragmentLoginprogressBinding;
|
||||||
import com.newsblur.network.APIManager;
|
import com.newsblur.network.APIManager;
|
||||||
import com.newsblur.network.domain.LoginResponse;
|
import com.newsblur.network.domain.LoginResponse;
|
||||||
import com.newsblur.util.PrefsUtils;
|
import com.newsblur.util.PrefsUtils;
|
||||||
|
@ -30,14 +25,10 @@ import com.newsblur.util.UIUtils;
|
||||||
public class LoginProgressFragment extends Fragment {
|
public class LoginProgressFragment extends Fragment {
|
||||||
|
|
||||||
private APIManager apiManager;
|
private APIManager apiManager;
|
||||||
@Bind(R.id.login_logging_in) TextView updateStatus;
|
|
||||||
@Bind(R.id.login_retrieving_feeds) TextView retrievingFeeds;
|
|
||||||
@Bind(R.id.login_profile_picture) ImageView loginProfilePicture;
|
|
||||||
@Bind(R.id.login_feed_progress) ProgressBar feedProgress;
|
|
||||||
@Bind(R.id.login_logging_in_progress) ProgressBar loggingInProgress;
|
|
||||||
private LoginTask loginTask;
|
private LoginTask loginTask;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
private FragmentLoginprogressBinding binding;
|
||||||
|
|
||||||
public static LoginProgressFragment getInstance(String username, String password) {
|
public static LoginProgressFragment getInstance(String username, String password) {
|
||||||
LoginProgressFragment fragment = new LoginProgressFragment();
|
LoginProgressFragment fragment = new LoginProgressFragment();
|
||||||
|
@ -61,7 +52,7 @@ public class LoginProgressFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.fragment_loginprogress, null);
|
View v = inflater.inflate(R.layout.fragment_loginprogress, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = FragmentLoginprogressBinding.bind(v);
|
||||||
|
|
||||||
loginTask = new LoginTask();
|
loginTask = new LoginTask();
|
||||||
loginTask.execute();
|
loginTask.execute();
|
||||||
|
@ -73,7 +64,7 @@ public class LoginProgressFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute() {
|
protected void onPreExecute() {
|
||||||
Animation a = AnimationUtils.loadAnimation(getActivity(), R.anim.text_up);
|
Animation a = AnimationUtils.loadAnimation(getActivity(), R.anim.text_up);
|
||||||
updateStatus.startAnimation(a);
|
binding.loginLoggingIn.startAnimation(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,20 +81,20 @@ public class LoginProgressFragment extends Fragment {
|
||||||
if (c == null) return; // we might have run past the lifecycle of the activity
|
if (c == null) return; // we might have run past the lifecycle of the activity
|
||||||
if (!result.isError()) {
|
if (!result.isError()) {
|
||||||
final Animation a = AnimationUtils.loadAnimation(c, R.anim.text_down);
|
final Animation a = AnimationUtils.loadAnimation(c, R.anim.text_down);
|
||||||
updateStatus.setText(R.string.login_logged_in);
|
binding.loginLoggingIn.setText(R.string.login_logged_in);
|
||||||
loggingInProgress.setVisibility(View.GONE);
|
binding.loginLoggingInProgress.setVisibility(View.GONE);
|
||||||
updateStatus.startAnimation(a);
|
binding.loginLoggingIn.startAnimation(a);
|
||||||
|
|
||||||
Bitmap userImage = PrefsUtils.getUserImage(c);
|
Bitmap userImage = PrefsUtils.getUserImage(c);
|
||||||
if (userImage != null ) {
|
if (userImage != null ) {
|
||||||
loginProfilePicture.setVisibility(View.VISIBLE);
|
binding.loginProfilePicture.setVisibility(View.VISIBLE);
|
||||||
loginProfilePicture.setImageBitmap(UIUtils.clipAndRound(userImage, 10f, false));
|
binding.loginProfilePicture.setImageBitmap(UIUtils.clipAndRound(userImage, 10f, false));
|
||||||
}
|
}
|
||||||
feedProgress.setVisibility(View.VISIBLE);
|
binding.loginFeedProgress.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
final Animation b = AnimationUtils.loadAnimation(c, R.anim.text_up);
|
final Animation b = AnimationUtils.loadAnimation(c, R.anim.text_up);
|
||||||
retrievingFeeds.setText(R.string.login_retrieving_feeds);
|
binding.loginRetrievingFeeds.setText(R.string.login_retrieving_feeds);
|
||||||
retrievingFeeds.startAnimation(b);
|
binding.loginFeedProgress.startAnimation(b);
|
||||||
|
|
||||||
Intent startMain = new Intent(getActivity(), Main.class);
|
Intent startMain = new Intent(getActivity(), Main.class);
|
||||||
c.startActivity(startMain);
|
c.startActivity(startMain);
|
||||||
|
|
|
@ -3,6 +3,8 @@ package com.newsblur.fragment;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
@ -10,39 +12,27 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.TextView.OnEditorActionListener;
|
import android.widget.TextView.OnEditorActionListener;
|
||||||
import android.widget.ViewSwitcher;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.LoginProgress;
|
import com.newsblur.activity.LoginProgress;
|
||||||
import com.newsblur.activity.RegisterProgress;
|
import com.newsblur.activity.RegisterProgress;
|
||||||
|
import com.newsblur.databinding.FragmentLoginregisterBinding;
|
||||||
import com.newsblur.network.APIConstants;
|
import com.newsblur.network.APIConstants;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
import com.newsblur.util.PrefsUtils;
|
import com.newsblur.util.PrefsUtils;
|
||||||
|
|
||||||
public class LoginRegisterFragment extends Fragment {
|
public class LoginRegisterFragment extends Fragment {
|
||||||
|
|
||||||
@Bind(R.id.login_username) EditText username;
|
private FragmentLoginregisterBinding binding;
|
||||||
@Bind(R.id.login_password) EditText password;
|
|
||||||
@Bind(R.id.registration_username) EditText register_username;
|
|
||||||
@Bind(R.id.registration_password) EditText register_password;
|
|
||||||
@Bind(R.id.registration_email) EditText register_email;
|
|
||||||
@Bind(R.id.login_viewswitcher) ViewSwitcher viewSwitcher;
|
|
||||||
@Bind(R.id.login_custom_server) View customServer;
|
|
||||||
@Bind(R.id.login_custom_server_value) EditText customServerValue;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
final View v = inflater.inflate(R.layout.fragment_loginregister, container, false);
|
final View v = inflater.inflate(R.layout.fragment_loginregister, container, false);
|
||||||
ButterKnife.bind(this, v);
|
binding = FragmentLoginregisterBinding.bind(v);
|
||||||
|
|
||||||
password.setOnEditorActionListener(new OnEditorActionListener() {
|
binding.loginPassword.setOnEditorActionListener(new OnEditorActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onEditorAction(TextView arg0, int actionId, KeyEvent event) {
|
public boolean onEditorAction(TextView arg0, int actionId, KeyEvent event) {
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE ) {
|
if (actionId == EditorInfo.IME_ACTION_DONE ) {
|
||||||
|
@ -52,7 +42,7 @@ public class LoginRegisterFragment extends Fragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
register_email.setOnEditorActionListener(new OnEditorActionListener() {
|
binding.registrationEmail.setOnEditorActionListener(new OnEditorActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onEditorAction(TextView arg0, int actionId, KeyEvent event) {
|
public boolean onEditorAction(TextView arg0, int actionId, KeyEvent event) {
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE ) {
|
if (actionId == EditorInfo.IME_ACTION_DONE ) {
|
||||||
|
@ -65,36 +55,77 @@ public class LoginRegisterFragment extends Fragment {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.login_button) void logIn() {
|
@Override
|
||||||
if (!TextUtils.isEmpty(username.getText().toString())) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
binding.loginButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
logIn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.registrationButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
signUp();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.loginChangeToLogin.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
showLogin();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.loginChangeToRegister.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
showRegister();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.loginForgotPassword.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
launchForgotPasswordPage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.loginCustomServer.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
showCustomServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logIn() {
|
||||||
|
if (!TextUtils.isEmpty(binding.loginUsername.getText().toString())) {
|
||||||
// set the custom server endpoint before any API access, even the cookie fetch.
|
// set the custom server endpoint before any API access, even the cookie fetch.
|
||||||
APIConstants.setCustomServer(customServerValue.getText().toString());
|
APIConstants.setCustomServer(binding.loginCustomServerValue.getText().toString());
|
||||||
PrefsUtils.saveCustomServer(getActivity(), customServerValue.getText().toString());
|
PrefsUtils.saveCustomServer(getActivity(), binding.loginCustomServerValue.getText().toString());
|
||||||
|
|
||||||
Intent i = new Intent(getActivity(), LoginProgress.class);
|
Intent i = new Intent(getActivity(), LoginProgress.class);
|
||||||
i.putExtra("username", username.getText().toString());
|
i.putExtra("username", binding.loginUsername.getText().toString());
|
||||||
i.putExtra("password", password.getText().toString());
|
i.putExtra("password", binding.loginUsername.getText().toString());
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.registration_button) void signUp() {
|
private void signUp() {
|
||||||
Intent i = new Intent(getActivity(), RegisterProgress.class);
|
Intent i = new Intent(getActivity(), RegisterProgress.class);
|
||||||
i.putExtra("username", register_username.getText().toString());
|
i.putExtra("username", binding.registrationUsername.getText().toString());
|
||||||
i.putExtra("password", register_password.getText().toString());
|
i.putExtra("password", binding.registrationPassword.getText().toString());
|
||||||
i.putExtra("email", register_email.getText().toString());
|
i.putExtra("email", binding.registrationEmail.getText().toString());
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.login_change_to_login) void showLogin() {
|
private void showLogin() {
|
||||||
viewSwitcher.showPrevious();
|
binding.loginViewswitcher.showPrevious();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.login_change_to_register) void showRegister() {
|
private void showRegister() {
|
||||||
viewSwitcher.showNext();
|
binding.loginViewswitcher.showNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.login_forgot_password) void launchForgotPasswordPage() {
|
private void launchForgotPasswordPage() {
|
||||||
try {
|
try {
|
||||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||||
i.setData(Uri.parse(AppConstants.FORGOT_PASWORD_URL));
|
i.setData(Uri.parse(AppConstants.FORGOT_PASWORD_URL));
|
||||||
|
@ -104,9 +135,8 @@ public class LoginRegisterFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.login_custom_server) void showCustomServer() {
|
private void showCustomServer() {
|
||||||
customServer.setVisibility(View.GONE);
|
binding.loginCustomServer.setVisibility(View.GONE);
|
||||||
customServerValue.setVisibility(View.VISIBLE);
|
binding.loginCustomServerValue.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
|
@ -1,19 +1,17 @@
|
||||||
package com.newsblur.fragment;
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.widget.RadioButton;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.ReadfilterDialogBinding;
|
||||||
import com.newsblur.util.ReadFilter;
|
import com.newsblur.util.ReadFilter;
|
||||||
import com.newsblur.util.ReadFilterChangedListener;
|
import com.newsblur.util.ReadFilterChangedListener;
|
||||||
|
|
||||||
|
@ -21,8 +19,7 @@ public class ReadFilterDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
private static String CURRENT_FILTER = "currentFilter";
|
private static String CURRENT_FILTER = "currentFilter";
|
||||||
private ReadFilter currentValue;
|
private ReadFilter currentValue;
|
||||||
@Bind(R.id.radio_all) RadioButton allButton;
|
private ReadfilterDialogBinding binding;
|
||||||
@Bind(R.id.radio_unread) RadioButton unreadButton;
|
|
||||||
|
|
||||||
public static ReadFilterDialogFragment newInstance(ReadFilter currentValue) {
|
public static ReadFilterDialogFragment newInstance(ReadFilter currentValue) {
|
||||||
ReadFilterDialogFragment dialog = new ReadFilterDialogFragment();
|
ReadFilterDialogFragment dialog = new ReadFilterDialogFragment();
|
||||||
|
@ -42,10 +39,10 @@ public class ReadFilterDialogFragment extends DialogFragment {
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||||
currentValue = (ReadFilter) getArguments().getSerializable(CURRENT_FILTER);
|
currentValue = (ReadFilter) getArguments().getSerializable(CURRENT_FILTER);
|
||||||
View v = inflater.inflate(R.layout.readfilter_dialog, null);
|
View v = inflater.inflate(R.layout.readfilter_dialog, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = ReadfilterDialogBinding.bind(v);
|
||||||
|
|
||||||
allButton.setChecked(currentValue == ReadFilter.ALL);
|
binding.radioAll.setChecked(currentValue == ReadFilter.ALL);
|
||||||
unreadButton.setChecked(currentValue == ReadFilter.UNREAD);
|
binding.radioUnread.setChecked(currentValue == ReadFilter.UNREAD);
|
||||||
|
|
||||||
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
||||||
|
@ -53,14 +50,31 @@ public class ReadFilterDialogFragment extends DialogFragment {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.radio_all) void selectAll() {
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
binding.radioAll.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
selectAll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioUnread.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
selectUnread();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectAll() {
|
||||||
if (currentValue != ReadFilter.ALL) {
|
if (currentValue != ReadFilter.ALL) {
|
||||||
((ReadFilterChangedListener) getActivity()).readFilterChanged(ReadFilter.ALL);
|
((ReadFilterChangedListener) getActivity()).readFilterChanged(ReadFilter.ALL);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.radio_unread) void selectUnread() {
|
private void selectUnread() {
|
||||||
if (currentValue != ReadFilter.UNREAD) {
|
if (currentValue != ReadFilter.UNREAD) {
|
||||||
((ReadFilterChangedListener) getActivity()).readFilterChanged(ReadFilter.UNREAD);
|
((ReadFilterChangedListener) getActivity()).readFilterChanged(ReadFilter.UNREAD);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
package com.newsblur.fragment;
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.widget.RadioButton;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.ReadingfontDialogBinding;
|
||||||
import com.newsblur.util.ReadingFontChangedListener;
|
import com.newsblur.util.ReadingFontChangedListener;
|
||||||
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mark on 02/05/2017.
|
* Created by mark on 02/05/2017.
|
||||||
*/
|
*/
|
||||||
|
@ -26,14 +24,7 @@ public class ReadingFontDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
private String currentValue;
|
private String currentValue;
|
||||||
|
|
||||||
@Bind(R.id.radio_anonymous) RadioButton anonymousButton;
|
private ReadingfontDialogBinding binding;
|
||||||
@Bind(R.id.radio_chronicle) RadioButton chronicleButton;
|
|
||||||
@Bind(R.id.radio_default) RadioButton defaultButton;
|
|
||||||
@Bind(R.id.radio_gotham) RadioButton gothamButton;
|
|
||||||
@Bind(R.id.radio_noto_sans) RadioButton notoSansButton;
|
|
||||||
@Bind(R.id.radio_noto_serif) RadioButton notoSerifButton;
|
|
||||||
@Bind(R.id.radio_open_sans_condensed) RadioButton openSansCondensedButton;
|
|
||||||
@Bind(R.id.radio_whitney) RadioButton whitneyButton;
|
|
||||||
|
|
||||||
public static ReadingFontDialogFragment newInstance(String selectedFont) {
|
public static ReadingFontDialogFragment newInstance(String selectedFont) {
|
||||||
ReadingFontDialogFragment dialog = new ReadingFontDialogFragment();
|
ReadingFontDialogFragment dialog = new ReadingFontDialogFragment();
|
||||||
|
@ -52,16 +43,16 @@ public class ReadingFontDialogFragment extends DialogFragment {
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||||
currentValue = getArguments().getString(SELECTED_FONT);
|
currentValue = getArguments().getString(SELECTED_FONT);
|
||||||
View v = inflater.inflate(R.layout.readingfont_dialog, null);
|
View v = inflater.inflate(R.layout.readingfont_dialog, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = ReadingfontDialogBinding.bind(v);
|
||||||
|
|
||||||
anonymousButton.setChecked(currentValue.equals(getString(R.string.anonymous_pro_font_prefvalue)));
|
binding.radioAnonymous.setChecked(currentValue.equals(getString(R.string.anonymous_pro_font_prefvalue)));
|
||||||
chronicleButton.setChecked(currentValue.equals(getString(R.string.chronicle_font_prefvalue)));
|
binding.radioChronicle.setChecked(currentValue.equals(getString(R.string.chronicle_font_prefvalue)));
|
||||||
defaultButton.setChecked(currentValue.equals(getString(R.string.default_font_prefvalue)));
|
binding.radioDefault.setChecked(currentValue.equals(getString(R.string.default_font_prefvalue)));
|
||||||
gothamButton.setChecked(currentValue.equals(getString(R.string.gotham_narrow_font_prefvalue)));
|
binding.radioGotham.setChecked(currentValue.equals(getString(R.string.gotham_narrow_font_prefvalue)));
|
||||||
notoSansButton.setChecked(currentValue.equals(getString(R.string.noto_sans_font_prefvalue)));
|
binding.radioNotoSans.setChecked(currentValue.equals(getString(R.string.noto_sans_font_prefvalue)));
|
||||||
notoSerifButton.setChecked(currentValue.equals(getString(R.string.noto_serif_font_prefvalue)));
|
binding.radioNotoSerif.setChecked(currentValue.equals(getString(R.string.noto_serif_font_prefvalue)));
|
||||||
openSansCondensedButton.setChecked(currentValue.equals(getString(R.string.open_sans_condensed_font_prefvalue)));
|
binding.radioOpenSansCondensed.setChecked(currentValue.equals(getString(R.string.open_sans_condensed_font_prefvalue)));
|
||||||
whitneyButton.setChecked(currentValue.equals(getString(R.string.whitney_font_prefvalue)));
|
binding.radioWhitney.setChecked(currentValue.equals(getString(R.string.whitney_font_prefvalue)));
|
||||||
|
|
||||||
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
||||||
|
@ -69,8 +60,57 @@ public class ReadingFontDialogFragment extends DialogFragment {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.radio_anonymous) void selectAnonymousPro() {
|
@Override
|
||||||
switchFont(getString(R.string.anonymous_pro_font_prefvalue));
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
binding.radioAnonymous.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.anonymous_pro_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioDefault.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.default_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioChronicle.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.chronicle_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioGotham.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.gotham_narrow_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioNotoSans.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.noto_sans_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioNotoSerif.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.noto_serif_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioOpenSansCondensed.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.open_sans_condensed_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioWhitney.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
switchFont(getString(R.string.whitney_font_prefvalue));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchFont(String newValue) {
|
private void switchFont(String newValue) {
|
||||||
|
@ -79,32 +119,4 @@ public class ReadingFontDialogFragment extends DialogFragment {
|
||||||
currentValue = newValue;
|
currentValue = newValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@OnClick(R.id.radio_chronicle) void selectChronicle() {
|
|
||||||
switchFont(getString(R.string.chronicle_font_prefvalue));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.radio_default) void selectDefault() {
|
|
||||||
switchFont(getString(R.string.default_font_prefvalue));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.radio_gotham) void selectGotham() {
|
|
||||||
switchFont(getString(R.string.gotham_narrow_font_prefvalue));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.radio_noto_sans) void selectNotoSans() {
|
|
||||||
switchFont(getString(R.string.noto_sans_font_prefvalue));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.radio_noto_serif) void selectNotoSerif() {
|
|
||||||
switchFont(getString(R.string.noto_serif_font_prefvalue));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.radio_open_sans_condensed) void selectOpenSansCondensed() {
|
|
||||||
switchFont(getString(R.string.open_sans_condensed_font_prefvalue));
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.radio_whitney) void selectWhitney() {
|
|
||||||
switchFont(getString(R.string.whitney_font_prefvalue));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,12 +7,15 @@ import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.GradientDrawable;
|
import android.graphics.drawable.GradientDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -26,22 +29,17 @@ import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.webkit.WebView.HitTestResult;
|
import android.webkit.WebView.HitTestResult;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
import android.widget.ScrollView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.FeedItemsList;
|
import com.newsblur.activity.FeedItemsList;
|
||||||
import com.newsblur.activity.NbActivity;
|
import com.newsblur.activity.NbActivity;
|
||||||
import com.newsblur.activity.Reading;
|
import com.newsblur.activity.Reading;
|
||||||
|
import com.newsblur.databinding.FragmentReadingitemBinding;
|
||||||
|
import com.newsblur.databinding.IncludeReadingItemCommentBinding;
|
||||||
import com.newsblur.domain.Classifier;
|
import com.newsblur.domain.Classifier;
|
||||||
import com.newsblur.domain.Feed;
|
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
import com.newsblur.domain.UserDetails;
|
import com.newsblur.domain.UserDetails;
|
||||||
import com.newsblur.service.OriginalTextService;
|
import com.newsblur.service.OriginalTextService;
|
||||||
|
@ -54,14 +52,9 @@ import com.newsblur.util.PrefsUtils;
|
||||||
import com.newsblur.util.StoryUtils;
|
import com.newsblur.util.StoryUtils;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
import com.newsblur.util.ViewUtils;
|
import com.newsblur.util.ViewUtils;
|
||||||
import com.newsblur.view.FlowLayout;
|
|
||||||
import com.newsblur.view.NewsblurWebview;
|
|
||||||
import com.newsblur.view.ReadingScrollView;
|
import com.newsblur.view.ReadingScrollView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -76,24 +69,12 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
private LayoutInflater inflater;
|
private LayoutInflater inflater;
|
||||||
private String feedColor, feedTitle, feedFade, feedBorder, feedIconUrl, faviconText;
|
private String feedColor, feedTitle, feedFade, feedBorder, feedIconUrl, faviconText;
|
||||||
private Classifier classifier;
|
private Classifier classifier;
|
||||||
@Bind(R.id.reading_webview) NewsblurWebview web;
|
|
||||||
@Bind(R.id.custom_view_container) ViewGroup webviewCustomViewLayout;
|
|
||||||
@Bind(R.id.reading_scrollview) ScrollView fragmentScrollview;
|
|
||||||
private BroadcastReceiver textSizeReceiver, readingFontReceiver;
|
private BroadcastReceiver textSizeReceiver, readingFontReceiver;
|
||||||
@Bind(R.id.reading_item_title) TextView itemTitle;
|
|
||||||
@Bind(R.id.reading_item_authors) TextView itemAuthors;
|
|
||||||
@Bind(R.id.reading_feed_title) TextView itemFeed;
|
|
||||||
private boolean displayFeedDetails;
|
private boolean displayFeedDetails;
|
||||||
@Bind(R.id.reading_item_tags) FlowLayout tagContainer;
|
|
||||||
private View view;
|
private View view;
|
||||||
private UserDetails user;
|
private UserDetails user;
|
||||||
private DefaultFeedView selectedFeedView;
|
private DefaultFeedView selectedFeedView;
|
||||||
private boolean textViewUnavailable;
|
private boolean textViewUnavailable;
|
||||||
@Bind(R.id.reading_textloading) TextView textViewLoadingMsg;
|
|
||||||
@Bind(R.id.reading_textmodefailed) TextView textViewLoadingFailedMsg;
|
|
||||||
@Bind(R.id.save_story_button) Button saveButton;
|
|
||||||
@Bind(R.id.share_story_button) Button shareButton;
|
|
||||||
@Bind(R.id.story_context_menu_button) Button menuButton;
|
|
||||||
|
|
||||||
/** The story HTML, as provided by the 'content' element of the stories API. */
|
/** The story HTML, as provided by the 'content' element of the stories API. */
|
||||||
private String storyContent;
|
private String storyContent;
|
||||||
|
@ -115,6 +96,9 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
|
|
||||||
private final Object WEBVIEW_CONTENT_MUTEX = new Object();
|
private final Object WEBVIEW_CONTENT_MUTEX = new Object();
|
||||||
|
|
||||||
|
private FragmentReadingitemBinding binding;
|
||||||
|
private IncludeReadingItemCommentBinding itemCommentBinding;
|
||||||
|
|
||||||
public static ReadingItemFragment newInstance(Story story, String feedTitle, String feedFaviconColor, String feedFaviconFade, String feedFaviconBorder, String faviconText, String faviconUrl, Classifier classifier, boolean displayFeedDetails, String sourceUserId) {
|
public static ReadingItemFragment newInstance(Story story, String feedTitle, String feedFaviconColor, String feedFaviconFade, String feedFaviconBorder, String faviconText, String faviconUrl, Classifier classifier, boolean displayFeedDetails, String sourceUserId) {
|
||||||
ReadingItemFragment readingFragment = new ReadingItemFragment();
|
ReadingItemFragment readingFragment = new ReadingItemFragment();
|
||||||
|
|
||||||
|
@ -168,8 +152,8 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
int heightm = fragmentScrollview.getChildAt(0).getMeasuredHeight();
|
int heightm = binding.readingScrollview.getChildAt(0).getMeasuredHeight();
|
||||||
int pos = fragmentScrollview.getScrollY();
|
int pos = binding.readingScrollview.getScrollY();
|
||||||
outState.putFloat(BUNDLE_SCROLL_POS_REL, (((float)pos)/heightm));
|
outState.putFloat(BUNDLE_SCROLL_POS_REL, (((float)pos)/heightm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +161,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
getActivity().unregisterReceiver(textSizeReceiver);
|
getActivity().unregisterReceiver(textSizeReceiver);
|
||||||
getActivity().unregisterReceiver(readingFontReceiver);
|
getActivity().unregisterReceiver(readingFontReceiver);
|
||||||
web.setOnTouchListener(null);
|
binding.readingWebview.setOnTouchListener(null);
|
||||||
view.setOnTouchListener(null);
|
view.setOnTouchListener(null);
|
||||||
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(null);
|
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(null);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -187,7 +171,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
// state into the webview so it behaves.
|
// state into the webview so it behaves.
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
if (this.web != null ) { this.web.onPause(); }
|
if (this.binding.readingWebview != null ) { this.binding.readingWebview.onPause(); }
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,25 +179,26 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
reloadStoryContent();
|
reloadStoryContent();
|
||||||
if (this.web != null ) { this.web.onResume(); }
|
if (this.binding.readingWebview != null ) { this.binding.readingWebview.onResume(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
this.inflater = inflater;
|
this.inflater = inflater;
|
||||||
view = inflater.inflate(R.layout.fragment_readingitem, null);
|
view = inflater.inflate(R.layout.fragment_readingitem, null);
|
||||||
ButterKnife.bind(this, view);
|
binding = FragmentReadingitemBinding.bind(view);
|
||||||
|
itemCommentBinding = IncludeReadingItemCommentBinding.bind(binding.getRoot());
|
||||||
|
|
||||||
Reading activity = (Reading) getActivity();
|
Reading activity = (Reading) getActivity();
|
||||||
fs = activity.getFeedSet();
|
fs = activity.getFeedSet();
|
||||||
|
|
||||||
selectedFeedView = PrefsUtils.getDefaultViewModeForFeed(activity, story.feedId);
|
selectedFeedView = PrefsUtils.getDefaultViewModeForFeed(activity, story.feedId);
|
||||||
|
|
||||||
registerForContextMenu(web);
|
registerForContextMenu(binding.readingWebview);
|
||||||
web.setCustomViewLayout(webviewCustomViewLayout);
|
binding.readingWebview.setCustomViewLayout(binding.customViewContainer);
|
||||||
web.setWebviewWrapperLayout(fragmentScrollview);
|
binding.readingWebview.setWebviewWrapperLayout(binding.readingScrollview);
|
||||||
web.setBackgroundColor(Color.TRANSPARENT);
|
binding.readingWebview.setBackgroundColor(Color.TRANSPARENT);
|
||||||
web.fragment = this;
|
binding.readingWebview.fragment = this;
|
||||||
web.activity = activity;
|
binding.readingWebview.activity = activity;
|
||||||
|
|
||||||
setupItemMetadata();
|
setupItemMetadata();
|
||||||
updateShareButton();
|
updateShareButton();
|
||||||
|
@ -228,6 +213,29 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
binding.storyContextMenuButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onClickMenuButton();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
itemCommentBinding.saveStoryButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
clickSave();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
itemCommentBinding.shareStoryButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
clickShare();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setupImmersiveViewGestureDetector() {
|
private void setupImmersiveViewGestureDetector() {
|
||||||
// Change the system visibility on the decorview from the activity so that the state is maintained as we page through
|
// Change the system visibility on the decorview from the activity so that the state is maintained as we page through
|
||||||
// fragments
|
// fragments
|
||||||
|
@ -239,7 +247,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
return gestureDetector.onTouchEvent(motionEvent);
|
return gestureDetector.onTouchEvent(motionEvent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
web.setOnTouchListener(touchListener);
|
binding.readingWebview.setOnTouchListener(touchListener);
|
||||||
view.setOnTouchListener(touchListener);
|
view.setOnTouchListener(touchListener);
|
||||||
|
|
||||||
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(immersiveViewHandler);
|
getActivity().getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(immersiveViewHandler);
|
||||||
|
@ -247,7 +255,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||||
HitTestResult result = web.getHitTestResult();
|
HitTestResult result = binding.readingWebview.getHitTestResult();
|
||||||
if (result.getType() == HitTestResult.IMAGE_TYPE ||
|
if (result.getType() == HitTestResult.IMAGE_TYPE ||
|
||||||
result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE ) {
|
result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE ) {
|
||||||
// if the long-pressed item was an image, see if we can pop up a little dialogue
|
// if the long-pressed item was an image, see if we can pop up a little dialogue
|
||||||
|
@ -298,8 +306,8 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.story_context_menu_button) void onClickMenuButton() {
|
private void onClickMenuButton() {
|
||||||
PopupMenu pm = new PopupMenu(getActivity(), menuButton);
|
PopupMenu pm = new PopupMenu(getActivity(), binding.storyContextMenuButton);
|
||||||
Menu menu = pm.getMenu();
|
Menu menu = pm.getMenu();
|
||||||
pm.getMenuInflater().inflate(R.menu.story_context, menu);
|
pm.getMenuInflater().inflate(R.menu.story_context, menu);
|
||||||
|
|
||||||
|
@ -313,6 +321,8 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
menu.findItem(R.id.menu_theme_dark).setChecked(true);
|
menu.findItem(R.id.menu_theme_dark).setChecked(true);
|
||||||
} else if (themeValue == ThemeValue.BLACK) {
|
} else if (themeValue == ThemeValue.BLACK) {
|
||||||
menu.findItem(R.id.menu_theme_black).setChecked(true);
|
menu.findItem(R.id.menu_theme_black).setChecked(true);
|
||||||
|
} else if (themeValue == ThemeValue.AUTO) {
|
||||||
|
menu.findItem(R.id.menu_theme_auto).setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.setOnMenuItemClickListener(this);
|
pm.setOnMenuItemClickListener(this);
|
||||||
|
@ -360,7 +370,11 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
} else if (item.getItemId() == R.id.menu_reading_markunread) {
|
} else if (item.getItemId() == R.id.menu_reading_markunread) {
|
||||||
FeedUtils.markStoryUnread(story, getActivity());
|
FeedUtils.markStoryUnread(story, getActivity());
|
||||||
return true;
|
return true;
|
||||||
} else if (item.getItemId() == R.id.menu_theme_light) {
|
} else if (item.getItemId() == R.id.menu_theme_auto) {
|
||||||
|
PrefsUtils.setSelectedTheme(getActivity(), ThemeValue.AUTO);
|
||||||
|
UIUtils.restartActivity(getActivity());
|
||||||
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.menu_theme_light) {
|
||||||
PrefsUtils.setSelectedTheme(getActivity(), ThemeValue.LIGHT);
|
PrefsUtils.setSelectedTheme(getActivity(), ThemeValue.LIGHT);
|
||||||
UIUtils.restartActivity(getActivity());
|
UIUtils.restartActivity(getActivity());
|
||||||
return true;
|
return true;
|
||||||
|
@ -386,7 +400,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.save_story_button) void clickSave() {
|
private void clickSave() {
|
||||||
if (story.starred) {
|
if (story.starred) {
|
||||||
FeedUtils.setStorySaved(story.storyHash, false, getActivity());
|
FeedUtils.setStorySaved(story.storyHash, false, getActivity());
|
||||||
} else {
|
} else {
|
||||||
|
@ -395,24 +409,24 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSaveButton() {
|
private void updateSaveButton() {
|
||||||
if (saveButton == null) return;
|
if (itemCommentBinding.saveStoryButton == null) return;
|
||||||
saveButton.setText(story.starred ? R.string.unsave_this : R.string.save_this);
|
itemCommentBinding.saveStoryButton.setText(story.starred ? R.string.unsave_this : R.string.save_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.share_story_button) void clickShare() {
|
private void clickShare() {
|
||||||
DialogFragment newFragment = ShareDialogFragment.newInstance(story, sourceUserId);
|
DialogFragment newFragment = ShareDialogFragment.newInstance(story, sourceUserId);
|
||||||
newFragment.show(getFragmentManager(), "dialog");
|
newFragment.show(getFragmentManager(), "dialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateShareButton() {
|
private void updateShareButton() {
|
||||||
if (shareButton == null) return;
|
if (itemCommentBinding.shareStoryButton == null) return;
|
||||||
for (String userId : story.sharedUserIds) {
|
for (String userId : story.sharedUserIds) {
|
||||||
if (TextUtils.equals(userId, user.id)) {
|
if (TextUtils.equals(userId, user.id)) {
|
||||||
shareButton.setText(R.string.already_shared);
|
itemCommentBinding.shareStoryButton.setText(R.string.already_shared);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shareButton.setText(R.string.share_this);
|
itemCommentBinding.shareStoryButton.setText(R.string.share_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupItemCommentsAndShares() {
|
private void setupItemCommentsAndShares() {
|
||||||
|
@ -443,28 +457,28 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
feedHeaderBorder.setBackgroundColor(Color.parseColor("#" + feedBorder));
|
feedHeaderBorder.setBackgroundColor(Color.parseColor("#" + feedBorder));
|
||||||
|
|
||||||
if (TextUtils.equals(faviconText, "black")) {
|
if (TextUtils.equals(faviconText, "black")) {
|
||||||
itemFeed.setTextColor(UIUtils.getColor(getActivity(), R.color.text));
|
binding.readingFeedTitle.setTextColor(UIUtils.getColor(getActivity(), R.color.text));
|
||||||
itemFeed.setShadowLayer(1, 0, 1, UIUtils.getColor(getActivity(), R.color.half_white));
|
binding.readingFeedTitle.setShadowLayer(1, 0, 1, UIUtils.getColor(getActivity(), R.color.half_white));
|
||||||
} else {
|
} else {
|
||||||
itemFeed.setTextColor(UIUtils.getColor(getActivity(), R.color.white));
|
binding.readingFeedTitle.setTextColor(UIUtils.getColor(getActivity(), R.color.white));
|
||||||
itemFeed.setShadowLayer(1, 0, 1, UIUtils.getColor(getActivity(), R.color.half_black));
|
binding.readingFeedTitle.setShadowLayer(1, 0, 1, UIUtils.getColor(getActivity(), R.color.half_black));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!displayFeedDetails) {
|
if (!displayFeedDetails) {
|
||||||
itemFeed.setVisibility(View.GONE);
|
binding.readingFeedTitle.setVisibility(View.GONE);
|
||||||
feedIcon.setVisibility(View.GONE);
|
feedIcon.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
FeedUtils.iconLoader.displayImage(feedIconUrl, feedIcon, 0, false);
|
FeedUtils.iconLoader.displayImage(feedIconUrl, feedIcon, 0, false);
|
||||||
itemFeed.setText(feedTitle);
|
binding.readingFeedTitle.setText(feedTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
itemDate.setText(StoryUtils.formatLongDate(getActivity(), story.timestamp));
|
itemDate.setText(StoryUtils.formatLongDate(getActivity(), story.timestamp));
|
||||||
|
|
||||||
if (story.tags.length <= 0) {
|
if (story.tags.length <= 0) {
|
||||||
tagContainer.setVisibility(View.GONE);
|
binding.readingItemTags.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
itemAuthors.setOnClickListener(new OnClickListener() {
|
binding.readingItemAuthors.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (story.feedId.equals("0")) return; // cannot train on feedless stories
|
if (story.feedId.equals("0")) return; // cannot train on feedless stories
|
||||||
|
@ -473,7 +487,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
itemFeed.setOnClickListener(new OnClickListener() {
|
binding.readingFeedTitle.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (story.feedId.equals("0")) return; // cannot train on feedless stories
|
if (story.feedId.equals("0")) return; // cannot train on feedless stories
|
||||||
|
@ -482,7 +496,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
itemTitle.setOnClickListener(new OnClickListener() {
|
binding.readingItemTitle.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||||
|
@ -506,7 +520,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
Drawable tag_green_background = UIUtils.getDrawable(getActivity(), R.drawable.tag_background_positive);
|
Drawable tag_green_background = UIUtils.getDrawable(getActivity(), R.drawable.tag_background_positive);
|
||||||
Drawable tag_red_background = UIUtils.getDrawable(getActivity(), R.drawable.tag_background_negative);
|
Drawable tag_red_background = UIUtils.getDrawable(getActivity(), R.drawable.tag_background_negative);
|
||||||
|
|
||||||
tagContainer.removeAllViews();
|
binding.readingItemTags.removeAllViews();
|
||||||
for (String tag : story.tags) {
|
for (String tag : story.tags) {
|
||||||
// TODO: these textviews with compound images are buggy, but stubbed in to let colourblind users
|
// TODO: these textviews with compound images are buggy, but stubbed in to let colourblind users
|
||||||
// see what is going on. these should be replaced with proper Chips when the v28 Chip lib
|
// see what is going on. these should be replaced with proper Chips when the v28 Chip lib
|
||||||
|
@ -549,21 +563,21 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tagContainer.addView(v);
|
binding.readingItemTags.addView(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(story.authors)) {
|
if (!TextUtils.isEmpty(story.authors)) {
|
||||||
itemAuthors.setText("• " + story.authors);
|
binding.readingItemAuthors.setText("• " + story.authors);
|
||||||
if (classifier != null && classifier.authors.containsKey(story.authors)) {
|
if (classifier != null && classifier.authors.containsKey(story.authors)) {
|
||||||
switch (classifier.authors.get(story.authors)) {
|
switch (classifier.authors.get(story.authors)) {
|
||||||
case Classifier.LIKE:
|
case Classifier.LIKE:
|
||||||
itemAuthors.setTextColor(UIUtils.getColor(getActivity(), R.color.positive));
|
binding.readingItemAuthors.setTextColor(UIUtils.getColor(getActivity(), R.color.positive));
|
||||||
break;
|
break;
|
||||||
case Classifier.DISLIKE:
|
case Classifier.DISLIKE:
|
||||||
itemAuthors.setTextColor(UIUtils.getColor(getActivity(), R.color.negative));
|
binding.readingItemAuthors.setTextColor(UIUtils.getColor(getActivity(), R.color.negative));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
itemAuthors.setTextColor(UIUtils.getThemedColor(getActivity(), R.attr.readingItemMetadata, android.R.attr.textColor));
|
binding.readingItemAuthors.setTextColor(UIUtils.getThemedColor(getActivity(), R.attr.readingItemMetadata, android.R.attr.textColor));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,7 +585,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
|
|
||||||
String title = story.title;
|
String title = story.title;
|
||||||
title = UIUtils.colourTitleFromClassifier(title, classifier);
|
title = UIUtils.colourTitleFromClassifier(title, classifier);
|
||||||
itemTitle.setText(UIUtils.fromHtml(title));
|
binding.readingItemTitle.setText(UIUtils.fromHtml(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void switchSelectedViewMode() {
|
public void switchSelectedViewMode() {
|
||||||
|
@ -613,8 +627,8 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
|
|
||||||
private void reloadStoryContent() {
|
private void reloadStoryContent() {
|
||||||
// reset indicators
|
// reset indicators
|
||||||
textViewLoadingMsg.setVisibility(View.GONE);
|
binding.readingTextloading.setVisibility(View.GONE);
|
||||||
textViewLoadingFailedMsg.setVisibility(View.GONE);
|
binding.readingTextmodefailed.setVisibility(View.GONE);
|
||||||
enableProgress(false);
|
enableProgress(false);
|
||||||
|
|
||||||
boolean needStoryContent = false;
|
boolean needStoryContent = false;
|
||||||
|
@ -623,10 +637,10 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
needStoryContent = true;
|
needStoryContent = true;
|
||||||
} else {
|
} else {
|
||||||
if (textViewUnavailable) {
|
if (textViewUnavailable) {
|
||||||
textViewLoadingFailedMsg.setVisibility(View.VISIBLE);
|
binding.readingTextmodefailed.setVisibility(View.VISIBLE);
|
||||||
needStoryContent = true;
|
needStoryContent = true;
|
||||||
} else if (originalText == null) {
|
} else if (originalText == null) {
|
||||||
textViewLoadingMsg.setVisibility(View.VISIBLE);
|
binding.readingTextloading.setVisibility(View.VISIBLE);
|
||||||
enableProgress(true);
|
enableProgress(true);
|
||||||
loadOriginalText();
|
loadOriginalText();
|
||||||
// still show the story mode version, as the text mode one may take some time
|
// still show the story mode version, as the text mode one may take some time
|
||||||
|
@ -782,11 +796,20 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"dark_reading.css\" />");
|
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"dark_reading.css\" />");
|
||||||
} else if (themeValue == ThemeValue.BLACK) {
|
} else if (themeValue == ThemeValue.BLACK) {
|
||||||
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"black_reading.css\" />");
|
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"black_reading.css\" />");
|
||||||
|
} else if (themeValue == ThemeValue.AUTO) {
|
||||||
|
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||||
|
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
|
||||||
|
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"dark_reading.css\" />");
|
||||||
|
} else if (nightModeFlags == Configuration.UI_MODE_NIGHT_NO) {
|
||||||
|
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"light_reading.css\" />");
|
||||||
|
} else if (nightModeFlags == Configuration.UI_MODE_NIGHT_UNDEFINED) {
|
||||||
|
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"light_reading.css\" />");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
builder.append("</head><body><div class=\"NB-story\">");
|
builder.append("</head><body><div class=\"NB-story\">");
|
||||||
builder.append(storyText);
|
builder.append(storyText);
|
||||||
builder.append("</div></body></html>");
|
builder.append("</div></body></html>");
|
||||||
web.loadDataWithBaseURL("file:///android_asset/", builder.toString(), "text/html", "UTF-8", null);
|
binding.readingWebview.loadDataWithBaseURL("file:///android_asset/", builder.toString(), "text/html", "UTF-8", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,10 +910,10 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
// insufficient time to allow the WebView to actually finish internally computing state and size.
|
// insufficient time to allow the WebView to actually finish internally computing state and size.
|
||||||
// an additional fixed delay is added in a last ditch attempt to give the black-box platform
|
// an additional fixed delay is added in a last ditch attempt to give the black-box platform
|
||||||
// threads a chance to finish their work.
|
// threads a chance to finish their work.
|
||||||
fragmentScrollview.postDelayed(new Runnable() {
|
binding.readingScrollview.postDelayed(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
int relPos = Math.round(fragmentScrollview.getChildAt(0).getMeasuredHeight() * savedScrollPosRel);
|
int relPos = Math.round(binding.readingScrollview.getChildAt(0).getMeasuredHeight() * savedScrollPosRel);
|
||||||
fragmentScrollview.scrollTo(0, relPos);
|
binding.readingScrollview.scrollTo(0, relPos);
|
||||||
}
|
}
|
||||||
}, 75L);
|
}, 75L);
|
||||||
}
|
}
|
||||||
|
@ -903,7 +926,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
private class TextSizeReceiver extends BroadcastReceiver {
|
private class TextSizeReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
web.setTextSize(intent.getFloatExtra(TEXT_SIZE_VALUE, 1.0f));
|
binding.readingWebview.setTextSize(intent.getFloatExtra(TEXT_SIZE_VALUE, 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,7 +947,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onSingleTapUp(MotionEvent e) {
|
public boolean onSingleTapUp(MotionEvent e) {
|
||||||
if (web.wasLinkClicked()) {
|
if (binding.readingWebview.wasLinkClicked()) {
|
||||||
// Clicked a link so ignore immersive view
|
// Clicked a link so ignore immersive view
|
||||||
return super.onSingleTapUp(e);
|
return super.onSingleTapUp(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
package com.newsblur.fragment;
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.view.ViewPager;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.Reading;
|
import com.newsblur.activity.Reading;
|
||||||
|
import com.newsblur.databinding.FragmentReadingpagerBinding;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A fragment to hold the story pager. Eventually this fragment should hold much of the UI and logic
|
* A fragment to hold the story pager. Eventually this fragment should hold much of the UI and logic
|
||||||
|
@ -21,8 +18,6 @@ import com.newsblur.activity.Reading;
|
||||||
*/
|
*/
|
||||||
public class ReadingPagerFragment extends NbFragment {
|
public class ReadingPagerFragment extends NbFragment {
|
||||||
|
|
||||||
@Bind(R.id.reading_pager) ViewPager pager;
|
|
||||||
|
|
||||||
public static ReadingPagerFragment newInstance() {
|
public static ReadingPagerFragment newInstance() {
|
||||||
ReadingPagerFragment fragment = new ReadingPagerFragment();
|
ReadingPagerFragment fragment = new ReadingPagerFragment();
|
||||||
Bundle arguments = new Bundle();
|
Bundle arguments = new Bundle();
|
||||||
|
@ -33,12 +28,12 @@ public class ReadingPagerFragment extends NbFragment {
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.fragment_readingpager, null);
|
View v = inflater.inflate(R.layout.fragment_readingpager, null);
|
||||||
ButterKnife.bind(this, v);
|
FragmentReadingpagerBinding binding = FragmentReadingpagerBinding.bind(v);
|
||||||
|
|
||||||
Reading activity = ((Reading) getActivity());
|
Reading activity = ((Reading) getActivity());
|
||||||
|
|
||||||
pager.addOnPageChangeListener(activity);
|
binding.readingPager.addOnPageChangeListener(activity);
|
||||||
activity.offerPager(pager, getChildFragmentManager());
|
activity.offerPager(binding.readingPager, getChildFragmentManager());
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,23 +3,19 @@ package com.newsblur.fragment;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.widget.ViewSwitcher;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
import com.newsblur.activity.AddSocial;
|
import com.newsblur.activity.AddSocial;
|
||||||
import com.newsblur.activity.Login;
|
import com.newsblur.activity.Login;
|
||||||
|
import com.newsblur.databinding.FragmentRegisterprogressBinding;
|
||||||
import com.newsblur.network.APIManager;
|
import com.newsblur.network.APIManager;
|
||||||
import com.newsblur.network.domain.RegisterResponse;
|
import com.newsblur.network.domain.RegisterResponse;
|
||||||
|
|
||||||
|
@ -31,9 +27,7 @@ public class RegisterProgressFragment extends Fragment {
|
||||||
private String password;
|
private String password;
|
||||||
private String email;
|
private String email;
|
||||||
private RegisterTask registerTask;
|
private RegisterTask registerTask;
|
||||||
@Bind(R.id.register_viewswitcher) ViewSwitcher switcher;
|
private FragmentRegisterprogressBinding binding;
|
||||||
@Bind(R.id.registering_next_1) Button next;
|
|
||||||
@Bind(R.id.registerprogress_logo) ImageView registerProgressLogo;
|
|
||||||
|
|
||||||
public static RegisterProgressFragment getInstance(String username, String password, String email) {
|
public static RegisterProgressFragment getInstance(String username, String password, String email) {
|
||||||
RegisterProgressFragment fragment = new RegisterProgressFragment();
|
RegisterProgressFragment fragment = new RegisterProgressFragment();
|
||||||
|
@ -59,12 +53,12 @@ public class RegisterProgressFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.fragment_registerprogress, null);
|
View v = inflater.inflate(R.layout.fragment_registerprogress, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = FragmentRegisterprogressBinding.bind(v);
|
||||||
|
|
||||||
registerProgressLogo.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.rotate));
|
binding.registerprogressLogo.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.rotate));
|
||||||
|
|
||||||
if (registerTask != null) {
|
if (registerTask != null) {
|
||||||
switcher.showNext();
|
binding.registerViewswitcher.showNext();
|
||||||
} else {
|
} else {
|
||||||
registerTask = new RegisterTask();
|
registerTask = new RegisterTask();
|
||||||
registerTask.execute();
|
registerTask.execute();
|
||||||
|
@ -73,7 +67,18 @@ public class RegisterProgressFragment extends Fragment {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.registering_next_1) void next() {
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
binding.registeringNext1.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void next() {
|
||||||
Intent i = new Intent(getActivity(), AddSocial.class);
|
Intent i = new Intent(getActivity(), AddSocial.class);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +93,7 @@ public class RegisterProgressFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(RegisterResponse response) {
|
protected void onPostExecute(RegisterResponse response) {
|
||||||
if (response.authenticated) {
|
if (response.authenticated) {
|
||||||
switcher.showNext();
|
binding.registerViewswitcher.showNext();
|
||||||
} else {
|
} else {
|
||||||
String errorMessage = response.getErrorMessage();
|
String errorMessage = response.getErrorMessage();
|
||||||
if(errorMessage == null) {
|
if(errorMessage == null) {
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.DialogRenameBinding;
|
||||||
|
import com.newsblur.domain.Feed;
|
||||||
|
import com.newsblur.network.APIManager;
|
||||||
|
import com.newsblur.util.AppConstants;
|
||||||
|
import com.newsblur.util.FeedUtils;
|
||||||
|
|
||||||
|
public class RenameDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
|
private static final String FEED = "feed";
|
||||||
|
private static final String FOLDER = "folder";
|
||||||
|
private static final String FOLDER_NAME = "folder_name";
|
||||||
|
private static final String FOLDER_PARENT = "folder_parent";
|
||||||
|
private static final String RENAME_TYPE = "rename_type";
|
||||||
|
|
||||||
|
public static RenameDialogFragment newInstance(Feed feed) {
|
||||||
|
RenameDialogFragment fragment = new RenameDialogFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putSerializable(FEED, feed);
|
||||||
|
args.putString(RENAME_TYPE, FEED);
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RenameDialogFragment newInstance(String folderName, String folderParent) {
|
||||||
|
RenameDialogFragment fragment = new RenameDialogFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(FOLDER_NAME, folderName);
|
||||||
|
args.putString(FOLDER_PARENT, folderParent);
|
||||||
|
args.putString(RENAME_TYPE, FOLDER);
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||||
|
View v = inflater.inflate(R.layout.dialog_rename, null);
|
||||||
|
final DialogRenameBinding binding = DialogRenameBinding.bind(v);
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
|
builder.setView(v);
|
||||||
|
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
RenameDialogFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (getArguments().getString(RENAME_TYPE).equals(FEED)) {
|
||||||
|
final Feed feed = (Feed) getArguments().getSerializable(FEED);
|
||||||
|
builder.setTitle(String.format(getResources().getString(R.string.title_rename_feed), feed.title));
|
||||||
|
binding.inputName.setText(feed.title);
|
||||||
|
builder.setPositiveButton(R.string.feed_name_save, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
FeedUtils.renameFeed(activity, feed.feedId, binding.inputName.getText().toString());
|
||||||
|
RenameDialogFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else { // FOLDER
|
||||||
|
final String folderName = getArguments().getString(FOLDER_NAME);
|
||||||
|
final String folderParentName = getArguments().getString(FOLDER_PARENT);
|
||||||
|
|
||||||
|
builder.setTitle(String.format(getResources().getString(R.string.title_rename_folder), folderName));
|
||||||
|
binding.inputName.setText(folderName);
|
||||||
|
|
||||||
|
builder.setPositiveButton(R.string.folder_name_save, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
String newFolderName = binding.inputName.getText().toString().toUpperCase();
|
||||||
|
if (TextUtils.isEmpty(newFolderName)) {
|
||||||
|
Toast.makeText(activity, R.string.add_folder_name, Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String inFolder = "";
|
||||||
|
if (!TextUtils.isEmpty(folderParentName) && !folderParentName.equals(AppConstants.ROOT_FOLDER)) {
|
||||||
|
inFolder = folderParentName;
|
||||||
|
}
|
||||||
|
FeedUtils.renameFolder(folderName, newFolderName, inFolder, activity, new APIManager(activity));
|
||||||
|
RenameDialogFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,69 +0,0 @@
|
||||||
package com.newsblur.fragment;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.v4.app.DialogFragment;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
|
||||||
import com.newsblur.domain.Feed;
|
|
||||||
import com.newsblur.util.FeedUtils;
|
|
||||||
|
|
||||||
public class RenameFeedFragment extends DialogFragment {
|
|
||||||
|
|
||||||
private Feed feed;
|
|
||||||
|
|
||||||
@Bind(R.id.feed_name_field) EditText feedNameView;
|
|
||||||
|
|
||||||
public static RenameFeedFragment newInstance(Feed feed) {
|
|
||||||
RenameFeedFragment fragment = new RenameFeedFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putSerializable("feed", feed);
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
feed = (Feed) getArguments().getSerializable("feed");
|
|
||||||
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
|
||||||
View v = inflater.inflate(R.layout.dialog_rename_feed, null);
|
|
||||||
ButterKnife.bind(this, v);
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
||||||
builder.setTitle(String.format(getResources().getString(R.string.title_rename_feed), feed.title));
|
|
||||||
builder.setView(v);
|
|
||||||
|
|
||||||
feedNameView.setText(feed.title);
|
|
||||||
|
|
||||||
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
RenameFeedFragment.this.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setPositiveButton(R.string.feed_name_save, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
FeedUtils.renameFeed(activity, feed.feedId, feedNameView.getText().toString());
|
|
||||||
RenameFeedFragment.this.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Dialog dialog = builder.create();
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.newsblur.fragment;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
|
||||||
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.network.APIManager;
|
||||||
|
import com.newsblur.util.FeedUtils;
|
||||||
|
|
||||||
|
public class SaveSearchFragment extends DialogFragment {
|
||||||
|
|
||||||
|
private static final String FEED_ID = "feed_id";
|
||||||
|
private static final String QUERY = "query";
|
||||||
|
|
||||||
|
public static SaveSearchFragment newInstance(String feedId, String query) {
|
||||||
|
SaveSearchFragment frag = new SaveSearchFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(FEED_ID, feedId);
|
||||||
|
args.putString(QUERY, query);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
builder.setMessage(String.format(getResources().getString(R.string.add_saved_search_message), getArguments().getString(QUERY)));
|
||||||
|
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
FeedUtils.saveSearch(getArguments().getString(FEED_ID), getArguments().getString(QUERY), getActivity(), new APIManager(getActivity()));
|
||||||
|
SaveSearchFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
SaveSearchFragment.this.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import com.newsblur.domain.UserProfile;
|
||||||
import com.newsblur.fragment.ReplyDialogFragment;
|
import com.newsblur.fragment.ReplyDialogFragment;
|
||||||
import com.newsblur.util.FeedUtils;
|
import com.newsblur.util.FeedUtils;
|
||||||
import com.newsblur.util.PrefsUtils;
|
import com.newsblur.util.PrefsUtils;
|
||||||
|
import com.newsblur.util.UIUtils;
|
||||||
import com.newsblur.util.ViewUtils;
|
import com.newsblur.util.ViewUtils;
|
||||||
import com.newsblur.view.FlowLayout;
|
import com.newsblur.view.FlowLayout;
|
||||||
|
|
||||||
|
@ -96,7 +97,7 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
||||||
|
|
||||||
View commentView = inflater.inflate(R.layout.include_comment, null);
|
View commentView = inflater.inflate(R.layout.include_comment, null);
|
||||||
TextView commentText = (TextView) commentView.findViewById(R.id.comment_text);
|
TextView commentText = (TextView) commentView.findViewById(R.id.comment_text);
|
||||||
commentText.setText(comment.commentText);
|
commentText.setText(UIUtils.fromHtml(comment.commentText));
|
||||||
ImageView commentImage = (ImageView) commentView.findViewById(R.id.comment_user_image);
|
ImageView commentImage = (ImageView) commentView.findViewById(R.id.comment_user_image);
|
||||||
|
|
||||||
TextView commentSharedDate = (TextView) commentView.findViewById(R.id.comment_shareddate);
|
TextView commentSharedDate = (TextView) commentView.findViewById(R.id.comment_shareddate);
|
||||||
|
@ -161,7 +162,7 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
||||||
for (final Reply reply : replies) {
|
for (final Reply reply : replies) {
|
||||||
View replyView = inflater.inflate(R.layout.include_reply, null);
|
View replyView = inflater.inflate(R.layout.include_reply, null);
|
||||||
TextView replyText = (TextView) replyView.findViewById(R.id.reply_text);
|
TextView replyText = (TextView) replyView.findViewById(R.id.reply_text);
|
||||||
replyText.setText(reply.text);
|
replyText.setText(UIUtils.fromHtml(reply.text));
|
||||||
ImageView replyImage = (ImageView) replyView.findViewById(R.id.reply_user_image);
|
ImageView replyImage = (ImageView) replyView.findViewById(R.id.reply_user_image);
|
||||||
|
|
||||||
final UserProfile replyUser = FeedUtils.dbHelper.getUserProfile(reply.userId);
|
final UserProfile replyUser = FeedUtils.dbHelper.getUserProfile(reply.userId);
|
||||||
|
|
|
@ -14,20 +14,15 @@ import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.DialogTrainstoryBinding;
|
||||||
import com.newsblur.domain.Classifier;
|
import com.newsblur.domain.Classifier;
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
import com.newsblur.util.FeedSet;
|
import com.newsblur.util.FeedSet;
|
||||||
import com.newsblur.util.FeedUtils;
|
import com.newsblur.util.FeedUtils;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
import com.newsblur.view.SelectOnlyEditText;
|
|
||||||
|
|
||||||
public class StoryIntelTrainerFragment extends DialogFragment {
|
public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
|
|
||||||
|
@ -35,17 +30,7 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
private FeedSet fs;
|
private FeedSet fs;
|
||||||
private Classifier classifier;
|
private Classifier classifier;
|
||||||
private Integer newTitleTraining;
|
private Integer newTitleTraining;
|
||||||
|
private DialogTrainstoryBinding binding;
|
||||||
@Bind(R.id.intel_tag_header) TextView headerTags;
|
|
||||||
@Bind(R.id.intel_author_header) TextView headerAuthor;
|
|
||||||
@Bind(R.id.intel_title_selection) SelectOnlyEditText titleSelection;
|
|
||||||
@Bind(R.id.intel_title_like) Button titleLikeButton;
|
|
||||||
@Bind(R.id.intel_title_dislike) Button titleDislikeButton;
|
|
||||||
@Bind(R.id.intel_title_clear) Button titleClearButton;
|
|
||||||
@Bind(R.id.existing_title_intel_container) LinearLayout titleRowsContainer;
|
|
||||||
@Bind(R.id.existing_tag_intel_container) LinearLayout tagRowsContainer;
|
|
||||||
@Bind(R.id.existing_author_intel_container) LinearLayout authorRowsContainer;
|
|
||||||
@Bind(R.id.existing_feed_intel_container) LinearLayout feedRowsContainer;
|
|
||||||
|
|
||||||
public static StoryIntelTrainerFragment newInstance(Story story, FeedSet fs) {
|
public static StoryIntelTrainerFragment newInstance(Story story, FeedSet fs) {
|
||||||
if (story.feedId.equals("0")) {
|
if (story.feedId.equals("0")) {
|
||||||
|
@ -69,44 +54,44 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||||
View v = inflater.inflate(R.layout.dialog_trainstory, null);
|
View v = inflater.inflate(R.layout.dialog_trainstory, null);
|
||||||
ButterKnife.bind(this, v);
|
binding = DialogTrainstoryBinding.bind(v);
|
||||||
|
|
||||||
// set up the special title training box for the title from this story and the associated buttons
|
// set up the special title training box for the title from this story and the associated buttons
|
||||||
titleSelection.setText(story.title);
|
binding.intelTitleSelection.setText(story.title);
|
||||||
// the layout sets inputType="none" on this EditText, but a widespread platform bug requires us
|
// the layout sets inputType="none" on this EditText, but a widespread platform bug requires us
|
||||||
// to also set this programmatically to make the field read-only for selection.
|
// to also set this programmatically to make the field read-only for selection.
|
||||||
titleSelection.setInputType(InputType.TYPE_NULL);
|
binding.intelTitleSelection.setInputType(InputType.TYPE_NULL);
|
||||||
// the user is selecting for our custom widget, not to copy/paste
|
// the user is selecting for our custom widget, not to copy/paste
|
||||||
titleSelection.disableActionMenu();
|
binding.intelTitleSelection.disableActionMenu();
|
||||||
// pre-select the whole title to make it easier for the user to manipulate the selection handles
|
// pre-select the whole title to make it easier for the user to manipulate the selection handles
|
||||||
titleSelection.selectAll();
|
binding.intelTitleSelection.selectAll();
|
||||||
// do this after init and selection to prevent toast spam
|
// do this after init and selection to prevent toast spam
|
||||||
titleSelection.setForceSelection(true);
|
binding.intelTitleSelection.setForceSelection(true);
|
||||||
// the disposition buttons for a new title training don't immediately impact the classifier object,
|
// the disposition buttons for a new title training don't immediately impact the classifier object,
|
||||||
// lest the user want to change selection substring after choosing the disposition. so just store
|
// lest the user want to change selection substring after choosing the disposition. so just store
|
||||||
// the training factor in a variable that can be pulled on completion
|
// the training factor in a variable that can be pulled on completion
|
||||||
titleLikeButton.setOnClickListener(new OnClickListener() {
|
binding.intelTitleLike.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
newTitleTraining = Classifier.LIKE;
|
newTitleTraining = Classifier.LIKE;
|
||||||
titleLikeButton.setBackgroundResource(R.drawable.ic_like_active);
|
binding.intelTitleLike.setBackgroundResource(R.drawable.ic_like_active);
|
||||||
titleDislikeButton.setBackgroundResource(R.drawable.ic_dislike_gray55);
|
binding.intelTitleDislike.setBackgroundResource(R.drawable.ic_dislike_gray55);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
titleDislikeButton.setOnClickListener(new OnClickListener() {
|
binding.intelTitleDislike.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
newTitleTraining = Classifier.DISLIKE;
|
newTitleTraining = Classifier.DISLIKE;
|
||||||
titleLikeButton.setBackgroundResource(R.drawable.ic_like_gray55);
|
binding.intelTitleLike.setBackgroundResource(R.drawable.ic_like_gray55);
|
||||||
titleDislikeButton.setBackgroundResource(R.drawable.ic_dislike_active);
|
binding.intelTitleDislike.setBackgroundResource(R.drawable.ic_dislike_active);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
titleClearButton.setOnClickListener(new OnClickListener() {
|
binding.intelTitleClear.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
newTitleTraining = null;
|
newTitleTraining = null;
|
||||||
titleLikeButton.setBackgroundResource(R.drawable.ic_like_gray55);
|
binding.intelTitleLike.setBackgroundResource(R.drawable.ic_like_gray55);
|
||||||
titleDislikeButton.setBackgroundResource(R.drawable.ic_dislike_gray55);
|
binding.intelTitleDislike.setBackgroundResource(R.drawable.ic_dislike_gray55);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -117,7 +102,7 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
||||||
label.setText(rule.getKey());
|
label.setText(rule.getKey());
|
||||||
UIUtils.setupIntelDialogRow(row, classifier.title, rule.getKey());
|
UIUtils.setupIntelDialogRow(row, classifier.title, rule.getKey());
|
||||||
titleRowsContainer.addView(row);
|
binding.existingTitleIntelContainer.addView(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,9 +112,9 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
TextView label = (TextView) row.findViewById(R.id.intel_row_label);
|
||||||
label.setText(tag);
|
label.setText(tag);
|
||||||
UIUtils.setupIntelDialogRow(row, classifier.tags, tag);
|
UIUtils.setupIntelDialogRow(row, classifier.tags, tag);
|
||||||
tagRowsContainer.addView(row);
|
binding.existingTagIntelContainer.addView(row);
|
||||||
}
|
}
|
||||||
if (story.tags.length < 1) headerTags.setVisibility(View.GONE);
|
if (story.tags.length < 1) binding.intelTagHeader.setVisibility(View.GONE);
|
||||||
|
|
||||||
// there is a single author per story
|
// there is a single author per story
|
||||||
if (!TextUtils.isEmpty(story.authors)) {
|
if (!TextUtils.isEmpty(story.authors)) {
|
||||||
|
@ -137,9 +122,9 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
TextView labelAuthor = (TextView) rowAuthor.findViewById(R.id.intel_row_label);
|
TextView labelAuthor = (TextView) rowAuthor.findViewById(R.id.intel_row_label);
|
||||||
labelAuthor.setText(story.authors);
|
labelAuthor.setText(story.authors);
|
||||||
UIUtils.setupIntelDialogRow(rowAuthor, classifier.authors, story.authors);
|
UIUtils.setupIntelDialogRow(rowAuthor, classifier.authors, story.authors);
|
||||||
authorRowsContainer.addView(rowAuthor);
|
binding.existingAuthorIntelContainer.addView(rowAuthor);
|
||||||
} else {
|
} else {
|
||||||
headerAuthor.setVisibility(View.GONE);
|
binding.intelAuthorHeader.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// there is a single feed to be trained, but it is a bit odd in that the label is the title and
|
// there is a single feed to be trained, but it is a bit odd in that the label is the title and
|
||||||
|
@ -148,7 +133,7 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
TextView labelFeed = (TextView) rowFeed.findViewById(R.id.intel_row_label);
|
TextView labelFeed = (TextView) rowFeed.findViewById(R.id.intel_row_label);
|
||||||
labelFeed.setText(FeedUtils.getFeedTitle(story.feedId));
|
labelFeed.setText(FeedUtils.getFeedTitle(story.feedId));
|
||||||
UIUtils.setupIntelDialogRow(rowFeed, classifier.feeds, story.feedId);
|
UIUtils.setupIntelDialogRow(rowFeed, classifier.feeds, story.feedId);
|
||||||
feedRowsContainer.addView(rowFeed);
|
binding.existingFeedIntelContainer.addView(rowFeed);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle(R.string.story_intel_dialog_title);
|
builder.setTitle(R.string.story_intel_dialog_title);
|
||||||
|
@ -163,8 +148,8 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
||||||
builder.setPositiveButton(R.string.dialog_story_intel_save, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.dialog_story_intel_save, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
if ((newTitleTraining != null) && (!TextUtils.isEmpty(titleSelection.getSelection()))) {
|
if ((newTitleTraining != null) && (!TextUtils.isEmpty(binding.intelTitleSelection.getSelection()))) {
|
||||||
classifier.title.put(titleSelection.getSelection(), newTitleTraining);
|
classifier.title.put(binding.intelTitleSelection.getSelection(), newTitleTraining);
|
||||||
}
|
}
|
||||||
FeedUtils.updateClassifier(story.feedId, classifier, fs, activity);
|
FeedUtils.updateClassifier(story.feedId, classifier, fs, activity);
|
||||||
StoryIntelTrainerFragment.this.dismiss();
|
StoryIntelTrainerFragment.this.dismiss();
|
||||||
|
|
|
@ -7,13 +7,9 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.widget.RadioButton;
|
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.StoryorderDialogBinding;
|
||||||
import com.newsblur.util.StoryOrder;
|
import com.newsblur.util.StoryOrder;
|
||||||
import com.newsblur.util.StoryOrderChangedListener;
|
import com.newsblur.util.StoryOrderChangedListener;
|
||||||
|
|
||||||
|
@ -21,8 +17,6 @@ public class StoryOrderDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
private static String CURRENT_ORDER = "currentOrder";
|
private static String CURRENT_ORDER = "currentOrder";
|
||||||
private StoryOrder currentValue;
|
private StoryOrder currentValue;
|
||||||
@Bind(R.id.radio_newest) RadioButton newestButton;
|
|
||||||
@Bind(R.id.radio_oldest) RadioButton oldestButton;
|
|
||||||
|
|
||||||
public static StoryOrderDialogFragment newInstance(StoryOrder currentValue) {
|
public static StoryOrderDialogFragment newInstance(StoryOrder currentValue) {
|
||||||
StoryOrderDialogFragment dialog = new StoryOrderDialogFragment();
|
StoryOrderDialogFragment dialog = new StoryOrderDialogFragment();
|
||||||
|
@ -42,25 +36,38 @@ public class StoryOrderDialogFragment extends DialogFragment {
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||||
currentValue = (StoryOrder) getArguments().getSerializable(CURRENT_ORDER);
|
currentValue = (StoryOrder) getArguments().getSerializable(CURRENT_ORDER);
|
||||||
View v = inflater.inflate(R.layout.storyorder_dialog, null);
|
View v = inflater.inflate(R.layout.storyorder_dialog, null);
|
||||||
ButterKnife.bind(this, v);
|
StoryorderDialogBinding binding = StoryorderDialogBinding.bind(v);
|
||||||
|
|
||||||
newestButton.setChecked(currentValue == StoryOrder.NEWEST);
|
binding.radioNewest.setChecked(currentValue == StoryOrder.NEWEST);
|
||||||
oldestButton.setChecked(currentValue == StoryOrder.OLDEST);
|
binding.radioOldest.setChecked(currentValue == StoryOrder.OLDEST);
|
||||||
|
|
||||||
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
getDialog().getWindow().getAttributes().gravity = Gravity.BOTTOM;
|
||||||
|
|
||||||
|
binding.radioNewest.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
selectNewest();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.radioOldest.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
selectOldest();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.radio_newest) void selectNewest() {
|
private void selectNewest() {
|
||||||
if (currentValue != StoryOrder.NEWEST) {
|
if (currentValue != StoryOrder.NEWEST) {
|
||||||
((StoryOrderChangedListener) getActivity()).storyOrderChanged(StoryOrder.NEWEST);
|
((StoryOrderChangedListener) getActivity()).storyOrderChanged(StoryOrder.NEWEST);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.radio_oldest) void selectOldest() {
|
private void selectOldest() {
|
||||||
if (currentValue != StoryOrder.OLDEST) {
|
if (currentValue != StoryOrder.OLDEST) {
|
||||||
((StoryOrderChangedListener) getActivity()).storyOrderChanged(StoryOrder.OLDEST);
|
((StoryOrderChangedListener) getActivity()).storyOrderChanged(StoryOrder.OLDEST);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,11 @@ public class APIConstants {
|
||||||
public static final String PATH_SET_NOTIFICATIONS = "/notifications/feed/";
|
public static final String PATH_SET_NOTIFICATIONS = "/notifications/feed/";
|
||||||
public static final String PATH_INSTA_FETCH = "/rss_feeds/exception_retry";
|
public static final String PATH_INSTA_FETCH = "/rss_feeds/exception_retry";
|
||||||
public static final String PATH_RENAME_FEED = "/reader/rename_feed";
|
public static final String PATH_RENAME_FEED = "/reader/rename_feed";
|
||||||
|
public static final String PATH_DELETE_SEARCH = "/reader/delete_search";
|
||||||
|
public static final String PATH_SAVE_SEARCH = "/reader/save_search";
|
||||||
|
public static final String PATH_ADD_FOLDER = "/reader/add_folder";
|
||||||
|
public static final String PATH_DELETE_FOLDER = "/reader/delete_folder";
|
||||||
|
public static final String PATH_RENAME_FOLDER = "/reader/rename_folder";
|
||||||
|
|
||||||
public static String buildUrl(String path) {
|
public static String buildUrl(String path) {
|
||||||
return CurrentUrlBase + path;
|
return CurrentUrlBase + path;
|
||||||
|
@ -121,6 +126,9 @@ public class APIConstants {
|
||||||
public static final String PARAMETER_RESET_FETCH = "reset_fetch";
|
public static final String PARAMETER_RESET_FETCH = "reset_fetch";
|
||||||
public static final String PARAMETER_INFREQUENT = "infrequent";
|
public static final String PARAMETER_INFREQUENT = "infrequent";
|
||||||
public static final String PARAMETER_FEEDTITLE = "feed_title";
|
public static final String PARAMETER_FEEDTITLE = "feed_title";
|
||||||
|
public static final String PARAMETER_FOLDER_TO_DELETE = "folder_to_delete";
|
||||||
|
public static final String PARAMETER_FOLDER_TO_RENAME = "folder_to_rename";
|
||||||
|
public static final String PARAMETER_NEW_FOLDER_NAME = "new_folder_name";
|
||||||
|
|
||||||
public static final String VALUE_PREFIX_SOCIAL = "social:";
|
public static final String VALUE_PREFIX_SOCIAL = "social:";
|
||||||
public static final String VALUE_ALLSOCIAL = "river:blurblogs"; // the magic value passed to the mark-read API for all social feeds
|
public static final String VALUE_ALLSOCIAL = "river:blurblogs"; // the magic value passed to the mark-read API for all social feeds
|
||||||
|
|
|
@ -15,6 +15,7 @@ import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
@ -550,11 +551,21 @@ public class APIManager {
|
||||||
return (CommentResponse) response.getResponse(gson, CommentResponse.class);
|
return (CommentResponse) response.getResponse(gson, CommentResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddFeedResponse addFeed(String feedUrl) {
|
public NewsBlurResponse addFolder(String folderName) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(APIConstants.PARAMETER_FOLDER, folderName);
|
||||||
|
APIResponse response = post(buildUrl(APIConstants.PATH_ADD_FOLDER), values);
|
||||||
|
return response.getResponse(gson, NewsBlurResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddFeedResponse addFeed(String feedUrl, @Nullable String folderName) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(APIConstants.PARAMETER_URL, feedUrl);
|
values.put(APIConstants.PARAMETER_URL, feedUrl);
|
||||||
|
if (!TextUtils.isEmpty(folderName) && !folderName.equals(AppConstants.ROOT_FOLDER)) {
|
||||||
|
values.put(APIConstants.PARAMETER_FOLDER, folderName);
|
||||||
|
}
|
||||||
APIResponse response = post(buildUrl(APIConstants.PATH_ADD_FEED), values);
|
APIResponse response = post(buildUrl(APIConstants.PATH_ADD_FEED), values);
|
||||||
return (AddFeedResponse) response.getResponse(gson, AddFeedResponse.class);
|
return response.getResponse(gson, AddFeedResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedResult[] searchForFeed(String searchTerm) {
|
public FeedResult[] searchForFeed(String searchTerm) {
|
||||||
|
@ -579,6 +590,30 @@ public class APIManager {
|
||||||
return response.getResponse(gson, NewsBlurResponse.class);
|
return response.getResponse(gson, NewsBlurResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NewsBlurResponse deleteFolder(String folderName, String inFolder) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(APIConstants.PARAMETER_FOLDER_TO_DELETE, folderName);
|
||||||
|
values.put(APIConstants.PARAMETER_IN_FOLDER, inFolder);
|
||||||
|
APIResponse response = post(buildUrl(APIConstants.PATH_DELETE_FOLDER), values);
|
||||||
|
return response.getResponse(gson, NewsBlurResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NewsBlurResponse deleteSearch(String feedId, String query) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(APIConstants.PARAMETER_FEEDID, feedId);
|
||||||
|
values.put(APIConstants.PARAMETER_QUERY, query);
|
||||||
|
APIResponse response = post(buildUrl(APIConstants.PATH_DELETE_SEARCH), values);
|
||||||
|
return response.getResponse(gson, NewsBlurResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NewsBlurResponse saveSearch(String feedId, String query) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(APIConstants.PARAMETER_FEEDID, feedId);
|
||||||
|
values.put(APIConstants.PARAMETER_QUERY, query);
|
||||||
|
APIResponse response = post(buildUrl(APIConstants.PATH_SAVE_SEARCH), values);
|
||||||
|
return response.getResponse(gson, NewsBlurResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
public NewsBlurResponse saveFeedChooser(Set<String> feeds) {
|
public NewsBlurResponse saveFeedChooser(Set<String> feeds) {
|
||||||
ValueMultimap values = new ValueMultimap();
|
ValueMultimap values = new ValueMultimap();
|
||||||
for (String feed : feeds) {
|
for (String feed : feeds) {
|
||||||
|
@ -617,6 +652,15 @@ public class APIManager {
|
||||||
return response.getResponse(gson, NewsBlurResponse.class);
|
return response.getResponse(gson, NewsBlurResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NewsBlurResponse renameFolder(String folderName, String newFolderName, String inFolder) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(APIConstants.PARAMETER_FOLDER_TO_RENAME, folderName);
|
||||||
|
values.put(APIConstants.PARAMETER_NEW_FOLDER_NAME, newFolderName);
|
||||||
|
values.put(APIConstants.PARAMETER_IN_FOLDER, inFolder);
|
||||||
|
APIResponse response = post(buildUrl(APIConstants.PATH_RENAME_FOLDER), values);
|
||||||
|
return response.getResponse(gson, NewsBlurResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
/* HTTP METHODS */
|
/* HTTP METHODS */
|
||||||
|
|
||||||
private APIResponse get(final String urlString) {
|
private APIResponse get(final String urlString) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.domain.Folder;
|
import com.newsblur.domain.Folder;
|
||||||
|
import com.newsblur.domain.SavedSearch;
|
||||||
import com.newsblur.domain.SocialFeed;
|
import com.newsblur.domain.SocialFeed;
|
||||||
import com.newsblur.domain.StarredCount;
|
import com.newsblur.domain.StarredCount;
|
||||||
import com.newsblur.util.AppConstants;
|
import com.newsblur.util.AppConstants;
|
||||||
|
@ -30,6 +31,7 @@ public class FeedFolderResponse {
|
||||||
public Set<Feed> feeds;
|
public Set<Feed> feeds;
|
||||||
public Set<SocialFeed> socialFeeds;
|
public Set<SocialFeed> socialFeeds;
|
||||||
public Set<StarredCount> starredCounts;
|
public Set<StarredCount> starredCounts;
|
||||||
|
public Set<SavedSearch> savedSearches;
|
||||||
|
|
||||||
public boolean isAuthenticated;
|
public boolean isAuthenticated;
|
||||||
public boolean isPremium;
|
public boolean isPremium;
|
||||||
|
@ -109,6 +111,16 @@ public class FeedFolderResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
savedSearches = new HashSet<>();
|
||||||
|
JsonArray savedSearchesArray = (JsonArray) asJsonObject.get("saved_searches");
|
||||||
|
if (savedSearchesArray != null) {
|
||||||
|
for (int i=0; i<savedSearchesArray.size(); i++) {
|
||||||
|
JsonElement jsonElement = savedSearchesArray.get(i);
|
||||||
|
SavedSearch savedSearch = gson.fromJson(jsonElement, SavedSearch.class);
|
||||||
|
savedSearches.add(savedSearch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parseTime = System.currentTimeMillis() - startTime;
|
parseTime = System.currentTimeMillis() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ public class StoryTypeAdapter implements JsonDeserializer<Story> {
|
||||||
|
|
||||||
// any characters we don't want in the short description, such as newlines or placeholders
|
// any characters we don't want in the short description, such as newlines or placeholders
|
||||||
private final static Pattern ShortContentExcludes = Pattern.compile("[\\uFFFC\\u000A\\u000B\\u000C\\u000D]");
|
private final static Pattern ShortContentExcludes = Pattern.compile("[\\uFFFC\\u000A\\u000B\\u000C\\u000D]");
|
||||||
|
private final static Pattern httpSniff = Pattern.compile("(?:http):\\/\\/");
|
||||||
|
|
||||||
public StoryTypeAdapter() {
|
public StoryTypeAdapter() {
|
||||||
this.gson = new GsonBuilder()
|
this.gson = new GsonBuilder()
|
||||||
|
@ -39,6 +40,14 @@ public class StoryTypeAdapter implements JsonDeserializer<Story> {
|
||||||
|
|
||||||
// Convert story_timestamp to milliseconds
|
// Convert story_timestamp to milliseconds
|
||||||
story.timestamp = story.timestamp * 1000;
|
story.timestamp = story.timestamp * 1000;
|
||||||
|
|
||||||
|
// replace http image urls with https
|
||||||
|
if (httpSniff.matcher(story.content).find() && story.secureImageUrls != null && story.secureImageUrls.size() > 0) {
|
||||||
|
for (String httpUrl : story.secureImageUrls.keySet()) {
|
||||||
|
String httpsUrl = story.secureImageUrls.get(httpUrl);
|
||||||
|
story.content = story.content.replace(httpUrl, httpsUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// populate the shortContent field
|
// populate the shortContent field
|
||||||
if (story.content != null) {
|
if (story.content != null) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import static com.newsblur.database.BlurDatabaseHelper.closeQuietly;
|
||||||
import com.newsblur.database.DatabaseConstants;
|
import com.newsblur.database.DatabaseConstants;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.domain.Folder;
|
import com.newsblur.domain.Folder;
|
||||||
|
import com.newsblur.domain.SavedSearch;
|
||||||
import com.newsblur.domain.SocialFeed;
|
import com.newsblur.domain.SocialFeed;
|
||||||
import com.newsblur.domain.StarredCount;
|
import com.newsblur.domain.StarredCount;
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
|
@ -586,6 +587,12 @@ public class NBSyncService extends JobService {
|
||||||
for (StarredCount sc : feedResponse.starredCounts) {
|
for (StarredCount sc : feedResponse.starredCounts) {
|
||||||
starredCountValues.add(sc.getValues());
|
starredCountValues.add(sc.getValues());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// saved searches table
|
||||||
|
List<ContentValues> savedSearchesValues = new ArrayList<>();
|
||||||
|
for (SavedSearch savedSearch : feedResponse.savedSearches) {
|
||||||
|
savedSearchesValues.add(savedSearch.getValues());
|
||||||
|
}
|
||||||
// the API vends the starred total as a different element, roll it into
|
// the API vends the starred total as a different element, roll it into
|
||||||
// the starred counts table using a special tag
|
// the starred counts table using a special tag
|
||||||
StarredCount totalStarred = new StarredCount();
|
StarredCount totalStarred = new StarredCount();
|
||||||
|
@ -593,7 +600,7 @@ public class NBSyncService extends JobService {
|
||||||
totalStarred.tag = StarredCount.TOTAL_STARRED;
|
totalStarred.tag = StarredCount.TOTAL_STARRED;
|
||||||
starredCountValues.add(totalStarred.getValues());
|
starredCountValues.add(totalStarred.getValues());
|
||||||
|
|
||||||
dbHelper.setFeedsFolders(folderValues, feedValues, socialFeedValues, starredCountValues);
|
dbHelper.setFeedsFolders(folderValues, feedValues, socialFeedValues, starredCountValues, savedSearchesValues);
|
||||||
|
|
||||||
lastFFWriteMillis = System.currentTimeMillis() - startTime;
|
lastFFWriteMillis = System.currentTimeMillis() - startTime;
|
||||||
lastFeedCount = feedValues.size();
|
lastFeedCount = feedValues.size();
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.newsblur.util;
|
||||||
|
|
||||||
|
public enum DefaultBrowser {
|
||||||
|
SYSTEM_DEFAULT,
|
||||||
|
IN_APP_BROWSER,
|
||||||
|
CHROME,
|
||||||
|
FIREFOX,
|
||||||
|
OPERA_MINI;
|
||||||
|
|
||||||
|
public static DefaultBrowser getDefaultBrowser(String preferenceValue) {
|
||||||
|
switch (preferenceValue) {
|
||||||
|
case "IN_APP_BROWSER":
|
||||||
|
return IN_APP_BROWSER;
|
||||||
|
case "CHROME":
|
||||||
|
return CHROME;
|
||||||
|
case "FIREFOX":
|
||||||
|
return FIREFOX;
|
||||||
|
case "OPERA_MINI":
|
||||||
|
return OPERA_MINI;
|
||||||
|
case "SYSTEM_DEFAULT":
|
||||||
|
default:
|
||||||
|
return SYSTEM_DEFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ public class FeedSet implements Serializable {
|
||||||
|
|
||||||
private String folderName;
|
private String folderName;
|
||||||
private String searchQuery;
|
private String searchQuery;
|
||||||
|
private String searchFeedId;
|
||||||
private boolean isFilterSaved = false;
|
private boolean isFilterSaved = false;
|
||||||
private boolean muted = false;
|
private boolean muted = false;
|
||||||
|
|
||||||
|
@ -75,17 +76,6 @@ public class FeedSet implements Serializable {
|
||||||
return fs;
|
return fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience constructor for multiple feeds with IDs
|
|
||||||
*/
|
|
||||||
public static FeedSet multipleFeeds(Set<String> feedIds) {
|
|
||||||
FeedSet fs = new FeedSet();
|
|
||||||
fs.feeds = new HashSet<>(feedIds.size());
|
|
||||||
fs.feeds.addAll(feedIds);
|
|
||||||
fs.feeds = Collections.unmodifiableSet(fs.feeds);
|
|
||||||
return fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience constructor for all (non-social) feeds.
|
* Convenience constructor for all (non-social) feeds.
|
||||||
*/
|
*/
|
||||||
|
@ -133,6 +123,16 @@ public class FeedSet implements Serializable {
|
||||||
return fs;
|
return fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience constructor for a single saved search.
|
||||||
|
*/
|
||||||
|
public static FeedSet singleSavedSearch(String feedId, String searchQuery) {
|
||||||
|
FeedSet fs = new FeedSet();
|
||||||
|
fs.searchQuery = searchQuery;
|
||||||
|
fs.searchFeedId = feedId;
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience constructor for global shared stories feed.
|
* Convenience constructor for global shared stories feed.
|
||||||
*/
|
*/
|
||||||
|
@ -281,6 +281,10 @@ public class FeedSet implements Serializable {
|
||||||
return this.searchQuery;
|
return this.searchQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSearchFeedId() {
|
||||||
|
return this.searchFeedId;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFilterSaved(boolean isFilterSaved) {
|
public void setFilterSaved(boolean isFilterSaved) {
|
||||||
this.isFilterSaved = isFilterSaved;
|
this.isFilterSaved = isFilterSaved;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Set;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
@ -18,6 +19,7 @@ import com.newsblur.domain.Classifier;
|
||||||
import com.newsblur.domain.Feed;
|
import com.newsblur.domain.Feed;
|
||||||
import com.newsblur.domain.Folder;
|
import com.newsblur.domain.Folder;
|
||||||
import com.newsblur.domain.SocialFeed;
|
import com.newsblur.domain.SocialFeed;
|
||||||
|
import com.newsblur.domain.StarredCount;
|
||||||
import com.newsblur.domain.Story;
|
import com.newsblur.domain.Story;
|
||||||
import com.newsblur.fragment.ReadingActionConfirmationFragment;
|
import com.newsblur.fragment.ReadingActionConfirmationFragment;
|
||||||
import com.newsblur.network.APIManager;
|
import com.newsblur.network.APIManager;
|
||||||
|
@ -109,6 +111,40 @@ public class FeedUtils {
|
||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void deleteSavedSearch(final String feedId, final String query, final Context context, final APIManager apiManager) {
|
||||||
|
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||||
|
@Override
|
||||||
|
protected NewsBlurResponse doInBackground(Void... voids) {
|
||||||
|
return apiManager.deleteSearch(feedId, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(NewsBlurResponse newsBlurResponse) {
|
||||||
|
if (!newsBlurResponse.isError()) {
|
||||||
|
dbHelper.deleteSavedSearch(feedId, query);
|
||||||
|
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveSearch(final String feedId, final String query, final Context context, final APIManager apiManager) {
|
||||||
|
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||||
|
@Override
|
||||||
|
protected NewsBlurResponse doInBackground(Void... voids) {
|
||||||
|
return apiManager.saveSearch(feedId, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(NewsBlurResponse newsBlurResponse) {
|
||||||
|
if (!newsBlurResponse.isError()) {
|
||||||
|
NBSyncService.forceFeedsFolders();
|
||||||
|
triggerSync(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
public static void deleteFeed(final String feedId, final String folderName, final Context context, final APIManager apiManager) {
|
public static void deleteFeed(final String feedId, final String folderName, final Context context, final APIManager apiManager) {
|
||||||
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -140,6 +176,42 @@ public class FeedUtils {
|
||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void deleteFolder(final String folderName, final String inFolder, final Context context, final APIManager apiManager) {
|
||||||
|
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||||
|
@Override
|
||||||
|
protected NewsBlurResponse doInBackground(Void... voids) {
|
||||||
|
return apiManager.deleteFolder(folderName, inFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(NewsBlurResponse result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
if (!result.isError()) {
|
||||||
|
NBSyncService.forceFeedsFolders();
|
||||||
|
triggerSync(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void renameFolder(final String folderName, final String newFolderName, final String inFolder, final Context context, final APIManager apiManager) {
|
||||||
|
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||||
|
@Override
|
||||||
|
protected NewsBlurResponse doInBackground(Void... voids) {
|
||||||
|
return apiManager.renameFolder(folderName, newFolderName, inFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(NewsBlurResponse result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
if (!result.isError()) {
|
||||||
|
NBSyncService.forceFeedsFolders();
|
||||||
|
triggerSync(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
public static void markStoryUnread(final Story story, final Context context) {
|
public static void markStoryUnread(final Story story, final Context context) {
|
||||||
new AsyncTask<Void, Void, Void>() {
|
new AsyncTask<Void, Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -518,4 +590,8 @@ public class FeedUtils {
|
||||||
return dbHelper.getSocialFeed(feedId);
|
return dbHelper.getSocialFeed(feedId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static StarredCount getStarredFeedByTag(String feedId) {
|
||||||
|
return dbHelper.getStarredFeedByTag(feedId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ public class PrefConstants {
|
||||||
|
|
||||||
public static final String FEED_DEFAULT_FEED_VIEW_PREFIX = "feed_default_feed_view_";
|
public static final String FEED_DEFAULT_FEED_VIEW_PREFIX = "feed_default_feed_view_";
|
||||||
|
|
||||||
|
public static final String DEFAULT_BROWSER = "default_browser";
|
||||||
|
|
||||||
public static final String READ_STORIES_FOLDER_NAME = "read_stories";
|
public static final String READ_STORIES_FOLDER_NAME = "read_stories";
|
||||||
public static final String SAVED_STORIES_FOLDER_NAME = "saved_stories";
|
public static final String SAVED_STORIES_FOLDER_NAME = "saved_stories";
|
||||||
public static final String READING_ENTER_IMMERSIVE_SINGLE_TAP = "immersive_enter_single_tap";
|
public static final String READING_ENTER_IMMERSIVE_SINGLE_TAP = "immersive_enter_single_tap";
|
||||||
|
@ -85,6 +87,7 @@ public class PrefConstants {
|
||||||
|
|
||||||
public static final String THEME = "theme";
|
public static final String THEME = "theme";
|
||||||
public enum ThemeValue {
|
public enum ThemeValue {
|
||||||
|
AUTO,
|
||||||
LIGHT,
|
LIGHT,
|
||||||
DARK,
|
DARK,
|
||||||
BLACK;
|
BLACK;
|
||||||
|
|
|
@ -14,7 +14,11 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Bitmap.CompressFormat;
|
import android.graphics.Bitmap.CompressFormat;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
@ -777,6 +781,15 @@ public class PrefsUtils {
|
||||||
activity.setTheme(R.style.NewsBlurDarkTheme);
|
activity.setTheme(R.style.NewsBlurDarkTheme);
|
||||||
} else if (value == ThemeValue.BLACK) {
|
} else if (value == ThemeValue.BLACK) {
|
||||||
activity.setTheme(R.style.NewsBlurBlackTheme);
|
activity.setTheme(R.style.NewsBlurBlackTheme);
|
||||||
|
} else if (value == ThemeValue.AUTO) {
|
||||||
|
int nightModeFlags = activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||||
|
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
|
||||||
|
activity.setTheme(R.style.NewsBlurDarkTheme);
|
||||||
|
} else if (nightModeFlags == Configuration.UI_MODE_NIGHT_NO) {
|
||||||
|
activity.setTheme(R.style.NewsBlurTheme);
|
||||||
|
} else if (nightModeFlags == Configuration.UI_MODE_NIGHT_UNDEFINED) {
|
||||||
|
activity.setTheme(R.style.NewsBlurTheme);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -945,4 +958,13 @@ public class PrefsUtils {
|
||||||
editor.putString(PrefConstants.WIDGET_BACKGROUND, widgetBackground.toString());
|
editor.putString(PrefConstants.WIDGET_BACKGROUND, widgetBackground.toString());
|
||||||
editor.commit();
|
editor.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DefaultBrowser getDefaultBrowser(Context context) {
|
||||||
|
return DefaultBrowser.getDefaultBrowser(getDefaultBrowserString(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDefaultBrowserString(Context context) {
|
||||||
|
SharedPreferences preferences = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
|
||||||
|
return preferences.getString(PrefConstants.DEFAULT_BROWSER, DefaultBrowser.SYSTEM_DEFAULT.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.newsblur.view;
|
package com.newsblur.view;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
@ -16,8 +17,11 @@ import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import com.newsblur.activity.InAppBrowser;
|
||||||
import com.newsblur.activity.Reading;
|
import com.newsblur.activity.Reading;
|
||||||
import com.newsblur.fragment.ReadingItemFragment;
|
import com.newsblur.fragment.ReadingItemFragment;
|
||||||
|
import com.newsblur.util.DefaultBrowser;
|
||||||
|
import com.newsblur.util.PrefsUtils;
|
||||||
|
|
||||||
public class NewsblurWebview extends WebView {
|
public class NewsblurWebview extends WebView {
|
||||||
|
|
||||||
|
@ -88,21 +92,15 @@ public class NewsblurWebview extends WebView {
|
||||||
|
|
||||||
class NewsblurWebViewClient extends WebViewClient {
|
class NewsblurWebViewClient extends WebViewClient {
|
||||||
@Override
|
@Override
|
||||||
// this was deprecated in API 24 but the replacement only added in the same release.
|
|
||||||
// the suppression can be removed when we move past 24
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
// as of v43.0.2357.121 of the system WebView, links no longer open in the user's chosen
|
|
||||||
// browser, but open in-app. Override the default behaviour so it works as expected on
|
|
||||||
// all devices.
|
|
||||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||||
Uri uri = Uri.parse(url);
|
handleUri(Uri.parse(url));
|
||||||
try {
|
return true;
|
||||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
}
|
||||||
i.setData(uri);
|
|
||||||
context.startActivity(i);
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
} catch (Exception e) {
|
@Override
|
||||||
com.newsblur.util.Log.e(this.getClass().getName(), "device cannot open URLs");
|
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||||
}
|
handleUri(request.getUrl());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +113,46 @@ public class NewsblurWebview extends WebView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleUri(Uri uri) {
|
||||||
|
DefaultBrowser defaultBrowser = PrefsUtils.getDefaultBrowser(context);
|
||||||
|
if (defaultBrowser == DefaultBrowser.SYSTEM_DEFAULT) {
|
||||||
|
openSystemDefaultBrowser(uri);
|
||||||
|
} else if (defaultBrowser == DefaultBrowser.IN_APP_BROWSER) {
|
||||||
|
Intent intent = new Intent(context, InAppBrowser.class);
|
||||||
|
intent.putExtra(InAppBrowser.URI, uri);
|
||||||
|
context.startActivity(intent);
|
||||||
|
} else if (defaultBrowser == DefaultBrowser.CHROME) {
|
||||||
|
openExternalBrowserApp(uri, "com.android.chrome");
|
||||||
|
} else if (defaultBrowser == DefaultBrowser.FIREFOX) {
|
||||||
|
openExternalBrowserApp(uri, "org.mozilla.firefox");
|
||||||
|
} else if (defaultBrowser == DefaultBrowser.OPERA_MINI) {
|
||||||
|
openExternalBrowserApp(uri, "com.opera.mini.native");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openSystemDefaultBrowser(Uri uri) {
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.setData(uri);
|
||||||
|
context.startActivity(intent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
com.newsblur.util.Log.e(this.getClass().getName(), "device cannot open URLs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openExternalBrowserApp(Uri uri, String packageName) {
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.setData(uri);
|
||||||
|
intent.setPackage(packageName);
|
||||||
|
context.startActivity(intent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
com.newsblur.util.Log.e(this.getClass().getName(), "apps not available to open URLs");
|
||||||
|
// fallback to system default if apps cannot be opened
|
||||||
|
openSystemDefaultBrowser(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this WCC implements the bare minimum callbacks to get HTML5 fullscreen video working
|
// this WCC implements the bare minimum callbacks to get HTML5 fullscreen video working
|
||||||
class NewsblurWebChromeClient extends WebChromeClient {
|
class NewsblurWebChromeClient extends WebChromeClient {
|
||||||
public View customView;
|
public View customView;
|
||||||
|
|
|
@ -5,14 +5,10 @@ import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
import com.newsblur.R;
|
import com.newsblur.R;
|
||||||
|
import com.newsblur.databinding.StateToggleBinding;
|
||||||
import com.newsblur.util.StateFilter;
|
import com.newsblur.util.StateFilter;
|
||||||
import com.newsblur.util.UIUtils;
|
import com.newsblur.util.UIUtils;
|
||||||
|
|
||||||
|
@ -27,52 +23,53 @@ public class StateToggleButton extends LinearLayout {
|
||||||
|
|
||||||
private int parentWidthPX = 0;
|
private int parentWidthPX = 0;
|
||||||
|
|
||||||
@Bind(R.id.toggle_all) ViewGroup allButton;
|
private StateToggleBinding binding;
|
||||||
@Bind(R.id.toggle_all_icon) View allButtonIcon;
|
|
||||||
@Bind(R.id.toggle_all_text) View allButtonText;
|
|
||||||
@Bind(R.id.toggle_some) ViewGroup someButton;
|
|
||||||
@Bind(R.id.toggle_some_icon) View someButtonIcon;
|
|
||||||
@Bind(R.id.toggle_some_text) View someButtonText;
|
|
||||||
@Bind(R.id.toggle_focus) ViewGroup focusButton;
|
|
||||||
@Bind(R.id.toggle_focus_icon) View focusButtonIcon;
|
|
||||||
@Bind(R.id.toggle_focus_text) View focusButtonText;
|
|
||||||
@Bind(R.id.toggle_saved) ViewGroup savedButton;
|
|
||||||
@Bind(R.id.toggle_saved_icon) View savedButtonIcon;
|
|
||||||
@Bind(R.id.toggle_saved_text) View savedButtonText;
|
|
||||||
|
|
||||||
public StateToggleButton(Context context, AttributeSet art) {
|
public StateToggleButton(Context context, AttributeSet art) {
|
||||||
super(context, art);
|
super(context, art);
|
||||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
View view = inflater.inflate(R.layout.state_toggle, this);
|
View view = inflater.inflate(R.layout.state_toggle, this);
|
||||||
ButterKnife.bind(this, view);
|
binding = StateToggleBinding.bind(view);
|
||||||
|
|
||||||
// smooth layout transitions are enabled in our layout XML; this smooths out toggle
|
// smooth layout transitions are enabled in our layout XML; this smooths out toggle
|
||||||
// transitions on newer devices
|
// transitions on newer devices
|
||||||
allButton.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
binding.toggleAll.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
||||||
someButton.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
binding.toggleSome.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
||||||
focusButton.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
binding.toggleFocus.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
||||||
savedButton.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
binding.toggleSaved.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
||||||
|
|
||||||
setState(state);
|
setState(state);
|
||||||
|
|
||||||
|
binding.toggleAll.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setState(StateFilter.ALL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.toggleSome.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setState(StateFilter.SOME);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.toggleFocus.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setState(StateFilter.BEST);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.toggleSaved.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setState(StateFilter.SAVED);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStateListener(final StateChangedListener stateChangedListener) {
|
public void setStateListener(final StateChangedListener stateChangedListener) {
|
||||||
this.stateChangedListener = stateChangedListener;
|
this.stateChangedListener = stateChangedListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick({R.id.toggle_all, R.id.toggle_some, R.id.toggle_focus, R.id.toggle_saved})
|
|
||||||
public void onClickToggle(View v) {
|
|
||||||
if (v.getId() == R.id.toggle_all) {
|
|
||||||
setState(StateFilter.ALL);
|
|
||||||
} else if (v.getId() == R.id.toggle_some) {
|
|
||||||
setState(StateFilter.SOME);
|
|
||||||
} else if (v.getId() == R.id.toggle_focus) {
|
|
||||||
setState(StateFilter.BEST);
|
|
||||||
} else if (v.getId() == R.id.toggle_saved) {
|
|
||||||
setState(StateFilter.SAVED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setState(StateFilter state) {
|
public void setState(StateFilter state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
updateButtonStates();
|
updateButtonStates();
|
||||||
|
@ -93,21 +90,21 @@ public class StateToggleButton extends LinearLayout {
|
||||||
if (widthDP > COLLAPSE_WIDTH_DP) compactMode = false;
|
if (widthDP > COLLAPSE_WIDTH_DP) compactMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
allButtonText.setVisibility((!compactMode || state == StateFilter.ALL) ? View.VISIBLE : View.GONE);
|
binding.toggleAllText.setVisibility((!compactMode || state == StateFilter.ALL) ? View.VISIBLE : View.GONE);
|
||||||
allButton.setEnabled(state != StateFilter.ALL);
|
binding.toggleAll.setEnabled(state != StateFilter.ALL);
|
||||||
allButtonIcon.setAlpha(state == StateFilter.ALL ? 1.0f : 0.6f);
|
binding.toggleAllIcon.setAlpha(state == StateFilter.ALL ? 1.0f : 0.6f);
|
||||||
|
|
||||||
someButtonText.setVisibility((!compactMode || state == StateFilter.SOME) ? View.VISIBLE : View.GONE);
|
binding.toggleSomeText.setVisibility((!compactMode || state == StateFilter.SOME) ? View.VISIBLE : View.GONE);
|
||||||
someButton.setEnabled(state != StateFilter.SOME);
|
binding.toggleSome.setEnabled(state != StateFilter.SOME);
|
||||||
someButtonIcon.setAlpha(state == StateFilter.SOME ? 1.0f : 0.6f);
|
binding.toggleSomeIcon.setAlpha(state == StateFilter.SOME ? 1.0f : 0.6f);
|
||||||
|
|
||||||
focusButtonText.setVisibility((!compactMode || state == StateFilter.BEST) ? View.VISIBLE : View.GONE);
|
binding.toggleFocusText.setVisibility((!compactMode || state == StateFilter.BEST) ? View.VISIBLE : View.GONE);
|
||||||
focusButton.setEnabled(state != StateFilter.BEST);
|
binding.toggleFocus.setEnabled(state != StateFilter.BEST);
|
||||||
focusButtonIcon.setAlpha(state == StateFilter.BEST ? 1.0f : 0.6f);
|
binding.toggleFocusIcon.setAlpha(state == StateFilter.BEST ? 1.0f : 0.6f);
|
||||||
|
|
||||||
savedButtonText.setVisibility((!compactMode || state == StateFilter.SAVED) ? View.VISIBLE : View.GONE);
|
binding.toggleSavedText.setVisibility((!compactMode || state == StateFilter.SAVED) ? View.VISIBLE : View.GONE);
|
||||||
savedButton.setEnabled(state != StateFilter.SAVED);
|
binding.toggleSaved.setEnabled(state != StateFilter.SAVED);
|
||||||
savedButtonIcon.setAlpha(state == StateFilter.SAVED ? 1.0f : 0.6f);
|
binding.toggleSavedIcon.setAlpha(state == StateFilter.SAVED ? 1.0f : 0.6f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface StateChangedListener {
|
public interface StateChangedListener {
|
||||||
|
|
|
@ -150,4 +150,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||||
|
if (!ThemeManager.themeManager.isDarkTheme) {
|
||||||
|
if (@available(iOS 13.0, *)) {
|
||||||
|
return UIStatusBarStyleDarkContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIStatusBarStyleLightContent;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -734,8 +734,9 @@ static const CGFloat kFolderTitleHeight = 36.0;
|
||||||
if (self.operation == FeedChooserOperationMuteSites) {
|
if (self.operation == FeedChooserOperationMuteSites) {
|
||||||
UIImage *image = [UIImage imageNamed:@"mute_feed_on.png"];
|
UIImage *image = [UIImage imageNamed:@"mute_feed_on.png"];
|
||||||
UIImage *highlightedImage = [UIImage imageNamed:@"mute_feed_off.png"];
|
UIImage *highlightedImage = [UIImage imageNamed:@"mute_feed_off.png"];
|
||||||
|
UIImageView *imageView = [[UIImageView alloc] initWithImage:image highlightedImage:highlightedImage];
|
||||||
cell.accessoryView = [[UIImageView alloc] initWithImage:image highlightedImage:highlightedImage];
|
imageView.highlighted = [tableView.indexPathsForSelectedRows containsObject:indexPath];
|
||||||
|
cell.accessoryView = imageView;
|
||||||
} else {
|
} else {
|
||||||
cell.accessoryView = nil;
|
cell.accessoryView = nil;
|
||||||
}
|
}
|
||||||
|
@ -778,6 +779,10 @@ static const CGFloat kFolderTitleHeight = 36.0;
|
||||||
[self setWidgetIncludes:YES itemForIndexPath:indexPath];
|
[self setWidgetIncludes:YES itemForIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIImageView *imageView = (UIImageView *)[tableView cellForRowAtIndexPath:indexPath].accessoryView;
|
||||||
|
|
||||||
|
imageView.highlighted = YES;
|
||||||
|
|
||||||
[self updateControls];
|
[self updateControls];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,6 +791,10 @@ static const CGFloat kFolderTitleHeight = 36.0;
|
||||||
[self setWidgetIncludes:NO itemForIndexPath:indexPath];
|
[self setWidgetIncludes:NO itemForIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIImageView *imageView = (UIImageView *)[tableView cellForRowAtIndexPath:indexPath].accessoryView;
|
||||||
|
|
||||||
|
imageView.highlighted = NO;
|
||||||
|
|
||||||
[self updateControls];
|
[self updateControls];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,6 @@
|
||||||
@property (nonatomic) UISearchBar *searchBar;
|
@property (nonatomic) UISearchBar *searchBar;
|
||||||
@property (nonatomic) IBOutlet UIView *messageView;
|
@property (nonatomic) IBOutlet UIView *messageView;
|
||||||
@property (nonatomic) IBOutlet UILabel *messageLabel;
|
@property (nonatomic) IBOutlet UILabel *messageLabel;
|
||||||
@property (nonatomic, strong) id standardInteractivePopGestureDelegate;
|
|
||||||
|
|
||||||
@property (nonatomic, readwrite) BOOL pageFetching;
|
@property (nonatomic, readwrite) BOOL pageFetching;
|
||||||
@property (nonatomic, readwrite) BOOL pageFinished;
|
@property (nonatomic, readwrite) BOOL pageFinished;
|
||||||
|
|
|
@ -332,10 +332,6 @@
|
||||||
|
|
||||||
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
self.appDelegate = (NewsBlurAppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||||
|
|
||||||
if (self.standardInteractivePopGestureDelegate == nil) {
|
|
||||||
self.standardInteractivePopGestureDelegate = self.navigationController.interactivePopGestureRecognizer.delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
|
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
|
||||||
[self setUserAvatarLayout:orientation];
|
[self setUserAvatarLayout:orientation];
|
||||||
self.finishedAnimatingIn = NO;
|
self.finishedAnimatingIn = NO;
|
||||||
|
@ -453,10 +449,6 @@
|
||||||
- (void)viewDidAppear:(BOOL)animated {
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
|
|
||||||
if (self.navigationController.interactivePopGestureRecognizer.delegate != self.standardInteractivePopGestureDelegate) {
|
|
||||||
self.navigationController.interactivePopGestureRecognizer.delegate = self.standardInteractivePopGestureDelegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appDelegate.inStoryDetail && self.isPhoneOrCompact) {
|
if (appDelegate.inStoryDetail && self.isPhoneOrCompact) {
|
||||||
appDelegate.inStoryDetail = NO;
|
appDelegate.inStoryDetail = NO;
|
||||||
// [appDelegate.storyPageControl resetPages];
|
// [appDelegate.storyPageControl resetPages];
|
||||||
|
@ -663,7 +655,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.storyTitlesTable reloadData];
|
[self.storyTitlesTable reloadData];
|
||||||
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
|
[storyTitlesTable scrollRectToVisible:CGRectMake(0, CGRectGetHeight(self.searchBar.frame), 1, 1) animated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)beginOfflineTimer {
|
- (void)beginOfflineTimer {
|
||||||
|
@ -774,7 +766,7 @@
|
||||||
NSInteger storyCount = storiesCollection.storyCount;
|
NSInteger storyCount = storiesCollection.storyCount;
|
||||||
if (storyCount == 0) {
|
if (storyCount == 0) {
|
||||||
[self.storyTitlesTable reloadData];
|
[self.storyTitlesTable reloadData];
|
||||||
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
|
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
|
||||||
}
|
}
|
||||||
if (storiesCollection.feedPage == 1) {
|
if (storiesCollection.feedPage == 1) {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
|
||||||
|
@ -970,7 +962,7 @@
|
||||||
NSInteger storyCount = storiesCollection.storyCount;
|
NSInteger storyCount = storiesCollection.storyCount;
|
||||||
if (storyCount == 0) {
|
if (storyCount == 0) {
|
||||||
[self.storyTitlesTable reloadData];
|
[self.storyTitlesTable reloadData];
|
||||||
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
|
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, CGRectGetHeight(self.searchBar.frame), 1) animated:YES];
|
||||||
// [self.notifier initWithTitle:@"Loading more..." inView:self.view];
|
// [self.notifier initWithTitle:@"Loading more..." inView:self.view];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2193,34 +2185,15 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!everything && !infrequent && !read && !saved) {
|
|
||||||
NSString *deleteText = [NSString stringWithFormat:@"Delete %@",
|
|
||||||
appDelegate.storiesCollection.isRiverView ?
|
|
||||||
@"this entire folder" :
|
|
||||||
@"this site"];
|
|
||||||
|
|
||||||
[viewController addTitle:deleteText iconName:@"menu_icn_delete.png" selectionShouldDismiss:NO handler:^{
|
|
||||||
[self confirmDeleteSite:weakViewController.navigationController];
|
|
||||||
}];
|
|
||||||
|
|
||||||
[viewController addTitle:@"Move to another folder" iconName:@"menu_icn_move.png" selectionShouldDismiss:NO handler:^{
|
|
||||||
[self openMoveView:weakViewController.navigationController];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!infrequent && !saved && !read) {
|
if (!infrequent && !saved && !read) {
|
||||||
NSString *renameText = [NSString stringWithFormat:@"Rename this %@", appDelegate.storiesCollection.isRiverView ? @"folder" : @"site"];
|
NSString *manageText = [NSString stringWithFormat:@"Manage this %@", appDelegate.storiesCollection.isRiverView ? @"folder" : @"site"];
|
||||||
|
|
||||||
[viewController addTitle:renameText iconName:@"menu_icn_rename.png" selectionShouldDismiss:YES handler:^{
|
[viewController addTitle:manageText iconName:@"menu_icn_move.png" selectionShouldDismiss:NO handler:^{
|
||||||
[self openRenameSite];
|
[self manageSite:weakViewController.navigationController manageText:manageText everything:everything];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!appDelegate.storiesCollection.isRiverView && !infrequent && !saved && !read) {
|
if (!appDelegate.storiesCollection.isRiverView && !infrequent && !saved && !read) {
|
||||||
[viewController addTitle:@"Mute this site" iconName:@"menu_icn_mute.png" selectionShouldDismiss:NO handler:^{
|
|
||||||
[self confirmMuteSite:weakViewController.navigationController];
|
|
||||||
}];
|
|
||||||
|
|
||||||
[viewController addTitle:@"Train this site" iconName:@"menu_icn_train.png" selectionShouldDismiss:YES handler:^{
|
[viewController addTitle:@"Train this site" iconName:@"menu_icn_train.png" selectionShouldDismiss:YES handler:^{
|
||||||
[self openTrainSite];
|
[self openTrainSite];
|
||||||
}];
|
}];
|
||||||
|
@ -2366,6 +2339,41 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)manageSite:(UINavigationController *)menuNavigationController manageText:(NSString *)manageText everything:(BOOL)everything {
|
||||||
|
MenuViewController *viewController = [MenuViewController new];
|
||||||
|
__weak MenuViewController *weakViewController = viewController;
|
||||||
|
viewController.title = manageText;
|
||||||
|
|
||||||
|
if (!everything) {
|
||||||
|
NSString *deleteText = [NSString stringWithFormat:@"Delete %@",
|
||||||
|
appDelegate.storiesCollection.isRiverView ?
|
||||||
|
@"this entire folder" :
|
||||||
|
@"this site"];
|
||||||
|
|
||||||
|
[viewController addTitle:deleteText iconName:@"menu_icn_delete.png" selectionShouldDismiss:NO handler:^{
|
||||||
|
[self confirmDeleteSite:weakViewController.navigationController];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[viewController addTitle:@"Move to another folder" iconName:@"menu_icn_move.png" selectionShouldDismiss:NO handler:^{
|
||||||
|
[self openMoveView:weakViewController.navigationController];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *renameText = [NSString stringWithFormat:@"Rename this %@", appDelegate.storiesCollection.isRiverView ? @"folder" : @"site"];
|
||||||
|
|
||||||
|
[viewController addTitle:renameText iconName:@"menu_icn_rename.png" selectionShouldDismiss:YES handler:^{
|
||||||
|
[self openRenameSite];
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (!appDelegate.storiesCollection.isRiverView) {
|
||||||
|
[viewController addTitle:@"Mute this site" iconName:@"menu_icn_mute.png" selectionShouldDismiss:NO handler:^{
|
||||||
|
[self confirmMuteSite:weakViewController.navigationController];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
[menuNavigationController pushViewController:viewController animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)confirmDeleteSite:(UINavigationController *)menuNavigationController {
|
- (void)confirmDeleteSite:(UINavigationController *)menuNavigationController {
|
||||||
MenuViewController *viewController = [MenuViewController new];
|
MenuViewController *viewController = [MenuViewController new];
|
||||||
viewController.title = @"Positive?";
|
viewController.title = @"Positive?";
|
||||||
|
@ -2491,6 +2499,10 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
||||||
NSString *thisIdentifier = [NSString stringWithFormat:@"%@", storiesCollection.activeFeed[@"id"]];
|
NSString *thisIdentifier = [NSString stringWithFormat:@"%@", storiesCollection.activeFeed[@"id"]];
|
||||||
[activeIdentifiers removeObject:thisIdentifier];
|
[activeIdentifiers removeObject:thisIdentifier];
|
||||||
|
|
||||||
|
for (NSString *feedId in self.appDelegate.dictInactiveFeeds.allKeys) {
|
||||||
|
[activeIdentifiers removeObject:feedId];
|
||||||
|
}
|
||||||
|
|
||||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/save_feed_chooser", self.appDelegate.url];
|
NSString *urlString = [NSString stringWithFormat:@"%@/reader/save_feed_chooser", self.appDelegate.url];
|
||||||
|
|
||||||
|
@ -2739,8 +2751,10 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([ThemeManager themeManager].isDarkTheme) {
|
if ([ThemeManager themeManager].isDarkTheme) {
|
||||||
|
self.storyTitlesTable.indicatorStyle = UIScrollViewIndicatorStyleWhite;
|
||||||
self.searchBar.keyboardAppearance = UIKeyboardAppearanceDark;
|
self.searchBar.keyboardAppearance = UIKeyboardAppearanceDark;
|
||||||
} else {
|
} else {
|
||||||
|
self.storyTitlesTable.indicatorStyle = UIScrollViewIndicatorStyleBlack;
|
||||||
self.searchBar.keyboardAppearance = UIKeyboardAppearanceDefault;
|
self.searchBar.keyboardAppearance = UIKeyboardAppearanceDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2802,7 +2816,7 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
||||||
storiesCollection.feedPage = 1;
|
storiesCollection.feedPage = 1;
|
||||||
self.pageFetching = YES;
|
self.pageFetching = YES;
|
||||||
[self.storyTitlesTable reloadData];
|
[self.storyTitlesTable reloadData];
|
||||||
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
|
[storyTitlesTable scrollRectToVisible:CGRectMake(0, CGRectGetHeight(self.searchBar.frame), 1, 1) animated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
@property (assign, nonatomic) int savedStoriesCount;
|
@property (assign, nonatomic) int savedStoriesCount;
|
||||||
@property (assign, nonatomic) BOOL isSocial;
|
@property (assign, nonatomic) BOOL isSocial;
|
||||||
@property (assign, nonatomic) BOOL isSaved;
|
@property (assign, nonatomic) BOOL isSaved;
|
||||||
|
@property (assign, nonatomic) BOOL isInactive;
|
||||||
@property (nonatomic) NSString *searchQuery;
|
@property (nonatomic) NSString *searchQuery;
|
||||||
@property (nonatomic) NSString *negativeCountStr;
|
@property (nonatomic) NSString *negativeCountStr;
|
||||||
@property (nonatomic) UnreadCountView *unreadCount;
|
@property (nonatomic) UnreadCountView *unreadCount;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue