mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
parent
4a43b0c1f3
commit
2d260e9324
83 changed files with 1104 additions and 544 deletions
|
@ -1,5 +1,5 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.6.0'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
|
@ -9,8 +9,9 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "com.google.dagger:hilt-android-gradle-plugin:2.38.1"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +26,8 @@ repositories {
|
|||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'dagger.hilt.android.plugin'
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.fragment:fragment-ktx:1.4.1'
|
||||
|
@ -41,6 +44,9 @@ dependencies {
|
|||
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-beta01'
|
||||
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
|
||||
implementation "com.google.dagger:hilt-android:2.38.1"
|
||||
kapt "com.google.dagger:hilt-compiler:2.38.1"
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
@ -4,7 +4,9 @@ import android.app.Application
|
|||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class NbApplication : Application(), DefaultLifecycleObserver {
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.newsblur.domain.UserDetails;
|
|||
import com.newsblur.fragment.ProfileActivitiesFragment;
|
||||
import com.newsblur.fragment.ProfileActivityDetailsFragment;
|
||||
import com.newsblur.fragment.ProfileInteractionsFragment;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
|
||||
/**
|
||||
* Created by mark on 15/06/15.
|
||||
|
@ -55,8 +56,8 @@ public class ActivityDetailsPagerAdapter extends FragmentPagerAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
public void setUser(UserDetails user) {
|
||||
interactionsFragment.setUser(profile, user);
|
||||
activitiesFragment.setUser(profile, user);
|
||||
public void setUser(UserDetails user, ImageLoader iconLoader) {
|
||||
interactionsFragment.setUser(profile, user, iconLoader);
|
||||
activitiesFragment.setUser(profile, user, iconLoader);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ import com.newsblur.R;
|
|||
import com.newsblur.fragment.AddSocialFragment;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class AddSocial extends NbActivity {
|
||||
|
||||
private FragmentManager fragmentManager;
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.newsblur.util.AppConstants;
|
|||
import com.newsblur.util.FeedOrderFilter;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.FolderViewFilter;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.ListOrderFilter;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
||||
|
@ -45,14 +46,18 @@ public class FeedChooserAdapter extends BaseExpandableListAdapter {
|
|||
protected FolderViewFilter folderViewFilter;
|
||||
protected ListOrderFilter listOrderFilter;
|
||||
protected FeedOrderFilter feedOrderFilter;
|
||||
protected final FeedUtils feedUtils;
|
||||
protected final ImageLoader iconLoader;
|
||||
|
||||
protected float textSize;
|
||||
|
||||
FeedChooserAdapter(Context context) {
|
||||
FeedChooserAdapter(Context context, FeedUtils feedUtils, ImageLoader iconLoader) {
|
||||
folderViewFilter = PrefsUtils.getFeedChooserFolderView(context);
|
||||
listOrderFilter = PrefsUtils.getFeedChooserListOrder(context);
|
||||
feedOrderFilter = PrefsUtils.getFeedChooserFeedOrder(context);
|
||||
textSize = PrefsUtils.getListTextSize(context);
|
||||
this.feedUtils = feedUtils;
|
||||
this.iconLoader = iconLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -141,7 +146,7 @@ public class FeedChooserAdapter extends BaseExpandableListAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
FeedUtils.iconLoader.displayImage(feed.faviconUrl, img, img.getHeight(), true);
|
||||
iconLoader.displayImage(feed.faviconUrl, img, img.getHeight(), true);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public class FeedItemsList extends ItemsList {
|
|||
|
||||
super.onCreate(bundle);
|
||||
|
||||
UIUtils.setupToolbar(this, feed.faviconUrl, feed.title, false);
|
||||
UIUtils.setupToolbar(this, feed.faviconUrl, feed.title, iconLoader, false);
|
||||
checkInAppReview();
|
||||
}
|
||||
|
||||
|
@ -79,19 +79,19 @@ public class FeedItemsList extends ItemsList {
|
|||
return true;
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_notifications_disable) {
|
||||
FeedUtils.disableNotifications(this, feed);
|
||||
feedUtils.disableNotifications(this, feed);
|
||||
return true;
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_notifications_focus) {
|
||||
FeedUtils.enableFocusNotifications(this, feed);
|
||||
feedUtils.enableFocusNotifications(this, feed);
|
||||
return true;
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_notifications_unread) {
|
||||
FeedUtils.enableUnreadNotifications(this, feed);
|
||||
feedUtils.enableUnreadNotifications(this, feed);
|
||||
return true;
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_instafetch_feed) {
|
||||
FeedUtils.instaFetchFeed(this, feed.feedId);
|
||||
feedUtils.instaFetchFeed(this, feed.feedId);
|
||||
this.finish();
|
||||
return true;
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ public class FeedItemsList extends ItemsList {
|
|||
// the name change won't be reflected until the activity finishes.
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_statistics) {
|
||||
FeedUtils.openStatistics(this, feed.feedId);
|
||||
feedUtils.openStatistics(this, feed.feedId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.newsblur.activity;
|
|||
import android.os.Bundle;
|
||||
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
public class FeedReading extends Reading {
|
||||
|
@ -16,14 +15,14 @@ public class FeedReading extends Reading {
|
|||
// if the activity got launch with a missing FeedSet, it will be in the process of cancelling
|
||||
return;
|
||||
}
|
||||
Feed feed = FeedUtils.dbHelper.getFeed(fs.getSingleFeed());
|
||||
Feed feed = dbHelper.getFeed(fs.getSingleFeed());
|
||||
if (feed == null) {
|
||||
// if this is somehow an intent so stale that the feed no longer exists, bail.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
UIUtils.setupToolbar(this, feed.faviconUrl, feed.title, false);
|
||||
UIUtils.setupToolbar(this, feed.faviconUrl, feed.title, iconLoader, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,17 +10,29 @@ import androidx.fragment.app.DialogFragment
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.activity.FeedSearchAdapter.OnFeedSearchResultClickListener
|
||||
import com.newsblur.databinding.ActivityFeedSearchBinding
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.domain.FeedResult
|
||||
import com.newsblur.fragment.AddFeedFragment
|
||||
import com.newsblur.fragment.AddFeedFragment.AddFeedProgressListener
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.ImageLoader
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FeedSearchActivity : NbActivity(), OnFeedSearchResultClickListener, AddFeedProgressListener {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
@IconLoader
|
||||
@Inject
|
||||
lateinit var iconLoader: ImageLoader
|
||||
|
||||
private val supportedUrlProtocols: MutableSet<String> = HashSet(2)
|
||||
|
||||
init {
|
||||
|
@ -30,7 +42,6 @@ class FeedSearchActivity : NbActivity(), OnFeedSearchResultClickListener, AddFee
|
|||
|
||||
private lateinit var adapter: FeedSearchAdapter
|
||||
private lateinit var binding: ActivityFeedSearchBinding
|
||||
private lateinit var apiManager: APIManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -38,7 +49,6 @@ class FeedSearchActivity : NbActivity(), OnFeedSearchResultClickListener, AddFee
|
|||
setContentView(binding.root)
|
||||
setupViews()
|
||||
setupListeners()
|
||||
apiManager = APIManager(this)
|
||||
binding.inputSearchQuery.requestFocus()
|
||||
}
|
||||
|
||||
|
@ -55,7 +65,7 @@ class FeedSearchActivity : NbActivity(), OnFeedSearchResultClickListener, AddFee
|
|||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(false)
|
||||
|
||||
adapter = FeedSearchAdapter(this)
|
||||
adapter = FeedSearchAdapter(this, iconLoader)
|
||||
binding.feedResultList.adapter = adapter
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,11 @@ import com.newsblur.R
|
|||
import com.newsblur.databinding.ViewFeedSearchRowBinding
|
||||
import com.newsblur.domain.FeedResult
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.util.ImageLoader
|
||||
|
||||
class FeedSearchAdapter(
|
||||
private val onClickListener: OnFeedSearchResultClickListener
|
||||
private val onClickListener: OnFeedSearchResultClickListener,
|
||||
private val iconLoader: ImageLoader
|
||||
) : RecyclerView.Adapter<FeedSearchAdapter.ViewHolder>() {
|
||||
|
||||
private val resultsList: MutableList<FeedResult> = mutableListOf()
|
||||
|
@ -44,7 +46,7 @@ class FeedSearchAdapter(
|
|||
fun bind(result: FeedResult) {
|
||||
val resultFaviconUrl = result.faviconUrl
|
||||
if (resultFaviconUrl.isNotEmpty()) {
|
||||
FeedUtils.iconLoader?.displayImage(resultFaviconUrl, binding.imgFeedIcon)
|
||||
iconLoader.displayImage(resultFaviconUrl, binding.imgFeedIcon)
|
||||
}
|
||||
|
||||
binding.textTitle.text = result.label
|
||||
|
|
|
@ -6,7 +6,6 @@ import android.view.MenuItem;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.fragment.InfrequentCutoffDialogFragment;
|
||||
import com.newsblur.fragment.InfrequentCutoffDialogFragment.InfrequentCutoffChangedListener;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
|
@ -33,7 +32,7 @@ public class InfrequentItemsList extends ItemsList implements InfrequentCutoffCh
|
|||
@Override
|
||||
public void infrequentCutoffChanged(int newValue) {
|
||||
PrefsUtils.setInfrequentCutoff(this, newValue);
|
||||
FeedUtils.dbHelper.clearInfrequentSession();
|
||||
dbHelper.clearInfrequentSession();
|
||||
restartReadingSession();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,34 +5,32 @@ import android.os.Bundle
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.service.SubscriptionSyncService
|
||||
import com.newsblur.util.*
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The very first activity we launch. Checks to see if there is a user logged in yet and then
|
||||
* either loads the Main UI or a Login screen as needed. Also responsible for warming up the
|
||||
* DB connection used by all other Activities.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class InitActivity : AppCompatActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
installSplashScreen().also {
|
||||
it.setKeepOnScreenCondition() {
|
||||
// keep showing the splash screen until FeedUtils.offerInitContext(...)
|
||||
// finishes and UI ready to display
|
||||
FeedUtils.dbHelper != null || FeedUtils.thumbnailLoader != null
|
||||
}
|
||||
}
|
||||
installSplashScreen()
|
||||
|
||||
lifecycleScope.executeAsyncTask(doInBackground = { start() })
|
||||
Log.i(this, "cold launching version " + PrefsUtils.getVersion(this))
|
||||
}
|
||||
|
||||
private fun start() {
|
||||
// this is the first Activity launched; use it to init the global singletons in FeedUtils
|
||||
FeedUtils.offerInitContext(this)
|
||||
|
||||
// it is safe to call repeatedly because creating an existing notification performs
|
||||
// no operation
|
||||
NotificationUtils.createNotificationChannel(this)
|
||||
|
@ -60,7 +58,7 @@ class InitActivity : AppCompatActivity() {
|
|||
private fun upgradeCheck() {
|
||||
val upgrade = PrefsUtils.checkForUpgrade(this)
|
||||
if (upgrade) {
|
||||
FeedUtils.dbHelper!!.dropAndRecreateTables()
|
||||
dbHelper.dropAndRecreateTables()
|
||||
// don't actually unset the upgrade flag, the sync service will do this same check and
|
||||
// update everything
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@ import android.widget.SeekBar;
|
|||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.databinding.ActivityItemslistBinding;
|
||||
import com.newsblur.di.IconLoader;
|
||||
import com.newsblur.fragment.ItemSetFragment;
|
||||
import com.newsblur.fragment.ReadFilterDialogFragment;
|
||||
import com.newsblur.fragment.SaveSearchFragment;
|
||||
|
@ -28,6 +30,7 @@ import com.newsblur.service.NBSyncService;
|
|||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.PrefConstants.ThemeValue;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.ReadFilter;
|
||||
|
@ -40,8 +43,23 @@ import com.newsblur.util.StoryOrderChangedListener;
|
|||
import com.newsblur.util.ThumbnailStyle;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public abstract class ItemsList extends NbActivity implements StoryOrderChangedListener, ReadFilterChangedListener, OnSeekBarChangeListener {
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
ImageLoader iconLoader;
|
||||
|
||||
public static final String EXTRA_FEED_SET = "feed_set";
|
||||
public static final String EXTRA_STORY_HASH = "story_hash";
|
||||
public static final String EXTRA_WIDGET_STORY = "widget_story";
|
||||
|
@ -68,13 +86,13 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
// this is not strictly necessary, since our first refresh with the fs will swap in
|
||||
// the correct session, but that can be delayed by sync backup, so we try here to
|
||||
// reduce UI lag, or in case somehow we got redisplayed in a zero-story state
|
||||
FeedUtils.prepareReadingSession(fs, false);
|
||||
feedUtils.prepareReadingSession(fs, false);
|
||||
|
||||
if (getIntent().getBooleanExtra(EXTRA_WIDGET_STORY, false)) {
|
||||
String hash = (String) getIntent().getSerializableExtra(EXTRA_STORY_HASH);
|
||||
UIUtils.startReadingActivity(fs, hash, this);
|
||||
} else if (PrefsUtils.isAutoOpenFirstUnread(this)) {
|
||||
if (FeedUtils.dbHelper.getUnreadCount(fs, intelState) > 0) {
|
||||
if (dbHelper.getUnreadCount(fs, intelState) > 0) {
|
||||
UIUtils.startReadingActivity(fs, Reading.FIND_FIRST_UNREAD, this);
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +300,7 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
finish();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.menu_mark_all_as_read) {
|
||||
FeedUtils.markRead(this, fs, null, null, R.array.mark_all_read_options, true);
|
||||
feedUtils.markRead(this, fs, null, null, R.array.mark_all_read_options, true);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.menu_story_order) {
|
||||
StoryOrder currentValue = getStoryOrder();
|
||||
|
@ -432,7 +450,7 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
String oldQuery = fs.getSearchQuery();
|
||||
fs.setSearchQuery(q);
|
||||
if (!TextUtils.equals(q, oldQuery)) {
|
||||
FeedUtils.prepareReadingSession(fs, true);
|
||||
feedUtils.prepareReadingSession(fs, true);
|
||||
triggerSync();
|
||||
itemSetFragment.resetEmptyState();
|
||||
itemSetFragment.hasUpdated();
|
||||
|
@ -474,7 +492,7 @@ public abstract class ItemsList extends NbActivity implements StoryOrderChangedL
|
|||
|
||||
protected void restartReadingSession() {
|
||||
NBSyncService.resetFetchState(fs);
|
||||
FeedUtils.prepareReadingSession(fs, true);
|
||||
feedUtils.prepareReadingSession(fs, true);
|
||||
triggerSync();
|
||||
itemSetFragment.resetEmptyState();
|
||||
itemSetFragment.hasUpdated();
|
||||
|
|
|
@ -15,11 +15,16 @@ import com.newsblur.service.SubscriptionSyncService
|
|||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.UIUtils
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LoginProgress : FragmentActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
private lateinit var binding: ActivityLoginProgressBinding
|
||||
private lateinit var apiManager: APIManager
|
||||
|
||||
override fun onCreate(bundle: Bundle?) {
|
||||
PrefsUtils.applyThemePreference(this)
|
||||
|
@ -31,8 +36,6 @@ class LoginProgress : FragmentActivity() {
|
|||
val username = intent.getStringExtra("username")
|
||||
val password = intent.getStringExtra("password")
|
||||
|
||||
apiManager = APIManager(this)
|
||||
|
||||
lifecycleScope.executeAsyncTask(
|
||||
onPreExecute = {
|
||||
val a = AnimationUtils.loadAnimation(this, R.anim.text_up)
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.widget.SeekBar;
|
|||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.databinding.ActivityMainBinding;
|
||||
import com.newsblur.fragment.FeedIntelligenceSelectorFragment;
|
||||
import com.newsblur.fragment.FolderListFragment;
|
||||
|
@ -45,8 +46,19 @@ import com.newsblur.util.UIUtils;
|
|||
import com.newsblur.view.StateToggleButton.StateChangedListener;
|
||||
import com.newsblur.widget.WidgetUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class Main extends NbActivity implements StateChangedListener, SwipeRefreshLayout.OnRefreshListener, AbsListView.OnScrollListener, PopupMenu.OnMenuItemClickListener, OnSeekBarChangeListener {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
public static final String EXTRA_FORCE_SHOW_FEED_ID = "force_show_feed_id";
|
||||
|
||||
private FolderListFragment folderFeedList;
|
||||
|
@ -110,7 +122,7 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
|||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
});
|
||||
|
||||
FeedUtils.currentFolderName = null;
|
||||
feedUtils.currentFolderName = null;
|
||||
|
||||
binding.mainMenuButton.setOnClickListener(v -> onClickMenuButton());
|
||||
binding.mainAddButton.setOnClickListener(v -> onClickAddButton());
|
||||
|
@ -151,7 +163,7 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
|||
// will be required, however inefficient
|
||||
folderFeedList.hasUpdated();
|
||||
|
||||
NBSyncService.resetReadingSession(FeedUtils.dbHelper);
|
||||
NBSyncService.resetReadingSession(dbHelper);
|
||||
NBSyncService.flushRecounts();
|
||||
|
||||
updateStatusIndicators();
|
||||
|
@ -296,12 +308,12 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
|||
startActivity(widgetIntent);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.menu_feedback_email) {
|
||||
PrefsUtils.sendLogEmail(this);
|
||||
PrefsUtils.sendLogEmail(this, dbHelper);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.menu_feedback_post) {
|
||||
try {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(PrefsUtils.createFeedbackLink(this)));
|
||||
i.setData(Uri.parse(PrefsUtils.createFeedbackLink(this, dbHelper)));
|
||||
startActivity(i);
|
||||
} catch (Exception e) {
|
||||
Log.wtf(this.getClass().getName(), "device cannot even open URLs to report feedback");
|
||||
|
|
|
@ -16,11 +16,13 @@ import androidx.core.content.ContextCompat;
|
|||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.databinding.ActivityMuteConfigBinding;
|
||||
import com.newsblur.di.IconLoader;
|
||||
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.ImageLoader;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
|
@ -29,8 +31,17 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class MuteConfig extends FeedChooser implements MuteConfigAdapter.FeedStateChangedListener {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
ImageLoader iconLoader;
|
||||
|
||||
private ActivityMuteConfigBinding binding;
|
||||
private boolean checkedInitFeedsLimit = false;
|
||||
|
||||
|
@ -66,7 +77,7 @@ public class MuteConfig extends FeedChooser implements MuteConfigAdapter.FeedSta
|
|||
|
||||
@Override
|
||||
void setupList() {
|
||||
adapter = new MuteConfigAdapter(this, this);
|
||||
adapter = new MuteConfigAdapter(this, feedUtils, iconLoader, this);
|
||||
binding.listView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
|
@ -162,8 +173,8 @@ public class MuteConfig extends FeedChooser implements MuteConfigAdapter.FeedSta
|
|||
}
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
if (isMute) FeedUtils.muteFeeds(this, adapter.feedIds);
|
||||
else FeedUtils.unmuteFeeds(this, adapter.feedIds);
|
||||
if (isMute) feedUtils.muteFeeds(this, adapter.feedIds);
|
||||
else feedUtils.unmuteFeeds(this, adapter.feedIds);
|
||||
}
|
||||
|
||||
private void showAccountFeedsLimitDialog(int exceededLimitCount) {
|
||||
|
@ -211,8 +222,8 @@ public class MuteConfig extends FeedChooser implements MuteConfigAdapter.FeedSta
|
|||
inactiveFeedIds.add(feed.feedId);
|
||||
}
|
||||
}
|
||||
FeedUtils.unmuteFeeds(this, activeFeedIds);
|
||||
FeedUtils.muteFeeds(this, inactiveFeedIds);
|
||||
feedUtils.unmuteFeeds(this, activeFeedIds);
|
||||
feedUtils.muteFeeds(this, inactiveFeedIds);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.widget.ImageView;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
@ -18,8 +19,8 @@ public class MuteConfigAdapter extends FeedChooserAdapter {
|
|||
|
||||
private FeedStateChangedListener listener;
|
||||
|
||||
MuteConfigAdapter(Context context, FeedStateChangedListener listener) {
|
||||
super(context);
|
||||
MuteConfigAdapter(Context context, FeedUtils feedUtils, ImageLoader imageLoader, FeedStateChangedListener listener) {
|
||||
super(context, feedUtils, imageLoader);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
|
@ -45,8 +46,8 @@ public class MuteConfigAdapter extends FeedChooserAdapter {
|
|||
}
|
||||
|
||||
// if allAreMute initially, we need to unMute feeds
|
||||
if (allAreMute) FeedUtils.unmuteFeeds(groupView.getContext(), feedIds);
|
||||
else FeedUtils.muteFeeds(groupView.getContext(), feedIds);
|
||||
if (allAreMute) feedUtils.unmuteFeeds(groupView.getContext(), feedIds);
|
||||
else feedUtils.muteFeeds(groupView.getContext(), feedIds);
|
||||
|
||||
listener.onFeedStateChanged();
|
||||
notifyDataChanged();
|
||||
|
@ -70,8 +71,8 @@ public class MuteConfigAdapter extends FeedChooserAdapter {
|
|||
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);
|
||||
if (feed.active) feedUtils.unmuteFeeds(childView.getContext(), feedIds);
|
||||
else feedUtils.muteFeeds(childView.getContext(), feedIds);
|
||||
|
||||
listener.onFeedStateChanged();
|
||||
notifyDataChanged();
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
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.database.BlurDatabaseHelper
|
||||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.UIUtils
|
||||
import com.newsblur.service.NBSyncReceiver
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.util.Log
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The base class for all Activities in the NewsBlur app. Handles enforcement of
|
||||
* login state and tracking of sync/update broadcasts.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
open class NbActivity : AppCompatActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
private var uniqueLoginKey: String? = null
|
||||
private var lastTheme: ThemeValue? = null
|
||||
|
||||
|
@ -37,13 +43,12 @@ open class NbActivity : AppCompatActivity() {
|
|||
lastTheme = PrefsUtils.getSelectedTheme(this)
|
||||
|
||||
super.onCreate(bundle)
|
||||
offerInitContext(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)
|
||||
PrefsUtils.logout(this, dbHelper)
|
||||
finish()
|
||||
}
|
||||
|
||||
|
@ -99,7 +104,7 @@ open class NbActivity : AppCompatActivity() {
|
|||
* Pokes the sync service to perform any pending sync actions.
|
||||
*/
|
||||
protected fun triggerSync() {
|
||||
triggerSync(this)
|
||||
FeedUtils.triggerSync(this)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,18 +11,26 @@ import androidx.lifecycle.lifecycleScope
|
|||
import com.android.billingclient.api.*
|
||||
import com.newsblur.R
|
||||
import com.newsblur.databinding.ActivityPremiumBinding
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.subscription.SubscriptionManager
|
||||
import com.newsblur.subscription.SubscriptionManagerImpl
|
||||
import com.newsblur.subscription.SubscriptionsListener
|
||||
import com.newsblur.util.*
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import nl.dionsegijn.konfetti.emitters.StreamEmitter
|
||||
import nl.dionsegijn.konfetti.models.Shape.Circle
|
||||
import nl.dionsegijn.konfetti.models.Shape.Square
|
||||
import nl.dionsegijn.konfetti.models.Size
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class Premium : NbActivity() {
|
||||
|
||||
@IconLoader
|
||||
@Inject
|
||||
lateinit var iconLoader: ImageLoader
|
||||
|
||||
private lateinit var binding: ActivityPremiumBinding
|
||||
private lateinit var subscriptionManager: SubscriptionManager
|
||||
|
||||
|
@ -64,7 +72,7 @@ class Premium : NbActivity() {
|
|||
}
|
||||
binding.textPolicies.text = UIUtils.fromHtml(getString(R.string.premium_policies))
|
||||
binding.textSubTitle.paintFlags = binding.textSubTitle.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
FeedUtils.iconLoader!!.displayImage(AppConstants.SHILOH_PHOTO_URL, binding.imgShiloh)
|
||||
iconLoader.displayImage(AppConstants.SHILOH_PHOTO_URL, binding.imgShiloh)
|
||||
}
|
||||
|
||||
private fun setupBilling() {
|
||||
|
|
|
@ -6,21 +6,32 @@ import android.view.MenuItem
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.R
|
||||
import com.newsblur.databinding.ActivityProfileBinding
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.fragment.ProfileDetailsFragment
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.ImageLoader
|
||||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.UIUtils
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class Profile : NbActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
lateinit var iconLoader: ImageLoader
|
||||
|
||||
private val detailsTag = "details"
|
||||
private var detailsFragment: ProfileDetailsFragment? = null
|
||||
private var activityDetailsPagerAdapter: ActivityDetailsPagerAdapter? = null
|
||||
private var userId: String? = null
|
||||
|
||||
private lateinit var binding: ActivityProfileBinding
|
||||
private lateinit var apiManager: APIManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -28,7 +39,6 @@ class Profile : NbActivity() {
|
|||
setContentView(binding.root)
|
||||
UIUtils.setupToolbar(this, R.drawable.logo, getString(R.string.profile), true)
|
||||
|
||||
apiManager = APIManager(this)
|
||||
userId = if (savedInstanceState == null) {
|
||||
intent.getStringExtra(USER_ID)
|
||||
} else {
|
||||
|
@ -84,7 +94,7 @@ class Profile : NbActivity() {
|
|||
onPostExecute = { userDetails ->
|
||||
if (userDetails != null && detailsFragment != null && activityDetailsPagerAdapter != null) {
|
||||
detailsFragment!!.setUser(this, userDetails, TextUtils.isEmpty(userId))
|
||||
activityDetailsPagerAdapter!!.setUser(userDetails)
|
||||
activityDetailsPagerAdapter!!.setUser(userDetails, iconLoader)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.google.android.material.progressindicator.CircularProgressIndicator
|
|||
import com.newsblur.R
|
||||
import com.newsblur.database.ReadingAdapter
|
||||
import com.newsblur.databinding.ActivityReadingBinding
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.domain.Story
|
||||
import com.newsblur.fragment.ReadingItemFragment
|
||||
import com.newsblur.fragment.ReadingPagerFragment
|
||||
|
@ -32,12 +33,22 @@ import com.newsblur.util.*
|
|||
import com.newsblur.util.PrefConstants.ThemeValue
|
||||
import com.newsblur.view.ReadingScrollView.ScrollChangeListener
|
||||
import com.newsblur.viewModel.StoriesViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.lang.Runnable
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
||||
@AndroidEntryPoint
|
||||
abstract class Reading : NbActivity(), OnPageChangeListener, OnSeekBarChangeListener,
|
||||
ScrollChangeListener, ReadingFontChangedListener {
|
||||
|
||||
@Inject
|
||||
lateinit var feedUtils: FeedUtils
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
lateinit var iconLoader: ImageLoader
|
||||
|
||||
@JvmField
|
||||
var fs: FeedSet? = null
|
||||
|
||||
|
@ -149,7 +160,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, OnSeekBarChangeList
|
|||
// this is not strictly necessary, since our first refresh with the fs will swap in
|
||||
// the correct session, but that can be delayed by sync backup, so we try here to
|
||||
// reduce UI lag, or in case somehow we got redisplayed in a zero-story state
|
||||
FeedUtils.prepareReadingSession(fs, false)
|
||||
feedUtils.prepareReadingSession(fs, false)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
@ -216,7 +227,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, OnSeekBarChangeList
|
|||
}
|
||||
|
||||
private fun setCursorData(cursor: Cursor) {
|
||||
if (!FeedUtils.dbHelper!!.isFeedSetReady(fs)) {
|
||||
if (!dbHelper.isFeedSetReady(fs)) {
|
||||
com.newsblur.util.Log.i(this.javaClass.name, "stale load")
|
||||
// the system can and will re-use activities, so during the initial mismatch of
|
||||
// data, don't show the old stories
|
||||
|
@ -317,7 +328,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, OnSeekBarChangeList
|
|||
if (fs!!.isSingleNormal) showFeedMetadata = false
|
||||
var sourceUserId: String? = null
|
||||
if (fs!!.singleSocialFeed != null) sourceUserId = fs!!.singleSocialFeed.key
|
||||
readingAdapter = ReadingAdapter(childFragmentManager, sourceUserId, showFeedMetadata, this)
|
||||
readingAdapter = ReadingAdapter(childFragmentManager, sourceUserId, showFeedMetadata, this, dbHelper)
|
||||
|
||||
pager.adapter = readingAdapter
|
||||
|
||||
|
@ -339,7 +350,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, OnSeekBarChangeList
|
|||
get() {
|
||||
// saved stories and global shared stories don't have unreads
|
||||
if (fs!!.isAllSaved || fs!!.isGlobalShared) return 0
|
||||
val result = FeedUtils.dbHelper!!.getUnreadCount(fs, intelState)
|
||||
val result = dbHelper.getUnreadCount(fs, intelState)
|
||||
return if (result < 0) 0 else result
|
||||
}
|
||||
|
||||
|
@ -395,7 +406,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, OnSeekBarChangeList
|
|||
}
|
||||
}
|
||||
if (isMarkStoryReadImmediately) {
|
||||
FeedUtils.markStoryAsRead(story, this@Reading)
|
||||
feedUtils.markStoryAsRead(story, this@Reading)
|
||||
}
|
||||
}
|
||||
checkStoryCount(position)
|
||||
|
@ -712,7 +723,7 @@ abstract class Reading : NbActivity(), OnPageChangeListener, OnSeekBarChangeList
|
|||
private fun overlaySendClick() {
|
||||
if (readingAdapter == null || pager == null) return
|
||||
val story = readingAdapter!!.getStory(pager!!.currentItem)
|
||||
FeedUtils.sendStoryUrl(story, this)
|
||||
feedUtils.sendStoryUrl(story, this)
|
||||
}
|
||||
|
||||
private fun overlayTextClick() {
|
||||
|
|
|
@ -11,15 +11,20 @@ import com.newsblur.databinding.ActivityRegisterProgressBinding
|
|||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Show progress screen while registering request is being processed. This
|
||||
* Activity doesn't extend NbActivity because it is one of the few
|
||||
* Activities that will be shown while the user is still logged out.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class RegisterProgress : FragmentActivity() {
|
||||
|
||||
private lateinit var apiManager: APIManager
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
private lateinit var binding: ActivityRegisterProgressBinding
|
||||
|
||||
override fun onCreate(bundle: Bundle?) {
|
||||
|
@ -28,8 +33,6 @@ class RegisterProgress : FragmentActivity() {
|
|||
binding = ActivityRegisterProgressBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
apiManager = APIManager(this)
|
||||
|
||||
val username = intent.getStringExtra("username")
|
||||
val password = intent.getStringExtra("password")
|
||||
val email = intent.getStringExtra("email")
|
||||
|
|
|
@ -16,7 +16,7 @@ public class SocialFeedItemsList extends ItemsList {
|
|||
socialFeed = (SocialFeed) getIntent().getSerializableExtra(EXTRA_SOCIAL_FEED);
|
||||
super.onCreate(bundle);
|
||||
|
||||
UIUtils.setupToolbar(this, socialFeed.photoUrl, socialFeed.feedTitle, false);
|
||||
UIUtils.setupToolbar(this, socialFeed.photoUrl, socialFeed.feedTitle, iconLoader, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,9 +11,9 @@ public class SocialFeedReading extends Reading {
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceBundle) {
|
||||
super.onCreate(savedInstanceBundle);
|
||||
SocialFeed socialFeed = FeedUtils.dbHelper.getSocialFeed(fs.getSingleSocialFeed().getKey());
|
||||
SocialFeed socialFeed = dbHelper.getSocialFeed(fs.getSingleSocialFeed().getKey());
|
||||
if (socialFeed == null) finish(); // don't open fatally stale intents
|
||||
UIUtils.setupToolbar(this, socialFeed.photoUrl, socialFeed.feedTitle, false);
|
||||
UIUtils.setupToolbar(this, socialFeed.photoUrl, socialFeed.feedTitle, iconLoader, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,8 +8,11 @@ import android.view.View;
|
|||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.databinding.ActivityWidgetConfigBinding;
|
||||
import com.newsblur.di.IconLoader;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
import com.newsblur.widget.WidgetUtils;
|
||||
|
@ -19,8 +22,17 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class WidgetConfig extends FeedChooser {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
ImageLoader iconLoader;
|
||||
|
||||
private ActivityWidgetConfigBinding binding;
|
||||
|
||||
@Override
|
||||
|
@ -68,7 +80,7 @@ public class WidgetConfig extends FeedChooser {
|
|||
|
||||
@Override
|
||||
void setupList() {
|
||||
adapter = new WidgetConfigAdapter(this);
|
||||
adapter = new WidgetConfigAdapter(this, feedUtils, iconLoader);
|
||||
binding.listView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,14 +8,16 @@ import android.widget.ImageView;
|
|||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class WidgetConfigAdapter extends FeedChooserAdapter {
|
||||
|
||||
WidgetConfigAdapter(Context context) {
|
||||
super(context);
|
||||
WidgetConfigAdapter(Context context, FeedUtils feedUtils, ImageLoader iconLoader) {
|
||||
super(context, feedUtils, iconLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.newsblur.database;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
@ -30,6 +32,7 @@ import com.newsblur.util.ReadingAction;
|
|||
import com.newsblur.util.ReadFilter;
|
||||
import com.newsblur.util.StateFilter;
|
||||
import com.newsblur.util.StoryOrder;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
|
@ -1585,7 +1588,7 @@ public class BlurDatabaseHelper {
|
|||
}
|
||||
|
||||
public void sendSyncUpdate(int updateType) {
|
||||
FeedUtils.syncUpdateStatus(context, updateType);
|
||||
UIUtils.syncUpdateStatus(context, updateType);
|
||||
}
|
||||
|
||||
private static String conjoinSelections(CharSequence... args) {
|
||||
|
@ -1621,4 +1624,16 @@ 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);
|
||||
}
|
||||
|
||||
public FeedSet feedSetFromFolderName(String folderName) {
|
||||
return FeedSet.folder(folderName, getFeedIdsRecursive(folderName));
|
||||
}
|
||||
|
||||
private Set<String> getFeedIdsRecursive(String folderName) {
|
||||
Folder folder = getFolder(folderName);
|
||||
if (folder == null) return emptySet();
|
||||
Set<String> feedIds = new HashSet<>(folder.feedIds);
|
||||
for (String child : folder.children) feedIds.addAll(getFeedIdsRecursive(child));
|
||||
return feedIds;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import com.newsblur.util.AppConstants;
|
|||
import com.newsblur.util.FeedListOrder;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.StateFilter;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
@ -124,6 +125,8 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
private Context context;
|
||||
private LayoutInflater inflater;
|
||||
private StateFilter currentState;
|
||||
private final ImageLoader iconLoader;
|
||||
private final BlurDatabaseHelper dbHelper;
|
||||
|
||||
// since we want to implement a custom expando that does group collapse/expand, we need
|
||||
// a way to call back to those functions on the listview from the onclick listener of
|
||||
|
@ -139,10 +142,12 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
|
||||
public String activeSearchQuery;
|
||||
|
||||
public FolderListAdapter(Context context, StateFilter currentState) {
|
||||
public FolderListAdapter(Context context, StateFilter currentState, ImageLoader iconLoader, BlurDatabaseHelper dbHelper) {
|
||||
this.currentState = currentState;
|
||||
this.context = context;
|
||||
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
this.iconLoader = iconLoader;
|
||||
this.dbHelper = dbHelper;
|
||||
|
||||
textSize = PrefsUtils.getListTextSize(context);
|
||||
}
|
||||
|
@ -253,7 +258,7 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
nameView.setText(f.feedTitle);
|
||||
nameView.setTextSize(textSize * defaultTextSize_childName);
|
||||
ImageView iconView = (ImageView) v.findViewById(R.id.row_socialfeed_icon);
|
||||
FeedUtils.iconLoader.displayImage(f.photoUrl, iconView);
|
||||
iconLoader.displayImage(f.photoUrl, iconView);
|
||||
TextView neutCounter = ((TextView) v.findViewById(R.id.row_socialsumneu));
|
||||
if (f.neutralCount > 0 && currentState != StateFilter.BEST) {
|
||||
neutCounter.setVisibility(View.VISIBLE);
|
||||
|
@ -293,8 +298,8 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
TextView nameView = v.findViewById(R.id.row_saved_search_title);
|
||||
nameView.setText(UIUtils.fromHtml(ss.feedTitle));
|
||||
ImageView iconView = v.findViewById(R.id.row_saved_search_icon);
|
||||
FeedUtils.iconLoader.preCheck(ss.faviconUrl, iconView);
|
||||
FeedUtils.iconLoader.displayImage(ss.faviconUrl, iconView);
|
||||
iconLoader.preCheck(ss.faviconUrl, iconView);
|
||||
iconLoader.displayImage(ss.faviconUrl, iconView);
|
||||
} else {
|
||||
if (v == null) v = inflater.inflate(R.layout.row_feed, parent, false);
|
||||
Feed f = activeFolderChildren.get(groupPosition).get(childPosition);
|
||||
|
@ -307,8 +312,8 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
nameView.setText(f.title);
|
||||
nameView.setTextSize(textSize * defaultTextSize_childName);
|
||||
ImageView iconView = (ImageView) v.findViewById(R.id.row_feedfavicon);
|
||||
FeedUtils.iconLoader.preCheck(f.faviconUrl, iconView);
|
||||
FeedUtils.iconLoader.displayImage(f.faviconUrl, iconView);
|
||||
iconLoader.preCheck(f.faviconUrl, iconView);
|
||||
iconLoader.displayImage(f.faviconUrl, iconView);
|
||||
TextView neutCounter = ((TextView) v.findViewById(R.id.row_feedneutral));
|
||||
TextView posCounter = ((TextView) v.findViewById(R.id.row_feedpositive));
|
||||
TextView savedCounter = ((TextView) v.findViewById(R.id.row_feedsaved));
|
||||
|
@ -407,7 +412,7 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
return FeedSet.allSaved();
|
||||
} else {
|
||||
String folderName = getGroupFolderName(groupPosition);
|
||||
FeedSet fs = FeedUtils.feedSetFromFolderName(folderName);
|
||||
FeedSet fs = dbHelper.feedSetFromFolderName(folderName);
|
||||
if (currentState == StateFilter.SAVED) fs.setFilterSaved(true);
|
||||
return fs;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package com.newsblur.database;
|
||||
|
||||
import static com.newsblur.service.NBSyncReceiver.UPDATE_STORY;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
@ -17,7 +15,7 @@ import com.newsblur.domain.Classifier;
|
|||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.fragment.LoadingFragment;
|
||||
import com.newsblur.fragment.ReadingItemFragment;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.service.NBSyncReceiver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -53,12 +51,14 @@ public class ReadingAdapter extends PagerAdapter {
|
|||
private Map<String,Classifier> classifiers = new HashMap<String,Classifier>(0);
|
||||
|
||||
private final ExecutorService executorService;
|
||||
private final BlurDatabaseHelper dbHelper;
|
||||
|
||||
public ReadingAdapter(FragmentManager fm, String sourceUserId, boolean showFeedMetadata, Reading activity) {
|
||||
public ReadingAdapter(FragmentManager fm, String sourceUserId, boolean showFeedMetadata, Reading activity, BlurDatabaseHelper dbHelper) {
|
||||
this.sourceUserId = sourceUserId;
|
||||
this.showFeedMetadata = showFeedMetadata;
|
||||
this.fm = fm;
|
||||
this.activity = activity;
|
||||
this.dbHelper = dbHelper;
|
||||
|
||||
this.fragments = new HashMap<String,ReadingItemFragment>();
|
||||
this.states = new HashMap<String,Fragment.SavedState>();
|
||||
|
@ -109,7 +109,7 @@ public class ReadingAdapter extends PagerAdapter {
|
|||
feedIdsSeen.add(s.feedId);
|
||||
}
|
||||
for (String feedId : feedIdsSeen) {
|
||||
classifiers.put(feedId, FeedUtils.dbHelper.getClassifierForFeed(feedId));
|
||||
classifiers.put(feedId, dbHelper.getClassifierForFeed(feedId));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -284,7 +284,7 @@ public class ReadingAdapter extends PagerAdapter {
|
|||
ReadingItemFragment rif = fragments.get(s.storyHash);
|
||||
if (rif != null ) {
|
||||
rif.offerStoryUpdate(s);
|
||||
rif.handleUpdate(UPDATE_STORY);
|
||||
rif.handleUpdate(NBSyncReceiver.UPDATE_STORY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ import java.util.concurrent.Executors;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.activity.FeedItemsList;
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.di.IconLoader;
|
||||
import com.newsblur.di.ThumbnailLoader;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
import com.newsblur.fragment.ItemSetFragment;
|
||||
|
@ -75,24 +77,35 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
|
||||
private Parcelable oldScrollState;
|
||||
|
||||
private final ImageLoader iconLoader;
|
||||
private final ImageLoader thumbnailLoader;
|
||||
private final FeedUtils feedUtils;
|
||||
private final ExecutorService executorService;
|
||||
|
||||
private NbActivity context;
|
||||
private ItemSetFragment fragment;
|
||||
private final NbActivity context;
|
||||
private final ItemSetFragment fragment;
|
||||
private FeedSet fs;
|
||||
private StoryListStyle listStyle;
|
||||
private boolean ignoreReadStatus;
|
||||
private boolean ignoreIntel;
|
||||
private boolean singleFeed;
|
||||
private float textSize;
|
||||
private UserDetails user;
|
||||
private final UserDetails user;
|
||||
private ThumbnailStyle thumbnailStyle;
|
||||
|
||||
public StoryViewAdapter(NbActivity context, ItemSetFragment fragment, FeedSet fs, StoryListStyle listStyle) {
|
||||
public StoryViewAdapter(NbActivity context,
|
||||
ItemSetFragment fragment,
|
||||
FeedSet fs,
|
||||
StoryListStyle listStyle,
|
||||
ImageLoader iconLoader,
|
||||
ImageLoader thumbnailLoader,
|
||||
FeedUtils feedUtils) {
|
||||
this.context = context;
|
||||
this.fragment = fragment;
|
||||
this.fs = fs;
|
||||
this.listStyle = listStyle;
|
||||
this.iconLoader = iconLoader;
|
||||
this.thumbnailLoader = thumbnailLoader;
|
||||
this.feedUtils = feedUtils;
|
||||
|
||||
if (fs.isGlobalShared()) {ignoreReadStatus = false; ignoreIntel = true; singleFeed = false;}
|
||||
if (fs.isAllSocial()) {ignoreReadStatus = false; ignoreIntel = false; singleFeed = false;}
|
||||
|
@ -401,36 +414,36 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_mark_story_as_read:
|
||||
FeedUtils.markStoryAsRead(story, context);
|
||||
feedUtils.markStoryAsRead(story, context);
|
||||
return true;
|
||||
|
||||
case R.id.menu_mark_story_as_unread:
|
||||
FeedUtils.markStoryUnread(story, context);
|
||||
feedUtils.markStoryUnread(story, context);
|
||||
return true;
|
||||
|
||||
case R.id.menu_mark_older_stories_as_read:
|
||||
FeedUtils.markRead(context, fs, story.timestamp, null, R.array.mark_older_read_options, false);
|
||||
feedUtils.markRead(context, fs, story.timestamp, null, R.array.mark_older_read_options, false);
|
||||
return true;
|
||||
|
||||
case R.id.menu_mark_newer_stories_as_read:
|
||||
FeedUtils.markRead(context, fs, null, story.timestamp, R.array.mark_newer_read_options, false);
|
||||
feedUtils.markRead(context, fs, null, story.timestamp, R.array.mark_newer_read_options, false);
|
||||
return true;
|
||||
|
||||
case R.id.menu_send_story:
|
||||
FeedUtils.sendStoryUrl(story, context);
|
||||
feedUtils.sendStoryUrl(story, context);
|
||||
return true;
|
||||
|
||||
case R.id.menu_send_story_full:
|
||||
FeedUtils.sendStoryFull(story, context);
|
||||
feedUtils.sendStoryFull(story, context);
|
||||
return true;
|
||||
|
||||
case R.id.menu_save_story:
|
||||
//TODO get folder name
|
||||
FeedUtils.setStorySaved(story, true, context, null);
|
||||
feedUtils.setStorySaved(story, true, context, null);
|
||||
return true;
|
||||
|
||||
case R.id.menu_unsave_story:
|
||||
FeedUtils.setStorySaved(story, false, context, null);
|
||||
feedUtils.setStorySaved(story, false, context, null);
|
||||
return true;
|
||||
|
||||
case R.id.menu_intel:
|
||||
|
@ -442,7 +455,7 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
case R.id.menu_go_to_feed:
|
||||
FeedSet fs = FeedSet.singleFeed(story.feedId);
|
||||
FeedItemsList.startActivity(context, fs,
|
||||
FeedUtils.getFeed(story.feedId), null);
|
||||
feedUtils.getFeed(story.feedId), null);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -477,19 +490,19 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
}
|
||||
switch (action) {
|
||||
case GEST_ACTION_MARKREAD:
|
||||
FeedUtils.markStoryAsRead(story, context);
|
||||
feedUtils.markStoryAsRead(story, context);
|
||||
break;
|
||||
case GEST_ACTION_MARKUNREAD:
|
||||
FeedUtils.markStoryUnread(story, context);
|
||||
feedUtils.markStoryUnread(story, context);
|
||||
break;
|
||||
case GEST_ACTION_SAVE:
|
||||
FeedUtils.setStorySaved(story, true, context, null);
|
||||
feedUtils.setStorySaved(story, true, context, null);
|
||||
break;
|
||||
case GEST_ACTION_UNSAVE:
|
||||
FeedUtils.setStorySaved(story, false, context, null);
|
||||
feedUtils.setStorySaved(story, false, context, null);
|
||||
break;
|
||||
case GEST_ACTION_STATISTICS:
|
||||
FeedUtils.openStatistics(context, story.feedId);
|
||||
feedUtils.openStatistics(context, story.feedId);
|
||||
break;
|
||||
case GEST_ACTION_NONE:
|
||||
default:
|
||||
|
@ -575,7 +588,7 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
|
||||
// lists with mixed feeds get added info, but single feeds do not
|
||||
if (!singleFeed) {
|
||||
FeedUtils.iconLoader.displayImage(story.extern_faviconUrl, vh.feedIconView);
|
||||
iconLoader.displayImage(story.extern_faviconUrl, vh.feedIconView);
|
||||
vh.feedTitleView.setText(story.extern_feedTitle);
|
||||
vh.feedIconView.setVisibility(View.VISIBLE);
|
||||
vh.feedTitleView.setVisibility(View.VISIBLE);
|
||||
|
@ -644,7 +657,7 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
// the view will display a stale, recycled thumb before the new one loads if the old is not cleared
|
||||
int thumbSizeGuess = vh.thumbTileView.getMeasuredHeight();
|
||||
vh.thumbTileView.setImageBitmap(null);
|
||||
vh.thumbLoader = FeedUtils.thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbTileView, thumbSizeGuess, true);
|
||||
vh.thumbLoader = thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbTileView, thumbSizeGuess, true);
|
||||
vh.lastThumbUrl = story.thumbnailUrl;
|
||||
}
|
||||
}
|
||||
|
@ -681,13 +694,13 @@ public class StoryViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
if (thumbnailStyle == ThumbnailStyle.LEFT_LARGE || thumbnailStyle == ThumbnailStyle.LEFT_SMALL) {
|
||||
int thumbSizeGuess = vh.thumbViewLeft.getMeasuredHeight();
|
||||
vh.thumbViewLeft.setImageBitmap(null);
|
||||
vh.thumbLoader = FeedUtils.thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbViewLeft, thumbSizeGuess, true);
|
||||
vh.thumbLoader = thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbViewLeft, thumbSizeGuess, true);
|
||||
vh.thumbViewRight.setVisibility(View.GONE);
|
||||
vh.thumbViewLeft.setVisibility(View.VISIBLE);
|
||||
} else if (thumbnailStyle == ThumbnailStyle.RIGHT_LARGE || thumbnailStyle == ThumbnailStyle.RIGHT_SMALL) {
|
||||
int thumbSizeGuess = vh.thumbViewRight.getMeasuredHeight();
|
||||
vh.thumbViewRight.setImageBitmap(null);
|
||||
vh.thumbLoader = FeedUtils.thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbViewRight, thumbSizeGuess, true);
|
||||
vh.thumbLoader = thumbnailLoader.displayImage(story.thumbnailUrl, vh.thumbViewRight, thumbSizeGuess, true);
|
||||
vh.thumbViewLeft.setVisibility(View.GONE);
|
||||
vh.thumbViewRight.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
|
25
clients/android/NewsBlur/src/com/newsblur/di/Annotations.kt
Normal file
25
clients/android/NewsBlur/src/com/newsblur/di/Annotations.kt
Normal file
|
@ -0,0 +1,25 @@
|
|||
package com.newsblur.di
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class StoryFileCache
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class IconFileCache
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ThumbnailFileCache
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class IconLoader
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ThumbnailLoader
|
||||
|
||||
|
21
clients/android/NewsBlur/src/com/newsblur/di/FeedModule.kt
Normal file
21
clients/android/NewsBlur/src/com/newsblur/di/FeedModule.kt
Normal file
|
@ -0,0 +1,21 @@
|
|||
package com.newsblur.di
|
||||
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.util.ImageLoader
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class FeedModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideFeedUtils(dbHelper: BlurDatabaseHelper, apiManager: APIManager) =
|
||||
FeedUtils(dbHelper, apiManager)
|
||||
}
|
30
clients/android/NewsBlur/src/com/newsblur/di/ImageModule.kt
Normal file
30
clients/android/NewsBlur/src/com/newsblur/di/ImageModule.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
package com.newsblur.di
|
||||
|
||||
import android.content.Context
|
||||
import com.newsblur.util.FileCache
|
||||
import com.newsblur.util.ImageLoader
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class ImageModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@IconLoader
|
||||
fun provideIconLoader(@ApplicationContext context: Context): ImageLoader =
|
||||
ImageLoader.asIconLoader(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@ThumbnailLoader
|
||||
fun provideThumbnailLoader(
|
||||
@ApplicationContext context: Context,
|
||||
@StoryFileCache fileCache: FileCache,
|
||||
): ImageLoader = ImageLoader.asThumbnailLoader(context, fileCache)
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.newsblur.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.newsblur.domain.Classifier
|
||||
import com.newsblur.domain.Feed
|
||||
import com.newsblur.domain.Story
|
||||
import com.newsblur.network.APIConstants
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.serialization.BooleanTypeAdapter
|
||||
import com.newsblur.serialization.ClassifierMapTypeAdapter
|
||||
import com.newsblur.serialization.DateStringTypeAdapter
|
||||
import com.newsblur.serialization.FeedListTypeAdapter
|
||||
import com.newsblur.serialization.StoryTypeAdapter
|
||||
import com.newsblur.util.AppConstants
|
||||
import com.newsblur.util.NetworkUtils
|
||||
import com.newsblur.util.PrefConstants
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Singleton
|
||||
|
||||
private typealias CustomUserAgent = String
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object NetworkModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideGson(): Gson = GsonBuilder().apply {
|
||||
registerTypeAdapter(Date::class.java, DateStringTypeAdapter())
|
||||
registerTypeAdapter(Boolean::class.java, BooleanTypeAdapter())
|
||||
registerTypeAdapter(Boolean::class.javaPrimitiveType, BooleanTypeAdapter())
|
||||
registerTypeAdapter(Story::class.java, StoryTypeAdapter())
|
||||
registerTypeAdapter(object : TypeToken<List<Feed?>?>() {}.type, FeedListTypeAdapter())
|
||||
registerTypeAdapter(object : TypeToken<Map<String?, Classifier?>?>() {}.type, ClassifierMapTypeAdapter())
|
||||
}.create()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder().apply {
|
||||
connectTimeout(AppConstants.API_CONN_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
readTimeout(AppConstants.API_READ_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
followSslRedirects(true)
|
||||
}.build()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideCustomUserAgent(sharedPreferences: SharedPreferences): CustomUserAgent {
|
||||
val appVersion: String = sharedPreferences.getString(AppConstants.LAST_APP_VERSION, "unknown_version")!!
|
||||
return NetworkUtils.getCustomUserAgent(appVersion)
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideApiManager(
|
||||
@ApplicationContext context: Context,
|
||||
customUserAgent: CustomUserAgent,
|
||||
gson: Gson,
|
||||
okHttpClient: OkHttpClient): APIManager =
|
||||
APIManager(context,
|
||||
gson,
|
||||
customUserAgent,
|
||||
okHttpClient)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.newsblur.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.util.FileCache
|
||||
import com.newsblur.util.PrefConstants
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class StorageModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSharedPrefs(@ApplicationContext context: Context): SharedPreferences =
|
||||
context.getSharedPreferences(PrefConstants.PREFERENCES, Context.MODE_PRIVATE)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideBlurDbHelper(@ApplicationContext context: Context): BlurDatabaseHelper =
|
||||
BlurDatabaseHelper(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@StoryFileCache
|
||||
fun provideStoryCache(@ApplicationContext context: Context): FileCache =
|
||||
FileCache.asStoryImageCache(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@IconFileCache
|
||||
fun provideIconCache(@ApplicationContext context: Context): FileCache =
|
||||
FileCache.asIconCache(context)
|
||||
}
|
|
@ -4,9 +4,9 @@ import android.content.ContentValues;
|
|||
import android.database.Cursor;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
|
@ -24,11 +24,11 @@ public class SavedSearch {
|
|||
public String feedTitle;
|
||||
public String faviconUrl;
|
||||
|
||||
public ContentValues getValues() {
|
||||
public ContentValues getValues(BlurDatabaseHelper dbHelper) {
|
||||
ContentValues values = new ContentValues();
|
||||
String feedTitle = "\"<b>" + query + "</b>\" in <b>" + getFeedTitle() + "</b>";
|
||||
String feedTitle = "\"<b>" + query + "</b>\" in <b>" + getFeedTitle(dbHelper) + "</b>";
|
||||
values.put(DatabaseConstants.SAVED_SEARCH_FEED_TITLE, feedTitle);
|
||||
values.put(DatabaseConstants.SAVED_SEARCH_FAVICON, getFaviconUrl());
|
||||
values.put(DatabaseConstants.SAVED_SEARCH_FAVICON, getFaviconUrl(dbHelper));
|
||||
values.put(DatabaseConstants.SAVED_SEARCH_ADDRESS, feedAddress);
|
||||
values.put(DatabaseConstants.SAVED_SEARCH_QUERY, query);
|
||||
values.put(DatabaseConstants.SAVED_SEARCH_FEED_ID, feedId);
|
||||
|
@ -48,7 +48,7 @@ public class SavedSearch {
|
|||
return savedSearch;
|
||||
}
|
||||
|
||||
private String getFeedTitle() {
|
||||
private String getFeedTitle(BlurDatabaseHelper dbHelper) {
|
||||
String feedTitle = null;
|
||||
|
||||
if (feedId.equals("river:")) {
|
||||
|
@ -57,14 +57,14 @@ public class SavedSearch {
|
|||
feedTitle = "Infrequent Site Stories";
|
||||
} else if (feedId.startsWith("river:")) {
|
||||
String folderName = feedId.replace("river:", "");
|
||||
FeedSet fs = FeedUtils.feedSetFromFolderName(folderName);
|
||||
FeedSet fs = dbHelper.feedSetFromFolderName(folderName);
|
||||
feedTitle = fs.getFolderName();
|
||||
} else if (feedId.equals("read")) {
|
||||
feedTitle = "Read Stories";
|
||||
} else if (feedId.startsWith("starred")) {
|
||||
feedTitle = "Saved Stories";
|
||||
String tag = feedId.replace("starred:", "");
|
||||
StarredCount starredFeed = FeedUtils.getStarredFeedByTag(tag);
|
||||
StarredCount starredFeed = dbHelper.getStarredFeedByTag(tag);
|
||||
if (starredFeed != null) {
|
||||
String tagSlug = tag.replace(" ", "-");
|
||||
if (starredFeed.tag.equals(tag) || starredFeed.tag.equals(tagSlug)) {
|
||||
|
@ -72,11 +72,11 @@ public class SavedSearch {
|
|||
}
|
||||
}
|
||||
} else if (feedId.startsWith("feed:")) {
|
||||
Feed feed = FeedUtils.getFeed(feedId.replace("feed:", ""));
|
||||
Feed feed = dbHelper.getFeed(feedId.replace("feed:", ""));
|
||||
if (feed == null) return null;
|
||||
feedTitle = feed.title;
|
||||
} else if (feedId.startsWith("social:")) {
|
||||
Feed feed = FeedUtils.getFeed(feedId.replace("social:", ""));
|
||||
Feed feed = dbHelper.getFeed(feedId.replace("social:", ""));
|
||||
if (feed == null) return null;
|
||||
feedTitle = feed.title;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ public class SavedSearch {
|
|||
return feedTitle;
|
||||
}
|
||||
|
||||
private String getFaviconUrl() {
|
||||
private String getFaviconUrl(BlurDatabaseHelper dbHelper) {
|
||||
String url = null;
|
||||
if (feedId.equals("river:") || feedId.equals("river:infrequent")) {
|
||||
url = "https://newsblur.com/media/img/icons/circular/ak-icon-allstories.png";
|
||||
|
@ -97,12 +97,12 @@ public class SavedSearch {
|
|||
} else if (feedId.startsWith("starred:")) {
|
||||
url = "https://newsblur.com/media/img/reader/tag.png";
|
||||
} else if (feedId.startsWith("feed:")) {
|
||||
Feed feed = FeedUtils.getFeed(feedId.replace("feed:", ""));
|
||||
Feed feed = dbHelper.getFeed(feedId.replace("feed:", ""));
|
||||
if (feed != null) {
|
||||
url = feed.faviconUrl;
|
||||
}
|
||||
} else if (feedId.startsWith("social:")) {
|
||||
Feed feed = FeedUtils.getFeed(feedId.replace("social:", ""));
|
||||
Feed feed = dbHelper.getFeed(feedId.replace("social:", ""));
|
||||
if (feed != null) {
|
||||
url = feed.faviconUrl;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.newsblur.R
|
||||
import com.newsblur.activity.Main
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.databinding.DialogAddFeedBinding
|
||||
import com.newsblur.databinding.RowAddFeedFolderBinding
|
||||
import com.newsblur.domain.Folder
|
||||
|
@ -23,17 +24,24 @@ import com.newsblur.fragment.AddFeedFragment.AddFeedAdapter.FolderViewHolder
|
|||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.service.NBSyncService
|
||||
import com.newsblur.util.AppConstants
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.util.UIUtils
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AddFeedFragment : DialogFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
private lateinit var binding: DialogAddFeedBinding
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val apiManager = APIManager(requireContext())
|
||||
val v = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_add_feed, null)
|
||||
binding = DialogAddFeedBinding.bind(v)
|
||||
|
||||
|
@ -61,7 +69,7 @@ class AddFeedFragment : DialogFragment() {
|
|||
}
|
||||
binding.recyclerViewFolders.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL))
|
||||
binding.recyclerViewFolders.adapter = adapter
|
||||
adapter.setFolders(FeedUtils.dbHelper!!.folders)
|
||||
adapter.setFolders(dbHelper.folders)
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,15 @@ import com.newsblur.activity.AddTwitter
|
|||
import com.newsblur.databinding.FragmentAddsocialBinding
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AddSocialFragment : Fragment() {
|
||||
|
||||
private lateinit var apiManager: APIManager
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
private lateinit var binding: FragmentAddsocialBinding
|
||||
|
||||
private var twitterAuthed = false
|
||||
|
@ -25,7 +30,6 @@ class AddSocialFragment : Fragment() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
retainInstance = true
|
||||
apiManager = APIManager(requireActivity())
|
||||
}
|
||||
|
||||
fun setTwitterAuthed() {
|
||||
|
|
|
@ -9,6 +9,9 @@ import androidx.fragment.app.DialogFragment;
|
|||
|
||||
import com.newsblur.R;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class AlertDialogFragment extends DialogFragment {
|
||||
private static final String MESSAGE = "message";
|
||||
|
||||
|
|
|
@ -22,13 +22,25 @@ import android.widget.CheckBox;
|
|||
import android.widget.ListAdapter;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.databinding.DialogChoosefoldersBinding;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class ChooseFoldersFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private Feed feed;
|
||||
|
||||
public static ChooseFoldersFragment newInstance(Feed feed) {
|
||||
|
@ -43,7 +55,7 @@ public class ChooseFoldersFragment extends DialogFragment {
|
|||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
feed = (Feed) getArguments().getSerializable("feed");
|
||||
final List<Folder> folders = FeedUtils.dbHelper.getFolders();
|
||||
final List<Folder> folders = dbHelper.getFolders();
|
||||
Collections.sort(folders, Folder.FolderComparator);
|
||||
|
||||
final Set<String> newFolders = new HashSet<String>();
|
||||
|
@ -73,7 +85,7 @@ public class ChooseFoldersFragment extends DialogFragment {
|
|||
builder.setPositiveButton(R.string.dialog_folders_save, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
FeedUtils.moveFeedToFolders(activity, feed.feedId, newFolders, oldFolders);
|
||||
feedUtils.moveFeedToFolders(activity, feed.feedId, newFolders, oldFolders);
|
||||
ChooseFoldersFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -16,7 +16,16 @@ import android.os.Bundle;
|
|||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class DeleteFeedFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private static final String FEED_TYPE = "feed_type";
|
||||
private static final String FEED_ID = "feed_id";
|
||||
private static final String FEED_NAME = "feed_name";
|
||||
|
@ -73,11 +82,11 @@ 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), 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), getActivity());
|
||||
feedUtils.deleteSavedSearch(getArguments().getString(FEED_ID), getArguments().getString(QUERY), getActivity());
|
||||
} else {
|
||||
FeedUtils.deleteSocialFeed(getArguments().getString(FEED_ID), getActivity());
|
||||
feedUtils.deleteSocialFeed(getArguments().getString(FEED_ID), getActivity());
|
||||
}
|
||||
// if called from a feed view, end it
|
||||
Activity activity = DeleteFeedFragment.this.getActivity();
|
||||
|
|
|
@ -10,12 +10,19 @@ import androidx.fragment.app.DialogFragment;
|
|||
import android.text.TextUtils;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class DeleteFolderFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private static final String FOLDER_NAME = "folder_name";
|
||||
private static final String FOLDER_PARENT = "folder_parent";
|
||||
|
||||
|
@ -42,7 +49,7 @@ public class DeleteFolderFragment extends DialogFragment {
|
|||
if (!TextUtils.isEmpty(folderParent) && !folderParent.equals(AppConstants.ROOT_FOLDER)) {
|
||||
inFolder = folderParent;
|
||||
}
|
||||
FeedUtils.deleteFolder(folderName, inFolder, getActivity(), new APIManager(getActivity()));
|
||||
feedUtils.deleteFolder(folderName, inFolder, getActivity());
|
||||
DeleteFolderFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -15,8 +15,16 @@ import com.newsblur.R;
|
|||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class EditReplyDialogFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private static final String STORY = "story";
|
||||
private static final String COMMENT_USER_ID = "comment_user_id";
|
||||
private static final String REPLY_ID = "reply_id";
|
||||
|
@ -54,14 +62,14 @@ public class EditReplyDialogFragment extends DialogFragment {
|
|||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
String replyText = reply.getText().toString();
|
||||
FeedUtils.updateReply(activity, story, commentUserId, replyId, replyText);
|
||||
feedUtils.updateReply(activity, story, commentUserId, replyId, replyText);
|
||||
EditReplyDialogFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.edit_reply_delete, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
FeedUtils.deleteReply(activity, story, commentUserId, replyId);
|
||||
feedUtils.deleteReply(activity, story, commentUserId, replyId);
|
||||
EditReplyDialogFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.view.View;
|
|||
import android.widget.TextView;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.databinding.DialogTrainfeedBinding;
|
||||
import com.newsblur.domain.Classifier;
|
||||
import com.newsblur.domain.Feed;
|
||||
|
@ -23,8 +24,19 @@ import com.newsblur.util.FeedSet;
|
|||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class FeedIntelTrainerFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
private Feed feed;
|
||||
private FeedSet fs;
|
||||
private Classifier classifier;
|
||||
|
@ -44,7 +56,7 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
|||
super.onCreate(savedInstanceState);
|
||||
feed = (Feed) getArguments().getSerializable("feed");
|
||||
fs = (FeedSet) getArguments().getSerializable("feedset");
|
||||
classifier = FeedUtils.dbHelper.getClassifierForFeed(feed.feedId);
|
||||
classifier = dbHelper.getClassifierForFeed(feed.feedId);
|
||||
|
||||
final Activity activity = getActivity();
|
||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||
|
@ -62,7 +74,7 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
|||
if (classifier.title.size() < 1) binding.intelTitleHeader.setVisibility(View.GONE);
|
||||
|
||||
// get the list of suggested tags
|
||||
List<String> allTags = FeedUtils.dbHelper.getTagsForFeed(feed.feedId);
|
||||
List<String> allTags = dbHelper.getTagsForFeed(feed.feedId);
|
||||
// augment that list with known trained tags
|
||||
for (Map.Entry<String, Integer> rule : classifier.tags.entrySet()) {
|
||||
if (!allTags.contains(rule.getKey())) {
|
||||
|
@ -79,7 +91,7 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
|||
if (allTags.size() < 1) binding.intelTagHeader.setVisibility(View.GONE);
|
||||
|
||||
// get the list of suggested authors
|
||||
List<String> allAuthors = FeedUtils.dbHelper.getAuthorsForFeed(feed.feedId);
|
||||
List<String> allAuthors = dbHelper.getAuthorsForFeed(feed.feedId);
|
||||
// augment that list with known trained authors
|
||||
for (Map.Entry<String, Integer> rule : classifier.authors.entrySet()) {
|
||||
if (!allAuthors.contains(rule.getKey())) {
|
||||
|
@ -115,7 +127,7 @@ public class FeedIntelTrainerFragment extends DialogFragment {
|
|||
builder.setPositiveButton(R.string.dialog_story_intel_save, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
FeedUtils.updateClassifier(feed.feedId, classifier, fs, activity);
|
||||
feedUtils.updateClassifier(feed.feedId, classifier, fs, activity);
|
||||
FeedIntelTrainerFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -43,8 +43,10 @@ import com.newsblur.activity.NbActivity;
|
|||
import com.newsblur.activity.ReadStoriesItemsList;
|
||||
import com.newsblur.activity.SavedStoriesItemsList;
|
||||
import com.newsblur.activity.SocialFeedItemsList;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.database.FolderListAdapter;
|
||||
import com.newsblur.databinding.FragmentFolderfeedlistBinding;
|
||||
import com.newsblur.di.IconLoader;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.domain.SavedSearch;
|
||||
|
@ -52,18 +54,33 @@ import com.newsblur.domain.SocialFeed;
|
|||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.PrefConstants;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.StateFilter;
|
||||
import com.newsblur.util.UIUtils;
|
||||
import com.newsblur.viewModel.AllFoldersViewModel;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class FolderListFragment extends NbFragment implements OnCreateContextMenuListener,
|
||||
OnChildClickListener,
|
||||
OnGroupClickListener,
|
||||
OnGroupCollapseListener,
|
||||
OnGroupExpandListener {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
ImageLoader iconLoader;
|
||||
|
||||
private AllFoldersViewModel allFoldersViewModel;
|
||||
private FolderListAdapter adapter;
|
||||
public StateFilter currentState = StateFilter.SOME;
|
||||
|
@ -80,9 +97,9 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
super.onCreate(savedInstanceState);
|
||||
allFoldersViewModel = new ViewModelProvider(this).get(AllFoldersViewModel.class);
|
||||
currentState = PrefsUtils.getStateFilter(getActivity());
|
||||
adapter = new FolderListAdapter(getActivity(), currentState);
|
||||
adapter = new FolderListAdapter(getActivity(), currentState, iconLoader, dbHelper);
|
||||
sharedPreferences = getActivity().getSharedPreferences(PrefConstants.PREFERENCES, 0);
|
||||
FeedUtils.currentFolderName = null;
|
||||
feedUtils.currentFolderName = null;
|
||||
// NB: it is by design that loaders are not started until we get a
|
||||
// ping from the sync service indicating that it has initialised
|
||||
}
|
||||
|
@ -291,15 +308,15 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
return true;
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_notifications_disable) {
|
||||
FeedUtils.disableNotifications(getActivity(), lastMenuFeed);
|
||||
feedUtils.disableNotifications(getActivity(), lastMenuFeed);
|
||||
return true;
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_notifications_focus) {
|
||||
FeedUtils.enableFocusNotifications(getActivity(), lastMenuFeed);
|
||||
feedUtils.enableFocusNotifications(getActivity(), lastMenuFeed);
|
||||
return true;
|
||||
}
|
||||
if (item.getItemId() == R.id.menu_notifications_unread) {
|
||||
FeedUtils.enableUnreadNotifications(getActivity(), lastMenuFeed);
|
||||
feedUtils.enableUnreadNotifications(getActivity(), lastMenuFeed);
|
||||
return true;
|
||||
}
|
||||
ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();
|
||||
|
@ -339,17 +356,17 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
} else if (item.getItemId() == R.id.menu_mute_feed) {
|
||||
Set<String> feedIds = new HashSet<String>();
|
||||
feedIds.add(adapter.getFeed(groupPosition, childPosition).feedId);
|
||||
FeedUtils.muteFeeds(getActivity(), feedIds);
|
||||
feedUtils.muteFeeds(getActivity(), feedIds);
|
||||
} else if (item.getItemId() == R.id.menu_unmute_feed) {
|
||||
Set<String> feedIds = new HashSet<String>();
|
||||
feedIds.add(adapter.getFeed(groupPosition, childPosition).feedId);
|
||||
FeedUtils.unmuteFeeds(getActivity(), feedIds);
|
||||
feedUtils.unmuteFeeds(getActivity(), feedIds);
|
||||
} else if (item.getItemId() == R.id.menu_mute_folder) {
|
||||
FeedUtils.muteFeeds(getActivity(), adapter.getAllFeedsForFolder(groupPosition));
|
||||
feedUtils.muteFeeds(getActivity(), adapter.getAllFeedsForFolder(groupPosition));
|
||||
} else if (item.getItemId() == R.id.menu_unmute_folder) {
|
||||
FeedUtils.unmuteFeeds(getActivity(), adapter.getAllFeedsForFolder(groupPosition));
|
||||
feedUtils.unmuteFeeds(getActivity(), adapter.getAllFeedsForFolder(groupPosition));
|
||||
} else if (item.getItemId() == R.id.menu_instafetch_feed) {
|
||||
FeedUtils.instaFetchFeed(getActivity(), adapter.getFeed(groupPosition, childPosition).feedId);
|
||||
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(getParentFragmentManager(), FeedIntelTrainerFragment.class.getName());
|
||||
|
@ -375,7 +392,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
}
|
||||
|
||||
private void markFeedsAsRead(FeedSet fs) {
|
||||
FeedUtils.markRead(((NbActivity) getActivity()), fs, null, null, R.array.mark_all_read_options, false);
|
||||
feedUtils.markRead(((NbActivity) getActivity()), fs, null, null, R.array.mark_all_read_options, false);
|
||||
adapter.lastFeedViewedId = fs.getSingleFeed();
|
||||
adapter.lastFolderViewed = fs.getFolderName();
|
||||
}
|
||||
|
@ -498,7 +515,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
|
||||
@Override
|
||||
public boolean onChildClick(ExpandableListView list, View childView, int groupPosition, int childPosition, long id) {
|
||||
FeedUtils.currentFolderName = null;
|
||||
feedUtils.currentFolderName = null;
|
||||
FeedSet fs = adapter.getChild(groupPosition, childPosition);
|
||||
if (adapter.isRowAllSharedStories(groupPosition)) {
|
||||
SocialFeed socialFeed = adapter.getSocialFeed(groupPosition, childPosition);
|
||||
|
@ -519,10 +536,10 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
// and the folder name is a bit of metadata needed by the UI/API
|
||||
String folderName = adapter.getGroupFolderName(groupPosition);
|
||||
if(folderName == null || folderName.equals(AppConstants.ROOT_FOLDER)){
|
||||
FeedUtils.currentFolderName = null;
|
||||
feedUtils.currentFolderName = null;
|
||||
}else{
|
||||
|
||||
FeedUtils.currentFolderName = folderName;
|
||||
feedUtils.currentFolderName = folderName;
|
||||
}
|
||||
FeedItemsList.startActivity(getActivity(), fs, feed, folderName);
|
||||
adapter.lastFeedViewedId = feed.feedId;
|
||||
|
@ -555,7 +572,7 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
} else if (feedId.startsWith("river:")) {
|
||||
intent = new Intent(getActivity(), FolderItemsList.class);
|
||||
String folderName = feedId.replace("river:", "");
|
||||
fs = FeedUtils.feedSetFromFolderName(folderName);
|
||||
fs = dbHelper.feedSetFromFolderName(folderName);
|
||||
intent.putExtra(FolderItemsList.EXTRA_FOLDER_NAME, folderName);
|
||||
} else if (feedId.equals("read")) {
|
||||
intent = new Intent(getActivity(), ReadStoriesItemsList.class);
|
||||
|
@ -569,14 +586,14 @@ public class FolderListFragment extends NbFragment implements OnCreateContextMen
|
|||
} else if (feedId.startsWith("feed:")) {
|
||||
intent = new Intent(getActivity(), FeedItemsList.class);
|
||||
String cleanFeedId = feedId.replace("feed:", "");
|
||||
Feed feed = FeedUtils.getFeed(cleanFeedId);
|
||||
Feed feed = feedUtils.getFeed(cleanFeedId);
|
||||
fs = FeedSet.singleFeed(cleanFeedId);
|
||||
intent.putExtra(FeedItemsList.EXTRA_FEED, feed);
|
||||
} else if (feedId.startsWith("social:")) {
|
||||
intent = new Intent(getActivity(), SocialFeedItemsList.class);
|
||||
String cleanFeedId = feedId.replace("social:", "");
|
||||
fs = FeedSet.singleFeed(cleanFeedId);
|
||||
Feed feed = FeedUtils.getFeed(cleanFeedId);
|
||||
Feed feed = feedUtils.getFeed(cleanFeedId);
|
||||
intent.putExtra(FeedItemsList.EXTRA_FEED, feed);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,17 @@ import android.widget.FrameLayout;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.activity.ItemsList;
|
||||
import com.newsblur.activity.NbActivity;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.database.StoryViewAdapter;
|
||||
import com.newsblur.databinding.FragmentItemgridBinding;
|
||||
import com.newsblur.databinding.RowFleuronBinding;
|
||||
import com.newsblur.di.IconLoader;
|
||||
import com.newsblur.di.ThumbnailLoader;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.service.NBSyncService;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.ReadFilter;
|
||||
import com.newsblur.util.StoryListStyle;
|
||||
|
@ -39,8 +43,27 @@ import com.newsblur.util.ViewUtils;
|
|||
import com.newsblur.view.ProgressThrobber;
|
||||
import com.newsblur.viewModel.StoriesViewModel;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class ItemSetFragment extends NbFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
ImageLoader iconLoader;
|
||||
|
||||
@Inject
|
||||
@ThumbnailLoader
|
||||
ImageLoader thumbnailLoader;
|
||||
|
||||
private static final String BUNDLE_GRIDSTATE = "gridstate";
|
||||
|
||||
protected boolean cursorSeenYet = false; // have we yet seen a valid cursor for our particular feedset?
|
||||
|
@ -164,7 +187,7 @@ public class ItemSetFragment extends NbFragment {
|
|||
}
|
||||
});
|
||||
|
||||
adapter = new StoryViewAdapter(((NbActivity) getActivity()), this, getFeedSet(), listStyle);
|
||||
adapter = new StoryViewAdapter(((NbActivity) getActivity()), this, getFeedSet(), listStyle, iconLoader, thumbnailLoader, feedUtils);
|
||||
adapter.addFooterView(footerView);
|
||||
adapter.addFooterView(fleuronBinding.getRoot());
|
||||
binding.itemgridfragmentGrid.setAdapter(adapter);
|
||||
|
@ -267,7 +290,7 @@ public class ItemSetFragment extends NbFragment {
|
|||
|
||||
private void setCursor(Cursor cursor) {
|
||||
if (cursor != null) {
|
||||
if (!FeedUtils.dbHelper.isFeedSetReady(getFeedSet())) {
|
||||
if (!dbHelper.isFeedSetReady(getFeedSet())) {
|
||||
// the DB hasn't caught up yet from the last story list; don't display stale stories.
|
||||
com.newsblur.util.Log.i(this.getClass().getName(), "stale load");
|
||||
updateAdapter(null);
|
||||
|
@ -451,7 +474,7 @@ public class ItemSetFragment extends NbFragment {
|
|||
int index = markEnd - i;
|
||||
Story story = adapter.getStory(index);
|
||||
if (story != null) {
|
||||
FeedUtils.markStoryAsRead(story, requireContext());
|
||||
feedUtils.markStoryAsRead(story, requireContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,24 @@ import androidx.fragment.app.DialogFragment
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.R
|
||||
import com.newsblur.activity.Main
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.databinding.LoginasDialogBinding
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.UIUtils
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LoginAsDialogFragment : DialogFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val builder = AlertDialog.Builder(requireActivity())
|
||||
builder.setTitle(R.string.loginas_title)
|
||||
|
@ -27,13 +37,12 @@ class LoginAsDialogFragment : DialogFragment() {
|
|||
|
||||
builder.setView(binding.root)
|
||||
builder.setPositiveButton(R.string.alert_dialog_ok) { _, _ ->
|
||||
val apiManager = APIManager(requireActivity())
|
||||
val username = binding.usernameField.text.toString()
|
||||
lifecycleScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
val result = apiManager.loginAs(username)
|
||||
if (result) {
|
||||
PrefsUtils.clearPrefsAndDbForLoginAs(requireActivity())
|
||||
PrefsUtils.clearPrefsAndDbForLoginAs(requireActivity(), dbHelper)
|
||||
apiManager.updateUserProfile()
|
||||
}
|
||||
result
|
||||
|
|
|
@ -8,10 +8,19 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class LogoutDialogFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
@ -19,7 +28,7 @@ public class LogoutDialogFragment extends DialogFragment {
|
|||
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
PrefsUtils.logout(getActivity());
|
||||
PrefsUtils.logout(getActivity(), dbHelper);
|
||||
// make sure the instance of Main that called us is killed now, or else the system
|
||||
// might try to recycle it with a stale login ID, which will cause it to self-destruct
|
||||
getActivity().finish();
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Context;
|
|||
import com.newsblur.domain.ActivityDetails;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
import com.newsblur.network.domain.ActivitiesResponse;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.view.ActivitiesAdapter;
|
||||
import com.newsblur.view.ActivityDetailsAdapter;
|
||||
|
||||
|
@ -14,8 +15,8 @@ import com.newsblur.view.ActivityDetailsAdapter;
|
|||
public class ProfileActivitiesFragment extends ProfileActivityDetailsFragment {
|
||||
|
||||
@Override
|
||||
protected ActivityDetailsAdapter createAdapter(Context context, UserDetails user) {
|
||||
return new ActivitiesAdapter(context, user);
|
||||
protected ActivityDetailsAdapter createAdapter(Context context, UserDetails user, ImageLoader imageLoader) {
|
||||
return new ActivitiesAdapter(context, user, iconLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,29 +13,37 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.R
|
||||
import com.newsblur.activity.Profile
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.databinding.FragmentProfileactivityBinding
|
||||
import com.newsblur.databinding.RowLoadingThrobberBinding
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.domain.ActivityDetails
|
||||
import com.newsblur.domain.UserDetails
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.*
|
||||
import com.newsblur.view.ActivityDetailsAdapter
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
abstract class ProfileActivityDetailsFragment : Fragment(), OnItemClickListener {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
lateinit var iconLoader: ImageLoader
|
||||
|
||||
private lateinit var binding: FragmentProfileactivityBinding
|
||||
private lateinit var footerBinding: RowLoadingThrobberBinding
|
||||
|
||||
@JvmField
|
||||
protected var apiManager: APIManager? = null
|
||||
private var adapter: ActivityDetailsAdapter? = null
|
||||
private var user: UserDetails? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
apiManager = APIManager(requireActivity())
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_profileactivity, null)
|
||||
binding = FragmentProfileactivityBinding.bind(view)
|
||||
|
@ -59,13 +67,13 @@ abstract class ProfileActivityDetailsFragment : Fragment(), OnItemClickListener
|
|||
return view
|
||||
}
|
||||
|
||||
fun setUser(context: Context?, user: UserDetails?) {
|
||||
fun setUser(context: Context?, user: UserDetails?, iconLoader: ImageLoader) {
|
||||
this.user = user
|
||||
adapter = createAdapter(context, user)
|
||||
adapter = createAdapter(context, user, iconLoader)
|
||||
displayActivities()
|
||||
}
|
||||
|
||||
protected abstract fun createAdapter(context: Context?, user: UserDetails?): ActivityDetailsAdapter?
|
||||
protected abstract fun createAdapter(context: Context?, user: UserDetails?, iconLoader: ImageLoader): ActivityDetailsAdapter?
|
||||
private fun displayActivities() {
|
||||
binding.profileDetailsActivitylist.adapter = adapter
|
||||
loadPage(1)
|
||||
|
@ -116,7 +124,7 @@ abstract class ProfileActivityDetailsFragment : Fragment(), OnItemClickListener
|
|||
i.putExtra(Profile.USER_ID, activity.withUserId)
|
||||
context.startActivity(i)
|
||||
} else if (activity.category == ActivityDetails.Category.FEED_SUBSCRIPTION) {
|
||||
val feed = FeedUtils.getFeed(activity.feedId)
|
||||
val feed = dbHelper.getFeed(activity.feedId)
|
||||
if (feed == null) {
|
||||
Toast.makeText(context, R.string.profile_feed_not_available, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
|
@ -133,7 +141,7 @@ abstract class ProfileActivityDetailsFragment : Fragment(), OnItemClickListener
|
|||
} else if (isSocialFeedCategory(activity)) {
|
||||
// Strip the social: prefix from feedId
|
||||
val socialFeedId = activity.feedId.substring(7)
|
||||
val feed = FeedUtils.getSocialFeed(socialFeedId)
|
||||
val feed = dbHelper.getSocialFeed(socialFeedId)
|
||||
if (feed == null) {
|
||||
Toast.makeText(context, R.string.profile_do_not_follow, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
|
|
|
@ -10,26 +10,32 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.newsblur.R
|
||||
import com.newsblur.databinding.FragmentProfiledetailsBinding
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.domain.UserDetails
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.util.ImageLoader
|
||||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.UIUtils
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ProfileDetailsFragment : Fragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
@IconLoader
|
||||
@Inject
|
||||
lateinit var iconLoader: ImageLoader
|
||||
|
||||
private var user: UserDetails? = null
|
||||
private var viewingSelf = false
|
||||
|
||||
private lateinit var apiManager: APIManager
|
||||
private lateinit var binding: FragmentProfiledetailsBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
apiManager = APIManager(requireContext())
|
||||
}
|
||||
|
||||
fun setUser(context: Context, user: UserDetails?, viewingSelf: Boolean) {
|
||||
this.user = user
|
||||
this.viewingSelf = viewingSelf
|
||||
|
@ -69,7 +75,7 @@ class ProfileDetailsFragment : Fragment() {
|
|||
binding.profileUserStatistics.profileFollowercount.text = user!!.followerCount.toString()
|
||||
binding.profileUserStatistics.profileFollowingcount.text = user!!.followingCount.toString()
|
||||
if (!viewingSelf) {
|
||||
FeedUtils.iconLoader!!.displayImage(user!!.photoUrl, binding.profilePicture)
|
||||
iconLoader.displayImage(user!!.photoUrl, binding.profilePicture)
|
||||
if (user!!.followedByYou) {
|
||||
binding.profileUnfollowButton.visibility = View.VISIBLE
|
||||
binding.profileFollowButton.visibility = View.GONE
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Context;
|
|||
import com.newsblur.domain.ActivityDetails;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
import com.newsblur.network.domain.InteractionsResponse;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.view.ActivityDetailsAdapter;
|
||||
import com.newsblur.view.InteractionsAdapter;
|
||||
|
||||
|
@ -14,8 +15,8 @@ import com.newsblur.view.InteractionsAdapter;
|
|||
public class ProfileInteractionsFragment extends ProfileActivityDetailsFragment {
|
||||
|
||||
@Override
|
||||
protected ActivityDetailsAdapter createAdapter(Context context, UserDetails user) {
|
||||
return new InteractionsAdapter(context, user);
|
||||
protected ActivityDetailsAdapter createAdapter(Context context, UserDetails user, ImageLoader iconLoader) {
|
||||
return new InteractionsAdapter(context, user, iconLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,8 +10,16 @@ import android.os.Bundle;
|
|||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class ReadingActionConfirmationFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private static final String READING_ACTION = "reading_action";
|
||||
private static final String DIALOG_TITLE = "dialog_title";
|
||||
private static final String DIALOG_MESSAGE = "dialog_message";
|
||||
|
@ -46,7 +54,7 @@ public class ReadingActionConfirmationFragment extends DialogFragment {
|
|||
builder.setItems(choicesId, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == 0) {
|
||||
FeedUtils.doAction(ra, getActivity());
|
||||
feedUtils.doAction(ra, getActivity());
|
||||
if (finishAfter) {
|
||||
getActivity().finish();
|
||||
}
|
||||
|
|
|
@ -22,8 +22,11 @@ import com.google.android.material.chip.Chip
|
|||
import com.newsblur.R
|
||||
import com.newsblur.activity.FeedItemsList
|
||||
import com.newsblur.activity.Reading
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.databinding.FragmentReadingitemBinding
|
||||
import com.newsblur.databinding.ReadingItemActionsBinding
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.di.StoryFileCache
|
||||
import com.newsblur.domain.Classifier
|
||||
import com.newsblur.domain.Story
|
||||
import com.newsblur.domain.UserDetails
|
||||
|
@ -35,11 +38,32 @@ import com.newsblur.service.NBSyncReceiver.Companion.UPDATE_TEXT
|
|||
import com.newsblur.service.OriginalTextService
|
||||
import com.newsblur.util.*
|
||||
import com.newsblur.util.PrefConstants.ThemeValue
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
||||
|
||||
@Inject
|
||||
lateinit var apiManager: APIManager
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
@Inject
|
||||
lateinit var feedUtils: FeedUtils
|
||||
|
||||
@Inject
|
||||
@IconLoader
|
||||
lateinit var iconLoader: ImageLoader
|
||||
|
||||
@Inject
|
||||
@StoryFileCache
|
||||
lateinit var storyImageCache: FileCache
|
||||
|
||||
@JvmField
|
||||
var story: Story? = null
|
||||
|
||||
|
@ -271,11 +295,11 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
true
|
||||
}
|
||||
R.id.menu_send_story -> {
|
||||
FeedUtils.sendStoryUrl(story, requireContext())
|
||||
feedUtils.sendStoryUrl(story, requireContext())
|
||||
true
|
||||
}
|
||||
R.id.menu_send_story_full -> {
|
||||
FeedUtils.sendStoryFull(story, requireContext())
|
||||
feedUtils.sendStoryFull(story, requireContext())
|
||||
true
|
||||
}
|
||||
R.id.menu_textsize -> {
|
||||
|
@ -290,14 +314,14 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
}
|
||||
R.id.menu_reading_save -> {
|
||||
if (story!!.starred) {
|
||||
FeedUtils.setStorySaved(story!!, false, requireContext(), null)
|
||||
feedUtils.setStorySaved(story!!, false, requireContext(), null)
|
||||
} else {
|
||||
FeedUtils.setStorySaved(story!!.storyHash, true, requireContext())
|
||||
feedUtils.setStorySaved(story!!.storyHash, true, requireContext())
|
||||
}
|
||||
true
|
||||
}
|
||||
R.id.menu_reading_markunread -> {
|
||||
FeedUtils.markStoryUnread(story!!, requireContext())
|
||||
feedUtils.markStoryUnread(story!!, requireContext())
|
||||
true
|
||||
}
|
||||
R.id.menu_theme_auto -> {
|
||||
|
@ -328,7 +352,7 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
true
|
||||
}
|
||||
R.id.menu_go_to_feed -> {
|
||||
FeedItemsList.startActivity(context, fs, FeedUtils.getFeed(story!!.feedId), null)
|
||||
FeedItemsList.startActivity(context, fs, dbHelper.getFeed(story!!.feedId), null)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
|
@ -337,8 +361,8 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
}
|
||||
|
||||
private fun clickMarkStoryRead() {
|
||||
if (story!!.read) FeedUtils.markStoryUnread(story!!, requireContext())
|
||||
else FeedUtils.markStoryAsRead(story!!, requireContext())
|
||||
if (story!!.read) feedUtils.markStoryUnread(story!!, requireContext())
|
||||
else feedUtils.markStoryAsRead(story!!, requireContext())
|
||||
}
|
||||
|
||||
private fun updateMarkReadButton() {
|
||||
|
@ -361,9 +385,9 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
|
||||
private fun clickSave() {
|
||||
if (story!!.starred) {
|
||||
FeedUtils.setStorySaved(story!!.storyHash, false, requireContext())
|
||||
feedUtils.setStorySaved(story!!.storyHash, false, requireContext())
|
||||
} else {
|
||||
FeedUtils.setStorySaved(story!!.storyHash, true, requireContext())
|
||||
feedUtils.setStorySaved(story!!.storyHash, true, requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,7 +411,7 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
}
|
||||
|
||||
private fun setupItemCommentsAndShares() {
|
||||
SetupCommentSectionTask(this, binding.root, layoutInflater, story).execute()
|
||||
SetupCommentSectionTask(this, binding.root, layoutInflater, story, iconLoader).execute()
|
||||
}
|
||||
|
||||
private fun setupItemMetadata() {
|
||||
|
@ -412,7 +436,7 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
binding.readingFeedTitle.visibility = View.GONE
|
||||
binding.readingFeedIcon.visibility = View.GONE
|
||||
} else {
|
||||
FeedUtils.iconLoader!!.displayImage(feedIconUrl, binding.readingFeedIcon)
|
||||
iconLoader.displayImage(feedIconUrl, binding.readingFeedIcon)
|
||||
binding.readingFeedTitle.text = feedTitle
|
||||
}
|
||||
|
||||
|
@ -634,7 +658,7 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
setupItemCommentsAndShares()
|
||||
}
|
||||
if (updateType and UPDATE_INTEL != 0) {
|
||||
classifier = FeedUtils.dbHelper!!.getClassifierForFeed(story!!.feedId)
|
||||
classifier = dbHelper.getClassifierForFeed(story!!.feedId)
|
||||
setupTagsAndIntel()
|
||||
}
|
||||
}
|
||||
|
@ -643,7 +667,7 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
story?.let { story ->
|
||||
lifecycleScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.getStoryText(story.storyHash)
|
||||
feedUtils.getStoryText(story.storyHash)
|
||||
},
|
||||
onPostExecute = { result ->
|
||||
if (result != null) {
|
||||
|
@ -669,7 +693,7 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
story?.let { story ->
|
||||
lifecycleScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.getStoryContent(story.storyHash)
|
||||
feedUtils.getStoryContent(story.storyHash)
|
||||
},
|
||||
onPostExecute = { result ->
|
||||
if (result != null) {
|
||||
|
@ -692,7 +716,6 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
binding.readingStoryChanges.setText(R.string.story_changes_loading)
|
||||
},
|
||||
doInBackground = {
|
||||
val apiManager = APIManager(requireContext())
|
||||
apiManager.getStoryChanges(story.storyHash, showChanges)
|
||||
},
|
||||
onPostExecute = { response ->
|
||||
|
@ -813,7 +836,7 @@ class ReadingItemFragment : NbFragment(), PopupMenu.OnMenuItemClickListener {
|
|||
val imageTagMatcher = imgSniff.matcher(html)
|
||||
while (imageTagMatcher.find()) {
|
||||
val url = imageTagMatcher.group(2)
|
||||
val localPath = FeedUtils.storyImageCache!!.getCachedLocation(url) ?: continue
|
||||
val localPath = storyImageCache.getCachedLocation(url) ?: continue
|
||||
html = html.replace(imageTagMatcher.group(1) + "\"" + url + "\"", "src=\"$localPath\"")
|
||||
imageUrlRemaps!![localPath] = url
|
||||
}
|
||||
|
|
|
@ -15,12 +15,19 @@ import android.widget.Toast;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.databinding.DialogRenameBinding;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class RenameDialogFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private static final String FEED = "feed";
|
||||
private static final String FOLDER = "folder";
|
||||
private static final String FOLDER_NAME = "folder_name";
|
||||
|
@ -71,7 +78,7 @@ public class RenameDialogFragment extends DialogFragment {
|
|||
builder.setPositiveButton(R.string.feed_name_save, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
FeedUtils.renameFeed(activity, feed.feedId, binding.inputName.getText().toString());
|
||||
feedUtils.renameFeed(activity, feed.feedId, binding.inputName.getText().toString());
|
||||
RenameDialogFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
@ -95,7 +102,7 @@ public class RenameDialogFragment extends DialogFragment {
|
|||
if (!TextUtils.isEmpty(folderParentName) && !folderParentName.equals(AppConstants.ROOT_FOLDER)) {
|
||||
inFolder = folderParentName;
|
||||
}
|
||||
FeedUtils.renameFolder(folderName, newFolderName, inFolder, activity, new APIManager(activity));
|
||||
feedUtils.renameFolder(folderName, newFolderName, inFolder, activity);
|
||||
RenameDialogFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -15,8 +15,16 @@ import com.newsblur.R;
|
|||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class ReplyDialogFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private static final String STORY = "story";
|
||||
private static final String COMMENT_USER_ID = "comment_user_id";
|
||||
private static final String COMMENT_USERNAME = "comment_username";
|
||||
|
@ -53,7 +61,7 @@ public class ReplyDialogFragment extends DialogFragment {
|
|||
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
FeedUtils.replyToComment(story.id, story.feedId, commentUserId, reply.getText().toString(), activity);
|
||||
feedUtils.replyToComment(story.id, story.feedId, commentUserId, reply.getText().toString(), activity);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
|
||||
|
|
|
@ -8,11 +8,18 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class SaveSearchFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
private static final String FEED_ID = "feed_id";
|
||||
private static final String QUERY = "query";
|
||||
|
||||
|
@ -33,7 +40,7 @@ public class SaveSearchFragment extends DialogFragment {
|
|||
builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
FeedUtils.saveSearch(getArguments().getString(FEED_ID), getArguments().getString(QUERY), getActivity(), new APIManager(getActivity()));
|
||||
feedUtils.saveSearch(getArguments().getString(FEED_ID), getArguments().getString(QUERY), getActivity());
|
||||
SaveSearchFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -7,11 +7,18 @@ import androidx.preference.PreferenceFragmentCompat;
|
|||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.service.NBSyncService;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.PrefConstants;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
private Preference deleteOfflineStoriesPref;
|
||||
|
||||
@Override
|
||||
|
@ -32,9 +39,12 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
private void deleteOfflineStories() {
|
||||
if (deleteOfflineStoriesPref != null) {
|
||||
deleteOfflineStoriesPref.setOnPreferenceClickListener(null);
|
||||
FeedUtils.syncOfflineStories(requireContext());
|
||||
deleteOfflineStoriesPref.setSummary("");
|
||||
deleteOfflineStoriesPref.setTitle(R.string.menu_delete_offline_stories_confirmation);
|
||||
|
||||
dbHelper.deleteStories();
|
||||
NBSyncService.forceFeedsFolders();
|
||||
FeedUtils.triggerSync(requireContext());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ import com.newsblur.view.RoundedImageView
|
|||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
|
||||
class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: View, inflater: LayoutInflater, story: Story?) {
|
||||
class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: View, inflater: LayoutInflater, story: Story?, iconLoader: ImageLoader) {
|
||||
|
||||
private var topCommentViews: ArrayList<View>? = null
|
||||
private var topShareViews: ArrayList<View>? = null
|
||||
|
@ -36,6 +36,7 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
private val context: Context?
|
||||
private val user: UserDetails
|
||||
private val manager: FragmentManager
|
||||
private val iconLoader: ImageLoader
|
||||
private var comments: MutableList<Comment>? = null
|
||||
|
||||
/**
|
||||
|
@ -54,7 +55,7 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
|
||||
private fun doInBackground() {
|
||||
if (context == null || story == null) return
|
||||
comments = FeedUtils.dbHelper!!.getComments(story.id)
|
||||
comments = fragment.dbHelper.getComments(story.id)
|
||||
topCommentViews = ArrayList()
|
||||
topShareViews = ArrayList()
|
||||
publicCommentViews = ArrayList()
|
||||
|
@ -70,7 +71,7 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
if (!comment.byFriend && !PrefsUtils.showPublicComments(context)) {
|
||||
continue
|
||||
}
|
||||
val commentUser = FeedUtils.dbHelper!!.getUserProfile(comment.userId)
|
||||
val commentUser = fragment.dbHelper.getUserProfile(comment.userId)
|
||||
// rarely, we get a comment but never got the user's profile, so we can't display it
|
||||
if (commentUser == null) {
|
||||
Log.w(this.javaClass.name, "cannot display comment from missing user ID: " + comment.userId)
|
||||
|
@ -94,9 +95,9 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
}
|
||||
for (id in comment.likingUsers) {
|
||||
val favouriteImage = RoundedImageView(context)
|
||||
val user = FeedUtils.dbHelper!!.getUserProfile(id)
|
||||
val user = fragment.dbHelper.getUserProfile(id)
|
||||
if (user != null) {
|
||||
FeedUtils.iconLoader!!.displayImage(user.photoUrl, favouriteImage)
|
||||
fragment.iconLoader.displayImage(user.photoUrl, favouriteImage)
|
||||
favouriteContainer.addView(favouriteImage)
|
||||
}
|
||||
}
|
||||
|
@ -107,9 +108,9 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
} else {
|
||||
favouriteIcon.setOnClickListener {
|
||||
if (!mutableListOf<String>(*comment.likingUsers).contains(user.id)) {
|
||||
FeedUtils.likeComment(story, comment.userId, context)
|
||||
fragment.feedUtils.likeComment(story, comment.userId, context)
|
||||
} else {
|
||||
FeedUtils.unlikeComment(story, comment.userId, context)
|
||||
fragment.feedUtils.unlikeComment(story, comment.userId, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,22 +119,22 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
replyIcon.visibility = View.INVISIBLE
|
||||
} else {
|
||||
replyIcon.setOnClickListener {
|
||||
val user = FeedUtils.dbHelper!!.getUserProfile(comment.userId)
|
||||
val user = fragment.dbHelper.getUserProfile(comment.userId)
|
||||
if (user != null) {
|
||||
val newFragment: DialogFragment = ReplyDialogFragment.newInstance(story, comment.userId, user.username)
|
||||
newFragment.show(manager, "dialog")
|
||||
}
|
||||
}
|
||||
}
|
||||
val replies = FeedUtils.dbHelper!!.getCommentReplies(comment.id)
|
||||
val replies = fragment.dbHelper.getCommentReplies(comment.id)
|
||||
for (reply in replies) {
|
||||
val replyView = inflater.inflate(R.layout.include_reply, null)
|
||||
val replyText = replyView.findViewById<View>(R.id.reply_text) as TextView
|
||||
replyText.text = UIUtils.fromHtml(reply.text)
|
||||
val replyImage = replyView.findViewById<View>(R.id.reply_user_image) as RoundedImageView
|
||||
val replyUser = FeedUtils.dbHelper!!.getUserProfile(reply.userId)
|
||||
val replyUser = fragment.dbHelper.getUserProfile(reply.userId)
|
||||
if (replyUser != null) {
|
||||
FeedUtils.iconLoader!!.displayImage(replyUser.photoUrl, replyImage)
|
||||
fragment.iconLoader.displayImage(replyUser.photoUrl, replyImage)
|
||||
replyImage.setOnClickListener {
|
||||
val i = Intent(context, Profile::class.java)
|
||||
i.putExtra(Profile.USER_ID, replyUser.userId)
|
||||
|
@ -176,13 +177,13 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
sourceUserImage.visibility = View.VISIBLE
|
||||
usershareImage.visibility = View.VISIBLE
|
||||
commentImage.visibility = View.INVISIBLE
|
||||
val sourceUser = FeedUtils.dbHelper!!.getUserProfile(comment.sourceUserId)
|
||||
val sourceUser = fragment.dbHelper.getUserProfile(comment.sourceUserId)
|
||||
if (sourceUser != null) {
|
||||
FeedUtils.iconLoader!!.displayImage(sourceUser.photoUrl, sourceUserImage)
|
||||
FeedUtils.iconLoader!!.displayImage(userPhoto, usershareImage)
|
||||
fragment.iconLoader.displayImage(sourceUser.photoUrl, sourceUserImage)
|
||||
fragment.iconLoader.displayImage(userPhoto, usershareImage)
|
||||
}
|
||||
} else {
|
||||
FeedUtils.iconLoader!!.displayImage(userPhoto, commentImage)
|
||||
fragment.iconLoader.displayImage(userPhoto, commentImage)
|
||||
}
|
||||
commentImage.setOnClickListener {
|
||||
val i = Intent(context, Profile::class.java)
|
||||
|
@ -200,7 +201,7 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
|
||||
// for actual comments, also populate the upper icon bar
|
||||
if (!comment.isPseudo) {
|
||||
val image = ViewUtils.createSharebarImage(context, commentUser.photoUrl, commentUser.userId)
|
||||
val image = ViewUtils.createSharebarImage(context, commentUser.photoUrl, commentUser.userId, iconLoader)
|
||||
topCommentViews!!.add(image)
|
||||
commentingUserIds.add(comment.userId)
|
||||
}
|
||||
|
@ -216,12 +217,12 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
|
||||
// now that we have all shares from the comments table and story object, populate the shares row
|
||||
for (userId in sharingUserIds) {
|
||||
val user = FeedUtils.dbHelper!!.getUserProfile(userId)
|
||||
val user = fragment.dbHelper.getUserProfile(userId)
|
||||
if (user == null) {
|
||||
Log.w(this.javaClass.name, "cannot display share from missing user ID: $userId")
|
||||
continue
|
||||
}
|
||||
val image = ViewUtils.createSharebarImage(context, user.photoUrl, user.userId)
|
||||
val image = ViewUtils.createSharebarImage(context, user.photoUrl, user.userId, iconLoader)
|
||||
topShareViews!!.add(image)
|
||||
}
|
||||
}
|
||||
|
@ -344,5 +345,6 @@ class SetupCommentSectionTask(private val fragment: ReadingItemFragment, view: V
|
|||
this.story = story
|
||||
viewHolder = WeakReference(view)
|
||||
user = PrefsUtils.getUserDetails(context)
|
||||
this.iconLoader = iconLoader
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import android.view.View;
|
|||
import android.widget.EditText;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.domain.Comment;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
|
@ -20,8 +21,19 @@ import com.newsblur.util.FeedUtils;
|
|||
import com.newsblur.util.PrefsUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class ShareDialogFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
private static final String STORY = "story";
|
||||
private static final String SOURCE_USER_ID = "sourceUserId";
|
||||
private Story story;
|
||||
|
@ -55,7 +67,7 @@ public class ShareDialogFragment extends DialogFragment {
|
|||
}
|
||||
|
||||
if (hasBeenShared) {
|
||||
previousComment = FeedUtils.dbHelper.getComment(story.id, user.id);
|
||||
previousComment = dbHelper.getComment(story.id, user.id);
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
|
@ -80,7 +92,7 @@ public class ShareDialogFragment extends DialogFragment {
|
|||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
String shareComment = commentEditText.getText().toString();
|
||||
FeedUtils.shareStory(story, shareComment, sourceUserId, activity);
|
||||
feedUtils.shareStory(story, shareComment, sourceUserId, activity);
|
||||
ShareDialogFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
@ -89,7 +101,7 @@ public class ShareDialogFragment extends DialogFragment {
|
|||
builder.setNegativeButton(negativeButtonText, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
FeedUtils.unshareStory(story, activity);
|
||||
feedUtils.unshareStory(story, activity);
|
||||
ShareDialogFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ import android.view.View.OnClickListener;
|
|||
import android.widget.TextView;
|
||||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.databinding.DialogTrainstoryBinding;
|
||||
import com.newsblur.domain.Classifier;
|
||||
import com.newsblur.domain.Story;
|
||||
|
@ -25,8 +26,19 @@ import com.newsblur.util.FeedSet;
|
|||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class StoryIntelTrainerFragment extends DialogFragment {
|
||||
|
||||
@Inject
|
||||
FeedUtils feedUtils;
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
private Story story;
|
||||
private FeedSet fs;
|
||||
private Classifier classifier;
|
||||
|
@ -50,7 +62,7 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
|||
super.onCreate(savedInstanceState);
|
||||
story = (Story) getArguments().getSerializable("story");
|
||||
fs = (FeedSet) getArguments().getSerializable("feedset");
|
||||
classifier = FeedUtils.dbHelper.getClassifierForFeed(story.feedId);
|
||||
classifier = dbHelper.getClassifierForFeed(story.feedId);
|
||||
|
||||
final Activity activity = getActivity();
|
||||
LayoutInflater inflater = LayoutInflater.from(activity);
|
||||
|
@ -132,7 +144,7 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
|||
// the intel identifier is the feed ID
|
||||
View rowFeed = inflater.inflate(R.layout.include_intel_row, null);
|
||||
TextView labelFeed = (TextView) rowFeed.findViewById(R.id.intel_row_label);
|
||||
labelFeed.setText(FeedUtils.getFeedTitle(story.feedId));
|
||||
labelFeed.setText(feedUtils.getFeedTitle(story.feedId));
|
||||
UIUtils.setupIntelDialogRow(rowFeed, classifier.feeds, story.feedId);
|
||||
binding.existingFeedIntelContainer.addView(rowFeed);
|
||||
|
||||
|
@ -152,7 +164,7 @@ public class StoryIntelTrainerFragment extends DialogFragment {
|
|||
if ((newTitleTraining != null) && (!TextUtils.isEmpty(binding.intelTitleSelection.getSelection()))) {
|
||||
classifier.title.put(binding.intelTitleSelection.getSelection(), newTitleTraining);
|
||||
}
|
||||
FeedUtils.updateClassifier(story.feedId, classifier, fs, activity);
|
||||
feedUtils.updateClassifier(story.feedId, classifier, fs, activity);
|
||||
StoryIntelTrainerFragment.this.dismiss();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -20,13 +20,19 @@ import com.newsblur.util.FeedSet
|
|||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.util.TagsAdapter
|
||||
import com.newsblur.viewModel.StoryUserTagsViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
@AndroidEntryPoint
|
||||
class StoryUserTagsFragment : DialogFragment(), TagsAdapter.OnTagClickListener {
|
||||
|
||||
@Inject
|
||||
lateinit var feedUtils: FeedUtils
|
||||
|
||||
private lateinit var story: Story
|
||||
private lateinit var fs: FeedSet
|
||||
private lateinit var binding: DialogStoryUserTagsBinding
|
||||
|
@ -228,6 +234,6 @@ class StoryUserTagsFragment : DialogFragment(), TagsAdapter.OnTagClickListener {
|
|||
private fun saveTags() {
|
||||
val savedTagList = getSavedTagsList()
|
||||
NBSyncService.forceFeedsFolders()
|
||||
FeedUtils.setStorySaved(story, true, requireContext(), savedTagList)
|
||||
feedUtils.setStorySaved(story, true, requireContext(), savedTagList)
|
||||
}
|
||||
}
|
|
@ -3,29 +3,22 @@ package com.newsblur.network;
|
|||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.newsblur.domain.Classifier;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.FeedResult;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.domain.ValueMultimap;
|
||||
import static com.newsblur.network.APIConstants.buildUrl;
|
||||
import com.newsblur.network.domain.ActivitiesResponse;
|
||||
|
@ -43,11 +36,6 @@ import com.newsblur.network.domain.StoryChangesResponse;
|
|||
import com.newsblur.network.domain.StoryTextResponse;
|
||||
import com.newsblur.network.domain.UnreadCountResponse;
|
||||
import com.newsblur.network.domain.UnreadStoryHashesResponse;
|
||||
import com.newsblur.serialization.BooleanTypeAdapter;
|
||||
import com.newsblur.serialization.ClassifierMapTypeAdapter;
|
||||
import com.newsblur.serialization.DateStringTypeAdapter;
|
||||
import com.newsblur.serialization.FeedListTypeAdapter;
|
||||
import com.newsblur.serialization.StoryTypeAdapter;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.NetworkUtils;
|
||||
|
@ -65,37 +53,17 @@ import okhttp3.Response;
|
|||
|
||||
public class APIManager {
|
||||
|
||||
private Context context;
|
||||
private Gson gson;
|
||||
private final Context context;
|
||||
private final Gson gson;
|
||||
private final OkHttpClient httpClient;
|
||||
private String customUserAgent;
|
||||
private OkHttpClient httpClient;
|
||||
|
||||
public APIManager(final Context context) {
|
||||
this.context = context;
|
||||
|
||||
public APIManager(final Context context, Gson gson, String customUserAgent, OkHttpClient httpClient) {
|
||||
APIConstants.setCustomServer(PrefsUtils.getCustomServer(context));
|
||||
|
||||
this.gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Date.class, new DateStringTypeAdapter())
|
||||
.registerTypeAdapter(Boolean.class, new BooleanTypeAdapter())
|
||||
.registerTypeAdapter(boolean.class, new BooleanTypeAdapter())
|
||||
.registerTypeAdapter(Story.class, new StoryTypeAdapter())
|
||||
.registerTypeAdapter(new TypeToken<List<Feed>>(){}.getType(), new FeedListTypeAdapter())
|
||||
.registerTypeAdapter(new TypeToken<Map<String,Classifier>>(){}.getType(), new ClassifierMapTypeAdapter())
|
||||
.create();
|
||||
|
||||
String appVersion = context.getSharedPreferences(PrefConstants.PREFERENCES, 0).getString(AppConstants.LAST_APP_VERSION, "unknown_version");
|
||||
this.customUserAgent = "NewsBlur Android app" +
|
||||
" (" + Build.MANUFACTURER + " " +
|
||||
Build.MODEL + " " +
|
||||
Build.VERSION.RELEASE + " " +
|
||||
appVersion + ")";
|
||||
|
||||
this.httpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(AppConstants.API_CONN_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
.readTimeout(AppConstants.API_READ_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
.followSslRedirects(true)
|
||||
.build();
|
||||
this.context = context;
|
||||
this.gson = gson;
|
||||
this.customUserAgent = customUserAgent;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public LoginResponse login(final String username, final String password) {
|
||||
|
@ -684,6 +652,10 @@ public class APIManager {
|
|||
return response.getResponse(gson, NewsBlurResponse.class);
|
||||
}
|
||||
|
||||
public void updateCustomUserAgent(String customUserAgent) {
|
||||
this.customUserAgent = customUserAgent;
|
||||
}
|
||||
|
||||
/* HTTP METHODS */
|
||||
|
||||
private APIResponse get(final String urlString) {
|
||||
|
@ -798,5 +770,4 @@ public class APIManager {
|
|||
com.newsblur.util.Log.w(this.getClass().getName(), "Abandoning API backoff due to interrupt.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import static com.newsblur.service.NBSyncReceiver.UPDATE_STORY;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.di.IconFileCache;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.domain.SavedSearch;
|
||||
|
@ -59,6 +60,10 @@ import java.util.concurrent.Executors;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
|
||||
/**
|
||||
* A background service to handle synchronisation with the NB servers.
|
||||
*
|
||||
|
@ -74,6 +79,7 @@ import java.util.concurrent.TimeUnit;
|
|||
* after sync operations are performed. Activities can then refresh views and
|
||||
* query this class to see if progress indicators should be active.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
public class NBSyncService extends JobService {
|
||||
|
||||
private static final Object COMPLETION_CALLBACKS_MUTEX = new Object();
|
||||
|
@ -147,8 +153,14 @@ public class NBSyncService extends JobService {
|
|||
ImagePrefetchService imagePrefetchService;
|
||||
private boolean forceHalted = false;
|
||||
|
||||
@Inject
|
||||
APIManager apiManager;
|
||||
|
||||
@Inject
|
||||
BlurDatabaseHelper dbHelper;
|
||||
|
||||
@IconFileCache
|
||||
@Inject
|
||||
FileCache iconCache;
|
||||
|
||||
/** The time of the last hard API failure we encountered. Used to implement back-off so that the sync
|
||||
|
@ -170,10 +182,7 @@ public class NBSyncService extends JobService {
|
|||
* parts of construction in onCreate, but save them for when we are in our own thread.
|
||||
*/
|
||||
private void finishConstruction() {
|
||||
if ((apiManager == null) || (dbHelper == null)) {
|
||||
apiManager = new APIManager(this);
|
||||
dbHelper = new BlurDatabaseHelper(this);
|
||||
iconCache = FileCache.asIconCache(this);
|
||||
if (cleanupService == null || imagePrefetchService == null) {
|
||||
cleanupService = new CleanupService(this);
|
||||
starredService = new StarredService(this);
|
||||
originalTextService = new OriginalTextService(this);
|
||||
|
@ -356,7 +365,11 @@ public class NBSyncService extends JobService {
|
|||
// v61+ is widely deployed
|
||||
FileCache.cleanUpOldCache1(this);
|
||||
FileCache.cleanUpOldCache2(this);
|
||||
PrefsUtils.updateVersion(this);
|
||||
String appVersion = PrefsUtils.getVersion(this);
|
||||
PrefsUtils.updateVersion(this, appVersion);
|
||||
// update user agent on api calls with latest app version
|
||||
String customUserAgent = NetworkUtils.getCustomUserAgent(appVersion);
|
||||
apiManager.updateCustomUserAgent(customUserAgent);
|
||||
}
|
||||
|
||||
boolean autoVac = PrefsUtils.isTimeToVacuum(this);
|
||||
|
@ -516,7 +529,7 @@ public class NBSyncService extends JobService {
|
|||
com.newsblur.util.Log.w(this.getClass().getName(), "Server ignored or rejected auth cookie.");
|
||||
if (authFails >= AppConstants.MAX_API_TRIES) {
|
||||
com.newsblur.util.Log.w(this.getClass().getName(), "too many auth fails, resetting cookie");
|
||||
PrefsUtils.logout(this);
|
||||
PrefsUtils.logout(this, dbHelper);
|
||||
}
|
||||
DoFeedsFolders = true;
|
||||
return;
|
||||
|
@ -604,7 +617,7 @@ public class NBSyncService extends JobService {
|
|||
// saved searches table
|
||||
List<ContentValues> savedSearchesValues = new ArrayList<>();
|
||||
for (SavedSearch savedSearch : feedResponse.savedSearches) {
|
||||
savedSearchesValues.add(savedSearch.getValues());
|
||||
savedSearchesValues.add(savedSearch.getValues(dbHelper));
|
||||
}
|
||||
// the API vends the starred total as a different element, roll it into
|
||||
// the starred counts table using a special tag
|
||||
|
@ -951,7 +964,7 @@ public class NBSyncService extends JobService {
|
|||
|
||||
Cursor cFocus = dbHelper.getNotifyFocusStoriesCursor();
|
||||
Cursor cUnread = dbHelper.getNotifyUnreadStoriesCursor();
|
||||
NotificationUtils.notifyStories(cFocus, cUnread, this, iconCache);
|
||||
NotificationUtils.notifyStories(this, cFocus, cUnread, iconCache, dbHelper);
|
||||
closeQuietly(cFocus);
|
||||
closeQuietly(cUnread);
|
||||
}
|
||||
|
@ -1222,10 +1235,6 @@ public class NBSyncService extends JobService {
|
|||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (dbHelper != null) {
|
||||
dbHelper.close();
|
||||
dbHelper = null;
|
||||
}
|
||||
com.newsblur.util.Log.d(this, "onDestroy done");
|
||||
} catch (Exception ex) {
|
||||
com.newsblur.util.Log.e(this, "unclean shutdown", ex);
|
||||
|
|
|
@ -21,6 +21,10 @@ import com.newsblur.util.Log
|
|||
import com.newsblur.util.NBScope
|
||||
import com.newsblur.util.PrefsUtils
|
||||
import com.newsblur.util.executeAsyncTask
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
|
@ -79,6 +83,13 @@ interface SubscriptionsListener {
|
|||
fun onBillingConnectionError(message: String? = null) {}
|
||||
}
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface SubscriptionManagerEntryPoint {
|
||||
|
||||
fun apiManager(): APIManager
|
||||
}
|
||||
|
||||
class SubscriptionManagerImpl(
|
||||
private val context: Context,
|
||||
private val scope: CoroutineScope = NBScope,
|
||||
|
@ -199,10 +210,11 @@ class SubscriptionManagerImpl(
|
|||
|
||||
override fun saveReceipt(purchase: Purchase) {
|
||||
Log.d(this, "saveReceipt: ${purchase.orderId}")
|
||||
val apiManager = APIManager(context)
|
||||
val hiltEntryPoint = EntryPointAccessors
|
||||
.fromApplication(context.applicationContext, SubscriptionManagerEntryPoint::class.java)
|
||||
scope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.saveReceipt(purchase.orderId, purchase.skus.first())
|
||||
hiltEntryPoint.apiManager().saveReceipt(purchase.orderId, purchase.skus.first())
|
||||
},
|
||||
onPostExecute = {
|
||||
if (!it.isError) {
|
||||
|
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
@ -13,27 +12,16 @@ import com.newsblur.fragment.ReadingActionConfirmationFragment
|
|||
import com.newsblur.network.APIConstants
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.service.NBSyncService
|
||||
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 com.newsblur.util.UIUtils.syncUpdateStatus
|
||||
import java.util.*
|
||||
|
||||
object FeedUtils {
|
||||
|
||||
// these are app-level singletons stored here for convenience. however, they
|
||||
// cannot be created lazily or via static init, they have to be created when
|
||||
// the main app context is created and it offers a reference
|
||||
@JvmField
|
||||
var dbHelper: BlurDatabaseHelper? = null
|
||||
|
||||
@JvmField
|
||||
var iconLoader: ImageLoader? = null
|
||||
|
||||
@JvmField
|
||||
var thumbnailLoader: ImageLoader? = null
|
||||
|
||||
var storyImageCache: FileCache? = null
|
||||
class FeedUtils(
|
||||
private val dbHelper: BlurDatabaseHelper,
|
||||
private val apiManager: APIManager,
|
||||
) {
|
||||
|
||||
// this is gross, but the feedset can't hold a folder title
|
||||
// without being mistaken for a folder feed.
|
||||
|
@ -42,37 +30,6 @@ object FeedUtils {
|
|||
@JvmField
|
||||
var currentFolderName: String? = null
|
||||
|
||||
@JvmStatic
|
||||
fun offerInitContext(context: Context) {
|
||||
if (dbHelper == null) {
|
||||
dbHelper = BlurDatabaseHelper(context.applicationContext)
|
||||
}
|
||||
if (iconLoader == null) {
|
||||
iconLoader = ImageLoader.asIconLoader(context.applicationContext)
|
||||
}
|
||||
if (storyImageCache == null) {
|
||||
storyImageCache = FileCache.asStoryImageCache(context.applicationContext)
|
||||
}
|
||||
if (thumbnailLoader == null) {
|
||||
thumbnailLoader = ImageLoader.asThumbnailLoader(context.applicationContext, storyImageCache)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun triggerSync(c: Context) {
|
||||
// NB: when our minSDKversion hits 28, it could be possible to start the service via the JobScheduler
|
||||
// with the setImportantWhileForeground() flag via an enqueue() and get rid of all legacy startService
|
||||
// code paths
|
||||
val i = Intent(c, NBSyncService::class.java)
|
||||
c.startService(i)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun dropAndRecreateTables() {
|
||||
dbHelper!!.dropAndRecreateTables()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun prepareReadingSession(fs: FeedSet?, resetFirst: Boolean) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
|
@ -94,7 +51,6 @@ object FeedUtils {
|
|||
setStorySaved(storyHash, saved, context, userTags)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setStorySaved(story: Story, saved: Boolean, context: Context, userTags: List<String?>?) {
|
||||
setStorySaved(story.storyHash, saved, context, userTags)
|
||||
}
|
||||
|
@ -105,29 +61,27 @@ object FeedUtils {
|
|||
val ra = if (saved) ReadingAction.saveStory(storyHash, userTags) else ReadingAction.unsaveStory(storyHash)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_STORY)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
triggerSync(context)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteSavedSearch(feedId: String?, query: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
APIManager(context).deleteSearch(feedId, query)
|
||||
apiManager.deleteSearch(feedId, query)
|
||||
},
|
||||
onPostExecute = { newsBlurResponse ->
|
||||
if (!newsBlurResponse.isError) {
|
||||
dbHelper!!.deleteSavedSearch(feedId, query)
|
||||
dbHelper.deleteSavedSearch(feedId, query)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun saveSearch(feedId: String?, query: String?, context: Context, apiManager: APIManager) {
|
||||
fun saveSearch(feedId: String?, query: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.saveSearch(feedId, query)
|
||||
|
@ -141,36 +95,33 @@ object FeedUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteFeed(feedId: String?, folderName: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
APIManager(context).deleteFeed(feedId, folderName)
|
||||
apiManager.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)
|
||||
dbHelper.deleteFeed(feedId)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteSocialFeed(userId: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
APIManager(context).unfollowUser(userId)
|
||||
apiManager.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)
|
||||
dbHelper.deleteSocialFeed(userId)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteFolder(folderName: String?, inFolder: String?, context: Context, apiManager: APIManager) {
|
||||
fun deleteFolder(folderName: String?, inFolder: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.deleteFolder(folderName, inFolder)
|
||||
|
@ -184,15 +135,7 @@ object FeedUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun syncOfflineStories(context: Context) {
|
||||
dbHelper!!.deleteStories()
|
||||
NBSyncService.forceFeedsFolders()
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun renameFolder(folderName: String?, newFolderName: String?, inFolder: String?, context: Context, apiManager: APIManager) {
|
||||
fun renameFolder(folderName: String?, newFolderName: String?, inFolder: String?, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
apiManager.renameFolder(folderName, newFolderName, inFolder)
|
||||
|
@ -206,7 +149,6 @@ object FeedUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun markStoryUnread(story: Story, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
|
@ -215,7 +157,6 @@ object FeedUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun markStoryAsRead(story: Story, context: Context) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
|
@ -228,7 +169,7 @@ object FeedUtils {
|
|||
try {
|
||||
// this shouldn't throw errors, but crash logs suggest something is racing it for DB resources.
|
||||
// capture logs in hopes of finding the correlated action
|
||||
dbHelper!!.touchStory(story.storyHash)
|
||||
dbHelper.touchStory(story.storyHash)
|
||||
} catch (e: Exception) {
|
||||
Log.e(FeedUtils::class.java.name, "error touching story state in DB", e)
|
||||
}
|
||||
|
@ -238,10 +179,10 @@ object FeedUtils {
|
|||
|
||||
// tell the sync service we need to mark read
|
||||
val ra = if (read) ReadingAction.markStoryRead(story.storyHash) else ReadingAction.markStoryUnread(story.storyHash)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
|
||||
// update unread state and unread counts in the local DB
|
||||
val impactedFeeds = dbHelper!!.setStoryReadState(story, read)
|
||||
val impactedFeeds = dbHelper.setStoryReadState(story, read)
|
||||
syncUpdateStatus(context, UPDATE_STORY)
|
||||
|
||||
NBSyncService.addRecountCandidates(impactedFeeds)
|
||||
|
@ -256,7 +197,7 @@ object FeedUtils {
|
|||
*/
|
||||
fun setStoryReadStateExternal(storyHash: String?, context: Context, read: Boolean) {
|
||||
val ra = if (read) ReadingAction.markStoryRead(storyHash) else ReadingAction.markStoryUnread(storyHash)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
|
||||
val feedId = inferFeedId(storyHash)
|
||||
val impactedFeed = FeedSet.singleFeed(feedId)
|
||||
|
@ -268,12 +209,11 @@ object FeedUtils {
|
|||
/**
|
||||
* Marks some or all of the stories in a FeedSet as read for an activity, handling confirmation dialogues as necessary.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun markRead(activity: NbActivity, fs: FeedSet, olderThan: Long?, newerThan: Long?, choicesRid: Int, finishAfter: Boolean) {
|
||||
val ra: ReadingAction = if (fs.isAllNormal && (olderThan != null || newerThan != null)) {
|
||||
// the mark-all-read API doesn't support range bounding, so we need to pass each and every
|
||||
// feed ID to the API instead.
|
||||
val newFeedSet = FeedSet.folder("all", dbHelper!!.allActiveFeeds)
|
||||
val newFeedSet = FeedSet.folder("all", dbHelper.allActiveFeeds)
|
||||
ReadingAction.markFeedRead(newFeedSet, olderThan, newerThan)
|
||||
} else {
|
||||
if (fs.singleFeed != null) {
|
||||
|
@ -286,7 +226,7 @@ object FeedUtils {
|
|||
}
|
||||
} else if (fs.isFolder) {
|
||||
val feedIds = fs.multipleFeeds
|
||||
val allActiveFeedIds = dbHelper!!.allActiveFeeds
|
||||
val allActiveFeedIds = dbHelper.allActiveFeeds
|
||||
val activeFeedIds: MutableSet<String> = HashSet()
|
||||
activeFeedIds.addAll(feedIds)
|
||||
activeFeedIds.retainAll(allActiveFeedIds)
|
||||
|
@ -328,10 +268,10 @@ object FeedUtils {
|
|||
fs.folderName
|
||||
}
|
||||
fs.isSingleSocial -> {
|
||||
getSocialFeed(fs.singleSocialFeed.key)?.feedTitle ?: ""
|
||||
dbHelper.getSocialFeed(fs.singleSocialFeed.key)?.feedTitle ?: ""
|
||||
}
|
||||
else -> {
|
||||
getFeed(fs.singleFeed)?.title ?: ""
|
||||
dbHelper.getFeed(fs.singleFeed)?.title ?: ""
|
||||
}
|
||||
}
|
||||
val dialog = ReadingActionConfirmationFragment.newInstance(ra, title, optionalOverrideMessage, choicesRid, finishAfter)
|
||||
|
@ -339,17 +279,14 @@ object FeedUtils {
|
|||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun disableNotifications(context: Context, feed: Feed) {
|
||||
updateFeedNotifications(context, feed, enable = false, focusOnly = false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun enableUnreadNotifications(context: Context, feed: Feed) {
|
||||
updateFeedNotifications(context, feed, enable = true, focusOnly = false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun enableFocusNotifications(context: Context, feed: Feed) {
|
||||
updateFeedNotifications(context, feed, enable = true, focusOnly = true)
|
||||
}
|
||||
|
@ -363,19 +300,18 @@ object FeedUtils {
|
|||
feed.setNotifyUnread()
|
||||
}
|
||||
feed.enableAndroidNotifications(enable)
|
||||
dbHelper!!.updateFeed(feed)
|
||||
dbHelper.updateFeed(feed)
|
||||
val ra = ReadingAction.setNotify(feed.feedId, feed.notificationTypes, feed.notificationFilter)
|
||||
doAction(ra, context)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun doAction(ra: ReadingAction?, context: Context) {
|
||||
requireNotNull(ra) { "ReadingAction must not be null" }
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
val impact = ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, impact)
|
||||
triggerSync(context)
|
||||
|
@ -383,13 +319,11 @@ object FeedUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun updateClassifier(feedId: String?, classifier: Classifier?, fs: FeedSet?, context: Context) {
|
||||
val ra = ReadingAction.updateIntel(feedId, classifier, fs)
|
||||
doAction(ra, context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun sendStoryUrl(story: Story?, context: Context) {
|
||||
if (story == null) return
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
|
@ -400,7 +334,6 @@ object FeedUtils {
|
|||
context.startActivity(Intent.createChooser(intent, "Send using"))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun sendStoryFull(story: Story?, context: Context) {
|
||||
if (story == null) return
|
||||
var body = getStoryText(story.storyHash)
|
||||
|
@ -413,32 +346,29 @@ object FeedUtils {
|
|||
context.startActivity(Intent.createChooser(intent, "Send using"))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shareStory(story: Story, comment: String?, sourceUserIdString: String?, context: Context) {
|
||||
var sourceUserId = sourceUserIdString
|
||||
if (story.sourceUserId != null) {
|
||||
sourceUserId = story.sourceUserId
|
||||
}
|
||||
val ra = ReadingAction.shareStory(story.storyHash, story.id, story.feedId, sourceUserId, comment)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL or UPDATE_STORY)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun renameFeed(context: Context, feedId: String?, newFeedName: String?) {
|
||||
val ra = ReadingAction.renameFeed(feedId, newFeedName)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
val impact = ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, impact)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun unshareStory(story: Story, context: Context) {
|
||||
val ra = ReadingAction.unshareStory(story.storyHash, story.id, story.feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL or UPDATE_STORY)
|
||||
triggerSync(context)
|
||||
|
@ -446,7 +376,7 @@ object FeedUtils {
|
|||
|
||||
fun likeComment(story: Story, commentUserId: String?, context: Context) {
|
||||
val ra = ReadingAction.likeComment(story.id, commentUserId, story.feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
|
@ -454,45 +384,40 @@ object FeedUtils {
|
|||
|
||||
fun unlikeComment(story: Story, commentUserId: String?, context: Context) {
|
||||
val ra = ReadingAction.unlikeComment(story.id, commentUserId, story.feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun replyToComment(storyId: String?, feedId: String?, commentUserId: String?, replyText: String?, context: Context) {
|
||||
val ra = ReadingAction.replyToComment(storyId, feedId, commentUserId, replyText)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun updateReply(context: Context, story: Story, commentUserId: String?, replyId: String?, replyText: String?) {
|
||||
val ra = ReadingAction.updateReply(story.id, story.feedId, commentUserId, replyId, replyText)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteReply(context: Context, story: Story, commentUserId: String?, replyId: String?) {
|
||||
val ra = ReadingAction.deleteReply(story.id, story.feedId, commentUserId, replyId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_SOCIAL)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun moveFeedToFolders(context: Context, feedId: String?, toFolders: Set<String?>, inFolders: Set<String?>?) {
|
||||
if (toFolders.isEmpty()) return
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
val apiManager = APIManager(context)
|
||||
apiManager.moveFeedToFolders(feedId, toFolders, inFolders)
|
||||
},
|
||||
onPostExecute = {
|
||||
|
@ -502,12 +427,10 @@ object FeedUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun muteFeeds(context: Context, feedIds: Set<String>) {
|
||||
updateFeedActiveState(context, feedIds, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun unmuteFeeds(context: Context, feedIds: Set<String>) {
|
||||
updateFeedActiveState(context, feedIds, true)
|
||||
}
|
||||
|
@ -515,7 +438,7 @@ object FeedUtils {
|
|||
private fun updateFeedActiveState(context: Context, feedIds: Set<String>, active: Boolean) {
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
val activeFeeds = dbHelper!!.allActiveFeeds
|
||||
val activeFeeds = dbHelper.allActiveFeeds
|
||||
for (feedId in feedIds) {
|
||||
if (active) {
|
||||
activeFeeds.add(feedId)
|
||||
|
@ -530,7 +453,7 @@ object FeedUtils {
|
|||
ReadingAction.muteFeeds(activeFeeds, feedIds)
|
||||
}
|
||||
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
|
@ -539,73 +462,53 @@ object FeedUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun instaFetchFeed(context: Context, feedId: String?) {
|
||||
val ra = ReadingAction.instaFetch(feedId)
|
||||
dbHelper!!.enqueueAction(ra)
|
||||
dbHelper.enqueueAction(ra)
|
||||
ra.doLocal(dbHelper)
|
||||
syncUpdateStatus(context, UPDATE_METADATA)
|
||||
triggerSync(context)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun feedSetFromFolderName(folderName: String): FeedSet =
|
||||
FeedSet.folder(folderName, getFeedIdsRecursive(folderName))
|
||||
fun getStoryText(hash: String?): String? = dbHelper.getStoryText(hash)
|
||||
|
||||
private fun getFeedIdsRecursive(folderName: String): Set<String> {
|
||||
val folder = dbHelper!!.getFolder(folderName) ?: return emptySet()
|
||||
val feedIds: MutableSet<String> = HashSet(folder.feedIds.size)
|
||||
for (id in folder.feedIds) feedIds.add(id)
|
||||
for (child in folder.children) feedIds.addAll(getFeedIdsRecursive(child))
|
||||
return feedIds
|
||||
}
|
||||
|
||||
fun getStoryText(hash: String?): String? = dbHelper!!.getStoryText(hash)
|
||||
|
||||
fun getStoryContent(hash: String?): String? = dbHelper!!.getStoryContent(hash)
|
||||
|
||||
/**
|
||||
* Infer the feed ID for a story from the story's hash. Useful for APIs
|
||||
* that takes a feed ID and story ID and only the story hash is known.
|
||||
*
|
||||
* TODO: this has a smell to it. can't all APIs just accept story hashes?
|
||||
*/
|
||||
@JvmStatic
|
||||
fun inferFeedId(storyHash: String?): String? {
|
||||
val parts = TextUtils.split(storyHash, ":")
|
||||
return if (parts.size != 2) null else parts[0]
|
||||
}
|
||||
fun getStoryContent(hash: String?): String? = dbHelper.getStoryContent(hash)
|
||||
|
||||
/**
|
||||
* Because story objects have to join on the feeds table to get feed metadata, there are times
|
||||
* where standalone stories are missing this info and it must be re-fetched. This is costly
|
||||
* and should be avoided where possible.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getFeedTitle(feedId: String?): String? = getFeed(feedId)?.title
|
||||
fun getFeedTitle(feedId: String?): String? = dbHelper.getFeed(feedId)?.title
|
||||
|
||||
@JvmStatic
|
||||
fun getFeed(feedId: String?): Feed? = dbHelper!!.getFeed(feedId)
|
||||
fun getFeed(feedId: String?): Feed? = dbHelper.getFeed(feedId)
|
||||
|
||||
fun getSocialFeed(feedId: String?): SocialFeed? = dbHelper!!.getSocialFeed(feedId)
|
||||
|
||||
@JvmStatic
|
||||
fun getStarredFeedByTag(feedId: String?): StarredCount? = dbHelper!!.getStarredFeedByTag(feedId)
|
||||
|
||||
@JvmStatic
|
||||
fun openStatistics(context: Context?, feedId: String) {
|
||||
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)
|
||||
}
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun triggerSync(context: Context) {
|
||||
// NB: when our minSDKversion hits 28, it could be possible to start the service via the JobScheduler
|
||||
// with the setImportantWhileForeground() flag via an enqueue() and get rid of all legacy startService
|
||||
// code paths
|
||||
val i = Intent(context, NBSyncService::class.java)
|
||||
context.startService(i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer the feed ID for a story from the story's hash. Useful for APIs
|
||||
* that takes a feed ID and story ID and only the story hash is known.
|
||||
*
|
||||
* TODO: this has a smell to it. can't all APIs just accept story hashes?
|
||||
*/
|
||||
@JvmStatic
|
||||
fun inferFeedId(storyHash: String?): String? {
|
||||
val parts = TextUtils.split(storyHash, ":")
|
||||
return if (parts.size != 2) null else parts[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ import android.widget.RemoteViews;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.network.APIConstants;
|
||||
|
||||
import dagger.hilt.android.internal.managers.FragmentComponentManager;
|
||||
|
||||
public class ImageLoader {
|
||||
|
||||
private final MemoryCache memoryCache;
|
||||
|
@ -194,7 +196,8 @@ public class ImageLoader {
|
|||
|
||||
private void setViewImage(Bitmap bitmap, PhotoToLoad photoToLoad) {
|
||||
BitmapDisplayer bitmapDisplayer = new BitmapDisplayer(bitmap, photoToLoad);
|
||||
Activity a = (Activity) photoToLoad.imageView.getContext();
|
||||
FragmentComponentManager.findActivity(photoToLoad.imageView.getContext());
|
||||
Activity a = (Activity) FragmentComponentManager.findActivity(photoToLoad.imageView.getContext());
|
||||
a.runOnUiThread(bitmapDisplayer);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.newsblur.util;
|
|||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -53,6 +54,7 @@ public class NetworkUtils {
|
|||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.d("NetworkUtils.loadURL", t.getMessage());
|
||||
// a huge number of things could go wrong fetching and storing an image. don't spam logs with them
|
||||
}
|
||||
return bytesRead;
|
||||
|
@ -67,4 +69,16 @@ public class NetworkUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String getCustomUserAgent(String appVersion) {
|
||||
return "NewsBlur Android app (" +
|
||||
Build.MANUFACTURER +
|
||||
" " +
|
||||
Build.MODEL +
|
||||
" " +
|
||||
Build.VERSION.RELEASE +
|
||||
" " +
|
||||
appVersion +
|
||||
")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.core.app.NotificationManagerCompat;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.activity.FeedReading;
|
||||
import com.newsblur.activity.Reading;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.domain.Story;
|
||||
|
||||
|
@ -30,8 +31,7 @@ public class NotificationUtils {
|
|||
* @param storiesFocus a cursor of unread, focus stories to notify, ordered newest to oldest
|
||||
* @param storiesUnread a cursor of unread, neutral stories to notify, ordered newest to oldest
|
||||
*/
|
||||
public static synchronized void notifyStories(Cursor storiesFocus, Cursor storiesUnread, Context context, FileCache iconCache) {
|
||||
FeedUtils.offerInitContext(context);
|
||||
public static synchronized void notifyStories(Context context, Cursor storiesFocus, Cursor storiesUnread, FileCache iconCache, BlurDatabaseHelper dbHelper) {
|
||||
NotificationManagerCompat nm = NotificationManagerCompat.from(context);
|
||||
|
||||
int count = 0;
|
||||
|
@ -41,12 +41,12 @@ public class NotificationUtils {
|
|||
nm.cancel(story.hashCode());
|
||||
continue;
|
||||
}
|
||||
if (FeedUtils.dbHelper.isStoryDismissed(story.storyHash)) {
|
||||
if (dbHelper.isStoryDismissed(story.storyHash)) {
|
||||
nm.cancel(story.hashCode());
|
||||
continue;
|
||||
}
|
||||
if (StoryUtils.hasOldTimestamp(story.timestamp)) {
|
||||
FeedUtils.dbHelper.putStoryDismissed(story.storyHash);
|
||||
dbHelper.putStoryDismissed(story.storyHash);
|
||||
nm.cancel(story.hashCode());
|
||||
continue;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class NotificationUtils {
|
|||
nm.notify(story.hashCode(), n);
|
||||
} else {
|
||||
nm.cancel(story.hashCode());
|
||||
FeedUtils.dbHelper.putStoryDismissed(story.storyHash);
|
||||
dbHelper.putStoryDismissed(story.storyHash);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
@ -65,12 +65,12 @@ public class NotificationUtils {
|
|||
nm.cancel(story.hashCode());
|
||||
continue;
|
||||
}
|
||||
if (FeedUtils.dbHelper.isStoryDismissed(story.storyHash)) {
|
||||
if (dbHelper.isStoryDismissed(story.storyHash)) {
|
||||
nm.cancel(story.hashCode());
|
||||
continue;
|
||||
}
|
||||
if (StoryUtils.hasOldTimestamp(story.timestamp)) {
|
||||
FeedUtils.dbHelper.putStoryDismissed(story.storyHash);
|
||||
dbHelper.putStoryDismissed(story.storyHash);
|
||||
nm.cancel(story.hashCode());
|
||||
continue;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class NotificationUtils {
|
|||
nm.notify(story.hashCode(), n);
|
||||
} else {
|
||||
nm.cancel(story.hashCode());
|
||||
FeedUtils.dbHelper.putStoryDismissed(story.storyHash);
|
||||
dbHelper.putStoryDismissed(story.storyHash);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
|
|
@ -4,15 +4,21 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.newsblur.activity.Reading
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class NotifyDismissReceiver : BroadcastReceiver() {
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
override fun onReceive(c: Context, i: Intent) {
|
||||
val storyHash = i.getStringExtra(Reading.EXTRA_STORY_HASH)
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.offerInitContext(c)
|
||||
FeedUtils.dbHelper!!.putStoryDismissed(storyHash)
|
||||
dbHelper.putStoryDismissed(storyHash)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,17 +4,26 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.newsblur.activity.Reading
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class NotifyMarkreadReceiver : BroadcastReceiver() {
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
@Inject
|
||||
lateinit var feedUtils: FeedUtils
|
||||
|
||||
override fun onReceive(c: Context, i: Intent) {
|
||||
val storyHash = i.getStringExtra(Reading.EXTRA_STORY_HASH)
|
||||
NotificationUtils.cancel(c, storyHash.hashCode())
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.offerInitContext(c)
|
||||
FeedUtils.dbHelper!!.putStoryDismissed(storyHash)
|
||||
FeedUtils.setStoryReadStateExternal(storyHash, c, true)
|
||||
dbHelper.putStoryDismissed(storyHash)
|
||||
feedUtils.setStoryReadStateExternal(storyHash, c, true)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,17 +4,26 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.newsblur.activity.Reading
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class NotifySaveReceiver : BroadcastReceiver() {
|
||||
|
||||
@Inject
|
||||
lateinit var dbHelper: BlurDatabaseHelper
|
||||
|
||||
@Inject
|
||||
lateinit var feedUtils: FeedUtils
|
||||
|
||||
override fun onReceive(c: Context, i: Intent) {
|
||||
val storyHash = i.getStringExtra(Reading.EXTRA_STORY_HASH)
|
||||
NotificationUtils.cancel(c, storyHash.hashCode())
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.offerInitContext(c)
|
||||
FeedUtils.dbHelper!!.putStoryDismissed(storyHash)
|
||||
FeedUtils.setStorySaved(storyHash, true, c)
|
||||
dbHelper.putStoryDismissed(storyHash)
|
||||
feedUtils.setStorySaved(storyHash, true, c)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.util.Log;
|
|||
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.activity.Login;
|
||||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
import com.newsblur.network.APIConstants;
|
||||
import com.newsblur.service.SubscriptionSyncService;
|
||||
|
@ -87,10 +88,10 @@ public class PrefsUtils {
|
|||
|
||||
}
|
||||
|
||||
public static void updateVersion(Context context) {
|
||||
public static void updateVersion(Context context, String appVersion) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
|
||||
// store the current version
|
||||
prefs.edit().putString(AppConstants.LAST_APP_VERSION, getVersion(context)).commit();
|
||||
prefs.edit().putString(AppConstants.LAST_APP_VERSION, appVersion).commit();
|
||||
// also make sure we auto-trigger an update, since all data are now gone
|
||||
prefs.edit().putLong(AppConstants.LAST_SYNC_TIME, 0L).commit();
|
||||
}
|
||||
|
@ -104,18 +105,18 @@ public class PrefsUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String createFeedbackLink(Context context) {
|
||||
public static String createFeedbackLink(Context context, BlurDatabaseHelper dbHelper) {
|
||||
StringBuilder s = new StringBuilder(AppConstants.FEEDBACK_URL);
|
||||
s.append("<give us some feedback!>%0A%0A%0A");
|
||||
String info = getDebugInfo(context);
|
||||
String info = getDebugInfo(context, dbHelper);
|
||||
s.append(info.replace("\n", "%0A"));
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public static void sendLogEmail(Context context) {
|
||||
public static void sendLogEmail(Context context, BlurDatabaseHelper dbHelper) {
|
||||
File f = com.newsblur.util.Log.getLogfile();
|
||||
if (f == null) return;
|
||||
String debugInfo = "Tell us a bit about your problem:\n\n\n\n" + getDebugInfo(context);
|
||||
String debugInfo = "Tell us a bit about your problem:\n\n\n\n" + getDebugInfo(context, dbHelper);
|
||||
android.net.Uri localPath = FileProvider.getUriForFile(context, "com.newsblur.fileprovider", f);
|
||||
Intent i = new Intent(Intent.ACTION_SEND);
|
||||
i.setType("*/*");
|
||||
|
@ -128,7 +129,7 @@ public class PrefsUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private static String getDebugInfo(Context context) {
|
||||
private static String getDebugInfo(Context context, BlurDatabaseHelper dbHelper) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("app version: ").append(getVersion(context));
|
||||
s.append("\n");
|
||||
|
@ -136,7 +137,7 @@ public class PrefsUtils {
|
|||
s.append("\n");
|
||||
s.append("device: ").append(Build.MANUFACTURER).append(" ").append(Build.MODEL).append(" (").append(Build.BOARD).append(")");
|
||||
s.append("\n");
|
||||
s.append("sqlite version: ").append(FeedUtils.dbHelper.getEngineVersion());
|
||||
s.append("sqlite version: ").append(dbHelper.getEngineVersion());
|
||||
s.append("\n");
|
||||
s.append("username: ").append(getUserDetails(context).username);
|
||||
s.append("\n");
|
||||
|
@ -166,7 +167,7 @@ public class PrefsUtils {
|
|||
return s.toString();
|
||||
}
|
||||
|
||||
public static void logout(Context context) {
|
||||
public static void logout(Context context, BlurDatabaseHelper dbHelper) {
|
||||
NBSyncService.softInterrupt();
|
||||
NBSyncService.clearState();
|
||||
|
||||
|
@ -179,7 +180,7 @@ public class PrefsUtils {
|
|||
context.getSharedPreferences(PrefConstants.PREFERENCES, 0).edit().clear().commit();
|
||||
|
||||
// wipe the local DB
|
||||
FeedUtils.dropAndRecreateTables();
|
||||
dbHelper.dropAndRecreateTables();
|
||||
|
||||
// disable widget
|
||||
WidgetUtils.disableWidgetUpdate(context);
|
||||
|
@ -193,7 +194,7 @@ public class PrefsUtils {
|
|||
context.startActivity(i);
|
||||
}
|
||||
|
||||
public static void clearPrefsAndDbForLoginAs(Context context) {
|
||||
public static void clearPrefsAndDbForLoginAs(Context context, BlurDatabaseHelper dbHelper) {
|
||||
NBSyncService.softInterrupt();
|
||||
NBSyncService.clearState();
|
||||
|
||||
|
@ -211,7 +212,7 @@ public class PrefsUtils {
|
|||
editor.commit();
|
||||
|
||||
// wipe the local DB
|
||||
FeedUtils.dropAndRecreateTables();
|
||||
dbHelper.dropAndRecreateTables();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,7 +31,6 @@ import android.text.TextUtils;
|
|||
import android.view.ContextMenu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
@ -45,10 +44,12 @@ import androidx.core.content.ContextCompat;
|
|||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.newsblur.NbApplication;
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.activity.*;
|
||||
import com.newsblur.domain.Classifier;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.service.NBSyncReceiver;
|
||||
|
||||
public class UIUtils {
|
||||
|
||||
|
@ -178,9 +179,9 @@ public class UIUtils {
|
|||
* Set up our customised ActionBar view that features the specified icon and title, sized
|
||||
* away from system standard to meet the NewsBlur visual style.
|
||||
*/
|
||||
public static void setupToolbar(AppCompatActivity activity, String imageUrl, String title, boolean showHomeEnabled) {
|
||||
public static void setupToolbar(AppCompatActivity activity, String imageUrl, String title, ImageLoader iconLoader, boolean showHomeEnabled) {
|
||||
ImageView iconView = setupCustomToolbar(activity, title, showHomeEnabled);
|
||||
FeedUtils.iconLoader.displayImage(imageUrl, iconView);
|
||||
iconLoader.displayImage(imageUrl, iconView);
|
||||
}
|
||||
|
||||
public static void setupToolbar(AppCompatActivity activity, int imageId, String title, boolean showHomeEnabled) {
|
||||
|
@ -590,4 +591,12 @@ public class UIUtils {
|
|||
return CustomTabsIntent.COLOR_SCHEME_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
public static void syncUpdateStatus(Context context, int updateType) {
|
||||
if (NbApplication.isAppForeground()) {
|
||||
Intent intent = new Intent(NBSyncReceiver.NB_SYNC_ACTION);
|
||||
intent.putExtra(NBSyncReceiver.NB_SYNC_UPDATE_TYPE, updateType);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ public class ViewUtils {
|
|||
|
||||
private ViewUtils() {} // util class - no instances
|
||||
|
||||
public static ImageView createSharebarImage(final Context context, final String photoUrl, final String userId) {
|
||||
public static ImageView createSharebarImage(final Context context, final String photoUrl, final String userId, ImageLoader iconLoader) {
|
||||
RoundedImageView image = new RoundedImageView(context);
|
||||
int imageLength = UIUtils.dp2px(context, 15);
|
||||
image.setMaxHeight(imageLength);
|
||||
|
@ -30,7 +30,7 @@ public class ViewUtils {
|
|||
image.setMaxWidth(imageLength);
|
||||
|
||||
image.setLayoutParams(imageParameters);
|
||||
FeedUtils.iconLoader.displayImage(photoUrl, image);
|
||||
iconLoader.displayImage(photoUrl, image);
|
||||
image.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.text.TextUtils;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.domain.ActivityDetails;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
|
||||
/**
|
||||
* Created by mark on 17/06/15.
|
||||
|
@ -17,8 +18,8 @@ public class ActivitiesAdapter extends ActivityDetailsAdapter {
|
|||
|
||||
private final String startedFollowing, repliedTo, favorited, subscribedTo, saved, signup, commentsOn, sharedStory, you;
|
||||
|
||||
public ActivitiesAdapter(final Context context, UserDetails user) {
|
||||
super(context, user);
|
||||
public ActivitiesAdapter(final Context context, UserDetails user, ImageLoader iconLoader) {
|
||||
super(context, user, iconLoader);
|
||||
|
||||
Resources resources = context.getResources();
|
||||
startedFollowing = resources.getString(R.string.profile_started_following);
|
||||
|
|
|
@ -15,20 +15,22 @@ import com.newsblur.domain.ActivityDetails;
|
|||
import com.newsblur.domain.ActivityDetails.Category;
|
||||
import com.newsblur.network.APIConstants;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
import com.newsblur.util.UIUtils;
|
||||
|
||||
public abstract class ActivityDetailsAdapter extends ArrayAdapter<ActivityDetails> {
|
||||
|
||||
private LayoutInflater inflater;
|
||||
private final ImageLoader iconLoader;
|
||||
private final LayoutInflater inflater;
|
||||
protected final String ago;
|
||||
protected ForegroundColorSpan linkColor, contentColor, quoteColor;
|
||||
protected UserDetails currentUserDetails;
|
||||
protected final UserDetails currentUserDetails;
|
||||
protected final boolean userIsYou;
|
||||
|
||||
public ActivityDetailsAdapter(final Context context, UserDetails user) {
|
||||
public ActivityDetailsAdapter(final Context context, UserDetails user, ImageLoader iconLoader) {
|
||||
super(context, R.layout.row_activity); // final argument seems unused since we override getView()
|
||||
inflater = LayoutInflater.from(context);
|
||||
|
||||
this.iconLoader = iconLoader;
|
||||
currentUserDetails = user;
|
||||
|
||||
Resources resources = context.getResources();
|
||||
|
@ -57,13 +59,13 @@ public abstract class ActivityDetailsAdapter extends ArrayAdapter<ActivityDetail
|
|||
|
||||
activityTime.setText(activity.timeSince.toUpperCase() + " " + ago);
|
||||
if (activity.category == Category.FEED_SUBSCRIPTION) {
|
||||
FeedUtils.iconLoader.displayImage(APIConstants.S3_URL_FEED_ICONS + activity.feedId + ".png", imageView);
|
||||
iconLoader.displayImage(APIConstants.S3_URL_FEED_ICONS + activity.feedId + ".png", imageView);
|
||||
} else if (activity.category == Category.SHARED_STORY) {
|
||||
FeedUtils.iconLoader.displayImage(currentUserDetails.photoUrl, imageView);
|
||||
iconLoader.displayImage(currentUserDetails.photoUrl, imageView);
|
||||
} else if (activity.category == Category.STAR) {
|
||||
imageView.setImageResource(R.drawable.ic_clock);
|
||||
} else if (activity.user != null) {
|
||||
FeedUtils.iconLoader.displayImage(activity.user.photoUrl, imageView);
|
||||
iconLoader.displayImage(activity.user.photoUrl, imageView);
|
||||
} else {
|
||||
imageView.setImageResource(R.drawable.logo);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import com.newsblur.util.UIUtils;
|
|||
* children as special case that should all be squares of the same size, for forming
|
||||
* icon grids. Many iterations ago inspired by the code referenced below.
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/549451/line-breaking-widget-layout-for-android
|
||||
* @see https://stackoverflow.com/questions/549451/line-breaking-widget-layout-for-android
|
||||
*/
|
||||
public class FlowLayout extends ViewGroup {
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.text.TextUtils;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.domain.ActivityDetails;
|
||||
import com.newsblur.domain.UserDetails;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
|
||||
/**
|
||||
* Created by mark on 17/06/15.
|
||||
|
@ -17,8 +18,8 @@ public class InteractionsAdapter extends ActivityDetailsAdapter {
|
|||
|
||||
private final String nowFollowingYou, repliedToYour, comment, reply, favoritedComments, reshared, your, you;
|
||||
|
||||
public InteractionsAdapter(final Context context, UserDetails user) {
|
||||
super(context, user);
|
||||
public InteractionsAdapter(final Context context, UserDetails user, ImageLoader iconLoader) {
|
||||
super(context, user, iconLoader);
|
||||
|
||||
Resources resources = context.getResources();
|
||||
nowFollowingYou = resources.getString(R.string.profile_now_following);
|
||||
|
|
|
@ -6,11 +6,15 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class AllFoldersViewModel : ViewModel() {
|
||||
@HiltViewModel
|
||||
class AllFoldersViewModel
|
||||
@Inject constructor(private val dbHelper: BlurDatabaseHelper): ViewModel() {
|
||||
|
||||
private val cancellationSignal = CancellationSignal()
|
||||
|
||||
|
@ -37,27 +41,27 @@ class AllFoldersViewModel : ViewModel() {
|
|||
fun getData() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
launch {
|
||||
FeedUtils.dbHelper!!.getSocialFeedsCursor(cancellationSignal).let {
|
||||
dbHelper.getSocialFeedsCursor(cancellationSignal).let {
|
||||
_socialFeeds.postValue(it)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
FeedUtils.dbHelper!!.getFoldersCursor(cancellationSignal).let {
|
||||
dbHelper.getFoldersCursor(cancellationSignal).let {
|
||||
_folders.postValue(it)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
FeedUtils.dbHelper!!.getFeedsCursor(cancellationSignal).let {
|
||||
dbHelper.getFeedsCursor(cancellationSignal).let {
|
||||
_feeds.postValue(it)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
FeedUtils.dbHelper!!.getSavedStoryCountsCursor(cancellationSignal).let {
|
||||
dbHelper.getSavedStoryCountsCursor(cancellationSignal).let {
|
||||
_savedStoryCounts.postValue(it)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
FeedUtils.dbHelper!!.getSavedSearchCursor(cancellationSignal).let {
|
||||
dbHelper.getSavedSearchCursor(cancellationSignal).let {
|
||||
_savedSearch.postValue(it)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,15 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class FeedFolderViewModel : ViewModel() {
|
||||
@HiltViewModel
|
||||
class FeedFolderViewModel
|
||||
@Inject constructor(private val dbHelper: BlurDatabaseHelper) : ViewModel() {
|
||||
|
||||
private val cancellationSignal = CancellationSignal()
|
||||
|
||||
|
@ -22,12 +26,12 @@ class FeedFolderViewModel : ViewModel() {
|
|||
fun getData() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
launch {
|
||||
FeedUtils.dbHelper!!.getFoldersCursor(cancellationSignal).let {
|
||||
dbHelper.getFoldersCursor(cancellationSignal).let {
|
||||
_folders.postValue(it)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
FeedUtils.dbHelper!!.getFeedsCursor(cancellationSignal).let {
|
||||
dbHelper.getFeedsCursor(cancellationSignal).let {
|
||||
_feeds.postValue(it)
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +40,7 @@ class FeedFolderViewModel : ViewModel() {
|
|||
|
||||
fun getFeeds() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
FeedUtils.dbHelper!!.getFeedsCursor(cancellationSignal).let {
|
||||
dbHelper.getFeedsCursor(cancellationSignal).let {
|
||||
_feeds.postValue(it)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,16 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.util.FeedSet
|
||||
import com.newsblur.util.FeedUtils
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class StoriesViewModel : ViewModel() {
|
||||
@HiltViewModel
|
||||
class StoriesViewModel
|
||||
@Inject constructor(private val dbHelper: BlurDatabaseHelper): ViewModel() {
|
||||
|
||||
private val cancellationSignal = CancellationSignal()
|
||||
private val _activeStoriesLiveData = MutableLiveData<Cursor>()
|
||||
|
@ -19,7 +23,7 @@ class StoriesViewModel : ViewModel() {
|
|||
|
||||
fun getActiveStories(fs: FeedSet) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
FeedUtils.dbHelper!!.getActiveStoriesCursor(fs, cancellationSignal).let {
|
||||
dbHelper.getActiveStoriesCursor(fs, cancellationSignal).let {
|
||||
_activeStoriesLiveData.postValue(it)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,15 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.newsblur.util.FeedUtils
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class StoryUserTagsViewModel : ViewModel() {
|
||||
@HiltViewModel
|
||||
class StoryUserTagsViewModel
|
||||
@Inject constructor(private val dbHelper: BlurDatabaseHelper): ViewModel() {
|
||||
|
||||
private val cancellationSignal = CancellationSignal()
|
||||
private val _savedStoryCountsLiveData = MutableLiveData<Cursor>()
|
||||
|
@ -18,7 +22,7 @@ class StoryUserTagsViewModel : ViewModel() {
|
|||
|
||||
fun getSavedStoryCounts() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val cursor = FeedUtils.dbHelper!!.getSavedStoryCountsCursor(cancellationSignal)
|
||||
val cursor = dbHelper.getSavedStoryCountsCursor(cancellationSignal)
|
||||
_savedStoryCountsLiveData.postValue(cursor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,27 +11,42 @@ import android.view.View
|
|||
import android.widget.RemoteViews
|
||||
import android.widget.RemoteViewsService.RemoteViewsFactory
|
||||
import com.newsblur.R
|
||||
import com.newsblur.database.BlurDatabaseHelper
|
||||
import com.newsblur.di.IconLoader
|
||||
import com.newsblur.di.ThumbnailLoader
|
||||
import com.newsblur.domain.Feed
|
||||
import com.newsblur.domain.Story
|
||||
import com.newsblur.network.APIManager
|
||||
import com.newsblur.util.*
|
||||
import com.newsblur.util.FeedUtils.offerInitContext
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import java.util.*
|
||||
import kotlin.math.min
|
||||
|
||||
class WidgetRemoteViewsFactory internal constructor(context: Context, intent: Intent) : RemoteViewsFactory {
|
||||
class WidgetRemoteViewsFactory(context: Context, intent: Intent) : RemoteViewsFactory {
|
||||
|
||||
private val context: Context
|
||||
private val apiManager: APIManager
|
||||
private val dbHelper: BlurDatabaseHelper
|
||||
private val iconLoader: ImageLoader
|
||||
private val thumbnailLoader: ImageLoader
|
||||
private var fs: FeedSet? = null
|
||||
private val appWidgetId: Int
|
||||
private var dataCompleted = false
|
||||
private val storyItems: MutableList<Story> = ArrayList()
|
||||
private val cancellationSignal = CancellationSignal()
|
||||
private var apiManager: APIManager? = null
|
||||
|
||||
init {
|
||||
Log.d(TAG, "Constructor")
|
||||
val hiltEntryPoint = EntryPointAccessors
|
||||
.fromApplication(context.applicationContext, WidgetRemoteViewsFactoryEntryPoint::class.java)
|
||||
this.context = context
|
||||
this.apiManager = hiltEntryPoint.apiManager()
|
||||
this.dbHelper = hiltEntryPoint.dbHelper()
|
||||
this.iconLoader = hiltEntryPoint.iconLoader()
|
||||
this.thumbnailLoader = hiltEntryPoint.thumbnailLoader()
|
||||
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||
}
|
||||
|
@ -47,19 +62,6 @@ class WidgetRemoteViewsFactory internal constructor(context: Context, intent: In
|
|||
*/
|
||||
override fun onCreate() {
|
||||
Log.d(TAG, "onCreate")
|
||||
apiManager = APIManager(context)
|
||||
// widget could be created before app init
|
||||
// wait for the dbHelper to be ready for use
|
||||
while (FeedUtils.dbHelper == null) {
|
||||
try {
|
||||
Thread.sleep(500)
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (FeedUtils.dbHelper == null) {
|
||||
offerInitContext(context)
|
||||
}
|
||||
}
|
||||
WidgetUtils.enableWidgetUpdate(context)
|
||||
}
|
||||
|
||||
|
@ -78,9 +80,9 @@ class WidgetRemoteViewsFactory internal constructor(context: Context, intent: In
|
|||
rv.setTextViewText(R.id.story_item_date, time)
|
||||
|
||||
// image dimensions same as R.layout.view_widget_story_item
|
||||
FeedUtils.iconLoader!!.displayWidgetImage(story.extern_faviconUrl, R.id.story_item_feedicon, UIUtils.dp2px(context, 19), rv)
|
||||
iconLoader.displayWidgetImage(story.extern_faviconUrl, R.id.story_item_feedicon, UIUtils.dp2px(context, 19), rv)
|
||||
if (PrefsUtils.getThumbnailStyle(context) != ThumbnailStyle.OFF && !TextUtils.isEmpty(story.thumbnailUrl)) {
|
||||
FeedUtils.thumbnailLoader!!.displayWidgetImage(story.thumbnailUrl, R.id.story_item_thumbnail, UIUtils.dp2px(context, 64), rv)
|
||||
thumbnailLoader.displayWidgetImage(story.thumbnailUrl, R.id.story_item_thumbnail, UIUtils.dp2px(context, 64), rv)
|
||||
} else {
|
||||
rv.setViewVisibility(R.id.story_item_thumbnail, View.GONE)
|
||||
}
|
||||
|
@ -141,13 +143,13 @@ class WidgetRemoteViewsFactory internal constructor(context: Context, intent: In
|
|||
return
|
||||
}
|
||||
Log.d(TAG, "onDataSetChanged - fetch stories")
|
||||
val response = apiManager!!.getStories(fs, 1, StoryOrder.NEWEST, ReadFilter.ALL)
|
||||
val response = apiManager.getStories(fs, 1, StoryOrder.NEWEST, ReadFilter.ALL)
|
||||
if (response?.stories == null) {
|
||||
Log.d(TAG, "Error fetching widget stories")
|
||||
} else {
|
||||
Log.d(TAG, "Fetched widget stories")
|
||||
processStories(response.stories)
|
||||
FeedUtils.dbHelper!!.insertStories(response, true)
|
||||
dbHelper.insertStories(response, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +175,7 @@ class WidgetRemoteViewsFactory internal constructor(context: Context, intent: In
|
|||
val feedMap = HashMap<String, Feed>()
|
||||
NBScope.executeAsyncTask(
|
||||
doInBackground = {
|
||||
FeedUtils.dbHelper!!.getFeedsCursor(cancellationSignal)
|
||||
dbHelper.getFeedsCursor(cancellationSignal)
|
||||
},
|
||||
onPostExecute = {
|
||||
while (it != null && it.moveToNext()) {
|
||||
|
@ -228,4 +230,19 @@ class WidgetRemoteViewsFactory internal constructor(context: Context, intent: In
|
|||
companion object {
|
||||
private const val TAG = "WidgetRemoteViewsFactory"
|
||||
}
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface WidgetRemoteViewsFactoryEntryPoint {
|
||||
|
||||
fun apiManager(): APIManager
|
||||
|
||||
fun dbHelper(): BlurDatabaseHelper
|
||||
|
||||
@IconLoader
|
||||
fun iconLoader(): ImageLoader
|
||||
|
||||
@ThumbnailLoader
|
||||
fun thumbnailLoader(): ImageLoader
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue