Decouple preferences
This commit is contained in:
parent
20363ee41c
commit
069a2ca329
|
@ -10,6 +10,7 @@ import androidx.test.espresso.matcher.RootMatchers;
|
|||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithmFactory;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
@ -397,7 +398,7 @@ public class PreferencesTest {
|
|||
onView(withId(R.id.select_dialog_listview)).perform(swipeDown());
|
||||
onView(withText(R.string.episode_cleanup_except_favorite_removal)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> UserPreferences.getEpisodeCleanupAlgorithm() instanceof ExceptFavoriteCleanupAlgorithm);
|
||||
.until(() -> EpisodeCleanupAlgorithmFactory.build() instanceof ExceptFavoriteCleanupAlgorithm);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -408,7 +409,7 @@ public class PreferencesTest {
|
|||
onView(withId(R.id.select_dialog_listview)).perform(swipeDown());
|
||||
onView(withText(R.string.episode_cleanup_queue_removal)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> UserPreferences.getEpisodeCleanupAlgorithm() instanceof APQueueCleanupAlgorithm);
|
||||
.until(() -> EpisodeCleanupAlgorithmFactory.build() instanceof APQueueCleanupAlgorithm);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -419,7 +420,7 @@ public class PreferencesTest {
|
|||
onView(withId(R.id.select_dialog_listview)).perform(swipeUp());
|
||||
onView(withText(R.string.episode_cleanup_never)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> UserPreferences.getEpisodeCleanupAlgorithm() instanceof APNullCleanupAlgorithm);
|
||||
.until(() -> EpisodeCleanupAlgorithmFactory.build() instanceof APNullCleanupAlgorithm);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -431,7 +432,7 @@ public class PreferencesTest {
|
|||
onView(withText(R.string.episode_cleanup_after_listening)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> {
|
||||
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
|
||||
EpisodeCleanupAlgorithm alg = EpisodeCleanupAlgorithmFactory.build();
|
||||
if (alg instanceof APCleanupAlgorithm) {
|
||||
APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm) alg;
|
||||
return cleanupAlg.getNumberOfHoursAfterPlayback() == 0;
|
||||
|
@ -450,7 +451,7 @@ public class PreferencesTest {
|
|||
onView(withText(search)).perform(click());
|
||||
Awaitility.await().atMost(1000, MILLISECONDS)
|
||||
.until(() -> {
|
||||
EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm();
|
||||
EpisodeCleanupAlgorithm alg = EpisodeCleanupAlgorithmFactory.build();
|
||||
if (alg instanceof APCleanupAlgorithm) {
|
||||
APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm) alg;
|
||||
return cleanupAlg.getNumberOfHoursAfterPlayback() == 72; // 5 days
|
||||
|
|
|
@ -231,6 +231,7 @@ public class MainActivity extends CastEnabledActivity {
|
|||
|
||||
// for backward compatibility, we only change defaults for fresh installs
|
||||
UserPreferences.setUpdateInterval(12);
|
||||
AutoUpdateManager.restartUpdateAlarm(this);
|
||||
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
edit.putBoolean(PREF_IS_FIRST_LAUNCH, false);
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.widget.ArrayAdapter;
|
|||
import androidx.appcompat.app.AlertDialog;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
import de.danoeh.antennapod.databinding.FeedRefreshDialogBinding;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
|
@ -70,6 +71,7 @@ public class FeedRefreshIntervalDialog {
|
|||
builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> {
|
||||
if (viewBinding.intervalRadioButton.isChecked()) {
|
||||
UserPreferences.setUpdateInterval(INTERVAL_VALUES_HOURS[viewBinding.spinner.getSelectedItemPosition()]);
|
||||
AutoUpdateManager.restartUpdateAlarm(context);
|
||||
} else if (viewBinding.timeRadioButton.isChecked()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
UserPreferences.setUpdateTimeOfDay(viewBinding.timePicker.getHour(),
|
||||
|
@ -78,8 +80,10 @@ public class FeedRefreshIntervalDialog {
|
|||
UserPreferences.setUpdateTimeOfDay(viewBinding.timePicker.getCurrentHour(),
|
||||
viewBinding.timePicker.getCurrentMinute());
|
||||
}
|
||||
AutoUpdateManager.restartUpdateAlarm(context);
|
||||
} else if (viewBinding.disableRadioButton.isChecked()) {
|
||||
UserPreferences.disableAutoUpdate(context);
|
||||
UserPreferences.disableAutoUpdate();
|
||||
AutoUpdateManager.disableAutoUpdate(context);
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected error.");
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.service.download.ProxyConfig;
|
||||
import de.danoeh.antennapod.model.download.ProxyConfig;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
|
|
@ -17,7 +17,7 @@ import java.util.Set;
|
|||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
|
||||
import de.danoeh.antennapod.core.feed.SubscriptionsFilter;
|
||||
import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
|
||||
import de.danoeh.antennapod.core.feed.SubscriptionsFilterGroup;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.ui.common.RecursiveRadioGroup;
|
||||
|
|
|
@ -14,7 +14,6 @@ import androidx.annotation.VisibleForTesting;
|
|||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import de.danoeh.antennapod.model.feed.FeedCounter;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
|
@ -32,16 +31,11 @@ import java.util.Set;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.model.feed.FeedCounter;
|
||||
import de.danoeh.antennapod.model.playback.MediaType;
|
||||
import de.danoeh.antennapod.core.feed.SubscriptionsFilter;
|
||||
import de.danoeh.antennapod.core.service.download.ProxyConfig;
|
||||
import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.ExceptFavoriteCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm;
|
||||
import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
|
||||
import de.danoeh.antennapod.model.download.ProxyConfig;
|
||||
import de.danoeh.antennapod.model.feed.SortOrder;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
|
||||
/**
|
||||
* Provides access to preferences set by the user in the settings screen. A
|
||||
|
@ -692,33 +686,22 @@ public class UserPreferences {
|
|||
.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the update interval value.
|
||||
*/
|
||||
public static void setUpdateInterval(long hours) {
|
||||
prefs.edit()
|
||||
.putString(PREF_UPDATE_INTERVAL, String.valueOf(hours))
|
||||
.apply();
|
||||
// when updating with an interval, we assume the user wants
|
||||
// to update *now* and then every 'hours' interval thereafter.
|
||||
AutoUpdateManager.restartUpdateAlarm(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the update interval value.
|
||||
*/
|
||||
public static void setUpdateTimeOfDay(int hourOfDay, int minute) {
|
||||
prefs.edit()
|
||||
.putString(PREF_UPDATE_INTERVAL, hourOfDay + ":" + minute)
|
||||
.apply();
|
||||
AutoUpdateManager.restartUpdateAlarm(context);
|
||||
}
|
||||
|
||||
public static void disableAutoUpdate(Context context) {
|
||||
public static void disableAutoUpdate() {
|
||||
prefs.edit()
|
||||
.putString(PREF_UPDATE_INTERVAL, "0")
|
||||
.apply();
|
||||
AutoUpdateManager.disableAutoUpdate(context);
|
||||
}
|
||||
|
||||
public static boolean gpodnetNotificationsEnabled() {
|
||||
|
@ -835,22 +818,6 @@ public class UserPreferences {
|
|||
.apply();
|
||||
}
|
||||
|
||||
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
|
||||
if (!isEnableAutodownload()) {
|
||||
return new APNullCleanupAlgorithm();
|
||||
}
|
||||
int cleanupValue = getEpisodeCleanupValue();
|
||||
if (cleanupValue == EPISODE_CLEANUP_EXCEPT_FAVORITE) {
|
||||
return new ExceptFavoriteCleanupAlgorithm();
|
||||
} else if (cleanupValue == EPISODE_CLEANUP_QUEUE) {
|
||||
return new APQueueCleanupAlgorithm();
|
||||
} else if (cleanupValue == EPISODE_CLEANUP_NULL) {
|
||||
return new APNullCleanupAlgorithm();
|
||||
} else {
|
||||
return new APCleanupAlgorithm(cleanupValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getEpisodeCleanupValue() {
|
||||
return Integer.parseInt(prefs.getString(PREF_EPISODE_CLEANUP, "" + EPISODE_CLEANUP_NULL));
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
|
|||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.BasicAuthorizationInterceptor;
|
||||
import de.danoeh.antennapod.core.service.UserAgentInterceptor;
|
||||
import de.danoeh.antennapod.model.download.ProxyConfig;
|
||||
import de.danoeh.antennapod.net.ssl.SslClientSetup;
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.Credentials;
|
||||
|
|
|
@ -20,6 +20,7 @@ import androidx.core.app.ServiceCompat;
|
|||
import androidx.core.content.ContextCompat;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
|
||||
import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithmFactory;
|
||||
import de.danoeh.antennapod.model.download.DownloadStatus;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
@ -455,7 +456,7 @@ public class DownloadService extends Service {
|
|||
Log.d(TAG, "Received enqueue request. #requests=" + requests.size());
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_CLEANUP_MEDIA, false)) {
|
||||
UserPreferences.getEpisodeCleanupAlgorithm().makeRoomForEpisodes(getApplicationContext(), requests.size());
|
||||
EpisodeCleanupAlgorithmFactory.build().makeRoomForEpisodes(getApplicationContext(), requests.size());
|
||||
}
|
||||
|
||||
for (DownloadRequest request : requests) {
|
||||
|
|
|
@ -20,15 +20,16 @@ import de.danoeh.antennapod.model.feed.Feed;
|
|||
import de.danoeh.antennapod.model.feed.FeedCounter;
|
||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.storage.database.LongIntMap;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
import de.danoeh.antennapod.storage.database.PodDBAdapter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class NewEpisodesNotification {
|
||||
private static final String TAG = "NewEpisodesNotification";
|
||||
private static final String GROUP_KEY = "de.danoeh.antennapod.EPISODES";
|
||||
|
||||
private LongIntMap countersBefore;
|
||||
private Map<Long, Integer> countersBefore;
|
||||
|
||||
public NewEpisodesNotification() {
|
||||
}
|
||||
|
@ -46,7 +47,7 @@ public class NewEpisodesNotification {
|
|||
return;
|
||||
}
|
||||
|
||||
int newEpisodesBefore = countersBefore.get(feed.getId());
|
||||
int newEpisodesBefore = countersBefore.containsKey(feed.getId()) ? countersBefore.get(feed.getId()) : 0;
|
||||
int newEpisodesAfter = getNewEpisodeCount(feed.getId());
|
||||
|
||||
Log.d(TAG, "New episodes before: " + newEpisodesBefore + ", after: " + newEpisodesAfter);
|
||||
|
@ -130,7 +131,8 @@ public class NewEpisodesNotification {
|
|||
private static int getNewEpisodeCount(long feedId) {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
int episodeCount = adapter.getFeedCounters(FeedCounter.SHOW_NEW, feedId).get(feedId);
|
||||
Map<Long, Integer> counters = adapter.getFeedCounters(FeedCounter.SHOW_NEW, feedId);
|
||||
int episodeCount = counters.containsKey(feedId) ? counters.get(feedId) : 0;
|
||||
adapter.close();
|
||||
return episodeCount;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public class AutomaticDownloadAlgorithm {
|
|||
|
||||
int autoDownloadableEpisodes = candidates.size();
|
||||
int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes();
|
||||
int deletedEpisodes = UserPreferences.getEpisodeCleanupAlgorithm()
|
||||
int deletedEpisodes = EpisodeCleanupAlgorithmFactory.build()
|
||||
.makeRoomForEpisodes(context, autoDownloadableEpisodes);
|
||||
boolean cacheIsUnlimited =
|
||||
UserPreferences.getEpisodeCacheSize() == UserPreferences.getEpisodeCacheSizeUnlimited();
|
||||
|
|
|
@ -21,7 +21,7 @@ import de.danoeh.antennapod.model.feed.FeedItem;
|
|||
import de.danoeh.antennapod.model.feed.FeedItemFilter;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.core.feed.SubscriptionsFilter;
|
||||
import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.model.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.storage.database.PodDBAdapter;
|
||||
|
@ -31,7 +31,6 @@ import de.danoeh.antennapod.storage.database.mapper.FeedCursorMapper;
|
|||
import de.danoeh.antennapod.storage.database.mapper.FeedItemCursorMapper;
|
||||
import de.danoeh.antennapod.storage.database.mapper.FeedMediaCursorMapper;
|
||||
import de.danoeh.antennapod.storage.database.mapper.FeedPreferencesCursorMapper;
|
||||
import de.danoeh.antennapod.storage.database.LongIntMap;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator;
|
||||
import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
|
||||
|
@ -881,7 +880,7 @@ public final class DBReader {
|
|||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
|
||||
final LongIntMap feedCounters = adapter.getFeedCounters(UserPreferences.getFeedCounterSetting());
|
||||
final Map<Long, Integer> feedCounters = adapter.getFeedCounters(UserPreferences.getFeedCounterSetting());
|
||||
SubscriptionsFilter subscriptionsFilter = UserPreferences.getSubscriptionsFilter();
|
||||
List<Feed> feeds = subscriptionsFilter.filter(getFeedList(adapter), feedCounters);
|
||||
|
||||
|
@ -889,8 +888,8 @@ public final class DBReader {
|
|||
int feedOrder = UserPreferences.getFeedOrder();
|
||||
if (feedOrder == UserPreferences.FEED_ORDER_COUNTER) {
|
||||
comparator = (lhs, rhs) -> {
|
||||
long counterLhs = feedCounters.get(lhs.getId());
|
||||
long counterRhs = feedCounters.get(rhs.getId());
|
||||
long counterLhs = feedCounters.containsKey(lhs.getId()) ? feedCounters.get(lhs.getId()) : 0;
|
||||
long counterRhs = feedCounters.containsKey(rhs.getId()) ? feedCounters.get(rhs.getId()) : 0;
|
||||
if (counterLhs > counterRhs) {
|
||||
// reverse natural order: podcast with most unplayed episodes first
|
||||
return -1;
|
||||
|
@ -913,11 +912,11 @@ public final class DBReader {
|
|||
}
|
||||
};
|
||||
} else if (feedOrder == UserPreferences.FEED_ORDER_MOST_PLAYED) {
|
||||
final LongIntMap playedCounters = adapter.getPlayedEpisodesCounters();
|
||||
final Map<Long, Integer> playedCounters = adapter.getPlayedEpisodesCounters();
|
||||
|
||||
comparator = (lhs, rhs) -> {
|
||||
long counterLhs = playedCounters.get(lhs.getId());
|
||||
long counterRhs = playedCounters.get(rhs.getId());
|
||||
long counterLhs = playedCounters.containsKey(lhs.getId()) ? playedCounters.get(lhs.getId()) : 0;
|
||||
long counterRhs = playedCounters.containsKey(rhs.getId()) ? playedCounters.get(rhs.getId()) : 0;
|
||||
if (counterLhs > counterRhs) {
|
||||
// podcast with most played episodes first
|
||||
return -1;
|
||||
|
@ -945,8 +944,8 @@ public final class DBReader {
|
|||
Map<String, NavDrawerData.TagDrawerItem> folders = new HashMap<>();
|
||||
for (Feed feed : feeds) {
|
||||
for (String tag : feed.getPreferences().getTags()) {
|
||||
NavDrawerData.FeedDrawerItem drawerItem = new NavDrawerData.FeedDrawerItem(feed, feed.getId(),
|
||||
feedCounters.get(feed.getId()));
|
||||
int counter = feedCounters.containsKey(feed.getId()) ? feedCounters.get(feed.getId()) : 0;
|
||||
NavDrawerData.FeedDrawerItem drawerItem = new NavDrawerData.FeedDrawerItem(feed, feed.getId(), counter);
|
||||
if (FeedPreferences.TAG_ROOT.equals(tag)) {
|
||||
items.add(drawerItem);
|
||||
continue;
|
||||
|
@ -967,7 +966,7 @@ public final class DBReader {
|
|||
items.addAll(foldersSorted);
|
||||
|
||||
NavDrawerData result = new NavDrawerData(items, queueSize, numNewItems, numDownloadedItems,
|
||||
feedCounters, UserPreferences.getEpisodeCleanupAlgorithm().getReclaimableItems());
|
||||
feedCounters, EpisodeCleanupAlgorithmFactory.build().getReclaimableItems());
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -228,7 +228,7 @@ public final class DBTasks {
|
|||
* @param context Used for accessing the DB.
|
||||
*/
|
||||
public static void performAutoCleanup(final Context context) {
|
||||
UserPreferences.getEpisodeCleanupAlgorithm().performCleanup(context);
|
||||
EpisodeCleanupAlgorithmFactory.build().performCleanup(context);
|
||||
}
|
||||
|
||||
private static Feed searchFeedByIdentifyingValueOrID(Feed feed) {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
|
||||
public abstract class EpisodeCleanupAlgorithmFactory {
|
||||
public static EpisodeCleanupAlgorithm build() {
|
||||
if (!UserPreferences.isEnableAutodownload()) {
|
||||
return new APNullCleanupAlgorithm();
|
||||
}
|
||||
int cleanupValue = UserPreferences.getEpisodeCleanupValue();
|
||||
switch (cleanupValue) {
|
||||
case UserPreferences.EPISODE_CLEANUP_EXCEPT_FAVORITE:
|
||||
return new ExceptFavoriteCleanupAlgorithm();
|
||||
case UserPreferences.EPISODE_CLEANUP_QUEUE:
|
||||
return new APQueueCleanupAlgorithm();
|
||||
case UserPreferences.EPISODE_CLEANUP_NULL:
|
||||
return new APNullCleanupAlgorithm();
|
||||
default:
|
||||
return new APCleanupAlgorithm(cleanupValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.storage.database.LongIntMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class NavDrawerData {
|
||||
public final List<DrawerItem> items;
|
||||
public final int queueSize;
|
||||
public final int numNewItems;
|
||||
public final int numDownloadedItems;
|
||||
public final LongIntMap feedCounters;
|
||||
public final Map<Long, Integer> feedCounters;
|
||||
public final int reclaimableSpace;
|
||||
|
||||
public NavDrawerData(List<DrawerItem> feeds,
|
||||
int queueSize,
|
||||
int numNewItems,
|
||||
int numDownloadedItems,
|
||||
LongIntMap feedIndicatorValues,
|
||||
Map<Long, Integer> feedIndicatorValues,
|
||||
int reclaimableSpace) {
|
||||
this.items = feeds;
|
||||
this.queueSize = queueSize;
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import de.danoeh.antennapod.storage.database.LongIntMap;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class LongLongMapTest {
|
||||
|
||||
@Test
|
||||
public void testEmptyMap() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
assertEquals(0, map.size());
|
||||
assertEquals("LongLongMap{}", map.toString());
|
||||
assertEquals(0, map.get(42));
|
||||
assertEquals(-1, map.get(42, -1));
|
||||
assertFalse(map.delete(42));
|
||||
assertEquals(-1, map.indexOfKey(42));
|
||||
assertEquals(-1, map.indexOfValue(42));
|
||||
assertEquals(1, map.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleElement() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
map.put(17, 42);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals("LongLongMap{17=42}", map.toString());
|
||||
assertEquals(42, map.get(17));
|
||||
assertEquals(42, map.get(17, -1));
|
||||
assertEquals(0, map.indexOfKey(17));
|
||||
assertEquals(0, map.indexOfValue(42));
|
||||
assertTrue(map.delete(17));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAndDelete() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
for(int i=0; i < 100; i++) {
|
||||
map.put(i * 17, i * 42);
|
||||
}
|
||||
assertEquals(100, map.size());
|
||||
assertEquals(0, map.get(0));
|
||||
assertEquals(42, map.get(17));
|
||||
assertEquals(42, map.get(17, -1));
|
||||
assertEquals(1, map.indexOfKey(17));
|
||||
assertEquals(1, map.indexOfValue(42));
|
||||
for(int i=0; i < 100; i++) {
|
||||
assertTrue(map.delete(i * 17));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverwrite() {
|
||||
LongIntMap map = new LongIntMap();
|
||||
map.put(17, 42);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals("LongLongMap{17=42}", map.toString());
|
||||
assertEquals(42, map.get(17));
|
||||
map.put(17, 23);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals("LongLongMap{17=23}", map.toString());
|
||||
assertEquals(23, map.get(17));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package de.danoeh.antennapod.core.service.download;
|
||||
package de.danoeh.antennapod.model.download;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
package de.danoeh.antennapod.core.feed;
|
||||
package de.danoeh.antennapod.model.feed;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.storage.database.LongIntMap;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||
import java.util.Map;
|
||||
|
||||
public class SubscriptionsFilter {
|
||||
private static final String divider = ",";
|
||||
|
@ -69,7 +66,7 @@ public class SubscriptionsFilter {
|
|||
/**
|
||||
* Run a list of feed items through the filter.
|
||||
*/
|
||||
public List<Feed> filter(List<Feed> items, LongIntMap feedCounters) {
|
||||
public List<Feed> filter(List<Feed> items, Map<Long, Integer> feedCounters) {
|
||||
if (properties.length == 0) {
|
||||
return items;
|
||||
}
|
||||
|
@ -104,7 +101,8 @@ public class SubscriptionsFilter {
|
|||
|
||||
if (showIfCounterGreaterZero) {
|
||||
for (int i = result.size() - 1; i >= 0; i--) {
|
||||
if (feedCounters.get(result.get(i).getId()) <= 0) {
|
||||
if (!feedCounters.containsKey(result.get(i).getId())
|
||||
|| feedCounters.get(result.get(i).getId()) <= 0) {
|
||||
result.remove(i);
|
||||
}
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
package de.danoeh.antennapod.storage.database;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Fast and memory efficient long to long map
|
||||
*/
|
||||
public class LongIntMap {
|
||||
|
||||
private long[] keys;
|
||||
private int[] values;
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Creates a new LongLongMap containing no mappings.
|
||||
*/
|
||||
public LongIntMap() {
|
||||
this(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SparseLongArray containing no mappings that will not
|
||||
* require any additional memory allocation to store the specified
|
||||
* number of mappings. If you supply an initial capacity of 0, the
|
||||
* sparse array will be initialized with a light-weight representation
|
||||
* not requiring any additional array allocations.
|
||||
*/
|
||||
public LongIntMap(int initialCapacity) {
|
||||
if(initialCapacity < 0) {
|
||||
throw new IllegalArgumentException("initial capacity must be 0 or higher");
|
||||
}
|
||||
keys = new long[initialCapacity];
|
||||
values = new int[initialCapacity];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases size of array if needed
|
||||
*/
|
||||
private void growIfNeeded() {
|
||||
if (size == keys.length) {
|
||||
// Resize.
|
||||
long[] newKeysArray = new long[size * 3 / 2 + 10];
|
||||
int[] newValuesArray = new int[size * 3 / 2 + 10];
|
||||
System.arraycopy(keys, 0, newKeysArray, 0, size);
|
||||
System.arraycopy(values, 0, newValuesArray, 0, size);
|
||||
keys = newKeysArray;
|
||||
values = newValuesArray;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the long mapped from the specified key, or <code>0</code>
|
||||
* if no such mapping has been made.
|
||||
*/
|
||||
public int get(long key) {
|
||||
return get(key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the long mapped from the specified key, or the specified value
|
||||
* if no such mapping has been made.
|
||||
*/
|
||||
public int get(long key, int valueIfKeyNotFound) {
|
||||
int index = indexOfKey(key);
|
||||
if(index >= 0) {
|
||||
return values[index];
|
||||
} else {
|
||||
return valueIfKeyNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping from the specified key, if there was any.
|
||||
*/
|
||||
public boolean delete(long key) {
|
||||
int index = indexOfKey(key);
|
||||
|
||||
if (index >= 0) {
|
||||
removeAt(index);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping at the given index.
|
||||
*/
|
||||
private void removeAt(int index) {
|
||||
System.arraycopy(keys, index + 1, keys, index, size - (index + 1));
|
||||
System.arraycopy(values, index + 1, values, index, size - (index + 1));
|
||||
size--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping from the specified key to the specified value,
|
||||
* replacing the previous mapping from the specified key if there
|
||||
* was one.
|
||||
*/
|
||||
public void put(long key, int value) {
|
||||
int index = indexOfKey(key);
|
||||
|
||||
if (index >= 0) {
|
||||
values[index] = value;
|
||||
} else {
|
||||
growIfNeeded();
|
||||
keys[size] = key;
|
||||
values[size] = value;
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of key-value mappings that this SparseIntArray
|
||||
* currently stores.
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an index in the range <code>0...size()-1</code>, returns
|
||||
* the key from the <code>index</code>th key-value mapping that this
|
||||
* SparseLongArray stores.
|
||||
*
|
||||
* <p>The keys corresponding to indices in ascending order are guaranteed to
|
||||
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
|
||||
* smallest key and <code>keyAt(size()-1)</code> will return the largest
|
||||
* key.</p>
|
||||
*/
|
||||
private long keyAt(int index) {
|
||||
if (index >= size) {
|
||||
throw new IndexOutOfBoundsException("n >= size()");
|
||||
} else if(index < 0) {
|
||||
throw new IndexOutOfBoundsException("n < 0");
|
||||
}
|
||||
return keys[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an index in the range <code>0...size()-1</code>, returns
|
||||
* the value from the <code>index</code>th key-value mapping that this
|
||||
* SparseLongArray stores.
|
||||
*
|
||||
* <p>The values corresponding to indices in ascending order are guaranteed
|
||||
* to be associated with keys in ascending order, e.g.,
|
||||
* <code>valueAt(0)</code> will return the value associated with the
|
||||
* smallest key and <code>valueAt(size()-1)</code> will return the value
|
||||
* associated with the largest key.</p>
|
||||
*/
|
||||
private int valueAt(int index) {
|
||||
if (index >= size) {
|
||||
throw new IndexOutOfBoundsException("n >= size()");
|
||||
} else if(index < 0) {
|
||||
throw new IndexOutOfBoundsException("n < 0");
|
||||
}
|
||||
return values[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for which {@link #keyAt} would return the
|
||||
* specified key, or a negative number if the specified
|
||||
* key is not mapped.
|
||||
*/
|
||||
public int indexOfKey(long key) {
|
||||
for(int i=0; i < size; i++) {
|
||||
if(keys[i] == key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an index for which {@link #valueAt} would return the
|
||||
* specified key, or a negative number if no keys map to the
|
||||
* specified value.
|
||||
* Beware that this is a linear search, unlike lookups by key,
|
||||
* and that multiple keys can map to the same value and this will
|
||||
* find only one of them.
|
||||
*/
|
||||
public int indexOfValue(long value) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (values[i] == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all key-value mappings from this SparseIntArray.
|
||||
*/
|
||||
public void clear() {
|
||||
keys = new long[10];
|
||||
values = new int[10];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the values contained in this map.
|
||||
*
|
||||
* @return a copy of the values contained in this map
|
||||
*/
|
||||
public int[] values() {
|
||||
return Arrays.copyOf(values, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (! (other instanceof LongIntMap)) {
|
||||
return false;
|
||||
}
|
||||
LongIntMap otherMap = (LongIntMap) other;
|
||||
if (size != otherMap.size) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (keys[i] != otherMap.keys[i] ||
|
||||
values[i] != otherMap.values[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 1;
|
||||
for (int i = 0; i < size; i++) {
|
||||
long value = values[i];
|
||||
hashCode = 31 * hashCode + (int)(value ^ (value >>> 32));
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (size() <= 0) {
|
||||
return "LongLongMap{}";
|
||||
}
|
||||
|
||||
StringBuilder buffer = new StringBuilder(size * 28);
|
||||
buffer.append("LongLongMap{");
|
||||
for (int i=0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
long key = keyAt(i);
|
||||
buffer.append(key);
|
||||
buffer.append('=');
|
||||
long value = valueAt(i);
|
||||
buffer.append(value);
|
||||
}
|
||||
buffer.append('}');
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -1175,7 +1175,7 @@ public class PodDBAdapter {
|
|||
return result;
|
||||
}
|
||||
|
||||
public final LongIntMap getFeedCounters(FeedCounter setting, long... feedIds) {
|
||||
public final Map<Long, Integer> getFeedCounters(FeedCounter setting, long... feedIds) {
|
||||
String whereRead;
|
||||
switch (setting) {
|
||||
case SHOW_NEW_UNPLAYED_SUM:
|
||||
|
@ -1194,12 +1194,12 @@ public class PodDBAdapter {
|
|||
case SHOW_NONE:
|
||||
// deliberate fall-through
|
||||
default: // NONE
|
||||
return new LongIntMap(0);
|
||||
return new HashMap<>();
|
||||
}
|
||||
return conditionalFeedCounterRead(whereRead, feedIds);
|
||||
}
|
||||
|
||||
private LongIntMap conditionalFeedCounterRead(String whereRead, long... feedIds) {
|
||||
private Map<Long, Integer> conditionalFeedCounterRead(String whereRead, long... feedIds) {
|
||||
String limitFeeds = "";
|
||||
if (feedIds.length > 0) {
|
||||
// work around TextUtils.join wanting only boxed items
|
||||
|
@ -1222,7 +1222,7 @@ public class PodDBAdapter {
|
|||
+ whereRead + " GROUP BY " + KEY_FEED;
|
||||
|
||||
Cursor c = db.rawQuery(query, null);
|
||||
LongIntMap result = new LongIntMap(c.getCount());
|
||||
Map<Long, Integer> result = new HashMap<>();
|
||||
if (c.moveToFirst()) {
|
||||
do {
|
||||
long feedId = c.getLong(0);
|
||||
|
@ -1234,7 +1234,7 @@ public class PodDBAdapter {
|
|||
return result;
|
||||
}
|
||||
|
||||
public final LongIntMap getPlayedEpisodesCounters(long... feedIds) {
|
||||
public final Map<Long, Integer> getPlayedEpisodesCounters(long... feedIds) {
|
||||
String whereRead = KEY_READ + "=" + FeedItem.PLAYED;
|
||||
return conditionalFeedCounterRead(whereRead, feedIds);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue