mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-04-13 09:42:01 +00:00
Merge branch 'sictiru'
* sictiru: Android v11.1.1. Update dependencies Cleanup. Use compat methods #1572 Web view custom contextual web search action Adding gradle wrapper properties. Adding gradle wrapper. NBScope for global scope coroutines Update android gradle and kotlin dependencies Cleanup NbActivity and remove static reference to all activities. Add broadcast receiver based sync mechanism between foreground activities and db updates by the background service. Check intent action in the receiver. #1556 Android 12 Splash Screen Android v11.1 (cleaner than 11.1.1 since 11.1 isn't even public yet)
This commit is contained in:
commit
ca0672220a
40 changed files with 528 additions and 432 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -83,7 +83,7 @@ media/safari/NewsBlur.safariextz
|
|||
clients/android/NewsBlur/.idea
|
||||
clients/android/NewsBlur/.gradle
|
||||
clients/android/NewsBlur/build.gradle
|
||||
clients/android/NewsBlur/gradle*
|
||||
clients/android/NewsBlur/gradlew*
|
||||
clients/android/NewsBlur/settings.gradle
|
||||
/docker/volumes/*
|
||||
|
||||
|
|
1
clients/android/NewsBlur/.gitignore
vendored
1
clients/android/NewsBlur/.gitignore
vendored
|
@ -14,6 +14,5 @@ libs/ActionBarSherlock/
|
|||
.project
|
||||
.gradle/
|
||||
app/
|
||||
gradle/
|
||||
*.gradle
|
||||
!build.gradle
|
||||
|
|
|
@ -12,13 +12,15 @@
|
|||
android:label="@string/newsblur"
|
||||
android:theme="@style/NewsBlurTheme"
|
||||
android:hardwareAccelerated="true"
|
||||
android:fullBackupContent="@xml/backupscheme" >
|
||||
android:fullBackupContent="@xml/backupscheme"
|
||||
android:name=".NbApplication">
|
||||
|
||||
<activity
|
||||
android:name=".activity.InitActivity"
|
||||
android:label="@string/newsblur"
|
||||
android:theme="@style/initStyle"
|
||||
android:noHistory="true">
|
||||
android:theme="@style/splashScreen"
|
||||
android:noHistory="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -146,7 +148,8 @@
|
|||
<service android:name=".widget.WidgetRemoteViewsService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<receiver android:name=".service.BootReceiver">
|
||||
<receiver android:name=".service.BootReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
|
@ -163,7 +166,8 @@
|
|||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/newsblur_appwidget_info" />
|
||||
</receiver>
|
||||
<receiver android:name=".service.TimeChangeReceiver">
|
||||
<receiver android:name=".service.TimeChangeReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter >
|
||||
<action android:name="android.intent.action.TIME_SET"/>
|
||||
</intent-filter>
|
||||
|
@ -183,7 +187,8 @@
|
|||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<activity android:name=".activity.AddFeedExternal">
|
||||
<activity android:name=".activity.AddFeedExternal"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
@ -214,6 +219,8 @@
|
|||
<data android:host="feeds2.feedburner.com"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<data android:scheme="http"/>
|
||||
<data android:scheme="https"/>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.5.30'
|
||||
ext.kotlin_version = '1.6.0'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
|
@ -9,7 +9,7 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.0'
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
@ -27,28 +27,29 @@ apply plugin: 'com.android.application'
|
|||
apply plugin: 'kotlin-android'
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.fragment:fragment-ktx:1.3.6'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.4.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.android.billingclient:billing:3.0.3'
|
||||
implementation 'nl.dionsegijn:konfetti:1.2.2'
|
||||
implementation 'com.google.android.play:core:1.10.0'
|
||||
implementation "com.google.android.material:material:1.3.0"
|
||||
implementation 'com.google.android.play:core:1.10.2'
|
||||
implementation "com.google.android.material:material:1.4.0"
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
|
||||
implementation "androidx.browser:browser:1.4.0"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.4.0'
|
||||
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
compileSdkVersion 31
|
||||
defaultConfig {
|
||||
applicationId "com.newsblur"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 196
|
||||
targetSdkVersion 31
|
||||
versionCode 198
|
||||
versionName "11.1.1"
|
||||
}
|
||||
compileOptions.with {
|
||||
|
|
BIN
clients/android/NewsBlur/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
clients/android/NewsBlur/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
8
clients/android/NewsBlur/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
8
clients/android/NewsBlur/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
#Wed Aug 11 15:59:29 EDT 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:bottom="44dp"
|
||||
android:drawable="@drawable/logo"
|
||||
android:left="44dp"
|
||||
android:right="44dp"
|
||||
android:top="44dp" />
|
||||
</layer-list>
|
||||
<!--This is a workaround until they fix the icon padding-->
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/logo"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:layout_centerInParent="true"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
|
@ -163,6 +163,7 @@
|
|||
<string name="menu_rename_feed">Rename feed</string>
|
||||
<string name="menu_story_list_style_choose">List style…</string>
|
||||
<string name="menu_save_search">Save Search</string>
|
||||
<string name="menu_web_search">Web search</string>
|
||||
<string name="list_style_list">List</string>
|
||||
<string name="list_style_grid_f">Grid (fine)</string>
|
||||
<string name="list_style_grid_m">Grid (medium)</string>
|
||||
|
@ -650,4 +651,6 @@
|
|||
<string name="story_notification_channel_id">story_notification_channel</string>
|
||||
<string name="story_notification_channel_name">New Stories</string>
|
||||
<string name="go_to_feed">Go to feed</string>
|
||||
|
||||
<string name="js_get_selection">(function(){return window.getSelection().toString()})()</string>
|
||||
</resources>
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
<item name="android:letterSpacing">0</item>
|
||||
</style>
|
||||
|
||||
<style name="initStyle" parent="Theme.MaterialComponents.Light.DarkActionBar.Bridge">
|
||||
<item name="android:windowBackground">@color/transparent</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<style name="splashScreen" parent="Theme.SplashScreen">
|
||||
<item name="windowSplashScreenBackground">@color/black</item>
|
||||
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_splash_screen</item>
|
||||
<item name="postSplashScreenTheme">@style/NewsBlurTheme</item>
|
||||
</style>
|
||||
|
||||
<style name="actionbar" parent="ThemeOverlay.MaterialComponents.Light">
|
||||
|
|
30
clients/android/NewsBlur/src/com/newsblur/NbApplication.kt
Normal file
30
clients/android/NewsBlur/src/com/newsblur/NbApplication.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
package com.newsblur
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
|
||||
class NbApplication : Application(), DefaultLifecycleObserver {
|
||||
|
||||
override fun onCreate() {
|
||||
super<Application>.onCreate()
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
super.onStart(owner)
|
||||
isAppForeground = true
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
super.onStop(owner)
|
||||
isAppForeground = false
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
var isAppForeground = false
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.newsblur.activity;
|
|||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import android.view.View;
|
||||
|
||||
|
@ -25,10 +27,10 @@ public class AddFeedExternal extends NbActivity implements AddFeedFragment.AddFe
|
|||
UIUtils.setupToolbar(this, R.drawable.logo, "Add Feed", true);
|
||||
|
||||
binding.loadingThrob.setEnabled(!ViewUtils.isPowerSaveMode(this));
|
||||
binding.loadingThrob.setColors(UIUtils.getColor(this, R.color.refresh_1),
|
||||
UIUtils.getColor(this, R.color.refresh_2),
|
||||
UIUtils.getColor(this, R.color.refresh_3),
|
||||
UIUtils.getColor(this, R.color.refresh_4));
|
||||
binding.loadingThrob.setColors(ContextCompat.getColor(this, R.color.refresh_1),
|
||||
ContextCompat.getColor(this, R.color.refresh_2),
|
||||
ContextCompat.getColor(this, R.color.refresh_3),
|
||||
ContextCompat.getColor(this, R.color.refresh_4));
|
||||
|
||||
Intent intent = getIntent();
|
||||
Uri uri = intent.getData();
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.newsblur.activity
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.R
|
||||
import com.newsblur.util.*
|
||||
|
||||
/**
|
||||
|
@ -13,17 +13,18 @@ import com.newsblur.util.*
|
|||
* DB connection used by all other Activities.
|
||||
*/
|
||||
class InitActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_init)
|
||||
|
||||
// do actual app launch after just a moment so the init screen smoothly loads
|
||||
lifecycleScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
start()
|
||||
}
|
||||
)
|
||||
installSplashScreen().also {
|
||||
it.setKeepVisibleCondition {
|
||||
// keep showing the splash screen until FeedUtils.offerInitContext(...)
|
||||
// finishes and UI ready to display
|
||||
FeedUtils.dbHelper != null || FeedUtils.thumbnailLoader != null
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.executeAsyncTask(doInBackground = { start() })
|
||||
Log.i(this, "cold launching version " + PrefsUtils.getVersion(this))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_REBUILD;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STATUS;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STORY;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_DB_READY;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_METADATA;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_REBUILD;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STATUS;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STATUS;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
|
|
@ -1,174 +0,0 @@
|
|||
package com.newsblur.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.PrefConstants.ThemeValue;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The base class for all Activities in the NewsBlur app. Handles enforcement of
|
||||
* login state and tracking of sync/update broadcasts.
|
||||
*/
|
||||
public class NbActivity extends AppCompatActivity {
|
||||
|
||||
public static final int UPDATE_DB_READY = (1<<0);
|
||||
public static final int UPDATE_METADATA = (1<<1);
|
||||
public static final int UPDATE_STORY = (1<<2);
|
||||
public static final int UPDATE_SOCIAL = (1<<3);
|
||||
public static final int UPDATE_INTEL = (1<<4);
|
||||
public static final int UPDATE_STATUS = (1<<5);
|
||||
public static final int UPDATE_TEXT = (1<<6);
|
||||
public static final int UPDATE_REBUILD = (1<<7);
|
||||
|
||||
private final static String UNIQUE_LOGIN_KEY = "uniqueLoginKey";
|
||||
private String uniqueLoginKey;
|
||||
|
||||
private ThemeValue lastTheme = null;
|
||||
|
||||
/**
|
||||
* Keep track of all activie activities so they can be notified when the sync service
|
||||
* has updated the DB. This is essentially an ultra-lightweight implementation of a
|
||||
* local, unfiltered broadcast manager.
|
||||
*/
|
||||
private static ArrayList<NbActivity> AllActivities = new ArrayList<NbActivity>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
com.newsblur.util.Log.offerContext(this);
|
||||
com.newsblur.util.Log.d(this, "onCreate");
|
||||
|
||||
// this is not redundant to the applyThemePreference() call in onResume. the theme needs to be set
|
||||
// before onCreate() in order to work
|
||||
PrefsUtils.applyThemePreference(this);
|
||||
lastTheme = PrefsUtils.getSelectedTheme(this);
|
||||
|
||||
// in rare cases of process interruption or DB corruption, an activity can launch without valid
|
||||
// login creds. redirect the user back to the loging workflow.
|
||||
if (PrefsUtils.getUserId(this) == null) {
|
||||
com.newsblur.util.Log.e(this, "post-login activity launched without valid login.");
|
||||
PrefsUtils.logout(this);
|
||||
finish();
|
||||
}
|
||||
|
||||
super.onCreate(bundle);
|
||||
|
||||
FeedUtils.offerInitContext(this);
|
||||
|
||||
if (bundle != null) {
|
||||
uniqueLoginKey = bundle.getString(UNIQUE_LOGIN_KEY);
|
||||
}
|
||||
if (uniqueLoginKey == null) {
|
||||
uniqueLoginKey = PrefsUtils.getUniqueLoginKey(this);
|
||||
}
|
||||
finishIfNotLoggedIn();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
com.newsblur.util.Log.d(this, "onResume" + UIUtils.getMemoryUsageDebug(this));
|
||||
super.onResume();
|
||||
finishIfNotLoggedIn();
|
||||
|
||||
// is is possible that another activity changed the theme while we were on the backstack
|
||||
if (lastTheme != PrefsUtils.getSelectedTheme(this)) {
|
||||
lastTheme = PrefsUtils.getSelectedTheme(this);
|
||||
PrefsUtils.applyThemePreference(this);
|
||||
UIUtils.restartActivity(this);
|
||||
}
|
||||
|
||||
synchronized (AllActivities) {
|
||||
AllActivities.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
com.newsblur.util.Log.d(this.getClass().getName(), "onPause");
|
||||
super.onPause();
|
||||
|
||||
synchronized (AllActivities) {
|
||||
AllActivities.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected void finishIfNotLoggedIn() {
|
||||
String currentLoginKey = PrefsUtils.getUniqueLoginKey(this);
|
||||
if(currentLoginKey == null || !currentLoginKey.equals(uniqueLoginKey)) {
|
||||
com.newsblur.util.Log.d(this.getClass().getName(), "This activity was for a different login. finishing it.");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle savedInstanceState) {
|
||||
com.newsblur.util.Log.d(this, "onSave");
|
||||
savedInstanceState.putString(UNIQUE_LOGIN_KEY, uniqueLoginKey);
|
||||
super.onSaveInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pokes the sync service to perform any pending sync actions.
|
||||
*/
|
||||
protected void triggerSync() {
|
||||
FeedUtils.triggerSync(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on each NB activity after the DB has been updated by the sync service.
|
||||
*
|
||||
* @param updateType one or more of the UPDATE_* flags in this class to indicate the
|
||||
* type of update being broadcast.
|
||||
*/
|
||||
protected void handleUpdate(int updateType) {
|
||||
com.newsblur.util.Log.w(this, "activity doesn't implement handleUpdate");
|
||||
}
|
||||
|
||||
private void _handleUpdate(final int updateType) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
handleUpdate(updateType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all activities in the app that the DB has been updated. Should only be called
|
||||
* by the sync service, which owns updating the DB.
|
||||
*/
|
||||
public static void updateAllActivities(int updateType) {
|
||||
synchronized (AllActivities) {
|
||||
for (NbActivity activity : AllActivities) {
|
||||
activity._handleUpdate(updateType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void toastError(final String message) {
|
||||
synchronized (AllActivities) {
|
||||
for (final NbActivity activity : AllActivities) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
UIUtils.safeToast(activity, message, Toast.LENGTH_SHORT);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of active/foreground NB activities. Used by the sync service to
|
||||
* determine if the app is active so we can honour user requests not to run in
|
||||
* the background.
|
||||
*/
|
||||
public static int getActiveActivityCount() {
|
||||
return AllActivities.size();
|
||||
}
|
||||
|
||||
}
|
116
clients/android/NewsBlur/src/com/newsblur/activity/NbActivity.kt
Normal file
116
clients/android/NewsBlur/src/com/newsblur/activity/NbActivity.kt
Normal file
|
@ -0,0 +1,116 @@
|
|||
package com.newsblur.activity
|
||||
|
||||
import android.content.IntentFilter
|
||||
import com.newsblur.util.FeedUtils.offerInitContext
|
||||
import com.newsblur.util.FeedUtils.triggerSync
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.newsblur.util.PrefConstants.ThemeValue
|
||||
import android.os.Bundle
|
||||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.UIUtils
|
||||
import com.newsblur.service.NBSyncReceiver
|
||||
import com.newsblur.util.Log
|
||||
|
||||
/**
|
||||
* The base class for all Activities in the NewsBlur app. Handles enforcement of
|
||||
* login state and tracking of sync/update broadcasts.
|
||||
*/
|
||||
open class NbActivity : AppCompatActivity() {
|
||||
|
||||
private var uniqueLoginKey: String? = null
|
||||
private var lastTheme: ThemeValue? = null
|
||||
|
||||
// Facilitates the db updates by the sync service on the UI
|
||||
private val serviceSyncReceiver = object : NBSyncReceiver() {
|
||||
override fun handleUpdateType(updateType: Int) {
|
||||
runOnUiThread { handleUpdate(updateType) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(bundle: Bundle?) {
|
||||
Log.offerContext(this)
|
||||
Log.d(this, "onCreate")
|
||||
|
||||
// this is not redundant to the applyThemePreference() call in onResume. the theme needs to be set
|
||||
// before onCreate() in order to work
|
||||
PrefsUtils.applyThemePreference(this)
|
||||
lastTheme = PrefsUtils.getSelectedTheme(this)
|
||||
|
||||
// in rare cases of process interruption or DB corruption, an activity can launch without valid
|
||||
// login creds. redirect the user back to the loging workflow.
|
||||
if (PrefsUtils.getUserId(this) == null) {
|
||||
Log.e(this, "post-login activity launched without valid login.")
|
||||
PrefsUtils.logout(this)
|
||||
finish()
|
||||
}
|
||||
|
||||
super.onCreate(bundle)
|
||||
offerInitContext(this)
|
||||
|
||||
bundle?.let {
|
||||
uniqueLoginKey = it.getString(UNIQUE_LOGIN_KEY)
|
||||
}
|
||||
|
||||
if (uniqueLoginKey == null) {
|
||||
uniqueLoginKey = PrefsUtils.getUniqueLoginKey(this)
|
||||
}
|
||||
|
||||
finishIfNotLoggedIn()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
Log.d(this, "onResume" + UIUtils.getMemoryUsageDebug(this))
|
||||
super.onResume()
|
||||
finishIfNotLoggedIn()
|
||||
|
||||
// is is possible that another activity changed the theme while we were on the backstack
|
||||
val currentSelectedTheme = PrefsUtils.getSelectedTheme(this)
|
||||
if (lastTheme != currentSelectedTheme) {
|
||||
lastTheme = currentSelectedTheme
|
||||
PrefsUtils.applyThemePreference(this)
|
||||
UIUtils.restartActivity(this)
|
||||
}
|
||||
registerReceiver(serviceSyncReceiver, IntentFilter().apply {
|
||||
addAction(NBSyncReceiver.NB_SYNC_ACTION)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
Log.d(this.javaClass.name, "onPause")
|
||||
super.onPause()
|
||||
unregisterReceiver(serviceSyncReceiver)
|
||||
}
|
||||
|
||||
private fun finishIfNotLoggedIn() {
|
||||
val currentLoginKey = PrefsUtils.getUniqueLoginKey(this)
|
||||
if (currentLoginKey == null || currentLoginKey != uniqueLoginKey) {
|
||||
Log.d(this.javaClass.name, "This activity was for a different login. finishing it.")
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
Log.d(this, "onSave")
|
||||
savedInstanceState.putString(UNIQUE_LOGIN_KEY, uniqueLoginKey)
|
||||
super.onSaveInstanceState(savedInstanceState)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pokes the sync service to perform any pending sync actions.
|
||||
*/
|
||||
protected fun triggerSync() {
|
||||
triggerSync(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on each NB activity after the DB has been updated by the sync service.
|
||||
*
|
||||
* @param updateType one or more of the UPDATE_* flags in this class to indicate the
|
||||
* type of update being broadcast.
|
||||
*/
|
||||
protected open fun handleUpdate(updateType: Int) {
|
||||
Log.w(this, "activity doesn't implement handleUpdate")
|
||||
}
|
||||
}
|
||||
|
||||
private const val UNIQUE_LOGIN_KEY = "uniqueLoginKey"
|
|
@ -24,6 +24,9 @@ import com.newsblur.databinding.ActivityReadingBinding
|
|||
import com.newsblur.domain.Story
|
||||
import com.newsblur.fragment.ReadingItemFragment
|
||||
import com.newsblur.fragment.ReadingPagerFragment
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_REBUILD
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_STATUS
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_STORY
|
||||
import com.newsblur.service.NBSyncService
|
||||
import com.newsblur.util.*
|
||||
import com.newsblur.util.PrefConstants.ThemeValue
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.newsblur.network.domain.CommentResponse;
|
|||
import com.newsblur.network.domain.StoriesResponse;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.ReadingAction;
|
||||
import com.newsblur.util.ReadFilter;
|
||||
|
@ -1641,6 +1642,10 @@ public class BlurDatabaseHelper {
|
|||
try {c.close();} catch (Exception e) {;}
|
||||
}
|
||||
|
||||
public void sendSyncUpdate(int updateType) {
|
||||
FeedUtils.syncUpdateStatus(context, updateType);
|
||||
}
|
||||
|
||||
private static String conjoinSelections(CharSequence... args) {
|
||||
StringBuilder s = null;
|
||||
for (CharSequence c : args) {
|
||||
|
@ -1674,5 +1679,4 @@ public class BlurDatabaseHelper {
|
|||
private Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
|
||||
return dbRO.query(distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit, cancellationSignal);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.newsblur.database;
|
||||
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STORY;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
@ -10,7 +12,6 @@ import androidx.viewpager.widget.PagerAdapter;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.activity.Reading;
|
||||
import com.newsblur.domain.Classifier;
|
||||
import com.newsblur.domain.Story;
|
||||
|
@ -283,7 +284,7 @@ public class ReadingAdapter extends PagerAdapter {
|
|||
ReadingItemFragment rif = fragments.get(s.storyHash);
|
||||
if (rif != null ) {
|
||||
rif.offerStoryUpdate(s);
|
||||
rif.handleUpdate(NbActivity.UPDATE_STORY);
|
||||
rif.handleUpdate(UPDATE_STORY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,9 @@ package com.newsblur.fragment;
|
|||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.activity.ItemsList;
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.SavedSearch;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
|
@ -75,18 +73,17 @@ public class DeleteFeedFragment extends DialogFragment {
|
|||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
if (getArguments().getString(FEED_TYPE).equals(NORMAL_FEED)) {
|
||||
FeedUtils.deleteFeed(getArguments().getString(FEED_ID), getArguments().getString(FOLDER_NAME), new APIManager(getActivity()));
|
||||
FeedUtils.deleteFeed(getArguments().getString(FEED_ID), getArguments().getString(FOLDER_NAME), getActivity());
|
||||
} else if (getArguments().getString(FEED_TYPE).equals(SAVED_SEARCH_FEED)) {
|
||||
FeedUtils.deleteSavedSearch(getArguments().getString(FEED_ID), getArguments().getString(QUERY), new APIManager(getActivity()));
|
||||
FeedUtils.deleteSavedSearch(getArguments().getString(FEED_ID), getArguments().getString(QUERY), getActivity());
|
||||
} else {
|
||||
FeedUtils.deleteSocialFeed(getArguments().getString(FEED_ID), new APIManager(getActivity()));
|
||||
FeedUtils.deleteSocialFeed(getArguments().getString(FEED_ID), getActivity());
|
||||
}
|
||||
// if called from a feed view, end it
|
||||
Activity activity = DeleteFeedFragment.this.getActivity();
|
||||
if (activity instanceof ItemsList) {
|
||||
activity.finish();
|
||||
}
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA);
|
||||
DeleteFeedFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.database.Cursor;
|
|||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
|
@ -202,7 +203,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
View v = inflater.inflate(R.layout.fragment_folderfeedlist, container);
|
||||
binding = FragmentFolderfeedlistBinding.bind(v);
|
||||
|
||||
binding.folderfeedList.setGroupIndicator(UIUtils.getDrawable(getActivity(), R.drawable.transparent));
|
||||
binding.folderfeedList.setGroupIndicator(ContextCompat.getDrawable(requireContext(), R.drawable.transparent));
|
||||
binding.folderfeedList.setOnCreateContextMenuListener(this);
|
||||
binding.folderfeedList.setOnChildClickListener(this);
|
||||
binding.folderfeedList.setOnGroupClickListener(this);
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.os.Bundle;
|
|||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
@ -121,21 +122,19 @@ public class ItemSetFragment extends NbFragment implements LoaderManager.LoaderC
|
|||
fleuronBinding = RowFleuronBinding.bind(fleuronView);
|
||||
|
||||
// disable the throbbers if animations are going to have a zero time scale
|
||||
boolean isDisableAnimations = ViewUtils.isPowerSaveMode(getActivity());
|
||||
boolean isDisableAnimations = ViewUtils.isPowerSaveMode(requireContext());
|
||||
|
||||
int[] colorsArray = {ContextCompat.getColor(requireContext(), R.color.refresh_1),
|
||||
ContextCompat.getColor(requireContext(), R.color.refresh_2),
|
||||
ContextCompat.getColor(requireContext(), R.color.refresh_3),
|
||||
ContextCompat.getColor(requireContext(), R.color.refresh_4)};
|
||||
binding.topLoadingThrob.setEnabled(!isDisableAnimations);
|
||||
binding.topLoadingThrob.setColors(UIUtils.getColor(getActivity(), R.color.refresh_1),
|
||||
UIUtils.getColor(getActivity(), R.color.refresh_2),
|
||||
UIUtils.getColor(getActivity(), R.color.refresh_3),
|
||||
UIUtils.getColor(getActivity(), R.color.refresh_4));
|
||||
binding.topLoadingThrob.setColors(colorsArray);
|
||||
|
||||
View footerView = inflater.inflate(R.layout.row_loading_throbber, null);
|
||||
bottomProgressView = (ProgressThrobber) footerView.findViewById(R.id.itemlist_loading_throb);
|
||||
bottomProgressView.setEnabled(!isDisableAnimations);
|
||||
bottomProgressView.setColors(UIUtils.getColor(getActivity(), R.color.refresh_1),
|
||||
UIUtils.getColor(getActivity(), R.color.refresh_2),
|
||||
UIUtils.getColor(getActivity(), R.color.refresh_3),
|
||||
UIUtils.getColor(getActivity(), R.color.refresh_4));
|
||||
bottomProgressView.setColors(colorsArray);
|
||||
|
||||
fleuronBinding.getRoot().setVisibility(View.INVISIBLE);
|
||||
fleuronBinding.containerSubscribe.setOnClickListener(view -> UIUtils.startPremiumActivity(requireContext()));
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.R
|
||||
|
@ -38,19 +39,17 @@ abstract class ProfileActivityDetailsFragment : Fragment(), OnItemClickListener
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_profileactivity, null)
|
||||
binding = FragmentProfileactivityBinding.bind(view)
|
||||
binding.emptyViewLoadingThrob.setColors(UIUtils.getColor(activity, R.color.refresh_1),
|
||||
UIUtils.getColor(activity, R.color.refresh_2),
|
||||
UIUtils.getColor(activity, R.color.refresh_3),
|
||||
UIUtils.getColor(activity, R.color.refresh_4))
|
||||
val colorsArray = intArrayOf(ContextCompat.getColor(requireContext(), R.color.refresh_1),
|
||||
ContextCompat.getColor(requireContext(), R.color.refresh_2),
|
||||
ContextCompat.getColor(requireContext(), R.color.refresh_3),
|
||||
ContextCompat.getColor(requireContext(), R.color.refresh_4))
|
||||
binding.emptyViewLoadingThrob.setColors(*colorsArray)
|
||||
binding.profileDetailsActivitylist.setFooterDividersEnabled(false)
|
||||
binding.profileDetailsActivitylist.emptyView = binding.emptyView
|
||||
|
||||
val footerView = inflater.inflate(R.layout.row_loading_throbber, null)
|
||||
footerBinding = RowLoadingThrobberBinding.bind(footerView)
|
||||
footerBinding.itemlistLoadingThrob.setColors(UIUtils.getColor(activity, R.color.refresh_1),
|
||||
UIUtils.getColor(activity, R.color.refresh_2),
|
||||
UIUtils.getColor(activity, R.color.refresh_3),
|
||||
UIUtils.getColor(activity, R.color.refresh_4))
|
||||
footerBinding.itemlistLoadingThrob.setColors(*colorsArray)
|
||||
binding.profileDetailsActivitylist.addFooterView(footerView, null, false)
|
||||
if (adapter != null) {
|
||||
displayActivities()
|
||||
|
|
|
@ -19,7 +19,6 @@ import androidx.lifecycle.lifecycleScope
|
|||
import com.google.android.material.chip.Chip
|
||||
import com.newsblur.R
|
||||
import com.newsblur.activity.FeedItemsList
|
||||
import com.newsblur.activity.NbActivity
|
||||
import com.newsblur.activity.Reading
|
||||
import com.newsblur.databinding.FragmentReadingitemBinding
|
||||
import com.newsblur.databinding.IncludeReadingItemCommentBinding
|
||||
|
@ -28,6 +27,10 @@ import com.newsblur.domain.Story
|
|||
import com.newsblur.domain.UserDetails
|
||||
import com.newsblur.fragment.StoryUserTagsFragment.Companion.newInstance
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_INTEL
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_SOCIAL
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_STORY
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_TEXT
|
||||
import com.newsblur.service.OriginalTextService
|
||||
import com.newsblur.util.*
|
||||
import com.newsblur.util.PrefConstants.ThemeValue
|
||||
|
@ -380,11 +383,11 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
binding.itemFeedBorder.setBackgroundColor(Color.parseColor("#$feedBorder"))
|
||||
|
||||
if (faviconText == "black") {
|
||||
binding.readingFeedTitle.setTextColor(UIUtils.getColor(requireContext(), R.color.text))
|
||||
binding.readingFeedTitle.setShadowLayer(1f, 0f, 1f, UIUtils.getColor(requireContext(), R.color.half_white))
|
||||
binding.readingFeedTitle.setTextColor(ContextCompat.getColor(requireContext(), R.color.text))
|
||||
binding.readingFeedTitle.setShadowLayer(1f, 0f, 1f, ContextCompat.getColor(requireContext(), R.color.half_white))
|
||||
} else {
|
||||
binding.readingFeedTitle.setTextColor(UIUtils.getColor(requireContext(), R.color.white))
|
||||
binding.readingFeedTitle.setShadowLayer(1f, 0f, 1f, UIUtils.getColor(requireContext(), R.color.half_black))
|
||||
binding.readingFeedTitle.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
|
||||
binding.readingFeedTitle.setShadowLayer(1f, 0f, 1f, ContextCompat.getColor(requireContext(), R.color.half_black))
|
||||
}
|
||||
if (!displayFeedDetails) {
|
||||
binding.readingFeedTitle.visibility = View.GONE
|
||||
|
@ -497,8 +500,8 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
binding.readingItemAuthors.text = "• " + story!!.authors
|
||||
if (classifier != null && classifier!!.authors.containsKey(story!!.authors)) {
|
||||
when (classifier!!.authors[story!!.authors]) {
|
||||
Classifier.LIKE -> binding.readingItemAuthors.setTextColor(UIUtils.getColor(requireContext(), R.color.positive))
|
||||
Classifier.DISLIKE -> binding.readingItemAuthors.setTextColor(UIUtils.getColor(requireContext(), R.color.negative))
|
||||
Classifier.LIKE -> binding.readingItemAuthors.setTextColor(ContextCompat.getColor(requireContext(), R.color.positive))
|
||||
Classifier.DISLIKE -> binding.readingItemAuthors.setTextColor(ContextCompat.getColor(requireContext(), R.color.negative))
|
||||
else -> binding.readingItemAuthors.setTextColor(UIUtils.getThemedColor(requireContext(), R.attr.readingItemMetadata, android.R.attr.textColor))
|
||||
}
|
||||
}
|
||||
|
@ -598,19 +601,19 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
}
|
||||
|
||||
fun handleUpdate(updateType: Int) {
|
||||
if (updateType and NbActivity.UPDATE_STORY != 0) {
|
||||
if (updateType and UPDATE_STORY != 0) {
|
||||
updateSaveButton()
|
||||
updateShareButton()
|
||||
setupItemCommentsAndShares()
|
||||
}
|
||||
if (updateType and NbActivity.UPDATE_TEXT != 0) {
|
||||
if (updateType and UPDATE_TEXT != 0) {
|
||||
reloadStoryContent()
|
||||
}
|
||||
if (updateType and NbActivity.UPDATE_SOCIAL != 0) {
|
||||
if (updateType and UPDATE_SOCIAL != 0) {
|
||||
updateShareButton()
|
||||
setupItemCommentsAndShares()
|
||||
}
|
||||
if (updateType and NbActivity.UPDATE_INTEL != 0) {
|
||||
if (updateType and UPDATE_INTEL != 0) {
|
||||
classifier = FeedUtils.dbHelper!!.getClassifierForFeed(story!!.feedId)
|
||||
setupTagsAndIntel()
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ public class NewsBlurResponse {
|
|||
public String message;
|
||||
public String[] errors;
|
||||
public long readTime;
|
||||
public int impactCode;
|
||||
|
||||
public boolean isError() {
|
||||
if (isProtocolError) return true;
|
||||
|
|
|
@ -7,6 +7,8 @@ import android.content.ComponentName;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.widget.WidgetUtils;
|
||||
|
||||
|
@ -17,10 +19,12 @@ import com.newsblur.widget.WidgetUtils;
|
|||
public class BootReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
com.newsblur.util.Log.d(this, "triggering sync service from device boot");
|
||||
scheduleSyncService(context);
|
||||
resetWidgetSync(context);
|
||||
public void onReceive(Context context, @Nullable Intent intent) {
|
||||
if (intent != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
com.newsblur.util.Log.d(this, "triggering sync service from device boot");
|
||||
scheduleSyncService(context);
|
||||
resetWidgetSync(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void scheduleSyncService(Context context) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package com.newsblur.service
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
abstract class NBSyncReceiver : BroadcastReceiver() {
|
||||
|
||||
abstract fun handleUpdateType(updateType: Int)
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action == NB_SYNC_ACTION) {
|
||||
handleUpdateType(intent.getIntExtra(NB_SYNC_UPDATE_TYPE, 0))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NB_SYNC_ACTION = "nb.sync.action"
|
||||
const val NB_SYNC_ERROR_MESSAGE = "nb_sync_error_msg"
|
||||
const val NB_SYNC_UPDATE_TYPE = "nb_sync_update_type"
|
||||
|
||||
const val UPDATE_DB_READY = 1 shl 0
|
||||
const val UPDATE_METADATA = 1 shl 1
|
||||
const val UPDATE_STORY = 1 shl 2
|
||||
const val UPDATE_SOCIAL = 1 shl 3
|
||||
const val UPDATE_INTEL = 1 shl 4
|
||||
const val UPDATE_STATUS = 1 shl 5
|
||||
const val UPDATE_TEXT = 1 shl 6
|
||||
const val UPDATE_REBUILD = 1 shl 7
|
||||
}
|
||||
}
|
|
@ -9,10 +9,18 @@ import android.content.Intent;
|
|||
import android.database.Cursor;
|
||||
import android.os.Process;
|
||||
|
||||
import com.newsblur.NbApplication;
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import static com.newsblur.database.BlurDatabaseHelper.closeQuietly;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_DB_READY;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_METADATA;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_REBUILD;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STATUS;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STORY;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
|
@ -182,7 +190,7 @@ public class NBSyncService extends JobService {
|
|||
public int onStartCommand(Intent intent, int flags, final int startId) {
|
||||
com.newsblur.util.Log.d(this, "onStartCommand");
|
||||
// only perform a sync if the app is actually running or background syncs are enabled
|
||||
if ((NbActivity.getActiveActivityCount() > 0) || PrefsUtils.isBackgroundNeeded(this)) {
|
||||
if (NbApplication.isAppForeground() || PrefsUtils.isBackgroundNeeded(this)) {
|
||||
HaltNow = false;
|
||||
// Services actually get invoked on the main system thread, and are not
|
||||
// allowed to do tangible work. We spawn a thread to do so.
|
||||
|
@ -215,7 +223,7 @@ public class NBSyncService extends JobService {
|
|||
public boolean onStartJob(final JobParameters params) {
|
||||
com.newsblur.util.Log.d(this, "onStartJob");
|
||||
// only perform a sync if the app is actually running or background syncs are enabled
|
||||
if ((NbActivity.getActiveActivityCount() > 0) || PrefsUtils.isBackgroundNeeded(this)) {
|
||||
if (NbApplication.isAppForeground() || PrefsUtils.isBackgroundNeeded(this)) {
|
||||
HaltNow = false;
|
||||
// Services actually get invoked on the main system thread, and are not
|
||||
// allowed to do tangible work. We spawn a thread to do so.
|
||||
|
@ -260,7 +268,7 @@ public class NBSyncService extends JobService {
|
|||
|
||||
Log.d(this, "starting primary sync");
|
||||
|
||||
if (NbActivity.getActiveActivityCount() < 1) {
|
||||
if (!NbApplication.isAppForeground()) {
|
||||
// if the UI isn't running, politely run at background priority
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
} else {
|
||||
|
@ -273,7 +281,7 @@ public class NBSyncService extends JobService {
|
|||
if (OfflineNow) {
|
||||
if (NetworkUtils.isOnline(this)) {
|
||||
OfflineNow = false;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
} else {
|
||||
com.newsblur.util.Log.d(this, "Abandoning sync: network still offline");
|
||||
return;
|
||||
|
@ -285,7 +293,7 @@ public class NBSyncService extends JobService {
|
|||
housekeeping();
|
||||
|
||||
// check to see if we are on an allowable network only after ensuring we have CPU
|
||||
if (!( (NbActivity.getActiveActivityCount() > 0) ||
|
||||
if (!( NbApplication.isAppForeground() ||
|
||||
PrefsUtils.isEnableNotifications(this) ||
|
||||
PrefsUtils.isBackgroundNetworkAllowed(this) ||
|
||||
WidgetUtils.hasActiveAppWidgets(this)) ) {
|
||||
|
@ -294,7 +302,7 @@ public class NBSyncService extends JobService {
|
|||
}
|
||||
|
||||
// ping activities to indicate that housekeeping is done, and the DB is safe to use
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_DB_READY);
|
||||
sendSyncUpdate(UPDATE_DB_READY);
|
||||
|
||||
// async text requests might have been queued up and are being waiting on by the live UI. give them priority
|
||||
originalTextService.start();
|
||||
|
@ -337,10 +345,10 @@ public class NBSyncService extends JobService {
|
|||
boolean upgraded = PrefsUtils.checkForUpgrade(this);
|
||||
if (upgraded) {
|
||||
HousekeepingRunning = true;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS | NbActivity.UPDATE_REBUILD);
|
||||
sendSyncUpdate(UPDATE_STATUS | UPDATE_REBUILD);
|
||||
// wipe the local DB if this is a first background run. if this is a first foreground
|
||||
// run, InitActivity will have wiped for us
|
||||
if (NbActivity.getActiveActivityCount() < 1) {
|
||||
if (!NbApplication.isAppForeground()) {
|
||||
dbHelper.dropAndRecreateTables();
|
||||
}
|
||||
// in case this is the first time we have run since moving the cache to the new location,
|
||||
|
@ -353,11 +361,11 @@ public class NBSyncService extends JobService {
|
|||
|
||||
boolean autoVac = PrefsUtils.isTimeToVacuum(this);
|
||||
// this will lock up the DB for a few seconds, only do it if the UI is hidden
|
||||
if (NbActivity.getActiveActivityCount() > 0) autoVac = false;
|
||||
if (NbApplication.isAppForeground()) autoVac = false;
|
||||
|
||||
if (upgraded || autoVac) {
|
||||
HousekeepingRunning = true;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
com.newsblur.util.Log.i(this.getClass().getName(), "rebuilding DB . . .");
|
||||
dbHelper.vacuum();
|
||||
com.newsblur.util.Log.i(this.getClass().getName(), ". . . . done rebuilding DB");
|
||||
|
@ -366,7 +374,7 @@ public class NBSyncService extends JobService {
|
|||
} finally {
|
||||
if (HousekeepingRunning) {
|
||||
HousekeepingRunning = false;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA);
|
||||
sendSyncUpdate(UPDATE_METADATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +395,7 @@ public class NBSyncService extends JobService {
|
|||
ActionsRunning = true;
|
||||
|
||||
actionsloop : while (c.moveToNext()) {
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
String id = c.getString(c.getColumnIndexOrThrow(DatabaseConstants.ACTION_ID));
|
||||
ReadingAction ra;
|
||||
try {
|
||||
|
@ -419,18 +427,19 @@ public class NBSyncService extends JobService {
|
|||
com.newsblur.util.Log.i(this.getClass().getName(), "Discarding reading action with fatal message.");
|
||||
dbHelper.clearAction(id);
|
||||
String message = response.getErrorMessage(null);
|
||||
if (message != null) NbActivity.toastError(message);
|
||||
if (message != null) sendToastError(message);
|
||||
} else {
|
||||
// success!
|
||||
dbHelper.clearAction(id);
|
||||
FollowupActions.add(ra);
|
||||
sendSyncUpdate(response.impactCode);
|
||||
}
|
||||
lastActionCount--;
|
||||
}
|
||||
} finally {
|
||||
closeQuietly(c);
|
||||
ActionsRunning = false;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,7 +457,7 @@ public class NBSyncService extends JobService {
|
|||
int impact = ra.doLocal(dbHelper, true);
|
||||
impactFlags |= impact;
|
||||
}
|
||||
NbActivity.updateAllActivities(impactFlags);
|
||||
sendSyncUpdate(impactFlags);
|
||||
|
||||
// if there is a feed fetch loop running, don't clear, there will likely be races for
|
||||
// stories that were just tapped as they were being re-fetched
|
||||
|
@ -484,7 +493,7 @@ public class NBSyncService extends JobService {
|
|||
com.newsblur.util.Log.i(this.getClass().getName(), "ready to sync feed list");
|
||||
|
||||
FFSyncRunning = true;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
|
||||
// there is an issue with feeds that have no folder or folders that list feeds that do not exist. capture them for workarounds.
|
||||
Set<String> debugFeedIdsFromFolders = new HashSet<String>();
|
||||
|
@ -618,7 +627,7 @@ public class NBSyncService extends JobService {
|
|||
|
||||
} finally {
|
||||
FFSyncRunning = false;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA | NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_METADATA | UPDATE_STATUS);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -633,7 +642,7 @@ public class NBSyncService extends JobService {
|
|||
if (RecountCandidates.size() < 1) return;
|
||||
|
||||
RecountsRunning = true;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
|
||||
// of all candidate feeds that were touched, now check to see if any
|
||||
// actually need their counts fetched
|
||||
|
@ -699,7 +708,7 @@ public class NBSyncService extends JobService {
|
|||
} finally {
|
||||
if (RecountsRunning) {
|
||||
RecountsRunning = false;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA | NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_METADATA | UPDATE_STATUS);
|
||||
}
|
||||
FlushRecounts = false;
|
||||
}
|
||||
|
@ -760,7 +769,7 @@ public class NBSyncService extends JobService {
|
|||
ReadFilter filter = PrefsUtils.getReadFilter(this, fs);
|
||||
|
||||
StorySyncRunning = true;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
|
||||
while (totalStoriesSeen < PendingFeedTarget) {
|
||||
if (stopSync()) return;
|
||||
|
@ -784,7 +793,7 @@ public class NBSyncService extends JobService {
|
|||
insertStories(apiResponse, fs);
|
||||
// re-do any very recent actions that were incorrectly overwritten by this page
|
||||
finishActions();
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STORY | NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STORY | UPDATE_STATUS);
|
||||
|
||||
prefetchOriginalText(apiResponse);
|
||||
|
||||
|
@ -804,7 +813,7 @@ public class NBSyncService extends JobService {
|
|||
|
||||
} finally {
|
||||
StorySyncRunning = false;
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
sendSyncUpdate(UPDATE_STATUS);
|
||||
synchronized (PENDING_FEED_MUTEX) {
|
||||
if (finished && fs.equals(PendingFeed)) PendingFeed = null;
|
||||
}
|
||||
|
@ -996,7 +1005,7 @@ public class NBSyncService extends JobService {
|
|||
}
|
||||
|
||||
private boolean backoffBackgroundCalls() {
|
||||
if (NbActivity.getActiveActivityCount() > 0) return false;
|
||||
if (NbApplication.isAppForeground()) return false;
|
||||
if (System.currentTimeMillis() > (lastAPIFailure + AppConstants.API_BACKGROUND_BACKOFF_MILLIS)) return false;
|
||||
com.newsblur.util.Log.i(this.getClass().getName(), "abandoning background sync due to recent API failures.");
|
||||
return true;
|
||||
|
@ -1128,7 +1137,7 @@ public class NBSyncService extends JobService {
|
|||
dbHelper.prepareReadingSession(fs);
|
||||
// note which feedset we are loading so we can trigger another reset when it changes
|
||||
dbHelper.setSessionFeedSet(fs);
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STORY | NbActivity.UPDATE_STATUS);
|
||||
dbHelper.sendSyncUpdate(UPDATE_STORY | UPDATE_STATUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1241,4 +1250,21 @@ public class NBSyncService extends JobService {
|
|||
return s.toString();
|
||||
}
|
||||
|
||||
protected void sendSyncUpdate(int update) {
|
||||
Intent i = new Intent(NBSyncReceiver.NB_SYNC_ACTION);
|
||||
i.putExtra(NBSyncReceiver.NB_SYNC_UPDATE_TYPE, update);
|
||||
broadcastSync(i);
|
||||
}
|
||||
|
||||
protected void sendToastError(@NonNull String message) {
|
||||
Intent i = new Intent(NBSyncReceiver.NB_SYNC_ACTION);
|
||||
i.putExtra(NBSyncReceiver.NB_SYNC_ERROR_MESSAGE, message);
|
||||
broadcastSync(i);
|
||||
}
|
||||
|
||||
private void broadcastSync(@NonNull Intent intent) {
|
||||
if (NbApplication.isAppForeground()) {
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.newsblur.service;
|
||||
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_TEXT;
|
||||
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.network.domain.StoryTextResponse;
|
||||
import com.newsblur.util.AppConstants;
|
||||
|
@ -84,7 +85,7 @@ public class OriginalTextService extends SubService {
|
|||
}
|
||||
}
|
||||
} finally {
|
||||
gotData(NbActivity.UPDATE_TEXT);
|
||||
parent.sendSyncUpdate(UPDATE_TEXT);
|
||||
hashes.removeAll(fetchedHashes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package com.newsblur.service;
|
||||
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STATUS;
|
||||
|
||||
import android.os.Process;
|
||||
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.NbApplication;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.Log;
|
||||
|
||||
|
@ -36,7 +38,7 @@ public abstract class SubService {
|
|||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
if (parent.stopSync()) return;
|
||||
if (NbActivity.getActiveActivityCount() < 1) {
|
||||
if (!NbApplication.isAppForeground()) {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_LESS_FAVORABLE );
|
||||
} else {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT + Process.THREAD_PRIORITY_LESS_FAVORABLE + Process.THREAD_PRIORITY_LESS_FAVORABLE );
|
||||
|
@ -52,7 +54,7 @@ public abstract class SubService {
|
|||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
parent.checkCompletion();
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STATUS);
|
||||
parent.sendSyncUpdate(UPDATE_STATUS);
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException ree) {
|
||||
|
@ -85,10 +87,6 @@ public abstract class SubService {
|
|||
}
|
||||
}
|
||||
|
||||
protected void gotData(int updateType) {
|
||||
NbActivity.updateAllActivities(updateType);
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
// don't advise completion until there are no tasks, or just one check task left
|
||||
return (executor.getQueue().size() > 0);
|
||||
|
@ -115,7 +113,7 @@ public abstract class SubService {
|
|||
long cooloffTimeMs = Math.round(cooloffTime / 1000000.0);
|
||||
if (cooloffTimeMs > AppConstants.DUTY_CYCLE_BACKOFF_CAP_MILLIS) cooloffTimeMs = AppConstants.DUTY_CYCLE_BACKOFF_CAP_MILLIS;
|
||||
|
||||
if (NbActivity.getActiveActivityCount() > 0 ) {
|
||||
if (NbApplication.isAppForeground()) {
|
||||
com.newsblur.util.Log.d(this.getClass().getName(), "Sleeping for : " + cooloffTimeMs + "ms to enforce max duty cycle.");
|
||||
try {
|
||||
Thread.sleep(cooloffTimeMs);
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
package com.newsblur.util
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
private const val TAG = "NBScope"
|
||||
|
||||
fun <R> CoroutineScope.executeAsyncTask(
|
||||
onPreExecute: () -> Unit = { },
|
||||
onPreExecute: () -> Unit = { },
|
||||
doInBackground: () -> R,
|
||||
onPostExecute: (R) -> Unit = { }) =
|
||||
onPostExecute: (R) -> Unit = { }) =
|
||||
launch {
|
||||
onPreExecute()
|
||||
val result = withContext(Dispatchers.IO) { doInBackground() }
|
||||
onPostExecute(result)
|
||||
}
|
||||
}
|
||||
|
||||
val NBScope = CoroutineScope(
|
||||
CoroutineName(TAG) +
|
||||
Dispatchers.Default +
|
||||
SupervisorJob() + // children coroutines won't stop parent if they cancel or error
|
||||
CoroutineExceptionHandler { context, throwable ->
|
||||
Log.e(TAG, "Coroutine exception on context $context with $throwable")
|
||||
})
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import com.newsblur.NbApplication
|
||||
import com.newsblur.R
|
||||
import com.newsblur.activity.NbActivity
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
|
@ -12,7 +13,10 @@ import com.newsblur.fragment.ReadingActionConfirmationFragment
|
|||
import com.newsblur.network.APIConstants
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.service.NBSyncService
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import com.newsblur.service.NBSyncReceiver
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_METADATA
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_SOCIAL
|
||||
import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_STORY
|
||||
import java.util.*
|
||||
|
||||
object FeedUtils {
|
||||
|
@ -70,7 +74,7 @@ object FeedUtils {
|
|||
|
||||
@JvmStatic
|
||||
fun prepareReadingSession(fs: FeedSet?, resetFirst: Boolean) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
try {
|
||||
if (resetFirst) NBSyncService.resetReadingSession(dbHelper)
|
||||
|
@ -96,11 +100,11 @@ object FeedUtils {
|
|||
}
|
||||
|
||||
private fun setStorySaved(storyHash: String?, saved: Boolean, context: Context, userTags: List<String?>?) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
val ra = if (saved) ReadingAction.saveStory(storyHash, userTags) else ReadingAction.unsaveStory(storyHash)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STORY)
|
||||
syncUpdateStatus(context, UPDATE_STORY)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
@ -108,15 +112,15 @@ object FeedUtils {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteSavedSearch(feedId: String?, query: String?, apiManager: APIManager) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
fun deleteSavedSearch(feedId: String?, query: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.deleteSearch(feedId, query)
|
||||
APIManager(context).deleteSearch(feedId, query)
|
||||
},
|
||||
onPostExecute = { newsBlurResponse ->
|
||||
if (!newsBlurResponse.isError) {
|
||||
dbHelper!!.deleteSavedSearch(feedId, query)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -124,7 +128,7 @@ object FeedUtils {
|
|||
|
||||
@JvmStatic
|
||||
fun saveSearch(feedId: String?, query: String?, context: Context, apiManager: APIManager) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.saveSearch(feedId, query)
|
||||
},
|
||||
|
@ -138,36 +142,36 @@ object FeedUtils {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteFeed(feedId: String?, folderName: String?, apiManager: APIManager) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
fun deleteFeed(feedId: String?, folderName: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.deleteFeed(feedId, folderName)
|
||||
APIManager(context).deleteFeed(feedId, folderName)
|
||||
},
|
||||
onPostExecute = {
|
||||
// TODO: we can't check result.isError() because the delete call sets the .message property on all calls. find a better error check
|
||||
dbHelper!!.deleteFeed(feedId)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteSocialFeed(userId: String?, apiManager: APIManager) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
fun deleteSocialFeed(userId: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.unfollowUser(userId)
|
||||
APIManager(context).unfollowUser(userId)
|
||||
},
|
||||
onPostExecute = {
|
||||
// TODO: we can't check result.isError() because the delete call sets the .message property on all calls. find a better error check
|
||||
dbHelper!!.deleteSocialFeed(userId)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteFolder(folderName: String?, inFolder: String?, context: Context, apiManager: APIManager) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.deleteFolder(folderName, inFolder)
|
||||
},
|
||||
|
@ -189,7 +193,7 @@ object FeedUtils {
|
|||
|
||||
@JvmStatic
|
||||
fun renameFolder(folderName: String?, newFolderName: String?, inFolder: String?, context: Context, apiManager: APIManager) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.renameFolder(folderName, newFolderName, inFolder)
|
||||
},
|
||||
|
@ -204,7 +208,7 @@ object FeedUtils {
|
|||
|
||||
@JvmStatic
|
||||
fun markStoryUnread(story: Story, context: Context) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
setStoryReadState(story, context, false)
|
||||
}
|
||||
|
@ -213,7 +217,7 @@ object FeedUtils {
|
|||
|
||||
@JvmStatic
|
||||
fun markStoryAsRead(story: Story, context: Context) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
setStoryReadState(story, context, true)
|
||||
}
|
||||
|
@ -238,7 +242,7 @@ object FeedUtils {
|
|||
|
||||
// update unread state and unread counts in the local DB
|
||||
val impactedFeeds = dbHelper!!.setStoryReadState(story, read)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_STORY)
|
||||
syncUpdateStatus(context, UPDATE_STORY)
|
||||
|
||||
NBSyncService.addRecountCandidates(impactedFeeds)
|
||||
triggerSync(context)
|
||||
|
@ -351,7 +355,7 @@ object FeedUtils {
|
|||
}
|
||||
|
||||
private fun updateFeedNotifications(context: Context, feed: Feed, enable: Boolean, focusOnly: Boolean) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
if (focusOnly) {
|
||||
feed.setNotifyFocus()
|
||||
|
@ -369,11 +373,11 @@ object FeedUtils {
|
|||
@JvmStatic
|
||||
fun doAction(ra: ReadingAction?, context: Context) {
|
||||
requireNotNull(ra) { "ReadingAction must not be null" }
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
val impact = ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(impact)
|
||||
syncUpdateStatus(context, impact)
|
||||
triggerSync(context)
|
||||
}
|
||||
)
|
||||
|
@ -418,7 +422,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.shareStory(story.storyHash, story.id, story.feedId, sourceUserId, comment)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_SOCIAL or NbActivity.UPDATE_STORY)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL or UPDATE_STORY)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -427,7 +431,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.renameFeed(feedId, newFeedName)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
val impact = ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(impact)
|
||||
syncUpdateStatus(context, impact)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -436,7 +440,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.unshareStory(story.storyHash, story.id, story.feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_SOCIAL or NbActivity.UPDATE_STORY)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL or UPDATE_STORY)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -444,7 +448,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.likeComment(story.id, commentUserId, story.feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_SOCIAL)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -452,7 +456,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.unlikeComment(story.id, commentUserId, story.feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_SOCIAL)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -461,7 +465,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.replyToComment(storyId, feedId, commentUserId, replyText)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_SOCIAL)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -470,7 +474,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.updateReply(story.id, story.feedId, commentUserId, replyId, replyText)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_SOCIAL)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -479,14 +483,14 @@ object FeedUtils {
|
|||
val ra = ReadingAction.deleteReply(story.id, story.feedId, commentUserId, replyId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_SOCIAL)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun moveFeedToFolders(context: Context, feedId: String?, toFolders: Set<String?>, inFolders: Set<String?>?) {
|
||||
if (toFolders.isEmpty()) return
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
val apiManager = APIManager(context)
|
||||
apiManager.moveFeedToFolders(feedId, toFolders, inFolders)
|
||||
|
@ -509,7 +513,7 @@ object FeedUtils {
|
|||
}
|
||||
|
||||
private fun updateFeedActiveState(context: Context, feedIds: Set<String>, active: Boolean) {
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
val activeFeeds = dbHelper!!.allActiveFeeds
|
||||
for (feedId in feedIds) {
|
||||
|
@ -529,7 +533,7 @@ object FeedUtils {
|
|||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
triggerSync(context)
|
||||
}
|
||||
)
|
||||
|
@ -540,7 +544,7 @@ object FeedUtils {
|
|||
val ra = ReadingAction.instaFetch(feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
NbActivity.updateAllActivities(NbActivity.UPDATE_METADATA)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
|
@ -593,4 +597,15 @@ object FeedUtils {
|
|||
val url = APIConstants.buildUrl(APIConstants.PATH_FEED_STATISTICS + feedId)
|
||||
UIUtils.handleUri(context, Uri.parse(url))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun syncUpdateStatus(context: Context, updateType: Int) {
|
||||
if (NbApplication.isAppForeground) {
|
||||
Intent(NBSyncReceiver.NB_SYNC_ACTION).apply {
|
||||
putExtra(NBSyncReceiver.NB_SYNC_UPDATE_TYPE, updateType)
|
||||
}.also {
|
||||
context.sendBroadcast(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,12 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.newsblur.activity.Reading
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
||||
class NotifyDismissReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(c: Context, i: Intent) {
|
||||
val storyHash = i.getStringExtra(Reading.EXTRA_STORY_HASH)
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.offerInitContext(c)
|
||||
FeedUtils.dbHelper!!.putStoryDismissed(storyHash)
|
||||
|
|
|
@ -4,14 +4,13 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.newsblur.activity.Reading
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
||||
class NotifyMarkreadReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(c: Context, i: Intent) {
|
||||
val storyHash = i.getStringExtra(Reading.EXTRA_STORY_HASH)
|
||||
NotificationUtils.cancel(c, storyHash.hashCode())
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.offerInitContext(c)
|
||||
FeedUtils.dbHelper!!.putStoryDismissed(storyHash)
|
||||
|
|
|
@ -4,14 +4,13 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.newsblur.activity.Reading
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
||||
class NotifySaveReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(c: Context, i: Intent) {
|
||||
val storyHash = i.getStringExtra(Reading.EXTRA_STORY_HASH)
|
||||
NotificationUtils.cancel(c, storyHash.hashCode())
|
||||
GlobalScope.executeAsyncTask(
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.offerInitContext(c)
|
||||
FeedUtils.dbHelper!!.putStoryDismissed(storyHash)
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package com.newsblur.util;
|
||||
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_INTEL;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_METADATA;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_SOCIAL;
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STORY;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.domain.Classifier;
|
||||
|
@ -13,13 +17,13 @@ import com.newsblur.network.domain.CommentResponse;
|
|||
import com.newsblur.network.domain.NewsBlurResponse;
|
||||
import com.newsblur.network.domain.StoriesResponse;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.service.NBSyncReceiver;
|
||||
import com.newsblur.service.NBSyncService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class ReadingAction implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
@ -370,7 +374,7 @@ public class ReadingAction implements Serializable {
|
|||
} else {
|
||||
com.newsblur.util.Log.w(this, "failed to refresh story data after action");
|
||||
}
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= NBSyncReceiver.UPDATE_SOCIAL;
|
||||
}
|
||||
if (commentResponse != null) {
|
||||
result = commentResponse;
|
||||
|
@ -379,10 +383,11 @@ public class ReadingAction implements Serializable {
|
|||
} else {
|
||||
com.newsblur.util.Log.w(this, "failed to refresh comment data after action");
|
||||
}
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= NBSyncReceiver.UPDATE_SOCIAL;
|
||||
}
|
||||
if (result != null && impact != 0) {
|
||||
result.impactCode = impact;
|
||||
}
|
||||
|
||||
NbActivity.updateAllActivities(impact);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -408,48 +413,48 @@ public class ReadingAction implements Serializable {
|
|||
dbHelper.markStoriesRead(feedSet, olderThan, newerThan);
|
||||
dbHelper.updateLocalFeedCounts(feedSet);
|
||||
}
|
||||
impact |= NbActivity.UPDATE_METADATA;
|
||||
impact |= NbActivity.UPDATE_STORY;
|
||||
impact |= UPDATE_METADATA;
|
||||
impact |= UPDATE_STORY;
|
||||
break;
|
||||
|
||||
case MARK_UNREAD:
|
||||
dbHelper.setStoryReadState(storyHash, false);
|
||||
impact |= NbActivity.UPDATE_METADATA;
|
||||
impact |= UPDATE_METADATA;
|
||||
break;
|
||||
|
||||
case SAVE:
|
||||
dbHelper.setStoryStarred(storyHash, userTags, true);
|
||||
impact |= NbActivity.UPDATE_METADATA;
|
||||
impact |= UPDATE_METADATA;
|
||||
break;
|
||||
|
||||
case UNSAVE:
|
||||
dbHelper.setStoryStarred(storyHash, null, false);
|
||||
impact |= NbActivity.UPDATE_METADATA;
|
||||
impact |= UPDATE_METADATA;
|
||||
break;
|
||||
|
||||
case SHARE:
|
||||
if (isFollowup) break; // shares are only placeholders
|
||||
dbHelper.setStoryShared(storyHash, true);
|
||||
dbHelper.insertCommentPlaceholder(storyId, feedId, commentReplyText);
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= NbActivity.UPDATE_STORY;
|
||||
impact |= UPDATE_SOCIAL;
|
||||
impact |= UPDATE_STORY;
|
||||
break;
|
||||
|
||||
case UNSHARE:
|
||||
dbHelper.setStoryShared(storyHash, false);
|
||||
dbHelper.clearSelfComments(storyId);
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= NbActivity.UPDATE_STORY;
|
||||
impact |= UPDATE_SOCIAL;
|
||||
impact |= UPDATE_STORY;
|
||||
break;
|
||||
|
||||
case LIKE_COMMENT:
|
||||
dbHelper.setCommentLiked(storyId, commentUserId, feedId, true);
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= UPDATE_SOCIAL;
|
||||
break;
|
||||
|
||||
case UNLIKE_COMMENT:
|
||||
dbHelper.setCommentLiked(storyId, commentUserId, feedId, false);
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= UPDATE_SOCIAL;
|
||||
break;
|
||||
|
||||
case REPLY:
|
||||
|
@ -459,22 +464,22 @@ public class ReadingAction implements Serializable {
|
|||
|
||||
case EDIT_REPLY:
|
||||
dbHelper.editReply(replyId, commentReplyText);
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= UPDATE_SOCIAL;
|
||||
break;
|
||||
|
||||
case DELETE_REPLY:
|
||||
dbHelper.deleteReply(replyId);
|
||||
impact |= NbActivity.UPDATE_SOCIAL;
|
||||
impact |= UPDATE_SOCIAL;
|
||||
break;
|
||||
|
||||
case MUTE_FEEDS:
|
||||
case UNMUTE_FEEDS:
|
||||
dbHelper.setFeedsActive(modifiedFeedIds, type == ActionType.UNMUTE_FEEDS);
|
||||
impact |= NbActivity.UPDATE_METADATA;
|
||||
impact |= UPDATE_METADATA;
|
||||
break;
|
||||
|
||||
case SET_NOTIFY:
|
||||
impact |= NbActivity.UPDATE_METADATA;
|
||||
impact |= UPDATE_METADATA;
|
||||
break;
|
||||
|
||||
case INSTA_FETCH:
|
||||
|
@ -489,12 +494,12 @@ public class ReadingAction implements Serializable {
|
|||
dbHelper.clearClassifiersForFeed(feedId);
|
||||
classifier.feedId = feedId;
|
||||
dbHelper.insertClassifier(classifier);
|
||||
impact |= NbActivity.UPDATE_INTEL;
|
||||
impact |= UPDATE_INTEL;
|
||||
break;
|
||||
|
||||
case RENAME_FEED:
|
||||
dbHelper.renameFeed(feedId, newFeedName);
|
||||
impact |= NbActivity.UPDATE_METADATA;
|
||||
impact |= UPDATE_METADATA;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -8,6 +8,7 @@ import static com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROL
|
|||
import static com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.SearchManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
|
@ -303,15 +304,6 @@ public class UIUtils {
|
|||
return memInfo;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static int getColor(Context activity, int rid) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return activity.getResources().getColor(rid, activity.getTheme());
|
||||
} else {
|
||||
return activity.getResources().getColor(rid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a color defined by our particular way of using styles that are indirectly defined by themes.
|
||||
*
|
||||
|
@ -376,15 +368,6 @@ public class UIUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Drawable getDrawable(Context activity, int rid) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return activity.getResources().getDrawable(rid, activity.getTheme());
|
||||
} else {
|
||||
return activity.getResources().getDrawable(rid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background resource of a view, working around a platform bug that causes the declared
|
||||
* padding to get reset.
|
||||
|
@ -440,26 +423,17 @@ public class UIUtils {
|
|||
*/
|
||||
public static void setupIntelDialogRow(final View row, final Map<String,Integer> classifier, final String key) {
|
||||
colourIntelDialogRow(row, classifier, key);
|
||||
row.findViewById(R.id.intel_row_like).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
classifier.put(key, Classifier.LIKE);
|
||||
colourIntelDialogRow(row, classifier, key);
|
||||
}
|
||||
row.findViewById(R.id.intel_row_like).setOnClickListener(v -> {
|
||||
classifier.put(key, Classifier.LIKE);
|
||||
colourIntelDialogRow(row, classifier, key);
|
||||
});
|
||||
row.findViewById(R.id.intel_row_dislike).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
classifier.put(key, Classifier.DISLIKE);
|
||||
colourIntelDialogRow(row, classifier, key);
|
||||
}
|
||||
row.findViewById(R.id.intel_row_dislike).setOnClickListener(v -> {
|
||||
classifier.put(key, Classifier.DISLIKE);
|
||||
colourIntelDialogRow(row, classifier, key);
|
||||
});
|
||||
row.findViewById(R.id.intel_row_clear).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
classifier.put(key, Classifier.CLEAR_LIKE);
|
||||
colourIntelDialogRow(row, classifier, key);
|
||||
}
|
||||
row.findViewById(R.id.intel_row_clear).setOnClickListener(v -> {
|
||||
classifier.put(key, Classifier.CLEAR_LIKE);
|
||||
colourIntelDialogRow(row, classifier, key);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -584,6 +558,16 @@ public class UIUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void openWebSearch(Context context, String query) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH );
|
||||
intent.putExtra(SearchManager.QUERY, query);
|
||||
context.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
com.newsblur.util.Log.e(context.getClass().getName(), "Browser app not available to search: " + query);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean needsPremiumAccess(Context context, FeedSet feedSet) {
|
||||
boolean isPremium = PrefsUtils.getIsPremium(context);
|
||||
boolean requiresPremium = feedSet.isFolder() || feedSet.isInfrequent() ||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package com.newsblur.view;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ActionMode;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.WebChromeClient;
|
||||
|
@ -16,24 +20,23 @@ import android.webkit.WebView;
|
|||
import android.webkit.WebViewClient;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.activity.Reading;
|
||||
import com.newsblur.fragment.ReadingItemFragment;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
public class NewsblurWebview extends WebView {
|
||||
|
||||
private NewsblurWebViewClient webViewClient;
|
||||
private NewsblurWebChromeClient webChromeClient;
|
||||
private final NewsblurWebChromeClient webChromeClient;
|
||||
private boolean isCustomViewShowing;
|
||||
private Context context;
|
||||
|
||||
public ReadingItemFragment fragment;
|
||||
// we need the less-abstract activity class in order to manipulate the overlay widgets
|
||||
public Reading activity;
|
||||
|
||||
public NewsblurWebview(Context context, AttributeSet attrs) {
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
public NewsblurWebview(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.context = context;
|
||||
|
||||
setVerticalScrollBarEnabled(false);
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
|
@ -46,30 +49,51 @@ public class NewsblurWebview extends WebView {
|
|||
getSettings().setAllowFileAccess(true);
|
||||
getSettings().setAppCacheEnabled(true);
|
||||
|
||||
// Explicitly remove the system default web search menu item in case it's available
|
||||
// to add a custom web search menu item to ensure menu item availability
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
|
||||
getSettings().getDisabledActionModeMenuItems() == WebSettings.MENU_ITEM_NONE) {
|
||||
getSettings().setDisabledActionModeMenuItems(WebSettings.MENU_ITEM_WEB_SEARCH);
|
||||
}
|
||||
|
||||
this.setScrollBarStyle(SCROLLBARS_INSIDE_OVERLAY);
|
||||
|
||||
// handle links, loading progress, and error callbacks
|
||||
webViewClient = new NewsblurWebViewClient();
|
||||
setWebViewClient(webViewClient);
|
||||
setWebViewClient(new NewsblurWebViewClient());
|
||||
|
||||
// do the minimum handling of view swapping so that fullscreen HTML5 works, for videos.
|
||||
webChromeClient = new NewsblurWebChromeClient();
|
||||
setWebChromeClient(webChromeClient);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a custom web search menu item to the web view contextual menu
|
||||
@Override
|
||||
public ActionMode startActionMode(ActionMode.Callback callback, int type) {
|
||||
ActionMode actionMode = super.startActionMode(callback, type);
|
||||
Menu menu = actionMode.getMenu();
|
||||
menu.add(R.string.menu_web_search).setOnMenuItemClickListener(menuItem -> {
|
||||
contextualWebSearch();
|
||||
actionMode.finish();
|
||||
return true;
|
||||
});
|
||||
return actionMode;
|
||||
}
|
||||
|
||||
private void contextualWebSearch() {
|
||||
evaluateJavascript(getContext().getString(R.string.js_get_selection), value -> {
|
||||
// remove beginning and ending double quotes
|
||||
String query = value.replaceAll("^\"|\"$", "");
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
UIUtils.openWebSearch(getContext(), query);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTextSize(float textSize) {
|
||||
String script = "javascript:document.body.style.fontSize='" + textSize + "em';";
|
||||
evaluateJavascript(script, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* http://stackoverflow.com/questions/5994066/webview-ontouch-handling-when-the-user-does-not-click-a-link
|
||||
*/
|
||||
public boolean wasLinkClicked() {
|
||||
WebView.HitTestResult result = getHitTestResult();
|
||||
return (result != null && result.getExtra() != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* If HTML5 views (like fullscreen video) are to work, we need a container in which to put them.
|
||||
* If the activity using this webview creates a hidden layout under/over this webview, we can
|
||||
|
@ -90,14 +114,14 @@ public class NewsblurWebview extends WebView {
|
|||
class NewsblurWebViewClient extends WebViewClient {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
UIUtils.handleUri(context, Uri.parse(url));
|
||||
UIUtils.handleUri(getContext(), Uri.parse(url));
|
||||
return true;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
UIUtils.handleUri(context, request.getUrl());
|
||||
UIUtils.handleUri(getContext(), request.getUrl());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -179,5 +203,4 @@ public class NewsblurWebview extends WebView {
|
|||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue