mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
Merge branch 'django1.10' into django1.11
* django1.10: (66 commits) Styling new features for dark mode. Adding style option for grid height. XS/S/M/L/XL Adding applinks to .well-known/apple app json. For #1361. #1377 (mark as read for titles only) iOS: project upgrade check https for all links. Saving saved story slugs. Slugifying saved story tags that have no slugs. Adding ssl to db machines. Fixing subscription cancelation error messge. Android v10.1b7. #1364 In App Review Showing addresses in email story share. #1369 Notification alerts. Skip old stories Android v10.1b6. iOS v10.1.1. Fixing backgrounds in newsletters. Fixing newsltter check which inaccurately added newsletter div to all stories. Styling side option buttons in iOS to be cleaner. iOS v10.1. ...
This commit is contained in:
commit
0b92bca89d
179 changed files with 3738 additions and 970 deletions
|
@ -279,7 +279,7 @@ If you need to move search servers and want to just delete everything in the sea
|
|||
NewsBlur comes complete with a test suite that tests the functionality of the rss_feeds,
|
||||
reader, and feed importer. To run the test suite:
|
||||
|
||||
./manage.py test --settings=utils.test-settings
|
||||
./manage.py test --settings=utils.test_settings
|
||||
|
||||
|
||||
## In Case of Downtime
|
||||
|
|
|
@ -492,7 +492,7 @@ class Profile(models.Model):
|
|||
|
||||
return ipn[0].payer_email
|
||||
|
||||
def activate_ios_premium(self, product_identifier, transaction_identifier, amount=36):
|
||||
def activate_ios_premium(self, transaction_identifier=None, amount=36):
|
||||
payments = PaymentHistory.objects.filter(user=self.user,
|
||||
payment_identifier=transaction_identifier,
|
||||
payment_date__gte=datetime.datetime.now()-datetime.timedelta(days=3))
|
||||
|
@ -512,7 +512,30 @@ class Profile(models.Model):
|
|||
if not self.is_premium:
|
||||
self.activate_premium()
|
||||
|
||||
logging.user(self.user, "~FG~BBNew iOS premium subscription: $%s~FW" % product_identifier)
|
||||
logging.user(self.user, "~FG~BBNew iOS premium subscription: $%s~FW" % amount)
|
||||
return True
|
||||
|
||||
def activate_android_premium(self, order_id=None, amount=36):
|
||||
payments = PaymentHistory.objects.filter(user=self.user,
|
||||
payment_identifier=order_id,
|
||||
payment_date__gte=datetime.datetime.now()-datetime.timedelta(days=3))
|
||||
if len(payments):
|
||||
# Already paid
|
||||
logging.user(self.user, "~FG~BBAlready paid Android premium subscription: $%s~FW" % amount)
|
||||
return False
|
||||
|
||||
PaymentHistory.objects.create(user=self.user,
|
||||
payment_date=datetime.datetime.now(),
|
||||
payment_amount=amount,
|
||||
payment_provider='android-subscription',
|
||||
payment_identifier=order_id)
|
||||
|
||||
self.setup_premium_history()
|
||||
|
||||
if not self.is_premium:
|
||||
self.activate_premium()
|
||||
|
||||
logging.user(self.user, "~FG~BBNew Android premium subscription: $%s~FW" % amount)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -22,6 +22,7 @@ urlpatterns = [
|
|||
url(r'^never_expire_premium/?', views.never_expire_premium, name='profile-never-expire-premium'),
|
||||
url(r'^upgrade_premium/?', views.upgrade_premium, name='profile-upgrade-premium'),
|
||||
url(r'^save_ios_receipt/?', views.save_ios_receipt, name='save-ios-receipt'),
|
||||
url(r'^save_android_receipt/?', views.save_android_receipt, name='save-android-receipt'),
|
||||
url(r'^update_payment_history/?', views.update_payment_history, name='profile-update-payment-history'),
|
||||
url(r'^delete_account/?', views.delete_account, name='profile-delete-account'),
|
||||
url(r'^forgot_password_return/?', views.forgot_password_return, name='profile-forgot-password-return'),
|
||||
|
|
|
@ -106,16 +106,17 @@ def signup(request):
|
|||
recaptcha = request.POST.get('g-recaptcha-response', None)
|
||||
recaptcha_error = None
|
||||
|
||||
if not recaptcha:
|
||||
recaptcha_error = "Please hit the \"I'm not a robot\" button."
|
||||
else:
|
||||
response = requests.post('https://www.google.com/recaptcha/api/siteverify', {
|
||||
'secret': settings.RECAPTCHA_SECRET_KEY,
|
||||
'response': recaptcha,
|
||||
})
|
||||
result = response.json()
|
||||
if not result['success']:
|
||||
recaptcha_error = "Really, please hit the \"I'm not a robot\" button."
|
||||
if settings.ENFORCE_SIGNUP_CAPTCHA:
|
||||
if not recaptcha:
|
||||
recaptcha_error = "Please hit the \"I'm not a robot\" button."
|
||||
else:
|
||||
response = requests.post('https://www.google.com/recaptcha/api/siteverify', {
|
||||
'secret': settings.RECAPTCHA_SECRET_KEY,
|
||||
'response': recaptcha,
|
||||
})
|
||||
result = response.json()
|
||||
if not result['success']:
|
||||
recaptcha_error = "Really, please hit the \"I'm not a robot\" button."
|
||||
|
||||
if request.method == "POST":
|
||||
form = SignupForm(data=request.POST, prefix="signup")
|
||||
|
@ -331,7 +332,7 @@ def save_ios_receipt(request):
|
|||
|
||||
logging.user(request, "~BM~FBSaving iOS Receipt: %s %s" % (product_identifier, transaction_identifier))
|
||||
|
||||
paid = request.user.profile.activate_ios_premium(product_identifier, transaction_identifier)
|
||||
paid = request.user.profile.activate_ios_premium(transaction_identifier)
|
||||
if paid:
|
||||
logging.user(request, "~BM~FBSending iOS Receipt email: %s %s" % (product_identifier, transaction_identifier))
|
||||
subject = "iOS Premium: %s (%s)" % (request.user.profile, product_identifier)
|
||||
|
@ -343,6 +344,26 @@ def save_ios_receipt(request):
|
|||
|
||||
return request.user.profile
|
||||
|
||||
@ajax_login_required
|
||||
@json.json_view
|
||||
def save_android_receipt(request):
|
||||
order_id = request.POST.get('order_id')
|
||||
product_id = request.POST.get('product_id')
|
||||
|
||||
logging.user(request, "~BM~FBSaving Android Receipt: %s %s" % (product_id, order_id))
|
||||
|
||||
paid = request.user.profile.activate_android_premium(order_id)
|
||||
if paid:
|
||||
logging.user(request, "~BM~FBSending Android Receipt email: %s %s" % (product_id, order_id))
|
||||
subject = "Android Premium: %s (%s)" % (request.user.profile, product_identifier)
|
||||
message = """User: %s (%s) -- Email: %s, product: %s, order: %s, receipt: %s""" % (request.user.username, request.user.pk, request.user.email, product_id, order_id, receipt)
|
||||
mail_admins(subject, message, fail_silently=True)
|
||||
else:
|
||||
logging.user(request, "~BM~FBNot sending Android Receipt email, already paid: %s %s" % (product_id, order_id))
|
||||
|
||||
|
||||
return request.user.profile
|
||||
|
||||
@login_required
|
||||
def stripe_form(request):
|
||||
user = request.user
|
||||
|
@ -692,4 +713,4 @@ def ios_subscription_status(request):
|
|||
|
||||
return {
|
||||
"code": 1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1016,10 +1016,15 @@ def starred_story_hashes(request):
|
|||
|
||||
mstories = MStarredStory.objects(
|
||||
user_id=user.pk
|
||||
).only('story_hash', 'starred_date').order_by('-starred_date')
|
||||
).only('story_hash', 'starred_date', 'starred_updated').order_by('-starred_date')
|
||||
|
||||
if include_timestamps:
|
||||
story_hashes = [(s.story_hash, s.starred_date.strftime("%s")) for s in mstories]
|
||||
story_hashes = []
|
||||
for s in mstories:
|
||||
date = s.starred_date
|
||||
if s.starred_updated:
|
||||
date = s.starred_updated
|
||||
story_hashes.append((s.story_hash, date.strftime("%s")))
|
||||
else:
|
||||
story_hashes = [s.story_hash for s in mstories]
|
||||
|
||||
|
@ -2653,8 +2658,8 @@ def send_story_email(request):
|
|||
|
||||
share_user_profile.save_sent_email()
|
||||
|
||||
logging.user(request, '~BMSharing story by email to %s recipient%s: ~FY~SB%s~SN~BM~FY/~SB%s' %
|
||||
(len(to_addresses), '' if len(to_addresses) == 1 else 's',
|
||||
logging.user(request, '~BMSharing story by email to %s recipient%s (%s): ~FY~SB%s~SN~BM~FY/~SB%s' %
|
||||
(len(to_addresses), '' if len(to_addresses) == 1 else 's', to_addresses,
|
||||
story['story_title'][:50], feed and feed.feed_title[:50]))
|
||||
|
||||
return {'code': code, 'message': message}
|
||||
|
|
|
@ -2834,6 +2834,7 @@ class MStarredStory(mongo.DynamicDocument):
|
|||
mongoengine's inheritance model on every single row."""
|
||||
user_id = mongo.IntField(unique_with=('story_guid',))
|
||||
starred_date = mongo.DateTimeField()
|
||||
starred_updated = mongo.DateTimeField()
|
||||
story_feed_id = mongo.IntField()
|
||||
story_date = mongo.DateTimeField()
|
||||
story_title = mongo.StringField(max_length=1024)
|
||||
|
@ -2880,7 +2881,8 @@ class MStarredStory(mongo.DynamicDocument):
|
|||
self.story_original_content_z = zlib.compress(self.story_original_content)
|
||||
self.story_original_content = None
|
||||
self.story_hash = self.feed_guid_hash
|
||||
|
||||
self.starred_updated = datetime.datetime.now()
|
||||
|
||||
return super(MStarredStory, self).save(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
|
@ -3011,6 +3013,11 @@ class MStarredStoryCounts(mongo.Document):
|
|||
secret_token = user.profile.secret_token
|
||||
|
||||
slug = self.slug if self.slug else ""
|
||||
if not self.slug and self.tag:
|
||||
slug = slugify(self.tag)
|
||||
self.slug = slug
|
||||
self.save()
|
||||
|
||||
return "%s/reader/starred_rss/%s/%s/%s" % (settings.NEWSBLUR_URL, self.user_id,
|
||||
secret_token, slug)
|
||||
|
||||
|
|
|
@ -128,6 +128,13 @@
|
|||
|
||||
<activity
|
||||
android:name=".activity.InAppBrowser" />
|
||||
|
||||
<activity
|
||||
android:name=".activity.Premium" />
|
||||
|
||||
<activity
|
||||
android:name=".activity.MuteConfig"
|
||||
android:launchMode="singleTask"/>
|
||||
|
||||
<activity
|
||||
android:name=".activity.SearchForFeeds" android:launchMode="singleTop" >
|
||||
|
@ -174,7 +181,7 @@
|
|||
android:exported="false">
|
||||
</receiver>
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.newsblur.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.4.10'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
|
@ -8,7 +9,8 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,33 +20,40 @@ repositories {
|
|||
url 'https://maven.google.com'
|
||||
}
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'checkstyle'
|
||||
|
||||
dependencies {
|
||||
implementation 'com.android.support:support-core-utils:28.0.0'
|
||||
implementation 'com.android.support:support-fragment:28.0.0'
|
||||
implementation 'com.android.support:support-core-ui:28.0.0'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.fragment:fragment:1.2.5'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.android.support:recyclerview-v7:28.0.0'
|
||||
implementation 'com.android.billingclient:billing:3.0.0'
|
||||
implementation 'nl.dionsegijn:konfetti:1.2.2'
|
||||
implementation 'com.github.jinatonic.confetti:confetti:1.1.2'
|
||||
implementation 'com.google.android.play:core:1.8.2'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 29
|
||||
defaultConfig {
|
||||
applicationId "com.newsblur"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 168
|
||||
targetSdkVersion 29
|
||||
versionCode 176
|
||||
versionName "10.1"
|
||||
}
|
||||
compileOptions.with {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_7
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
viewBinding.enabled = true
|
||||
android.buildFeatures.viewBinding = true
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
|
|
2
clients/android/NewsBlur/gradle.properties
Normal file
2
clients/android/NewsBlur/gradle.properties
Normal file
|
@ -0,0 +1,2 @@
|
|||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
20
clients/android/NewsBlur/release/output.json
Normal file
20
clients/android/NewsBlur/release/output.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"version": 1,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.newsblur",
|
||||
"variantName": "release",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"properties": [],
|
||||
"versionCode": 171,
|
||||
"versionName": "171",
|
||||
"enabled": true,
|
||||
"outputFile": "NewsBlur-release.apk"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -9,8 +9,7 @@
|
|||
<item
|
||||
android:top="0.5dp"
|
||||
android:bottom="0.5dp">
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/dark_feed_background_selected_end"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
<item
|
||||
android:top="0.5dp"
|
||||
android:bottom="0.5dp">
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/feed_background_selected_end"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
|
9
clients/android/NewsBlur/res/drawable/ic_bookmark.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_bookmark.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M19,18l2,1V3c0,-1.1 -0.9,-2 -2,-2H8.99C7.89,1 7,1.9 7,3h10c1.1,0 2,0.9 2,2v13zM15,5H5c-1.1,0 -2,0.9 -2,2v16l7,-3 7,3V7c0,-1.1 -0.9,-2 -2,-2z" />
|
||||
</vector>
|
9
clients/android/NewsBlur/res/drawable/ic_dining.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_dining.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M8.1,13.34l2.83,-2.83L3.91,3.5c-1.56,1.56 -1.56,4.09 0,5.66l4.19,4.18zM14.88,11.53c1.53,0.71 3.68,0.21 5.27,-1.38 1.91,-1.91 2.28,-4.65 0.81,-6.12 -1.46,-1.46 -4.2,-1.1 -6.12,0.81 -1.59,1.59 -2.09,3.74 -1.38,5.27L3.7,19.87l1.41,1.41L12,14.41l6.88,6.88 1.41,-1.41L13.41,13l1.47,-1.47z" />
|
||||
</vector>
|
9
clients/android/NewsBlur/res/drawable/ic_folder.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_folder.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z" />
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M21,9A1,1 0,0 1,22 10A1,1 0,0 1,21 11H16.53L16.4,12.21L14.2,17.15C14,17.65 13.47,18 12.86,18H8.5C7.7,18 7,17.27 7,16.5V10C7,9.61 7.16,9.26 7.43,9L11.63,4.1L12.4,4.84C12.6,5.03 12.72,5.29 12.72,5.58L12.69,5.8L11,9H21M2,18V10H5V18H2Z" />
|
||||
</vector>
|
9
clients/android/NewsBlur/res/drawable/ic_lock.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_lock.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
|
||||
</vector>
|
12
clients/android/NewsBlur/res/drawable/ic_rss_feed.xml
Normal file
12
clients/android/NewsBlur/res/drawable/ic_rss_feed.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M6.18,17.82m-2.18,0a2.18,2.18 0,1 1,4.36 0a2.18,2.18 0,1 1,-4.36 0" />
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M4,4.44v2.83c7.03,0 12.73,5.7 12.73,12.73h2.83c0,-8.59 -6.97,-15.56 -15.56,-15.56zM4,10.1v2.83c3.9,0 7.07,3.17 7.07,7.07h2.83c0,-5.47 -4.43,-9.9 -9.9,-9.9z" />
|
||||
</vector>
|
9
clients/android/NewsBlur/res/drawable/ic_search.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_search.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
|
||||
</vector>
|
9
clients/android/NewsBlur/res/drawable/ic_sync.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_sync.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" />
|
||||
</vector>
|
9
clients/android/NewsBlur/res/drawable/ic_text.xml
Normal file
9
clients/android/NewsBlur/res/drawable/ic_text.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#A6A6A6"
|
||||
android:pathData="M14,17L4,17v2h10v-2zM20,9L4,9v2h16L20,9zM4,15h16v-2L4,13v2zM4,5v2h16L20,5L4,5z" />
|
||||
</vector>
|
BIN
clients/android/NewsBlur/res/drawable/mute_feed_off.webp
Normal file
BIN
clients/android/NewsBlur/res/drawable/mute_feed_off.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 828 B |
BIN
clients/android/NewsBlur/res/drawable/mute_feed_on.webp
Normal file
BIN
clients/android/NewsBlur/res/drawable/mute_feed_on.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 686 B |
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
</LinearLayout>
|
|
@ -27,6 +27,13 @@
|
|||
android:layout_below="@id/itemlist_search_query"
|
||||
/>
|
||||
|
||||
<include layout="@layout/row_fleuron"
|
||||
android:id="@+id/footer_fleuron"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/itemlist_search_query"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemlist_sync_status"
|
||||
android:layout_width="fill_parent"
|
||||
|
|
|
@ -167,7 +167,7 @@
|
|||
/>
|
||||
|
||||
<!-- The scrollable and pull-able feed list. -->
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipe_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -180,7 +180,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:tag="folderFeedListFragment" />
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<!-- top_bar_border -->
|
||||
<View
|
||||
|
|
60
clients/android/NewsBlur/res/layout/activity_mute_config.xml
Normal file
60
clients/android/NewsBlur/res/layout/activity_mute_config.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?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"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/container_sites_count"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_reset_sites"
|
||||
style="?linkText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:padding="4dp"
|
||||
android:text="@string/mute_config_reset_button"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_sites"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="@string/mute_config_sites"
|
||||
android:textColor="@color/positive"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ExpandableListView
|
||||
android:id="@+id/list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:groupIndicator="@null" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_sync_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/status_overlay_background"
|
||||
android:gravity="center"
|
||||
android:padding="2dp"
|
||||
android:textColor="@color/status_overlay_text"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
293
clients/android/NewsBlur/res/layout/activity_premium.xml
Normal file
293
clients/android/NewsBlur/res/layout/activity_premium.xml
Normal file
|
@ -0,0 +1,293 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_going_premium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/premium_title_going_premium"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:lineSpacingExtra="@dimen/extra_line_spacing"
|
||||
android:text="@string/premium_subtitle"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_policies"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:lineSpacingExtra="@dimen/extra_line_spacing"
|
||||
android:text="@string/premium_policies"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/ic_hand_pointing_right" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_sub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_sub_title"
|
||||
style="?linkText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/premium_subscription_title"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_sub_price"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/premium_subscription_price"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_loading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/loading"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_sync" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_sync" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_folder" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_read_by_folder" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_search" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_search" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_bookmark" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_searchable_tags" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_lock" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_privacy_options" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_rss_feed" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_custom_rss" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_text" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_text_view" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_dining" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/premium_shiloh" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_shiloh"
|
||||
android:layout_width="104dp"
|
||||
android:layout_height="104dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/container_gone_premium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="120dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/premium_title_gone_premium"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_subscription_renewal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="320dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:lineSpacingExtra="@dimen/extra_line_spacing"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<nl.dionsegijn.konfetti.KonfettiView
|
||||
android:id="@+id/konfetti"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</ScrollView>
|
|
@ -10,13 +10,13 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/activity_details_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/profile_details">
|
||||
|
||||
<android.support.v4.view.PagerTitleStrip
|
||||
<androidx.viewpager.widget.PagerTitleStrip
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
|
@ -24,6 +24,6 @@
|
|||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp" />
|
||||
|
||||
</android.support.v4.view.ViewPager>
|
||||
</androidx.viewpager.widget.ViewPager>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -78,11 +78,11 @@
|
|||
android:layout_height="1dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
<androidx.recyclerview.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" />
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
</LinearLayout>
|
|
@ -8,7 +8,7 @@
|
|||
android:id="@+id/choose_folders_list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?divider"
|
||||
style="?android:listDivider"
|
||||
android:dividerHeight="2dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
android:layout_height="6dp"
|
||||
/>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/itemgridfragment_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
android:id="@+id/share_bar_underline"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
style="?divider"
|
||||
style="?android:divider"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
android:layout_height="match_parent"
|
||||
>
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/reading_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
|
@ -2,17 +2,41 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
>
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fleuron"
|
||||
android:src="@drawable/fleuron"
|
||||
android:layout_height="32dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
/>
|
||||
android:src="@drawable/fleuron" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_subscribe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_subscription"
|
||||
style="?defaultText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/premium_subscribers_folder" />
|
||||
|
||||
<TextView
|
||||
style="?linkText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/premium_subscribers" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
android:id="@+id/check_box"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:clickable="false"
|
||||
android:focusable="false" />
|
||||
|
||||
|
@ -20,7 +21,6 @@
|
|||
android:layout_width="19dp"
|
||||
android:layout_height="19dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="4dp"
|
||||
android:contentDescription="@string/description_row_feed_icon"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
|
@ -39,4 +39,13 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_toggle"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="4dp"
|
||||
android:contentDescription="@string/description_row_feed_mute_toggle"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
|
@ -63,6 +63,9 @@
|
|||
</group>
|
||||
</menu>
|
||||
</item>
|
||||
<item android:id="@+id/menu_statistics"
|
||||
android:title="@string/menu_statistics"
|
||||
android:showAsAction="never" />
|
||||
<item android:id="@+id/menu_delete_feed"
|
||||
android:title="@string/menu_delete_feed"
|
||||
android:showAsAction="never" />
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
android:title="@string/settings"
|
||||
android:showAsAction="never" />
|
||||
|
||||
<item android:id="@+id/menu_mute_sites"
|
||||
android:title="@string/mute_sites"
|
||||
android:showAsAction="never" />
|
||||
|
||||
<item android:id="@+id/menu_widget"
|
||||
android:title="@string/widget"
|
||||
android:showAsAction="never" />
|
||||
|
@ -43,6 +47,10 @@
|
|||
android:title="@string/menu_loginas"
|
||||
android:showAsAction="never"
|
||||
android:visible="false"/>
|
||||
|
||||
<item android:id="@+id/menu_premium_account"
|
||||
android:title="@string/menu_premium_account"
|
||||
android:showAsAction="never" />
|
||||
|
||||
<item android:id="@+id/menu_logout"
|
||||
android:title="@string/menu_logout"
|
||||
|
|
|
@ -54,6 +54,12 @@
|
|||
</group>
|
||||
</menu>
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/menu_mute_all"
|
||||
android:title="@string/menu_mute_all" />
|
||||
<item
|
||||
android:id="@+id/menu_mute_none"
|
||||
android:title="@string/menu_mute_none" />
|
||||
<item
|
||||
android:id="@+id/menu_select_all"
|
||||
android:title="@string/menu_select_all" />
|
|
@ -23,7 +23,6 @@
|
|||
<attr name="commentsHeader" format="string" />
|
||||
<attr name="rowBorderTop" format="string" />
|
||||
<attr name="rowBorderBottom" format="string" />
|
||||
<attr name="divider" format="string" />
|
||||
<attr name="profileCount" format="string" />
|
||||
<attr name="profileActivityList" format="string" />
|
||||
<attr name="itemHeaderDivider" format="string" />
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
<resources>
|
||||
<dimen name="thumbnails_small_size">50dp</dimen>
|
||||
<dimen name="thumbnails_size">90dp</dimen>
|
||||
<dimen name="extra_line_spacing">4dp</dimen>
|
||||
</resources>
|
|
@ -16,8 +16,7 @@
|
|||
<string name="login_next">Next</string>
|
||||
|
||||
<string name="title_feed_search">Search for feeds</string>
|
||||
<string name="add_feed_message">Add \"%s\" to your feeds?</string>
|
||||
|
||||
|
||||
<string name="loading">Loading…</string>
|
||||
<string name="orig_text_loading">Fetching story text…</string>
|
||||
|
||||
|
@ -29,6 +28,7 @@
|
|||
<string name="description_profile_picture">The user\'s profile picture</string>
|
||||
<string name="description_row_folder_icon">folder icon</string>
|
||||
<string name="description_row_feed_icon">feed icon</string>
|
||||
<string name="description_row_feed_mute_toggle">feed mute toggle</string>
|
||||
<string name="description_activity_icon">An icon illustrating the user\'s activity</string>
|
||||
<string name="description_follow_button">Follow or unfollow a user</string>
|
||||
<string name="description_comment_user">Comment user image</string>
|
||||
|
@ -135,6 +135,7 @@
|
|||
<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_delete_feed">Delete feed</string>
|
||||
<string name="menu_statistics">Statistics</string>
|
||||
<string name="menu_delete_saved_search">Delete saved search</string>
|
||||
<string name="menu_unfollow">Unfollow user</string>
|
||||
<string name="menu_choose_folders">Choose folders</string>
|
||||
|
@ -184,6 +185,8 @@
|
|||
<string name="menu_folder_view">Folder View</string>
|
||||
<string name="menu_folder_view_nested">Nested</string>
|
||||
<string name="menu_folder_view_flat">Flat</string>
|
||||
<string name="menu_mute_all">Mute All</string>
|
||||
<string name="menu_mute_none">Mute None</string>
|
||||
<string name="menu_select_all">Select All</string>
|
||||
<string name="menu_select_none">Select None</string>
|
||||
<string name="menu_widget_background">Widget Background</string>
|
||||
|
@ -213,6 +216,7 @@
|
|||
<string name="menu_feedback_post">Create a feedback post</string>
|
||||
<string name="menu_feedback_email">Email a bug report</string>
|
||||
<string name="menu_theme_choose">Theme…</string>
|
||||
<string name="menu_premium_account">Premium Account</string>
|
||||
|
||||
<string name="description_add_new_folder_icon">Add new folder icon</string>
|
||||
|
||||
|
@ -255,10 +259,34 @@
|
|||
<string name="feed_stories_per_month">%d stories/month</string>
|
||||
|
||||
<string name="settings">Preferences</string>
|
||||
<string name="mute_sites">Mute Sites</string>
|
||||
<string name="widget">Widget</string>
|
||||
<string name="title_widget_setup">Tap to setup in NewsBlur</string>
|
||||
<string name="title_no_subscriptions">No active subscriptions detected</string>
|
||||
<string name="title_widget_loading">Loading...</string>
|
||||
|
||||
<string name="premium_subscribers_folder">Reading by folder is only available to</string>
|
||||
<string name="premium_subscribers_search">Search is only available to</string>
|
||||
<string name="premium_subscribers">premium subscribers</string>
|
||||
<string name="premium_toolbar_title">NewsBlur Premium</string>
|
||||
<string name="premium_title_going_premium">Thank you so much for going premium!</string>
|
||||
<string name="premium_title_gone_premium">Thank you for going premium!</string>
|
||||
<string name="premium_subscription_renewal">Your premium subscription is set to\nrenew on %s</string>
|
||||
<string name="premium_subscription_expiration">Your premium subscription is set\nto expire on %s</string>
|
||||
<string name="premium_subscription_no_expiration">Your premium subscription is set\nto never expire. Whoa!</string>
|
||||
<string name="premium_subtitle">Upgrading to a NewsBlur premium subscription gives you all of these features. Payments will be charged to your Play Store account at confirmation of purchase. Subscription renew unless auto-renew is turned off at least 24 hours before the end of the current period. Cancel at any time from Account Settings in Play Store.</string>
|
||||
<string name="premium_policies"><![CDATA[See NewsBlur\'s <a href="https://newsblur.com/privacy">privacy policy</a> and <a href="https://newsblur.com/tos">terms of use</a> for details.]]></string>
|
||||
<string name="premium_subscription_title">NewsBlur Premium Subscription</string>
|
||||
<string name="premium_subscription_price">$35.99 per year ($3.00/month)</string>
|
||||
<string name="premium_subscription_details_error">Error retrieving subscription details</string>
|
||||
<string name="premium_sync">Sites updated up to 10x more often</string>
|
||||
<string name="premium_read_by_folder">River of News (reading by folder)</string>
|
||||
<string name="premium_search">Search sites and folders</string>
|
||||
<string name="premium_searchable_tags">Save stories with searchable tags</string>
|
||||
<string name="premium_privacy_options">Privacy options for your blurblog</string>
|
||||
<string name="premium_custom_rss">Custom RSS feeds for folders and saves stories</string>
|
||||
<string name="premium_text_view">Text view conveniently extracts the story</string>
|
||||
<string name="premium_shiloh">You feed Shiloh, my poor, hungry dog, for a month</string>
|
||||
|
||||
<string name="settings_cat_offline">Offline</string>
|
||||
<string name="settings_enable_offline">Download Stories</string>
|
||||
|
@ -268,6 +296,12 @@
|
|||
<string name="settings_keep_old_stories">Keep Stories after Reading</string>
|
||||
<string name="settings_keep_old_stories_sum">Disable to reduce storage usage</string>
|
||||
|
||||
<string name="mute_config_title">You can follow up to 64 sites with a free standard account</string>
|
||||
<string name="mute_config_message">Please mute %d sites or reset to most popular sites.</string>
|
||||
<string name="mute_config_reset_button">RESET TO POPULAR SITES</string>
|
||||
<string name="mute_config_upgrade">UPGRADE</string>
|
||||
<string name="mute_config_sites">%1$s/%2$s</string>
|
||||
|
||||
<string name="menu_network_select">Download Using</string>
|
||||
<string name="menu_network_select_sum">Restrict background data to chosen networks</string>
|
||||
<string name="menu_network_select_opt_any">Any Network</string>
|
||||
|
@ -364,7 +398,6 @@
|
|||
<string name="settings_reading">Reading</string>
|
||||
<string name="settings_immersive_enter_single_tap">Immersive Mode Via Single Tap</string>
|
||||
<string name="settings_show_content_preview">Show Content Preview Text</string>
|
||||
<string name="settings_show_thumbnails">Show Image Preview Thumbnails</string>
|
||||
<string name="settings_thumbnails_style">Image Preview Thumbnails</string>
|
||||
<string name="settings_notifications">Notifications</string>
|
||||
<string name="settings_enable_notifications">Enable Notifications</string>
|
||||
|
@ -461,12 +494,14 @@
|
|||
<string name="gest_action_markunread">Mark Story Unread</string>
|
||||
<string name="gest_action_save">Save Story</string>
|
||||
<string name="gest_action_unsave">Unsave Story</string>
|
||||
<string name="gest_action_statistics">Statistics</string>
|
||||
<string-array name="ltr_gesture_action_entries">
|
||||
<item>@string/gest_action_none</item>
|
||||
<item>@string/gest_action_markread</item>
|
||||
<item>@string/gest_action_markunread</item>
|
||||
<item>@string/gest_action_save</item>
|
||||
<item>@string/gest_action_unsave</item>
|
||||
<item>@string/gest_action_statistics</item>
|
||||
</string-array>
|
||||
<string-array name="ltr_gesture_action_values">
|
||||
<item>GEST_ACTION_NONE</item>
|
||||
|
@ -474,6 +509,7 @@
|
|||
<item>GEST_ACTION_MARKUNREAD</item>
|
||||
<item>GEST_ACTION_SAVE</item>
|
||||
<item>GEST_ACTION_UNSAVE</item>
|
||||
<item>GEST_ACTION_STATISTICS</item>
|
||||
</string-array>
|
||||
<string name="ltr_gesture_action_value">GEST_ACTION_MARKREAD</string>
|
||||
|
||||
|
@ -484,6 +520,7 @@
|
|||
<item>@string/gest_action_markunread</item>
|
||||
<item>@string/gest_action_save</item>
|
||||
<item>@string/gest_action_unsave</item>
|
||||
<item>@string/gest_action_statistics</item>
|
||||
</string-array>
|
||||
<string-array name="rtl_gesture_action_values">
|
||||
<item>GEST_ACTION_NONE</item>
|
||||
|
@ -491,6 +528,7 @@
|
|||
<item>GEST_ACTION_MARKUNREAD</item>
|
||||
<item>GEST_ACTION_SAVE</item>
|
||||
<item>GEST_ACTION_UNSAVE</item>
|
||||
<item>GEST_ACTION_STATISTICS</item>
|
||||
</string-array>
|
||||
<string name="rtl_gesture_action_value">GEST_ACTION_MARKUNREAD</string>
|
||||
|
||||
|
@ -556,7 +594,5 @@
|
|||
|
||||
<string name="story_notification_channel_id">story_notification_channel</string>
|
||||
<string name="story_notification_channel_name">New Stories</string>
|
||||
<string name="save_widget">Save Widget</string>
|
||||
<string name="select_feed">Select Feed</string>
|
||||
<string name="go_to_feed">Go to feed</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
|
@ -21,7 +21,7 @@ public class ActivityDetailsPagerAdapter extends FragmentPagerAdapter {
|
|||
private final Profile profile;
|
||||
|
||||
public ActivityDetailsPagerAdapter(FragmentManager fragmentManager, Profile profile) {
|
||||
super(fragmentManager);
|
||||
super(fragmentManager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
|
||||
this.profile = profile;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.newsblur.activity;
|
|||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.View;
|
||||
|
||||
import com.newsblur.R;
|
||||
|
|
|
@ -2,8 +2,8 @@ package com.newsblur.activity;
|
|||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
|
@ -46,6 +46,7 @@ public class AddSocial extends NbActivity {
|
|||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
switch (resultCode) {
|
||||
case AddTwitter.TWITTER_AUTHED:
|
||||
addSocialFragment.setTwitterAuthed();
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.util.FeedOrderFilter;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.FolderViewFilter;
|
||||
import com.newsblur.util.ListOrderFilter;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.WidgetBackground;
|
||||
import com.newsblur.widget.WidgetUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
abstract public class FeedChooser extends NbActivity {
|
||||
|
||||
protected FeedChooserAdapter adapter;
|
||||
protected ArrayList<Feed> feeds;
|
||||
protected ArrayList<Folder> folders;
|
||||
protected Map<String, Feed> feedMap = new HashMap<>();
|
||||
protected ArrayList<String> folderNames = new ArrayList<>();
|
||||
protected ArrayList<ArrayList<Feed>> folderChildren = new ArrayList<>();
|
||||
|
||||
abstract void bindLayout();
|
||||
|
||||
abstract void setupList();
|
||||
|
||||
abstract void processFeeds(Cursor cursor);
|
||||
|
||||
abstract void processData();
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
bindLayout();
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setupList();
|
||||
loadFeeds();
|
||||
loadFolders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_feed_chooser, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
ListOrderFilter listOrderFilter = PrefsUtils.getFeedChooserListOrder(this);
|
||||
if (listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
menu.findItem(R.id.menu_sort_order_ascending).setChecked(true);
|
||||
} else if (listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
menu.findItem(R.id.menu_sort_order_descending).setChecked(true);
|
||||
}
|
||||
|
||||
FeedOrderFilter feedOrderFilter = PrefsUtils.getFeedChooserFeedOrder(this);
|
||||
if (feedOrderFilter == FeedOrderFilter.NAME) {
|
||||
menu.findItem(R.id.menu_sort_by_name).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS) {
|
||||
menu.findItem(R.id.menu_sort_by_subs).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH) {
|
||||
menu.findItem(R.id.menu_sort_by_stories_month).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.RECENT_STORY) {
|
||||
menu.findItem(R.id.menu_sort_by_recent_story).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.OPENS) {
|
||||
menu.findItem(R.id.menu_sort_by_number_opens).setChecked(true);
|
||||
}
|
||||
|
||||
FolderViewFilter folderViewFilter = PrefsUtils.getFeedChooserFolderView(this);
|
||||
if (folderViewFilter == FolderViewFilter.NESTED) {
|
||||
menu.findItem(R.id.menu_folder_view_nested).setChecked(true);
|
||||
} else if (folderViewFilter == FolderViewFilter.FLAT) {
|
||||
menu.findItem(R.id.menu_folder_view_flat).setChecked(true);
|
||||
}
|
||||
|
||||
WidgetBackground widgetBackground = PrefsUtils.getWidgetBackground(this);
|
||||
if (widgetBackground == WidgetBackground.DEFAULT) {
|
||||
menu.findItem(R.id.menu_widget_background_default).setChecked(true);
|
||||
} else if (widgetBackground == WidgetBackground.TRANSPARENT) {
|
||||
menu.findItem(R.id.menu_widget_background_transparent).setChecked(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.menu_sort_order_ascending:
|
||||
replaceListOrderFilter(ListOrderFilter.ASCENDING);
|
||||
return true;
|
||||
case R.id.menu_sort_order_descending:
|
||||
replaceListOrderFilter(ListOrderFilter.DESCENDING);
|
||||
return true;
|
||||
case R.id.menu_sort_by_name:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.NAME);
|
||||
return true;
|
||||
case R.id.menu_sort_by_subs:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.SUBSCRIBERS);
|
||||
return true;
|
||||
case R.id.menu_sort_by_recent_story:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.RECENT_STORY);
|
||||
return true;
|
||||
case R.id.menu_sort_by_stories_month:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.STORIES_MONTH);
|
||||
return true;
|
||||
case R.id.menu_sort_by_number_opens:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.OPENS);
|
||||
return true;
|
||||
case R.id.menu_folder_view_nested:
|
||||
replaceFolderView(FolderViewFilter.NESTED);
|
||||
return true;
|
||||
case R.id.menu_folder_view_flat:
|
||||
replaceFolderView(FolderViewFilter.FLAT);
|
||||
return true;
|
||||
case R.id.menu_widget_background_default:
|
||||
setWidgetBackground(WidgetBackground.DEFAULT);
|
||||
return true;
|
||||
case R.id.menu_widget_background_transparent:
|
||||
setWidgetBackground(WidgetBackground.TRANSPARENT);
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setAdapterData() {
|
||||
adapter.setData(this.folderNames, this.folderChildren, this.feeds);
|
||||
}
|
||||
|
||||
private void replaceFeedOrderFilter(FeedOrderFilter feedOrderFilter) {
|
||||
PrefsUtils.setFeedChooserFeedOrder(this, feedOrderFilter);
|
||||
adapter.replaceFeedOrder(feedOrderFilter);
|
||||
}
|
||||
|
||||
private void replaceListOrderFilter(ListOrderFilter listOrderFilter) {
|
||||
PrefsUtils.setFeedChooserListOrder(this, listOrderFilter);
|
||||
adapter.replaceListOrder(listOrderFilter);
|
||||
}
|
||||
|
||||
private void replaceFolderView(FolderViewFilter folderViewFilter) {
|
||||
PrefsUtils.setFeedChooserFolderView(this, folderViewFilter);
|
||||
adapter.replaceFolderView(folderViewFilter);
|
||||
setAdapterData();
|
||||
}
|
||||
|
||||
private void setWidgetBackground(WidgetBackground widgetBackground) {
|
||||
PrefsUtils.setWidgetBackground(this, widgetBackground);
|
||||
WidgetUtils.updateWidget(this);
|
||||
}
|
||||
|
||||
private void loadFeeds() {
|
||||
Loader<Cursor> loader = FeedUtils.dbHelper.getFeedsLoader();
|
||||
loader.registerListener(loader.getId(), (loader1, cursor) -> processFeeds(cursor));
|
||||
loader.startLoading();
|
||||
}
|
||||
|
||||
private void loadFolders() {
|
||||
Loader<Cursor> loader = FeedUtils.dbHelper.getFoldersLoader();
|
||||
loader.registerListener(loader.getId(), (loader1, cursor) -> processFolders(cursor));
|
||||
loader.startLoading();
|
||||
}
|
||||
|
||||
private void processFolders(Cursor cursor) {
|
||||
ArrayList<Folder> folders = new ArrayList<>();
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Folder folder = Folder.fromCursor(cursor);
|
||||
if (!folder.feedIds.isEmpty()) {
|
||||
folders.add(folder);
|
||||
}
|
||||
}
|
||||
this.folders = folders;
|
||||
Collections.sort(this.folders, (o1, o2) -> Folder.compareFolderNames(o1.flatName(), o2.flatName()));
|
||||
processData();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedOrderFilter;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.FolderViewFilter;
|
||||
import com.newsblur.util.ListOrderFilter;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class FeedChooserAdapter extends BaseExpandableListAdapter {
|
||||
|
||||
protected final static int defaultTextSizeChild = 14;
|
||||
protected final static int defaultTextSizeGroup = 13;
|
||||
|
||||
protected Set<String> feedIds = new HashSet<>();
|
||||
protected ArrayList<String> folderNames = new ArrayList<>();
|
||||
protected ArrayList<ArrayList<Feed>> folderChildren = new ArrayList<>();
|
||||
|
||||
protected FolderViewFilter folderViewFilter;
|
||||
protected ListOrderFilter listOrderFilter;
|
||||
protected FeedOrderFilter feedOrderFilter;
|
||||
|
||||
protected float textSize;
|
||||
|
||||
FeedChooserAdapter(Context context) {
|
||||
folderViewFilter = PrefsUtils.getFeedChooserFolderView(context);
|
||||
listOrderFilter = PrefsUtils.getFeedChooserListOrder(context);
|
||||
feedOrderFilter = PrefsUtils.getFeedChooserFeedOrder(context);
|
||||
textSize = PrefsUtils.getListTextSize(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return folderNames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
return folderChildren.get(groupPosition).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup(int groupPosition) {
|
||||
return folderNames.get(groupPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Feed getChild(int groupPosition, int childPosition) {
|
||||
return folderChildren.get(groupPosition).get(childPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int groupPosition) {
|
||||
return folderNames.get(groupPosition).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return folderChildren.get(groupPosition).get(childPosition).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, final ViewGroup parent) {
|
||||
String folderName = folderNames.get(groupPosition);
|
||||
if (folderName.equals(AppConstants.ROOT_FOLDER)) {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_widget_config_root_folder, parent, false);
|
||||
} else {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_widget_config_folder, parent, false);
|
||||
TextView textName = convertView.findViewById(R.id.text_folder_name);
|
||||
textName.setTextSize(textSize * defaultTextSizeGroup);
|
||||
textName.setText(folderName);
|
||||
}
|
||||
|
||||
((ExpandableListView) parent).expandGroup(groupPosition);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_widget_config_feed, parent, false);
|
||||
}
|
||||
|
||||
final Feed feed = folderChildren.get(groupPosition).get(childPosition);
|
||||
TextView textTitle = convertView.findViewById(R.id.text_title);
|
||||
TextView textDetails = convertView.findViewById(R.id.text_details);
|
||||
final CheckBox checkBox = convertView.findViewById(R.id.check_box);
|
||||
ImageView img = convertView.findViewById(R.id.img);
|
||||
textTitle.setTextSize(textSize * defaultTextSizeChild);
|
||||
textDetails.setTextSize(textSize * defaultTextSizeChild);
|
||||
textTitle.setText(feed.title);
|
||||
checkBox.setChecked(feedIds.contains(feed.feedId));
|
||||
|
||||
if (feedOrderFilter == FeedOrderFilter.NAME || feedOrderFilter == FeedOrderFilter.OPENS) {
|
||||
textDetails.setText(parent.getContext().getString(R.string.feed_opens, feed.feedOpens));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS) {
|
||||
textDetails.setText(parent.getContext().getString(R.string.feed_subscribers, feed.subscribers));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH) {
|
||||
textDetails.setText(parent.getContext().getString(R.string.feed_stories_per_month, feed.storiesPerMonth));
|
||||
} else {
|
||||
// FeedOrderFilter.RECENT_STORY
|
||||
try {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
Date dateTime = dateFormat.parse(feed.lastStoryDate);
|
||||
CharSequence relativeTimeString = DateUtils.getRelativeTimeSpanString(dateTime.getTime(), System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS);
|
||||
textDetails.setText(relativeTimeString);
|
||||
} catch (Exception e) {
|
||||
textDetails.setText(feed.lastStoryDate);
|
||||
}
|
||||
}
|
||||
|
||||
FeedUtils.iconLoader.displayImage(feed.faviconUrl, img, 0, false, img.getHeight(), true);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
return super.areAllItemsEnabled();
|
||||
}
|
||||
|
||||
protected void setData(ArrayList<String> activeFoldersNames, ArrayList<ArrayList<Feed>> activeFolderChildren, ArrayList<Feed> feeds) {
|
||||
if (folderViewFilter == FolderViewFilter.NESTED) {
|
||||
this.folderNames = activeFoldersNames;
|
||||
this.folderChildren = activeFolderChildren;
|
||||
} else {
|
||||
this.folderNames = new ArrayList<>(1);
|
||||
this.folderNames.add(AppConstants.ROOT_FOLDER);
|
||||
this.folderChildren = new ArrayList<>();
|
||||
this.folderChildren.add(feeds);
|
||||
}
|
||||
this.notifyDataChanged();
|
||||
}
|
||||
|
||||
protected void replaceFeedOrder(FeedOrderFilter feedOrderFilter) {
|
||||
this.feedOrderFilter = feedOrderFilter;
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
protected void replaceListOrder(ListOrderFilter listOrderFilter) {
|
||||
this.listOrderFilter = listOrderFilter;
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
protected void replaceFolderView(FolderViewFilter folderViewFilter) {
|
||||
this.folderViewFilter = folderViewFilter;
|
||||
}
|
||||
|
||||
protected void notifyDataChanged() {
|
||||
for (ArrayList<Feed> feedList : this.folderChildren) {
|
||||
Collections.sort(feedList, getListComparator());
|
||||
}
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
protected void setFeedIds(Set<String> feedIds) {
|
||||
this.feedIds.clear();
|
||||
this.feedIds.addAll(feedIds);
|
||||
}
|
||||
|
||||
protected void replaceFeedIds(Set<String> feedIds) {
|
||||
setFeedIds(feedIds);
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private Comparator<Feed> getListComparator() {
|
||||
return (o1, o2) -> {
|
||||
if (feedOrderFilter == FeedOrderFilter.NAME && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return o1.title.compareTo(o2.title);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.NAME && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return o2.title.compareTo(o1.title);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return Integer.valueOf(o1.subscribers).compareTo(Integer.valueOf(o2.subscribers));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return Integer.valueOf(o2.subscribers).compareTo(Integer.valueOf(o1.subscribers));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.OPENS && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return Integer.compare(o1.feedOpens, o2.feedOpens);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.OPENS && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return Integer.compare(o2.feedOpens, o1.feedOpens);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.RECENT_STORY && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return compareLastStoryDateTimes(o1.lastStoryDate, o2.lastStoryDate, listOrderFilter);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.RECENT_STORY && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return compareLastStoryDateTimes(o1.lastStoryDate, o2.lastStoryDate, listOrderFilter);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return Integer.compare(o1.storiesPerMonth, o2.storiesPerMonth);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return Integer.compare(o2.storiesPerMonth, o1.storiesPerMonth);
|
||||
}
|
||||
return o1.title.compareTo(o2.title);
|
||||
};
|
||||
}
|
||||
|
||||
private int compareLastStoryDateTimes(String firstDateTime, String secondDateTime, ListOrderFilter listOrderFilter) {
|
||||
try {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
// found null last story date times on feeds
|
||||
if (TextUtils.isEmpty(firstDateTime)) {
|
||||
firstDateTime = "2000-01-01 00:00:00";
|
||||
}
|
||||
if (TextUtils.isEmpty(secondDateTime)) {
|
||||
secondDateTime = "2000-01-01 00:00:00";
|
||||
}
|
||||
|
||||
Date firstDate = dateFormat.parse(firstDateTime);
|
||||
Date secondDate = dateFormat.parse(secondDateTime);
|
||||
if (listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return firstDate.compareTo(secondDate);
|
||||
} else {
|
||||
return secondDate.compareTo(firstDate);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,10 +3,14 @@ package com.newsblur.activity;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.google.android.play.core.review.ReviewInfo;
|
||||
import com.google.android.play.core.review.ReviewManager;
|
||||
import com.google.android.play.core.review.ReviewManagerFactory;
|
||||
import com.google.android.play.core.tasks.Task;
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.fragment.DeleteFeedFragment;
|
||||
|
@ -14,6 +18,7 @@ import com.newsblur.fragment.FeedIntelTrainerFragment;
|
|||
import com.newsblur.fragment.RenameDialogFragment;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
public class FeedItemsList extends ItemsList {
|
||||
|
@ -22,6 +27,8 @@ public class FeedItemsList extends ItemsList {
|
|||
public static final String EXTRA_FOLDER_NAME = "folderName";
|
||||
private Feed feed;
|
||||
private String folderName;
|
||||
private ReviewManager reviewManager;
|
||||
private ReviewInfo reviewInfo;
|
||||
|
||||
public static void startActivity(Context context, FeedSet feedSet,
|
||||
Feed feed, String folderName) {
|
||||
|
@ -36,13 +43,28 @@ public class FeedItemsList extends ItemsList {
|
|||
protected void onCreate(Bundle bundle) {
|
||||
feed = (Feed) getIntent().getSerializableExtra(EXTRA_FEED);
|
||||
folderName = getIntent().getStringExtra(EXTRA_FOLDER_NAME);
|
||||
|
||||
|
||||
super.onCreate(bundle);
|
||||
|
||||
UIUtils.setCustomActionBar(this, feed.faviconUrl, feed.title);
|
||||
}
|
||||
checkInAppReview();
|
||||
}
|
||||
|
||||
public void deleteFeed() {
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// see checkInAppReview()
|
||||
if (reviewInfo != null) {
|
||||
Task<Void> flow = reviewManager.launchReviewFlow(this, reviewInfo);
|
||||
flow.addOnCompleteListener(task -> {
|
||||
PrefsUtils.setInAppReviewed(this);
|
||||
super.onBackPressed();
|
||||
});
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteFeed() {
|
||||
DialogFragment deleteFeedFragment = DeleteFeedFragment.newInstance(feed, folderName);
|
||||
deleteFeedFragment.show(getSupportFragmentManager(), "dialog");
|
||||
}
|
||||
|
@ -85,6 +107,10 @@ public class FeedItemsList extends ItemsList {
|
|||
// 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.
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_statistics) {
|
||||
FeedUtils.openStatistics(this, feed.feedId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -122,4 +148,16 @@ public class FeedItemsList extends ItemsList {
|
|||
String getSaveSearchFeedId() {
|
||||
return "feed:" + feed.feedId;
|
||||
}
|
||||
|
||||
private void checkInAppReview() {
|
||||
if (!PrefsUtils.hasInAppReviewed(this)) {
|
||||
reviewManager = ReviewManagerFactory.create(this);
|
||||
Task<ReviewInfo> request = reviewManager.requestReviewFlow();
|
||||
request.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
reviewInfo = task.getResult();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@ 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 androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.newsblur.databinding.ActivityInAppBrowserBinding;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
||||
|
@ -53,13 +54,4 @@ public class InAppBrowser extends FragmentActivity {
|
|||
|
||||
binding.webView.loadUrl(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (binding.webView.canGoBack()) {
|
||||
binding.webView.goBack();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
|
@ -97,7 +97,7 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
if (activeSearchQuery != null) {
|
||||
binding.itemlistSearchQuery.setText(activeSearchQuery);
|
||||
binding.itemlistSearchQuery.setVisibility(View.VISIBLE);
|
||||
fs.setSearchQuery(activeSearchQuery);
|
||||
checkSearchQuery();
|
||||
}
|
||||
|
||||
binding.itemlistSearchQuery.setOnKeyListener(new OnKeyListener() {
|
||||
|
@ -191,6 +191,7 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
menu.findItem(R.id.menu_instafetch_feed).setVisible(false);
|
||||
menu.findItem(R.id.menu_intel).setVisible(false);
|
||||
menu.findItem(R.id.menu_rename_feed).setVisible(false);
|
||||
menu.findItem(R.id.menu_statistics).setVisible(false);
|
||||
}
|
||||
|
||||
if (!fs.isInfrequent()) {
|
||||
|
@ -349,11 +350,16 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
}
|
||||
|
||||
private void checkSearchQuery() {
|
||||
String oldQuery = fs.getSearchQuery();
|
||||
String q = binding.itemlistSearchQuery.getText().toString().trim();
|
||||
if (q.length() < 1) {
|
||||
updateFleuron(false);
|
||||
q = null;
|
||||
} else if (!PrefsUtils.getIsPremium(this)) {
|
||||
updateFleuron(true);
|
||||
return;
|
||||
}
|
||||
|
||||
String oldQuery = fs.getSearchQuery();
|
||||
fs.setSearchQuery(q);
|
||||
if (!TextUtils.equals(q, oldQuery)) {
|
||||
FeedUtils.prepareReadingSession(fs, true);
|
||||
|
@ -364,6 +370,26 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
}
|
||||
}
|
||||
|
||||
private void updateFleuron(boolean requiresPremium) {
|
||||
FragmentTransaction transaction = getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
|
||||
|
||||
if (requiresPremium) {
|
||||
transaction.hide(itemSetFragment);
|
||||
binding.footerFleuron.textSubscription.setText(R.string.premium_subscribers_search);
|
||||
binding.footerFleuron.containerSubscribe.setVisibility(View.VISIBLE);
|
||||
binding.footerFleuron.getRoot().setVisibility(View.VISIBLE);
|
||||
binding.footerFleuron.containerSubscribe.setOnClickListener(view -> UIUtils.startPremiumActivity(this));
|
||||
} else {
|
||||
transaction.show(itemSetFragment);
|
||||
binding.footerFleuron.containerSubscribe.setVisibility(View.GONE);
|
||||
binding.footerFleuron.getRoot().setVisibility(View.GONE);
|
||||
binding.footerFleuron.containerSubscribe.setOnClickListener(null);
|
||||
}
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storyOrderChanged(StoryOrder newValue) {
|
||||
updateStoryOrderPreference(newValue);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import android.view.Window;
|
||||
|
||||
import com.newsblur.R;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import android.view.Window;
|
||||
|
||||
import com.newsblur.R;
|
||||
|
|
|
@ -5,9 +5,9 @@ import android.graphics.Bitmap;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
|
@ -373,6 +373,14 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
|||
} else if (item.getItemId() == R.id.menu_theme_black) {
|
||||
PrefsUtils.setSelectedTheme(this, ThemeValue.BLACK);
|
||||
UIUtils.restartActivity(this);
|
||||
} else if (item.getItemId() == R.id.menu_premium_account) {
|
||||
Intent intent = new Intent(this, Premium.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.menu_mute_sites) {
|
||||
Intent intent = new Intent(this, MuteConfig.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.databinding.ActivityMuteConfigBinding;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.service.NBSyncService;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class MuteConfig extends FeedChooser implements MuteConfigAdapter.FeedStateChangedListener {
|
||||
|
||||
private ActivityMuteConfigBinding binding;
|
||||
private boolean checkedInitFeedsLimit = false;
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
menu.findItem(R.id.menu_select_all).setVisible(false);
|
||||
menu.findItem(R.id.menu_select_none).setVisible(false);
|
||||
menu.findItem(R.id.menu_widget_background).setVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_mute_all:
|
||||
setFeedsState(true);
|
||||
return true;
|
||||
case R.id.menu_mute_none:
|
||||
setFeedsState(false);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void bindLayout() {
|
||||
binding = ActivityMuteConfigBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
void setupList() {
|
||||
adapter = new MuteConfigAdapter(this, this);
|
||||
binding.listView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
void processFeeds(Cursor cursor) {
|
||||
ArrayList<Feed> feeds = new ArrayList<>();
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Feed feed = Feed.fromCursor(cursor);
|
||||
feeds.add(feed);
|
||||
feedMap.put(feed.feedId, feed);
|
||||
}
|
||||
this.feeds = feeds;
|
||||
processData();
|
||||
}
|
||||
|
||||
@Override
|
||||
void processData() {
|
||||
if (folders != null && feeds != null) {
|
||||
for (Folder folder : folders) {
|
||||
ArrayList<Feed> children = new ArrayList<>();
|
||||
for (String feedId : folder.feedIds) {
|
||||
Feed feed = feedMap.get(feedId);
|
||||
if (!children.contains(feed)) {
|
||||
children.add(feed);
|
||||
}
|
||||
}
|
||||
folderNames.add(folder.flatName());
|
||||
folderChildren.add(children);
|
||||
}
|
||||
|
||||
setAdapterData();
|
||||
syncActiveFeedCount();
|
||||
checkedInitFeedsLimit = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapterData() {
|
||||
Set<String> feedIds = new HashSet<>(this.feeds.size());
|
||||
for (Feed feed : this.feeds) {
|
||||
feedIds.add(feed.feedId);
|
||||
}
|
||||
adapter.setFeedIds(feedIds);
|
||||
|
||||
super.setAdapterData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUpdate(int updateType) {
|
||||
super.handleUpdate(updateType);
|
||||
if ((updateType & UPDATE_STATUS) != 0) {
|
||||
String syncStatus = NBSyncService.getSyncStatusMessage(this, false);
|
||||
if (syncStatus != null) {
|
||||
binding.textSyncStatus.setText(syncStatus);
|
||||
binding.textSyncStatus.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.textSyncStatus.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeedStateChanged() {
|
||||
syncActiveFeedCount();
|
||||
}
|
||||
|
||||
private void syncActiveFeedCount() {
|
||||
// free standard accounts can follow up to 64 sites
|
||||
boolean isPremium = PrefsUtils.getIsPremium(this);
|
||||
if (!isPremium && feeds != null) {
|
||||
int activeSites = 0;
|
||||
for (Feed feed : feeds) {
|
||||
if (feed.active) {
|
||||
activeSites++;
|
||||
}
|
||||
}
|
||||
int textColorRes = activeSites > AppConstants.FREE_ACCOUNT_SITE_LIMIT ? R.color.negative : R.color.positive;
|
||||
binding.textSites.setTextColor(ContextCompat.getColor(this, textColorRes));
|
||||
binding.textSites.setText(String.format(getString(R.string.mute_config_sites), activeSites, AppConstants.FREE_ACCOUNT_SITE_LIMIT));
|
||||
showSitesCount();
|
||||
|
||||
if (activeSites > AppConstants.FREE_ACCOUNT_SITE_LIMIT && !checkedInitFeedsLimit) {
|
||||
showAccountFeedsLimitDialog(activeSites - AppConstants.FREE_ACCOUNT_SITE_LIMIT);
|
||||
}
|
||||
} else {
|
||||
hideSitesCount();
|
||||
}
|
||||
}
|
||||
|
||||
private void setFeedsState(boolean isMute) {
|
||||
for (Feed feed : feeds) {
|
||||
feed.active = !isMute;
|
||||
}
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
if (isMute) FeedUtils.muteFeeds(this, adapter.feedIds);
|
||||
else FeedUtils.unmuteFeeds(this, adapter.feedIds);
|
||||
}
|
||||
|
||||
private void showAccountFeedsLimitDialog(int exceededLimitCount) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.mute_config_title)
|
||||
.setMessage(String.format(getString(R.string.mute_config_message), exceededLimitCount))
|
||||
.setNeutralButton(android.R.string.ok, null)
|
||||
.setPositiveButton(R.string.mute_config_upgrade, (dialogInterface, i) -> openUpgradeToPremium())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showSitesCount() {
|
||||
ViewGroup.LayoutParams oldLayout = binding.listView.getLayoutParams();
|
||||
FrameLayout.LayoutParams newLayout = new FrameLayout.LayoutParams(oldLayout);
|
||||
newLayout.topMargin = UIUtils.dp2px(this, 56);
|
||||
binding.listView.setLayoutParams(newLayout);
|
||||
binding.containerSitesCount.setVisibility(View.VISIBLE);
|
||||
binding.textResetSites.setOnClickListener(view -> resetToPopularFeeds());
|
||||
}
|
||||
|
||||
private void hideSitesCount() {
|
||||
ViewGroup.LayoutParams oldLayout = binding.listView.getLayoutParams();
|
||||
FrameLayout.LayoutParams newLayout = new FrameLayout.LayoutParams(oldLayout);
|
||||
newLayout.topMargin = UIUtils.dp2px(this, 0);
|
||||
binding.listView.setLayoutParams(newLayout);
|
||||
binding.containerSitesCount.setVisibility(View.GONE);
|
||||
binding.textResetSites.setOnClickListener(null);
|
||||
}
|
||||
|
||||
// reset to most popular sites based on subscribers
|
||||
private void resetToPopularFeeds() {
|
||||
// sort descending by subscribers
|
||||
Collections.sort(feeds, (f1, f2) -> {
|
||||
if (TextUtils.isEmpty(f1.subscribers)) f1.subscribers = "0";
|
||||
if (TextUtils.isEmpty(f2.subscribers)) f2.subscribers = "0";
|
||||
return Integer.valueOf(f2.subscribers).compareTo(Integer.valueOf(f1.subscribers));
|
||||
});
|
||||
Set<String> activeFeedIds = new HashSet<>();
|
||||
Set<String> inactiveFeedIds = new HashSet<>();
|
||||
for (int index = 0; index < feeds.size(); index++) {
|
||||
Feed feed = feeds.get(index);
|
||||
if (index < AppConstants.FREE_ACCOUNT_SITE_LIMIT) {
|
||||
activeFeedIds.add(feed.feedId);
|
||||
} else {
|
||||
inactiveFeedIds.add(feed.feedId);
|
||||
}
|
||||
}
|
||||
FeedUtils.unmuteFeeds(this, activeFeedIds);
|
||||
FeedUtils.muteFeeds(this, inactiveFeedIds);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void openUpgradeToPremium() {
|
||||
Intent intent = new Intent(this, Premium.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class MuteConfigAdapter extends FeedChooserAdapter {
|
||||
|
||||
private FeedStateChangedListener listener;
|
||||
|
||||
MuteConfigAdapter(Context context, FeedStateChangedListener listener) {
|
||||
super(context);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, final ViewGroup parent) {
|
||||
View groupView = super.getGroupView(groupPosition, isExpanded, convertView, parent);
|
||||
|
||||
groupView.setOnClickListener(v -> {
|
||||
ArrayList<Feed> folderChild = MuteConfigAdapter.this.folderChildren.get(groupPosition);
|
||||
boolean allAreMute = true;
|
||||
for (Feed feed : folderChild) {
|
||||
if (feed.active) {
|
||||
allAreMute = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> feedIds = new HashSet<>(folderChild.size());
|
||||
for (Feed feed : folderChild) {
|
||||
// flip active flag
|
||||
feed.active = allAreMute;
|
||||
feedIds.add(feed.feedId);
|
||||
}
|
||||
|
||||
// if allAreMute initially, we need to unMute feeds
|
||||
if (allAreMute) FeedUtils.unmuteFeeds(groupView.getContext(), feedIds);
|
||||
else FeedUtils.muteFeeds(groupView.getContext(), feedIds);
|
||||
|
||||
listener.onFeedStateChanged();
|
||||
notifyDataChanged();
|
||||
});
|
||||
return groupView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {
|
||||
View childView = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
|
||||
final Feed feed = folderChildren.get(groupPosition).get(childPosition);
|
||||
final CheckBox checkBox = childView.findViewById(R.id.check_box);
|
||||
final ImageView imgToggle = childView.findViewById(R.id.img_toggle);
|
||||
checkBox.setVisibility(View.GONE);
|
||||
imgToggle.setVisibility(View.VISIBLE);
|
||||
|
||||
if (feed.active) imgToggle.setBackgroundResource(R.drawable.mute_feed_on);
|
||||
else imgToggle.setBackgroundResource(R.drawable.mute_feed_off);
|
||||
|
||||
childView.setOnClickListener(v -> {
|
||||
feed.active = !feed.active;
|
||||
Set<String> feedIds = new HashSet<>(1);
|
||||
feedIds.add(feed.feedId);
|
||||
if (feed.active) FeedUtils.unmuteFeeds(childView.getContext(), feedIds);
|
||||
else FeedUtils.muteFeeds(childView.getContext(), feedIds);
|
||||
|
||||
listener.onFeedStateChanged();
|
||||
notifyDataChanged();
|
||||
});
|
||||
return childView;
|
||||
}
|
||||
|
||||
interface FeedStateChangedListener {
|
||||
|
||||
void onFeedStateChanged();
|
||||
}
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.PrefConstants.ThemeValue;
|
||||
|
|
308
clients/android/NewsBlur/src/com/newsblur/activity/Premium.java
Normal file
308
clients/android/NewsBlur/src/com/newsblur/activity/Premium.java
Normal file
|
@ -0,0 +1,308 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import com.android.billingclient.api.AcknowledgePurchaseParams;
|
||||
import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.BillingClientStateListener;
|
||||
import com.android.billingclient.api.BillingFlowParams;
|
||||
import com.android.billingclient.api.BillingResult;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||
import com.android.billingclient.api.SkuDetails;
|
||||
import com.android.billingclient.api.SkuDetailsParams;
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.databinding.ActivityPremiumBinding;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.network.domain.NewsBlurResponse;
|
||||
import com.newsblur.service.NBSyncService;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.BetterLinkMovementMethod;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.Log;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import nl.dionsegijn.konfetti.emitters.StreamEmitter;
|
||||
import nl.dionsegijn.konfetti.models.Shape;
|
||||
import nl.dionsegijn.konfetti.models.Size;
|
||||
|
||||
public class Premium extends NbActivity {
|
||||
|
||||
private ActivityPremiumBinding binding;
|
||||
private BillingClient billingClient;
|
||||
private SkuDetails subscriptionDetails;
|
||||
private Purchase purchasedSubscription;
|
||||
|
||||
private AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = billingResult -> {
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
Log.d(Premium.this.getLocalClassName(), "acknowledgePurchaseResponseListener OK");
|
||||
verifyUserSubscriptionStatus();
|
||||
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.BILLING_UNAVAILABLE) {
|
||||
// Billing API version is not supported for the type requested.
|
||||
Log.d(Premium.this.getLocalClassName(), "acknowledgePurchaseResponseListener BILLING_UNAVAILABLE");
|
||||
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE) {
|
||||
// Network connection is down.
|
||||
Log.d(Premium.this.getLocalClassName(), "acknowledgePurchaseResponseListener SERVICE_UNAVAILABLE");
|
||||
} else {
|
||||
// Handle any other error codes.
|
||||
Log.d(Premium.this.getLocalClassName(), "acknowledgePurchaseResponseListener ERROR - message: " + billingResult.getDebugMessage());
|
||||
}
|
||||
};
|
||||
|
||||
private PurchasesUpdatedListener purchaseUpdateListener = (billingResult, purchases) -> {
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
|
||||
Log.d(Premium.this.getLocalClassName(), "purchaseUpdateListener OK");
|
||||
for (Purchase purchase : purchases) {
|
||||
handlePurchase(purchase);
|
||||
}
|
||||
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
|
||||
// Handle an error caused by a user cancelling the purchase flow.
|
||||
Log.d(Premium.this.getLocalClassName(), "purchaseUpdateListener USER_CANCELLED");
|
||||
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.BILLING_UNAVAILABLE) {
|
||||
// Billing API version is not supported for the type requested.
|
||||
Log.d(Premium.this.getLocalClassName(), "purchaseUpdateListener BILLING_UNAVAILABLE");
|
||||
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE) {
|
||||
// Network connection is down.
|
||||
Log.d(Premium.this.getLocalClassName(), "purchaseUpdateListener SERVICE_UNAVAILABLE");
|
||||
} else {
|
||||
// Handle any other error codes.
|
||||
Log.d(Premium.this.getLocalClassName(), "purchaseUpdateListener ERROR - message: " + billingResult.getDebugMessage());
|
||||
}
|
||||
};
|
||||
|
||||
private BillingClientStateListener billingClientStateListener = new BillingClientStateListener() {
|
||||
@Override
|
||||
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
// The BillingClient is ready. You can query purchases here.
|
||||
Log.d(Premium.this.getLocalClassName(), "onBillingSetupFinished OK");
|
||||
retrievePlayStoreSubscriptions();
|
||||
verifyUserSubscriptionStatus();
|
||||
} else {
|
||||
showSubscriptionDetailsError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingServiceDisconnected() {
|
||||
Log.d(Premium.this.getLocalClassName(), "onBillingServiceDisconnected");
|
||||
// Try to restart the connection on the next request to
|
||||
// Google Play by calling the startConnection() method.
|
||||
showSubscriptionDetailsError();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
binding = ActivityPremiumBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
setupUI();
|
||||
setupBillingClient();
|
||||
}
|
||||
|
||||
private void setupUI() {
|
||||
UIUtils.setCustomActionBar(this, R.drawable.logo, getString(R.string.premium_toolbar_title));
|
||||
|
||||
// linkify before setting the string resource
|
||||
BetterLinkMovementMethod.linkify(Linkify.WEB_URLS, binding.textPolicies)
|
||||
.setOnLinkClickListener((textView, url) -> {
|
||||
UIUtils.handleUri(Premium.this, Uri.parse(url));
|
||||
return true;
|
||||
});
|
||||
binding.textPolicies.setText(UIUtils.fromHtml(getString(R.string.premium_policies)));
|
||||
binding.textSubTitle.setPaintFlags(binding.textSubTitle.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
FeedUtils.iconLoader.displayImage(AppConstants.SHILOH_PHOTO_URL, binding.imgShiloh, 0, false);
|
||||
}
|
||||
|
||||
private void setupBillingClient() {
|
||||
billingClient = BillingClient.newBuilder(this)
|
||||
.setListener(purchaseUpdateListener)
|
||||
.enablePendingPurchases()
|
||||
.build();
|
||||
|
||||
billingClient.startConnection(billingClientStateListener);
|
||||
}
|
||||
|
||||
private void verifyUserSubscriptionStatus() {
|
||||
boolean hasNewsBlurSubscription = PrefsUtils.getIsPremium(this);
|
||||
Purchase playStoreSubscription = null;
|
||||
Purchase.PurchasesResult result = billingClient.queryPurchases(BillingClient.SkuType.SUBS);
|
||||
if (result.getPurchasesList() != null) {
|
||||
for (Purchase purchase : result.getPurchasesList()) {
|
||||
if (purchase.getSku().equals(AppConstants.PREMIUM_SKU)) {
|
||||
playStoreSubscription = purchase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNewsBlurSubscription || playStoreSubscription != null) {
|
||||
binding.containerGoingPremium.setVisibility(View.GONE);
|
||||
binding.containerGonePremium.setVisibility(View.VISIBLE);
|
||||
long expirationTimeMs = PrefsUtils.getPremiumExpire(this);
|
||||
String renewalString = null;
|
||||
|
||||
if (expirationTimeMs == 0) {
|
||||
renewalString = getString(R.string.premium_subscription_no_expiration);
|
||||
} else if (expirationTimeMs > 0) {
|
||||
// date constructor expects ms
|
||||
Date expirationDate = new Date(expirationTimeMs * 1000);
|
||||
DateFormat dateFormat = new SimpleDateFormat("EEE, MMMM d, yyyy", Locale.getDefault());
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
renewalString = getString(R.string.premium_subscription_renewal, dateFormat.format(expirationDate));
|
||||
|
||||
if (playStoreSubscription != null && !playStoreSubscription.isAutoRenewing()) {
|
||||
renewalString = getString(R.string.premium_subscription_expiration, dateFormat.format(expirationDate));
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(renewalString)) {
|
||||
binding.textSubscriptionRenewal.setText(renewalString);
|
||||
binding.textSubscriptionRenewal.setVisibility(View.VISIBLE);
|
||||
}
|
||||
showConfetti();
|
||||
}
|
||||
|
||||
if (!hasNewsBlurSubscription && playStoreSubscription != null) {
|
||||
purchasedSubscription = playStoreSubscription;
|
||||
notifyNewsBlurOfSubscription();
|
||||
}
|
||||
}
|
||||
|
||||
private void retrievePlayStoreSubscriptions() {
|
||||
List<String> skuList = new ArrayList<>(1);
|
||||
// add sub SKUs from Play Store
|
||||
skuList.add(AppConstants.PREMIUM_SKU);
|
||||
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
|
||||
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS);
|
||||
billingClient.querySkuDetailsAsync(params.build(), (billingResult, skuDetailsList) -> {
|
||||
Log.d(Premium.this.getLocalClassName(), "SkuDetailsResponse");
|
||||
processSkuDetailsList(skuDetailsList);
|
||||
});
|
||||
}
|
||||
|
||||
private void processSkuDetailsList(@Nullable List<SkuDetails> skuDetailsList) {
|
||||
if (skuDetailsList != null) {
|
||||
for (SkuDetails skuDetails : skuDetailsList) {
|
||||
if (skuDetails.getSku().equals(AppConstants.PREMIUM_SKU)) {
|
||||
Log.d(Premium.this.getLocalClassName(), "Sku detail: " + skuDetails.getTitle() + " | " + skuDetails.getDescription() + " | " + skuDetails.getPrice() + " | " + skuDetails.getSku());
|
||||
subscriptionDetails = skuDetails;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subscriptionDetails != null) {
|
||||
showSubscriptionDetails();
|
||||
} else {
|
||||
showSubscriptionDetailsError();
|
||||
}
|
||||
}
|
||||
|
||||
private void showSubscriptionDetailsError() {
|
||||
binding.textLoading.setText(R.string.premium_subscription_details_error);
|
||||
binding.textLoading.setVisibility(View.VISIBLE);
|
||||
binding.containerSub.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void showSubscriptionDetails() {
|
||||
// handling dynamic currency and pricing for 1Y subscriptions
|
||||
String currencySymbol = subscriptionDetails.getPrice().substring(0, 1);
|
||||
String priceString = subscriptionDetails.getPrice().substring(1);
|
||||
double price = Double.parseDouble(priceString);
|
||||
StringBuilder pricingText = new StringBuilder();
|
||||
pricingText.append(subscriptionDetails.getPrice());
|
||||
pricingText.append(" per year (");
|
||||
pricingText.append(currencySymbol);
|
||||
pricingText.append(String.format(Locale.getDefault(), "%.2f", price / 12));
|
||||
pricingText.append("/month)");
|
||||
|
||||
binding.textSubTitle.setText(subscriptionDetails.getTitle());
|
||||
binding.textSubPrice.setText(pricingText);
|
||||
binding.textLoading.setVisibility(View.GONE);
|
||||
binding.containerSub.setVisibility(View.VISIBLE);
|
||||
binding.containerSub.setOnClickListener(view -> launchBillingFlow(subscriptionDetails));
|
||||
}
|
||||
|
||||
private void launchBillingFlow(@NonNull SkuDetails skuDetails) {
|
||||
Log.d(Premium.this.getLocalClassName(), "launchBillingFlow for sku: " + skuDetails.getSku());
|
||||
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
|
||||
.setSkuDetails(skuDetails)
|
||||
.build();
|
||||
billingClient.launchBillingFlow(this, billingFlowParams);
|
||||
}
|
||||
|
||||
private void handlePurchase(Purchase purchase) {
|
||||
Log.d(Premium.this.getLocalClassName(), "handlePurchase: " + purchase.getOrderId());
|
||||
purchasedSubscription = purchase;
|
||||
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED && purchase.isAcknowledged()) {
|
||||
verifyUserSubscriptionStatus();
|
||||
} else if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED && !purchase.isAcknowledged()) {
|
||||
// need to acknowledge first time sub otherwise it will void
|
||||
Log.d(Premium.this.getLocalClassName(), "acknowledge purchase: " + purchase.getOrderId());
|
||||
AcknowledgePurchaseParams acknowledgePurchaseParams =
|
||||
AcknowledgePurchaseParams.newBuilder()
|
||||
.setPurchaseToken(purchase.getPurchaseToken())
|
||||
.build();
|
||||
billingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
|
||||
}
|
||||
}
|
||||
|
||||
private void showConfetti() {
|
||||
binding.konfetti.build()
|
||||
.addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA, Color.BLUE, Color.CYAN, Color.RED)
|
||||
.setDirection(90)
|
||||
.setFadeOutEnabled(true)
|
||||
.setTimeToLive(1000L)
|
||||
.addShapes(Shape.Square.INSTANCE, Shape.Circle.INSTANCE)
|
||||
.addSizes(new Size(10, 5f))
|
||||
.setPosition(0, binding.konfetti.getWidth() + 0f , -50f, -20f)
|
||||
.streamFor(100, StreamEmitter.INDEFINITE);
|
||||
}
|
||||
|
||||
private void notifyNewsBlurOfSubscription() {
|
||||
if (purchasedSubscription != null) {
|
||||
APIManager apiManager = new APIManager(this);
|
||||
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||
@Override
|
||||
protected NewsBlurResponse doInBackground(Void... voids) {
|
||||
return apiManager.saveReceipt(purchasedSubscription.getOrderId(), purchasedSubscription.getSku());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(NewsBlurResponse result) {
|
||||
super.onPostExecute(result);
|
||||
if (!result.isError()) {
|
||||
NBSyncService.forceFeedsFolders();
|
||||
triggerSync();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,9 +2,9 @@ package com.newsblur.activity;
|
|||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import android.text.TextUtils;
|
||||
import android.view.MenuItem;
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@ import android.content.res.Configuration;
|
|||
import android.database.Cursor;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v4.view.ViewPager.OnPageChangeListener;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
|
@ -178,7 +178,7 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
|||
transaction.commit();
|
||||
}
|
||||
|
||||
getSupportLoaderManager().initLoader(0, null, this);
|
||||
LoaderManager.getInstance(this).initLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -436,7 +436,7 @@ public abstract class Reading extends NbActivity implements OnPageChangeListener
|
|||
private void updateCursor() {
|
||||
synchronized (STORIES_MUTEX) {
|
||||
try {
|
||||
getSupportLoaderManager().restartLoader(0, null, this);
|
||||
LoaderManager.getInstance(this).restartLoader(0, null, this);
|
||||
} catch (IllegalStateException ise) {
|
||||
; // our heavy use of async can race loader calls, which it will gripe about, but this
|
||||
// is only a refresh call, so dropping a refresh during creation is perfectly fine.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.fragment.RegisterProgressFragment;
|
||||
|
|
|
@ -8,9 +8,10 @@ import java.util.Set;
|
|||
import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
||||
import androidx.loader.content.Loader;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
@ -55,7 +56,7 @@ public class SearchForFeeds extends NbActivity implements LoaderCallbacks<Search
|
|||
resultsList.setEmptyView(emptyView);
|
||||
resultsList.setOnItemClickListener(this);
|
||||
resultsList.setItemsCanFocus(false);
|
||||
searchLoader = getSupportLoaderManager().initLoader(0, new Bundle(), this);
|
||||
searchLoader = LoaderManager.getInstance(this).initLoader(0, new Bundle(), this);
|
||||
|
||||
onSearchRequested();
|
||||
}
|
||||
|
@ -70,6 +71,7 @@ public class SearchForFeeds extends NbActivity implements LoaderCallbacks<Search
|
|||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
handleIntent(intent);
|
||||
}
|
||||
|
@ -83,7 +85,7 @@ public class SearchForFeeds extends NbActivity implements LoaderCallbacks<Search
|
|||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(SearchAsyncTaskLoader.SEARCH_TERM, query);
|
||||
searchLoader = getSupportLoaderManager().restartLoader(0, bundle, this);
|
||||
searchLoader = LoaderManager.getInstance(this).restartLoader(0, bundle, this);
|
||||
|
||||
searchLoader.forceLoad();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
@ -14,43 +10,18 @@ import com.newsblur.R;
|
|||
import com.newsblur.databinding.ActivityWidgetConfigBinding;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.util.FeedOrderFilter;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.FolderViewFilter;
|
||||
import com.newsblur.util.ListOrderFilter;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.WidgetBackground;
|
||||
import com.newsblur.widget.WidgetUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class WidgetConfig extends NbActivity {
|
||||
public class WidgetConfig extends FeedChooser {
|
||||
|
||||
private WidgetConfigAdapter adapter;
|
||||
private ArrayList<Feed> feeds;
|
||||
private ArrayList<Folder> folders;
|
||||
private Map<String, Feed> feedMap = new HashMap<>();
|
||||
private ArrayList<String> folderNames = new ArrayList<>();
|
||||
private ArrayList<ArrayList<Feed>> folderChildren = new ArrayList<>();
|
||||
private ActivityWidgetConfigBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityWidgetConfigBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setupList();
|
||||
loadFeeds();
|
||||
loadFolders();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
@ -61,127 +32,46 @@ public class WidgetConfig extends NbActivity {
|
|||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_widget, menu);
|
||||
inflater.inflate(R.menu.menu_feed_chooser, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
ListOrderFilter listOrderFilter = PrefsUtils.getWidgetConfigListOrder(this);
|
||||
if (listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
menu.findItem(R.id.menu_sort_order_ascending).setChecked(true);
|
||||
} else if (listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
menu.findItem(R.id.menu_sort_order_descending).setChecked(true);
|
||||
}
|
||||
|
||||
FeedOrderFilter feedOrderFilter = PrefsUtils.getWidgetConfigFeedOrder(this);
|
||||
if (feedOrderFilter == FeedOrderFilter.NAME) {
|
||||
menu.findItem(R.id.menu_sort_by_name).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS) {
|
||||
menu.findItem(R.id.menu_sort_by_subs).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH) {
|
||||
menu.findItem(R.id.menu_sort_by_stories_month).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.RECENT_STORY) {
|
||||
menu.findItem(R.id.menu_sort_by_recent_story).setChecked(true);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.OPENS) {
|
||||
menu.findItem(R.id.menu_sort_by_number_opens).setChecked(true);
|
||||
}
|
||||
|
||||
FolderViewFilter folderViewFilter = PrefsUtils.getWidgetConfigFolderView(this);
|
||||
if (folderViewFilter == FolderViewFilter.NESTED) {
|
||||
menu.findItem(R.id.menu_folder_view_nested).setChecked(true);
|
||||
} else if (folderViewFilter == FolderViewFilter.FLAT) {
|
||||
menu.findItem(R.id.menu_folder_view_flat).setChecked(true);
|
||||
}
|
||||
|
||||
WidgetBackground widgetBackground = PrefsUtils.getWidgetBackground(this);
|
||||
if (widgetBackground == WidgetBackground.DEFAULT) {
|
||||
menu.findItem(R.id.menu_widget_background_default).setChecked(true);
|
||||
} else if (widgetBackground == WidgetBackground.TRANSPARENT) {
|
||||
menu.findItem(R.id.menu_widget_background_transparent).setChecked(true);
|
||||
}
|
||||
menu.findItem(R.id.menu_mute_all).setVisible(false);
|
||||
menu.findItem(R.id.menu_mute_none).setVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.menu_sort_order_ascending:
|
||||
replaceListOrderFilter(ListOrderFilter.ASCENDING);
|
||||
return true;
|
||||
case R.id.menu_sort_order_descending:
|
||||
replaceListOrderFilter(ListOrderFilter.DESCENDING);
|
||||
return true;
|
||||
case R.id.menu_sort_by_name:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.NAME);
|
||||
return true;
|
||||
case R.id.menu_sort_by_subs:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.SUBSCRIBERS);
|
||||
return true;
|
||||
case R.id.menu_sort_by_recent_story:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.RECENT_STORY);
|
||||
return true;
|
||||
case R.id.menu_sort_by_stories_month:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.STORIES_MONTH);
|
||||
return true;
|
||||
case R.id.menu_sort_by_number_opens:
|
||||
replaceFeedOrderFilter(FeedOrderFilter.OPENS);
|
||||
return true;
|
||||
case R.id.menu_folder_view_nested:
|
||||
replaceFolderView(FolderViewFilter.NESTED);
|
||||
return true;
|
||||
case R.id.menu_folder_view_flat:
|
||||
replaceFolderView(FolderViewFilter.FLAT);
|
||||
return true;
|
||||
case R.id.menu_select_all:
|
||||
selectAllFeeds();
|
||||
return true;
|
||||
case R.id.menu_select_none:
|
||||
replaceWidgetFeedIds(Collections.<String>emptySet());
|
||||
return true;
|
||||
case R.id.menu_widget_background_default:
|
||||
setWidgetBackground(WidgetBackground.DEFAULT);
|
||||
return true;
|
||||
case R.id.menu_widget_background_transparent:
|
||||
setWidgetBackground(WidgetBackground.TRANSPARENT);
|
||||
replaceWidgetFeedIds(Collections.emptySet());
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupList() {
|
||||
@Override
|
||||
void bindLayout() {
|
||||
binding = ActivityWidgetConfigBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
void setupList() {
|
||||
adapter = new WidgetConfigAdapter(this);
|
||||
binding.listView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void loadFeeds() {
|
||||
Loader<Cursor> loader = FeedUtils.dbHelper.getFeedsLoader();
|
||||
loader.registerListener(loader.getId(), new Loader.OnLoadCompleteListener<Cursor>() {
|
||||
@Override
|
||||
public void onLoadComplete(@NonNull Loader<Cursor> loader, @Nullable Cursor cursor) {
|
||||
processFeeds(cursor);
|
||||
}
|
||||
});
|
||||
loader.startLoading();
|
||||
}
|
||||
|
||||
private void loadFolders() {
|
||||
Loader<Cursor> loader = FeedUtils.dbHelper.getFoldersLoader();
|
||||
loader.registerListener(loader.getId(), new Loader.OnLoadCompleteListener<Cursor>() {
|
||||
@Override
|
||||
public void onLoadComplete(@NonNull Loader<Cursor> loader, @Nullable Cursor cursor) {
|
||||
processFolders(cursor);
|
||||
}
|
||||
});
|
||||
loader.startLoading();
|
||||
}
|
||||
|
||||
private void processFeeds(Cursor cursor) {
|
||||
@Override
|
||||
void processFeeds(Cursor cursor) {
|
||||
ArrayList<Feed> feeds = new ArrayList<>();
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Feed feed = Feed.fromCursor(cursor);
|
||||
|
@ -194,25 +84,25 @@ public class WidgetConfig extends NbActivity {
|
|||
processData();
|
||||
}
|
||||
|
||||
private void processFolders(Cursor cursor) {
|
||||
ArrayList<Folder> folders = new ArrayList<>();
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Folder folder = Folder.fromCursor(cursor);
|
||||
if (!folder.feedIds.isEmpty()) {
|
||||
folders.add(folder);
|
||||
@Override
|
||||
public void setAdapterData() {
|
||||
Set<String> feedIds = PrefsUtils.getWidgetFeedIds(this);
|
||||
// by default select all feeds
|
||||
if (feedIds == null) {
|
||||
feedIds = new HashSet<>(this.feeds.size());
|
||||
for (Feed feed : this.feeds) {
|
||||
feedIds.add(feed.feedId);
|
||||
}
|
||||
}
|
||||
this.folders = folders;
|
||||
Collections.sort(this.folders, new Comparator<Folder>() {
|
||||
@Override
|
||||
public int compare(Folder o1, Folder o2) {
|
||||
return Folder.compareFolderNames(o1.flatName(), o2.flatName());
|
||||
}
|
||||
});
|
||||
processData();
|
||||
adapter.setFeedIds(feedIds);
|
||||
|
||||
super.setAdapterData();
|
||||
binding.listView.setVisibility(this.feeds.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
binding.textNoSubscriptions.setVisibility(this.feeds.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void processData() {
|
||||
@Override
|
||||
void processData() {
|
||||
if (folders != null && feeds != null) {
|
||||
for (Folder folder : folders) {
|
||||
ArrayList<Feed> activeFeeds = new ArrayList<>();
|
||||
|
@ -226,7 +116,6 @@ public class WidgetConfig extends NbActivity {
|
|||
folderChildren.add(activeFeeds);
|
||||
}
|
||||
|
||||
setSelectedFeeds();
|
||||
setAdapterData();
|
||||
}
|
||||
}
|
||||
|
@ -243,44 +132,4 @@ public class WidgetConfig extends NbActivity {
|
|||
PrefsUtils.setWidgetFeedIds(this, feedIds);
|
||||
adapter.replaceFeedIds(feedIds);
|
||||
}
|
||||
|
||||
private void replaceFeedOrderFilter(FeedOrderFilter feedOrderFilter) {
|
||||
PrefsUtils.setWidgetConfigFeedOrder(this, feedOrderFilter);
|
||||
adapter.replaceFeedOrder(feedOrderFilter);
|
||||
}
|
||||
|
||||
private void replaceListOrderFilter(ListOrderFilter listOrderFilter) {
|
||||
PrefsUtils.setWidgetConfigListOrder(this, listOrderFilter);
|
||||
adapter.replaceListOrder(listOrderFilter);
|
||||
}
|
||||
|
||||
private void replaceFolderView(FolderViewFilter folderViewFilter) {
|
||||
PrefsUtils.setWidgetConfigFolderView(this, folderViewFilter);
|
||||
adapter.replaceFolderView(folderViewFilter);
|
||||
setAdapterData();
|
||||
}
|
||||
|
||||
private void setWidgetBackground(WidgetBackground widgetBackground) {
|
||||
PrefsUtils.setWidgetBackground(this, widgetBackground);
|
||||
WidgetUtils.updateWidget(this);
|
||||
}
|
||||
|
||||
private void setSelectedFeeds() {
|
||||
Set<String> feedIds = PrefsUtils.getWidgetFeedIds(this);
|
||||
// by default select all feeds
|
||||
if (feedIds == null) {
|
||||
feedIds = new HashSet<>(this.feeds.size());
|
||||
for (Feed feed : this.feeds) {
|
||||
feedIds.add(feed.feedId);
|
||||
}
|
||||
}
|
||||
adapter.setFeedIds(feedIds);
|
||||
}
|
||||
|
||||
private void setAdapterData() {
|
||||
adapter.setData(this.folderNames, this.folderChildren, this.feeds);
|
||||
|
||||
binding.listView.setVisibility(this.feeds.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
binding.textNoSubscriptions.setVisibility(this.feeds.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
|
@ -1,296 +1,72 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedOrderFilter;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.FolderViewFilter;
|
||||
import com.newsblur.util.ListOrderFilter;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class WidgetConfigAdapter extends BaseExpandableListAdapter {
|
||||
|
||||
private final static int defaultTextSizeChild = 14;
|
||||
private final static int defaultTextSizeGroup = 13;
|
||||
|
||||
private Set<String> feedIds = new HashSet<>();
|
||||
private ArrayList<String> folderNames = new ArrayList<>();
|
||||
private ArrayList<ArrayList<Feed>> folderChildren = new ArrayList<>();
|
||||
|
||||
private FolderViewFilter folderViewFilter;
|
||||
private ListOrderFilter listOrderFilter;
|
||||
private FeedOrderFilter feedOrderFilter;
|
||||
|
||||
private float textSize;
|
||||
public class WidgetConfigAdapter extends FeedChooserAdapter {
|
||||
|
||||
WidgetConfigAdapter(Context context) {
|
||||
folderViewFilter = PrefsUtils.getWidgetConfigFolderView(context);
|
||||
listOrderFilter = PrefsUtils.getWidgetConfigListOrder(context);
|
||||
feedOrderFilter = PrefsUtils.getWidgetConfigFeedOrder(context);
|
||||
textSize = PrefsUtils.getListTextSize(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return folderNames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
return folderChildren.get(groupPosition).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup(int groupPosition) {
|
||||
return folderNames.get(groupPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Feed getChild(int groupPosition, int childPosition) {
|
||||
return folderChildren.get(groupPosition).get(childPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int groupPosition) {
|
||||
return folderNames.get(groupPosition).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return folderChildren.get(groupPosition).get(childPosition).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, final ViewGroup parent) {
|
||||
String folderName = folderNames.get(groupPosition);
|
||||
if (folderName.equals(AppConstants.ROOT_FOLDER)) {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_widget_config_root_folder, parent, false);
|
||||
} else {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_widget_config_folder, parent, false);
|
||||
TextView textName = convertView.findViewById(R.id.text_folder_name);
|
||||
textName.setTextSize(textSize * defaultTextSizeGroup);
|
||||
textName.setText(folderName);
|
||||
}
|
||||
View groupView = super.getGroupView(groupPosition, isExpanded, convertView, parent);
|
||||
|
||||
((ExpandableListView) parent).expandGroup(groupPosition);
|
||||
|
||||
convertView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ArrayList<Feed> folderChild = WidgetConfigAdapter.this.folderChildren.get(groupPosition);
|
||||
// check all is selected
|
||||
boolean allSelected = true;
|
||||
for (Feed feed : folderChild) {
|
||||
if (!feedIds.contains(feed.feedId)) {
|
||||
allSelected = false;
|
||||
break;
|
||||
}
|
||||
groupView.setOnClickListener(v -> {
|
||||
ArrayList<Feed> folderChild = WidgetConfigAdapter.this.folderChildren.get(groupPosition);
|
||||
// check all is selected
|
||||
boolean allSelected = true;
|
||||
for (Feed feed : folderChild) {
|
||||
if (!feedIds.contains(feed.feedId)) {
|
||||
allSelected = false;
|
||||
break;
|
||||
}
|
||||
for (Feed feed : folderChild) {
|
||||
if (allSelected) {
|
||||
feedIds.remove(feed.feedId);
|
||||
} else {
|
||||
feedIds.add(feed.feedId);
|
||||
}
|
||||
}
|
||||
setWidgetFeedIds(parent.getContext());
|
||||
notifyDataChanged();
|
||||
}
|
||||
for (Feed feed : folderChild) {
|
||||
if (allSelected) {
|
||||
feedIds.remove(feed.feedId);
|
||||
} else {
|
||||
feedIds.add(feed.feedId);
|
||||
}
|
||||
}
|
||||
setWidgetFeedIds(parent.getContext());
|
||||
notifyDataChanged();
|
||||
});
|
||||
return convertView;
|
||||
return groupView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_widget_config_feed, parent, false);
|
||||
}
|
||||
|
||||
View childView = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
|
||||
final Feed feed = folderChildren.get(groupPosition).get(childPosition);
|
||||
TextView textTitle = convertView.findViewById(R.id.text_title);
|
||||
TextView textDetails = convertView.findViewById(R.id.text_details);
|
||||
final CheckBox checkBox = convertView.findViewById(R.id.check_box);
|
||||
ImageView img = convertView.findViewById(R.id.img);
|
||||
textTitle.setTextSize(textSize * defaultTextSizeChild);
|
||||
textDetails.setTextSize(textSize * defaultTextSizeChild);
|
||||
textTitle.setText(feed.title);
|
||||
checkBox.setChecked(feedIds.contains(feed.feedId));
|
||||
final CheckBox checkBox = childView.findViewById(R.id.check_box);
|
||||
final ImageView imgToggle = childView.findViewById(R.id.img_toggle);
|
||||
checkBox.setVisibility(View.VISIBLE);
|
||||
imgToggle.setVisibility(View.GONE);
|
||||
|
||||
if (feedOrderFilter == FeedOrderFilter.NAME || feedOrderFilter == FeedOrderFilter.OPENS) {
|
||||
textDetails.setText(parent.getContext().getString(R.string.feed_opens, feed.feedOpens));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS) {
|
||||
textDetails.setText(parent.getContext().getString(R.string.feed_subscribers, feed.subscribers));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH) {
|
||||
textDetails.setText(parent.getContext().getString(R.string.feed_stories_per_month, feed.storiesPerMonth));
|
||||
} else {
|
||||
// FeedOrderFilter.RECENT_STORY
|
||||
try {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
Date dateTime = dateFormat.parse(feed.lastStoryDate);
|
||||
CharSequence relativeTimeString = DateUtils.getRelativeTimeSpanString(dateTime.getTime(), System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS);
|
||||
textDetails.setText(relativeTimeString);
|
||||
} catch (Exception e) {
|
||||
textDetails.setText(feed.lastStoryDate);
|
||||
}
|
||||
}
|
||||
|
||||
FeedUtils.iconLoader.displayImage(feed.faviconUrl, img, 0, false, img.getHeight(), true);
|
||||
|
||||
convertView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
checkBox.setChecked(!checkBox.isChecked());
|
||||
if (checkBox.isChecked()) {
|
||||
feedIds.add(feed.feedId);
|
||||
} else {
|
||||
feedIds.remove(feed.feedId);
|
||||
}
|
||||
setWidgetFeedIds(parent.getContext());
|
||||
childView.setOnClickListener(v -> {
|
||||
checkBox.setChecked(!checkBox.isChecked());
|
||||
if (checkBox.isChecked()) {
|
||||
feedIds.add(feed.feedId);
|
||||
} else {
|
||||
feedIds.remove(feed.feedId);
|
||||
}
|
||||
setWidgetFeedIds(parent.getContext());
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
return super.areAllItemsEnabled();
|
||||
}
|
||||
|
||||
void setData(ArrayList<String> activeFoldersNames, ArrayList<ArrayList<Feed>> activeFolderChildren, ArrayList<Feed> feeds) {
|
||||
if (folderViewFilter == FolderViewFilter.NESTED) {
|
||||
this.folderNames = activeFoldersNames;
|
||||
this.folderChildren = activeFolderChildren;
|
||||
} else {
|
||||
this.folderNames = new ArrayList<>(1);
|
||||
this.folderNames.add(AppConstants.ROOT_FOLDER);
|
||||
this.folderChildren = new ArrayList<>();
|
||||
this.folderChildren.add(feeds);
|
||||
}
|
||||
this.notifyDataChanged();
|
||||
}
|
||||
|
||||
void replaceFeedOrder(FeedOrderFilter feedOrderFilter) {
|
||||
this.feedOrderFilter = feedOrderFilter;
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
void replaceListOrder(ListOrderFilter listOrderFilter) {
|
||||
this.listOrderFilter = listOrderFilter;
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
void replaceFolderView(FolderViewFilter folderViewFilter) {
|
||||
this.folderViewFilter = folderViewFilter;
|
||||
}
|
||||
|
||||
private void notifyDataChanged() {
|
||||
for (ArrayList<Feed> feedList : this.folderChildren) {
|
||||
Collections.sort(feedList, getListComparator());
|
||||
}
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
void setFeedIds(Set<String> feedIds) {
|
||||
this.feedIds.clear();
|
||||
this.feedIds.addAll(feedIds);
|
||||
}
|
||||
|
||||
void replaceFeedIds(Set<String> feedIds) {
|
||||
setFeedIds(feedIds);
|
||||
this.notifyDataSetChanged();
|
||||
return childView;
|
||||
}
|
||||
|
||||
private void setWidgetFeedIds(Context context) {
|
||||
PrefsUtils.setWidgetFeedIds(context, feedIds);
|
||||
}
|
||||
|
||||
private Comparator<Feed> getListComparator() {
|
||||
return new Comparator<Feed>() {
|
||||
@Override
|
||||
public int compare(Feed o1, Feed o2) {
|
||||
if (feedOrderFilter == FeedOrderFilter.NAME && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return o1.title.compareTo(o2.title);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.NAME && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return o2.title.compareTo(o1.title);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return Integer.valueOf(o1.subscribers).compareTo(Integer.valueOf(o2.subscribers));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.SUBSCRIBERS && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return Integer.valueOf(o2.subscribers).compareTo(Integer.valueOf(o1.subscribers));
|
||||
} else if (feedOrderFilter == FeedOrderFilter.OPENS && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return Integer.compare(o1.feedOpens, o2.feedOpens);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.OPENS && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return Integer.compare(o2.feedOpens, o1.feedOpens);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.RECENT_STORY && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return compareLastStoryDateTimes(o1.lastStoryDate, o2.lastStoryDate, listOrderFilter);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.RECENT_STORY && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return compareLastStoryDateTimes(o1.lastStoryDate, o2.lastStoryDate, listOrderFilter);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH && listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return Integer.compare(o1.storiesPerMonth, o2.storiesPerMonth);
|
||||
} else if (feedOrderFilter == FeedOrderFilter.STORIES_MONTH && listOrderFilter == ListOrderFilter.DESCENDING) {
|
||||
return Integer.compare(o2.storiesPerMonth, o1.storiesPerMonth);
|
||||
}
|
||||
return o1.title.compareTo(o2.title);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private int compareLastStoryDateTimes(String firstDateTime, String secondDateTime, ListOrderFilter listOrderFilter) {
|
||||
try {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
// found null last story date times on feeds
|
||||
if (TextUtils.isEmpty(firstDateTime)) {
|
||||
firstDateTime = "2000-01-01 00:00:00";
|
||||
}
|
||||
if (TextUtils.isEmpty(secondDateTime)) {
|
||||
secondDateTime = "2000-01-01 00:00:00";
|
||||
}
|
||||
|
||||
Date firstDate = dateFormat.parse(firstDateTime);
|
||||
Date secondDate = dateFormat.parse(secondDateTime);
|
||||
if (listOrderFilter == ListOrderFilter.ASCENDING) {
|
||||
return firstDate.compareTo(secondDate);
|
||||
} else {
|
||||
return secondDate.compareTo(firstDate);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ import android.database.Cursor;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.CancellationSignal;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.content.AsyncTaskLoader;
|
||||
import androidx.loader.content.Loader;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
|
|
|
@ -75,6 +75,8 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
public int totalSocialNeutCount = 0;
|
||||
/** Total positive unreads for all social feeds. */
|
||||
public int totalSocialPosiCount = 0;
|
||||
/** Total active feeds. */
|
||||
public int totalActiveFeedCount = 0;
|
||||
|
||||
/** Feeds, indexed by feed ID. */
|
||||
private Map<String,Feed> feeds = Collections.emptyMap();
|
||||
|
@ -557,6 +559,7 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
feedPosCounts = new HashMap<String,Integer>();
|
||||
totalNeutCount = 0;
|
||||
totalPosCount = 0;
|
||||
totalActiveFeedCount = 0;
|
||||
while (cursor.moveToNext()) {
|
||||
Feed f = Feed.fromCursor(cursor);
|
||||
feeds.put(f.feedId, f);
|
||||
|
@ -570,6 +573,9 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
feedNeutCounts.put(f.feedId, neut);
|
||||
totalNeutCount += neut;
|
||||
}
|
||||
if (f.active) {
|
||||
totalActiveFeedCount++;
|
||||
}
|
||||
}
|
||||
recountFeeds();
|
||||
notifyDataSetChanged();
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.content.Context;
|
|||
import android.database.Cursor;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.OperationCanceledException;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import androidx.loader.content.AsyncTaskLoader;
|
||||
|
||||
import com.newsblur.util.AppConstants;
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ package com.newsblur.database;
|
|||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
|
@ -178,7 +178,6 @@ public class ReadingAdapter extends PagerAdapter {
|
|||
}
|
||||
}
|
||||
fragment.setMenuVisibility(false);
|
||||
fragment.setUserVisibleHint(false);
|
||||
if (curTransaction == null) {
|
||||
curTransaction = fm.beginTransaction();
|
||||
}
|
||||
|
@ -208,11 +207,9 @@ public class ReadingAdapter extends PagerAdapter {
|
|||
if (fragment != lastActiveFragment) {
|
||||
if (lastActiveFragment != null) {
|
||||
lastActiveFragment.setMenuVisibility(false);
|
||||
lastActiveFragment.setUserVisibleHint(false);
|
||||
}
|
||||
if (fragment != null) {
|
||||
fragment.setMenuVisibility(true);
|
||||
fragment.setUserVisibleHint(true);
|
||||
}
|
||||
lastActiveFragment = fragment;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import android.database.Cursor;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.util.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.GestureDetector;
|
||||
|
@ -126,7 +126,11 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
}
|
||||
|
||||
public int getStoryCount() {
|
||||
return stories.size();
|
||||
if (fs != null && UIUtils.needsPremiumAccess(context, fs)) {
|
||||
return Math.min(3, stories.size());
|
||||
} else {
|
||||
return stories.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -464,6 +468,9 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
case GEST_ACTION_UNSAVE:
|
||||
FeedUtils.setStorySaved(story, false, context, null);
|
||||
break;
|
||||
case GEST_ACTION_STATISTICS:
|
||||
FeedUtils.openStatistics(context, story.feedId);
|
||||
break;
|
||||
case GEST_ACTION_NONE:
|
||||
default:
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.newsblur.domain;
|
|||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.Nullable;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
|
|
@ -6,12 +6,12 @@ import android.app.Dialog;
|
|||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
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 androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.HashSet;
|
|||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.newsblur.R;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
|
@ -15,7 +15,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
public class DeleteFeedFragment extends DialogFragment {
|
||||
private static final String FEED_TYPE = "feed_type";
|
||||
|
|
|
@ -4,9 +4,9 @@ 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 androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.newsblur.R;
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
|
|
@ -8,7 +8,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.newsblur.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
|
|
@ -8,9 +8,11 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
|
@ -35,6 +37,7 @@ import com.newsblur.activity.GlobalSharedStoriesItemsList;
|
|||
import com.newsblur.activity.InfrequentItemsList;
|
||||
import com.newsblur.activity.ItemsList;
|
||||
import com.newsblur.activity.Main;
|
||||
import com.newsblur.activity.MuteConfig;
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.activity.ReadStoriesItemsList;
|
||||
import com.newsblur.activity.SavedStoriesItemsList;
|
||||
|
@ -139,6 +142,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
checkOpenFolderPreferences();
|
||||
firstCursorSeenYet = true;
|
||||
pushUnreadCounts();
|
||||
checkAccountFeedsLimit();
|
||||
break;
|
||||
case SAVEDCOUNT_LOADER:
|
||||
adapter.setStarredCountCursor(cursor);
|
||||
|
@ -165,11 +169,11 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
if (isAdded()) {
|
||||
com.newsblur.util.Log.d(this, "loading feeds in mode: " + currentState);
|
||||
try {
|
||||
getLoaderManager().restartLoader(SOCIALFEEDS_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(FOLDERS_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(FEEDS_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(SAVEDCOUNT_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(SAVED_SEARCH_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).restartLoader(SOCIALFEEDS_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).restartLoader(FOLDERS_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).restartLoader(FEEDS_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).restartLoader(SAVEDCOUNT_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).restartLoader(SAVED_SEARCH_LOADER, null, this);
|
||||
} catch (Exception e) {
|
||||
// on heavily loaded devices, the time between isAdded() going false
|
||||
// and the loader subsystem shutting down can be nontrivial, causing
|
||||
|
@ -180,13 +184,13 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
|
||||
public synchronized void startLoaders() {
|
||||
if (isAdded()) {
|
||||
if (getLoaderManager().getLoader(FOLDERS_LOADER) == null) {
|
||||
if (LoaderManager.getInstance(this).getLoader(FOLDERS_LOADER) == null) {
|
||||
// if the loaders haven't yet been created, do so
|
||||
getLoaderManager().initLoader(SOCIALFEEDS_LOADER, null, this);
|
||||
getLoaderManager().initLoader(FOLDERS_LOADER, null, this);
|
||||
getLoaderManager().initLoader(FEEDS_LOADER, null, this);
|
||||
getLoaderManager().initLoader(SAVEDCOUNT_LOADER, null, this);
|
||||
getLoaderManager().initLoader(SAVED_SEARCH_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).initLoader(SOCIALFEEDS_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).initLoader(FOLDERS_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).initLoader(FEEDS_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).initLoader(SAVEDCOUNT_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).initLoader(SAVED_SEARCH_LOADER, null, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -364,7 +368,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
String folderName = adapter.getGroupFolderName(groupPosition);
|
||||
deleteFeedFragment = DeleteFeedFragment.newInstance(adapter.getFeed(groupPosition, childPosition), folderName);
|
||||
}
|
||||
deleteFeedFragment.show(getFragmentManager(), "dialog");
|
||||
deleteFeedFragment.show(getParentFragmentManager(), "dialog");
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.menu_mark_feed_as_read) {
|
||||
FeedSet fs = adapter.getChild(groupPosition, childPosition);
|
||||
|
@ -378,13 +382,13 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
||||
if (feed != null) {
|
||||
DialogFragment chooseFoldersFragment = ChooseFoldersFragment.newInstance(feed);
|
||||
chooseFoldersFragment.show(getFragmentManager(), "dialog");
|
||||
chooseFoldersFragment.show(getParentFragmentManager(), "dialog");
|
||||
}
|
||||
} else if (item.getItemId() == R.id.menu_rename_feed) {
|
||||
Feed feed = adapter.getFeed(groupPosition, childPosition);
|
||||
if (feed != null) {
|
||||
DialogFragment renameFeedFragment = RenameDialogFragment.newInstance(feed);
|
||||
renameFeedFragment.show(getFragmentManager(), "dialog");
|
||||
renameFeedFragment.show(getParentFragmentManager(), "dialog");
|
||||
}
|
||||
} else if (item.getItemId() == R.id.menu_mute_feed) {
|
||||
Set<String> feedIds = new HashSet<String>();
|
||||
|
@ -402,23 +406,23 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
FeedUtils.instaFetchFeed(getActivity(), adapter.getFeed(groupPosition, childPosition).feedId);
|
||||
} else if (item.getItemId() == R.id.menu_intel) {
|
||||
FeedIntelTrainerFragment intelFrag = FeedIntelTrainerFragment.newInstance(adapter.getFeed(groupPosition, childPosition), adapter.getChild(groupPosition, childPosition));
|
||||
intelFrag.show(getFragmentManager(), FeedIntelTrainerFragment.class.getName());
|
||||
intelFrag.show(getParentFragmentManager(), 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");
|
||||
deleteFeedFragment.show(getParentFragmentManager(), "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());
|
||||
deleteFolderFragment.show(getParentFragmentManager(), 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());
|
||||
renameDialogFragment.show(getParentFragmentManager(), renameDialogFragment.getTag());
|
||||
}
|
||||
|
||||
return super.onContextItemSelected(item);
|
||||
|
@ -581,6 +585,15 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
return true;
|
||||
}
|
||||
|
||||
private void checkAccountFeedsLimit() {
|
||||
new Handler().postDelayed(() -> {
|
||||
if (adapter.totalActiveFeedCount > AppConstants.FREE_ACCOUNT_SITE_LIMIT && !PrefsUtils.getIsPremium(requireContext())) {
|
||||
Intent intent = new Intent(requireActivity(), MuteConfig.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
private void openSavedSearch(SavedSearch savedSearch) {
|
||||
Intent intent = null;
|
||||
FeedSet fs = null;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.newsblur.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
|
@ -5,23 +5,24 @@ import android.graphics.Typeface;
|
|||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.activity.ItemsList;
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.database.StoryViewAdapter;
|
||||
import com.newsblur.databinding.FragmentItemgridBinding;
|
||||
import com.newsblur.databinding.RowFleuronBinding;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.service.NBSyncService;
|
||||
import com.newsblur.util.FeedSet;
|
||||
|
@ -57,7 +58,6 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
// loading indicator for when stories are present and fresh (at bottom of list)
|
||||
protected ProgressThrobber bottomProgressView;
|
||||
|
||||
private View fleuronFooter;
|
||||
// the fleuron has padding that can't be calculated until after layout, but only changes
|
||||
// rarely thereafter
|
||||
private boolean fleuronResized = false;
|
||||
|
@ -69,6 +69,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
public boolean fullFlingComplete = false;
|
||||
|
||||
private FragmentItemgridBinding binding;
|
||||
private RowFleuronBinding fleuronBinding;
|
||||
|
||||
public static ItemSetFragment newInstance() {
|
||||
ItemSetFragment fragment = new ItemSetFragment();
|
||||
|
@ -80,7 +81,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
getLoaderManager().initLoader(ITEMLIST_LOADER, null, this);
|
||||
LoaderManager.getInstance(this).initLoader(ITEMLIST_LOADER, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,6 +119,8 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_itemgrid, null);
|
||||
binding = FragmentItemgridBinding.bind(v);
|
||||
View fleuronView = inflater.inflate(R.layout.row_fleuron, null);
|
||||
fleuronBinding = RowFleuronBinding.bind(fleuronView);
|
||||
|
||||
// disable the throbbers if animations are going to have a zero time scale
|
||||
boolean isDisableAnimations = ViewUtils.isPowerSaveMode(getActivity());
|
||||
|
@ -136,8 +139,8 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
UIUtils.getColor(getActivity(), R.color.refresh_3),
|
||||
UIUtils.getColor(getActivity(), R.color.refresh_4));
|
||||
|
||||
fleuronFooter = inflater.inflate(R.layout.row_fleuron, null);
|
||||
fleuronFooter.setVisibility(View.INVISIBLE);
|
||||
fleuronBinding.getRoot().setVisibility(View.INVISIBLE);
|
||||
fleuronBinding.containerSubscribe.setOnClickListener(view -> UIUtils.startPremiumActivity(requireContext()));
|
||||
|
||||
binding.itemgridfragmentGrid.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
|
||||
@Override
|
||||
|
@ -165,7 +168,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
|
||||
adapter = new StoryViewAdapter(((NbActivity) getActivity()), this, getFeedSet(), listStyle);
|
||||
adapter.addFooterView(footerView);
|
||||
adapter.addFooterView(fleuronFooter);
|
||||
adapter.addFooterView(fleuronBinding.getRoot());
|
||||
binding.itemgridfragmentGrid.setAdapter(adapter);
|
||||
|
||||
// the layout manager needs to know that the footer rows span all the way across
|
||||
|
@ -231,7 +234,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
|
||||
public void hasUpdated() {
|
||||
if (isAdded() && !getFeedSet().isMuted()) {
|
||||
getLoaderManager().restartLoader(ITEMLIST_LOADER , null, this);
|
||||
LoaderManager.getInstance(this).restartLoader(ITEMLIST_LOADER , null, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,9 +296,6 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
}
|
||||
|
||||
private void updateLoadingIndicators() {
|
||||
// sanity check that we even have views yet
|
||||
if (fleuronFooter == null) return;
|
||||
|
||||
calcFleuronPadding();
|
||||
|
||||
if (getFeedSet().isMuted()) {
|
||||
|
@ -307,6 +307,15 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
return;
|
||||
}
|
||||
|
||||
if (cursorSeenYet && adapter.getRawStoryCount() > 0 && UIUtils.needsPremiumAccess(requireContext(), getFeedSet())) {
|
||||
fleuronBinding.getRoot().setVisibility(View.VISIBLE);
|
||||
fleuronBinding.containerSubscribe.setVisibility(View.VISIBLE);
|
||||
binding.topLoadingThrob.setVisibility(View.INVISIBLE);
|
||||
bottomProgressView.setVisibility(View.INVISIBLE);
|
||||
fleuronResized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (!cursorSeenYet) || NBSyncService.isFeedSetSyncing(getFeedSet(), getActivity()) ) {
|
||||
binding.emptyViewText.setText(R.string.empty_list_view_loading);
|
||||
binding.emptyViewText.setTypeface(null, Typeface.ITALIC);
|
||||
|
@ -319,7 +328,7 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
binding.topLoadingThrob.setVisibility(View.VISIBLE);
|
||||
bottomProgressView.setVisibility(View.GONE);
|
||||
}
|
||||
fleuronFooter.setVisibility(View.INVISIBLE);
|
||||
fleuronBinding.getRoot().setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
ReadFilter readFilter = PrefsUtils.getReadFilter(getActivity(), getFeedSet());
|
||||
if (readFilter == ReadFilter.UNREAD) {
|
||||
|
@ -333,7 +342,8 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
binding.topLoadingThrob.setVisibility(View.INVISIBLE);
|
||||
bottomProgressView.setVisibility(View.INVISIBLE);
|
||||
if (cursorSeenYet && NBSyncService.isFeedSetExhausted(getFeedSet()) && (adapter.getRawStoryCount() > 0)) {
|
||||
fleuronFooter.setVisibility(View.VISIBLE);
|
||||
fleuronBinding.containerSubscribe.setVisibility(View.GONE);
|
||||
fleuronBinding.getRoot().setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -417,6 +427,9 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
// don't bother checking on scroll up
|
||||
if (dy < 1) return;
|
||||
|
||||
// skip fetching more stories if premium access is required
|
||||
if (UIUtils.needsPremiumAccess(requireContext(), getFeedSet()) && adapter.getItemCount() >= 3) return;
|
||||
|
||||
ensureSufficientStories();
|
||||
|
||||
// the list can be scrolled past the last item thanks to the offset footer, but don't fling
|
||||
|
@ -500,21 +513,21 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
* be scrolled until the bottom most story reaches to top, for those who mark-by-scrolling.
|
||||
*/
|
||||
private void calcFleuronPadding() {
|
||||
if (fleuronResized) return;
|
||||
// sanity check that we even have views yet
|
||||
if (fleuronResized || fleuronBinding.getRoot().getLayoutParams() == null) return;
|
||||
int listHeight = binding.itemgridfragmentGrid.getMeasuredHeight();
|
||||
View innerView = fleuronFooter.findViewById(R.id.fleuron);
|
||||
ViewGroup.LayoutParams oldLayout = innerView.getLayoutParams();
|
||||
ViewGroup.MarginLayoutParams newLayout = new LinearLayout.LayoutParams(oldLayout);
|
||||
int marginPx_4dp = UIUtils.dp2px(getActivity(), 4);
|
||||
int defaultPx_100dp = UIUtils.dp2px(getActivity(), 100);
|
||||
int bufferPx_50dp = UIUtils.dp2px(getActivity(), 50);
|
||||
ViewGroup.LayoutParams oldLayout = fleuronBinding.getRoot().getLayoutParams();
|
||||
FrameLayout.LayoutParams newLayout = new FrameLayout.LayoutParams(oldLayout);
|
||||
int marginPx_4dp = UIUtils.dp2px(requireContext(), 4);
|
||||
int fleuronFooterHeightPx = fleuronBinding.getRoot().getMeasuredHeight();
|
||||
if (listHeight > 1) {
|
||||
newLayout.setMargins(0, marginPx_4dp, 0, listHeight-bufferPx_50dp);
|
||||
newLayout.setMargins(0, marginPx_4dp, 0, listHeight-fleuronFooterHeightPx);
|
||||
fleuronResized = true;
|
||||
} else {
|
||||
int defaultPx_100dp = UIUtils.dp2px(requireContext(), 100);
|
||||
newLayout.setMargins(0, marginPx_4dp, 0, defaultPx_100dp);
|
||||
}
|
||||
innerView.setLayoutParams(newLayout);
|
||||
fleuronBinding.getRoot().setLayoutParams(newLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.newsblur.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
|
@ -7,7 +7,7 @@ import android.content.DialogInterface;
|
|||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.content.Intent;
|
|||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
|
@ -3,9 +3,9 @@ package com.newsblur.fragment;
|
|||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -104,7 +104,7 @@ public class LoginRegisterFragment extends Fragment {
|
|||
|
||||
Intent i = new Intent(getActivity(), LoginProgress.class);
|
||||
i.putExtra("username", binding.loginUsername.getText().toString());
|
||||
i.putExtra("password", binding.loginUsername.getText().toString());
|
||||
i.putExtra("password", binding.loginPassword.getText().toString());
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.newsblur.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
|
@ -4,8 +4,8 @@ import android.content.Context;
|
|||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -138,7 +138,7 @@ public class ProfileDetailsFragment extends Fragment implements OnClickListener
|
|||
followButton.setVisibility(View.GONE);
|
||||
unfollowButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
FragmentManager fm = ProfileDetailsFragment.this.getFragmentManager();
|
||||
FragmentManager fm = ProfileDetailsFragment.this.getParentFragmentManager();
|
||||
AlertDialogFragment alertDialog = AlertDialogFragment.newAlertDialogFragment(getResources().getString(R.string.follow_error));
|
||||
alertDialog.show(fm, "fragment_edit_name");
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ public class ProfileDetailsFragment extends Fragment implements OnClickListener
|
|||
unfollowButton.setVisibility(View.GONE);
|
||||
followButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
FragmentManager fm = ProfileDetailsFragment.this.getFragmentManager();
|
||||
FragmentManager fm = ProfileDetailsFragment.this.getParentFragmentManager();
|
||||
AlertDialogFragment alertDialog = AlertDialogFragment.newAlertDialogFragment(getResources().getString(R.string.unfollow_error));
|
||||
alertDialog.show(fm, "fragment_edit_name");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.newsblur.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
|
@ -7,7 +7,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
public class ReadingActionConfirmationFragment extends DialogFragment {
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.newsblur.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
|
@ -14,9 +14,9 @@ import android.graphics.drawable.GradientDrawable;
|
|||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
|
@ -415,7 +415,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
|||
|
||||
private void clickShare() {
|
||||
DialogFragment newFragment = ShareDialogFragment.newInstance(story, sourceUserId);
|
||||
newFragment.show(getFragmentManager(), "dialog");
|
||||
newFragment.show(getParentFragmentManager(), "dialog");
|
||||
}
|
||||
|
||||
private void updateShareButton() {
|
||||
|
@ -483,7 +483,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
|||
public void onClick(View v) {
|
||||
if (story.feedId.equals("0")) return; // cannot train on feedless stories
|
||||
StoryIntelTrainerFragment intelFrag = StoryIntelTrainerFragment.newInstance(story, fs);
|
||||
intelFrag.show(getFragmentManager(), StoryIntelTrainerFragment.class.getName());
|
||||
intelFrag.show(getParentFragmentManager(), StoryIntelTrainerFragment.class.getName());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -492,17 +492,15 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
|||
public void onClick(View v) {
|
||||
if (story.feedId.equals("0")) return; // cannot train on feedless stories
|
||||
StoryIntelTrainerFragment intelFrag = StoryIntelTrainerFragment.newInstance(story, fs);
|
||||
intelFrag.show(getFragmentManager(), StoryIntelTrainerFragment.class.getName());
|
||||
intelFrag.show(getParentFragmentManager(), StoryIntelTrainerFragment.class.getName());
|
||||
}
|
||||
});
|
||||
|
||||
binding.readingItemTitle.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
try {
|
||||
i.setData(Uri.parse(story.permalink));
|
||||
startActivity(i);
|
||||
UIUtils.handleUri(requireContext(), Uri.parse(story.permalink));
|
||||
} catch (Throwable t) {
|
||||
// we don't actually know if the user will successfully be able to open whatever string
|
||||
// was in the permalink or if the Intent could throw errors
|
||||
|
@ -558,7 +556,7 @@ public class ReadingItemFragment extends NbFragment implements PopupMenu.OnMenuI
|
|||
public void onClick(View view) {
|
||||
if (story.feedId.equals("0")) return; // cannot train on feedless stories
|
||||
StoryIntelTrainerFragment intelFrag = StoryIntelTrainerFragment.newInstance(story, fs);
|
||||
intelFrag.show(getFragmentManager(), StoryIntelTrainerFragment.class.getName());
|
||||
intelFrag.show(getParentFragmentManager(), StoryIntelTrainerFragment.class.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ package com.newsblur.fragment;
|
|||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
|
@ -5,8 +5,8 @@ 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 androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
|
|
@ -4,8 +4,8 @@ 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 androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.network.APIManager;
|
||||
|
|
|
@ -10,8 +10,8 @@ import java.util.Set;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -28,7 +28,6 @@ import com.newsblur.domain.Reply;
|
|||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
import com.newsblur.domain.UserProfile;
|
||||
import com.newsblur.fragment.ReplyDialogFragment;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
@ -56,7 +55,7 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
|||
public SetupCommentSectionTask(ReadingItemFragment fragment, View view, LayoutInflater inflater, Story story) {
|
||||
this.fragment = fragment;
|
||||
this.context = fragment.getActivity();
|
||||
this.manager = fragment.getFragmentManager();
|
||||
this.manager = fragment.getParentFragmentManager();
|
||||
this.inflater = inflater;
|
||||
this.story = story;
|
||||
viewHolder = new WeakReference<View>(view);
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.app.AlertDialog;
|
|||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue