Merge branch 'develop' into do-not-allocate-arrays

This commit is contained in:
H. Lehmann 2020-01-09 17:06:11 +01:00 committed by GitHub
commit 34f19ed967
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 165 additions and 84 deletions

View File

@ -16,12 +16,11 @@ jobs:
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew assemblePlayDebugAndroidTest run: ./gradlew assemblePlayDebugAndroidTest
- name: Android Emulator test - name: Android Emulator test
uses: ReactiveCircus/android-emulator-runner@v1.0.1 uses: ReactiveCircus/android-emulator-runner@v2.2.0
with: with:
api-level: 28 api-level: 28
headless: true
disable-animations: true disable-animations: true
script: ./gradlew connectedPlayDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.notAnnotation=de.test.antennapod.IgnoreOnCi script: zsh .github/workflows/runTests.sh
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
if: failure() if: failure()
with: with:

6
.github/workflows/runTests.sh vendored Normal file
View File

@ -0,0 +1,6 @@
runTests() {
./gradlew connectedPlayDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.notAnnotation=de.test.antennapod.IgnoreOnCi
}
# Retry tests to make them less flaky
runTests || runTests || runTests

View File

@ -5,8 +5,8 @@ TomHennen
orionlee orionlee
domingos86 domingos86
andersonvom andersonvom
patheticpat
spacecowboy spacecowboy
patheticpat
brad brad
Cj-Malone Cj-Malone
gaul gaul
@ -122,14 +122,14 @@ Asturian (ast_ES): enolp
Azerbaijani: danieloeh, kotfenix Azerbaijani: danieloeh, kotfenix
Basque: gaztainalde, pospolos, zakurranputza Basque: gaztainalde, pospolos, zakurranputza
Bulgarian: solusitor Bulgarian: solusitor
Catalan: dvd1985, exort12, javiercoll, lambdani, marcmetallextrem, xc70 Catalan: dvd1985, exort12, javiercoll, Kintu, lambdani, marcmetallextrem, xc70
Chinese (zh_CN): bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, JayYoung, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru Chinese (zh_CN): bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, JayYoung, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
Chinese (zh_TW): gugod, nigelinux, pggdt, Solomon, ymhuang0808 Chinese (zh_TW): gugod, nigelinux, pggdt, Solomon, ymhuang0808
Czech (cs_CZ): anotheranonymoususer, elich, Hanzmeister, mcepl, petnek, svetlemodry Czech (cs_CZ): anotheranonymoususer, elich, Hanzmeister, mcepl, petnek, svetlemodry
Danish: CasperHN, jhertel Danish: CasperHN, jhertel
Dutch: e2jk, glotzbach, rwv, Vistaus Dutch: e2jk, glotzbach, rwv, Vistaus
English: mfietz, sterylmreep English: mfietz, sterylmreep
Estonian: Eraser Estonian: ByteHamster, Eraser, mahfiaz
Finnish: danieloeh, elguitar, Sahtor Finnish: danieloeh, elguitar, Sahtor
French: cactux, ChaoticMind, clombion, e2jk, edewaele, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow French: cactux, ChaoticMind, clombion, e2jk, edewaele, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
Galician: antiparvos, pikamoku, Raichely Galician: antiparvos, pikamoku, Raichely

View File

@ -18,8 +18,8 @@ android {
// "1.2.3-SNAPSHOT" -> 1020300 // "1.2.3-SNAPSHOT" -> 1020300
// "1.2.3-RC4" -> 1020304 // "1.2.3-RC4" -> 1020304
// "1.2.3" -> 1020395 // "1.2.3" -> 1020395
versionCode 1080005 versionCode 1080008
versionName "1.8.0-RC5" versionName "1.8.0-RC8"
testApplicationId "de.test.antennapod" testApplicationId "de.test.antennapod"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
generatedDensities = [] generatedDensities = []

View File

@ -236,7 +236,6 @@
android:value="de.danoeh.antennapod.activity.MainActivity"/> android:value="de.danoeh.antennapod.activity.MainActivity"/>
<!-- URLs ending with '.xml' or '.rss' --> <!-- URLs ending with '.xml' or '.rss' -->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
@ -252,7 +251,6 @@
</intent-filter> </intent-filter>
<!-- Feedburner URLs --> <!-- Feedburner URLs -->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
@ -268,7 +266,6 @@
</intent-filter> </intent-filter>
<!-- Files with mimeType rss/xml/atom --> <!-- Files with mimeType rss/xml/atom -->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
@ -284,7 +281,6 @@
</intent-filter> </intent-filter>
<!-- Podcast protocols --> <!-- Podcast protocols -->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
@ -297,6 +293,21 @@
<data android:scheme="antennapod-subscribe"/> <data android:scheme="antennapod-subscribe"/>
</intent-filter> </intent-filter>
<!-- Support for subscribeonandroid.com URLS -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:pathPattern=".*\\..*/.*" />
<data android:host="subscribeonandroid.com" />
<data android:host="www.subscribeonandroid.com" />
<data android:host="*subscribeonandroid.com" />
<data android:scheme="http" />
<data android:scheme="https" />
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND"/>

View File

@ -5,8 +5,8 @@ TomHennen;5216560;Maintainer (retired)
orionlee;250644;Contributor orionlee;250644;Contributor
domingos86;9538859;Contributor domingos86;9538859;Contributor
andersonvom;69922;Contributor andersonvom;69922;Contributor
patheticpat;16046;Contributor
spacecowboy;223655;Contributor spacecowboy;223655;Contributor
patheticpat;16046;Contributor
brad;1614;Contributor brad;1614;Contributor
Cj-Malone;10121513;Contributor Cj-Malone;10121513;Contributor
gaul;848247;Contributor gaul;848247;Contributor

1 danieloeh 968613 Original creator of AntennaPod (retired)
5 orionlee 250644 Contributor
6 domingos86 9538859 Contributor
7 andersonvom 69922 Contributor
patheticpat 16046 Contributor
8 spacecowboy 223655 Contributor
9 patheticpat 16046 Contributor
10 brad 1614 Contributor
11 Cj-Malone 10121513 Contributor
12 gaul 848247 Contributor

View File

@ -3,14 +3,14 @@ Asturian (ast_ES);enolp
Azerbaijani;danieloeh, kotfenix Azerbaijani;danieloeh, kotfenix
Basque;gaztainalde, pospolos, zakurranputza Basque;gaztainalde, pospolos, zakurranputza
Bulgarian;solusitor Bulgarian;solusitor
Catalan;dvd1985, exort12, javiercoll, lambdani, marcmetallextrem, xc70 Catalan;dvd1985, exort12, javiercoll, Kintu, lambdani, marcmetallextrem, xc70
Chinese (zh_CN);bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, JayYoung, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru Chinese (zh_CN);bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, JayYoung, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
Chinese (zh_TW);gugod, nigelinux, pggdt, Solomon, ymhuang0808 Chinese (zh_TW);gugod, nigelinux, pggdt, Solomon, ymhuang0808
Czech (cs_CZ);anotheranonymoususer, elich, Hanzmeister, mcepl, petnek, svetlemodry Czech (cs_CZ);anotheranonymoususer, elich, Hanzmeister, mcepl, petnek, svetlemodry
Danish;CasperHN, jhertel Danish;CasperHN, jhertel
Dutch;e2jk, glotzbach, rwv, Vistaus Dutch;e2jk, glotzbach, rwv, Vistaus
English;mfietz, sterylmreep English;mfietz, sterylmreep
Estonian;Eraser Estonian;ByteHamster, Eraser, mahfiaz
Finnish;danieloeh, elguitar, Sahtor Finnish;danieloeh, elguitar, Sahtor
French;cactux, ChaoticMind, clombion, e2jk, edewaele, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow French;cactux, ChaoticMind, clombion, e2jk, edewaele, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
Galician;antiparvos, pikamoku, Raichely Galician;antiparvos, pikamoku, Raichely

1 Arabic abdelrahman.fahem93, abdunnasir, abuzar3.khalid, desha, iDemo, mohamedagamy, msahouli, nabilMaghura
3 Azerbaijani danieloeh, kotfenix
4 Basque gaztainalde, pospolos, zakurranputza
5 Bulgarian solusitor
6 Catalan dvd1985, exort12, javiercoll, lambdani, marcmetallextrem, xc70 dvd1985, exort12, javiercoll, Kintu, lambdani, marcmetallextrem, xc70
7 Chinese (zh_CN) bebeauties38, cyril3, domingos86, dudeG, ErlichLiu, Felix2yu, gaohongyuan, Guaidaodl, Huck0, iconteral, JayYoung, jhxie, kavdx, kyleehee, linxiangyu, molisiye, owen8877, RainSlide, Sak94664, spice2wolf, stellaxuyi, tupunco, wi24rd, wongsyrone, xukeek, yangyang, yiqiok, YogaGuru
8 Chinese (zh_TW) gugod, nigelinux, pggdt, Solomon, ymhuang0808
9 Czech (cs_CZ) anotheranonymoususer, elich, Hanzmeister, mcepl, petnek, svetlemodry
10 Danish CasperHN, jhertel
11 Dutch e2jk, glotzbach, rwv, Vistaus
12 English mfietz, sterylmreep
13 Estonian Eraser ByteHamster, Eraser, mahfiaz
14 Finnish danieloeh, elguitar, Sahtor
15 French cactux, ChaoticMind, clombion, e2jk, edewaele, lacouture, LouFex, Matth78, mfietz, Poussinou, repat, Sioul, sterylmreep, TacoTheDank, Tilwa, vcariven, whenrow
16 Galician antiparvos, pikamoku, Raichely

View File

@ -134,6 +134,10 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
} else { } else {
Log.d(TAG, "Activity was started with url " + feedUrl); Log.d(TAG, "Activity was started with url " + feedUrl);
setLoadingLayout(); setLoadingLayout();
// Remove subscribeonandroid.com from feed URL in order to subscribe to the actual feed URL
if (feedUrl.contains("subscribeonandroid.com")) {
feedUrl = feedUrl.replaceFirst("((www.)?(subscribeonandroid.com/))", "");
}
if (savedInstanceState == null) { if (savedInstanceState == null) {
startFeedDownload(feedUrl, null, null); startFeedDownload(feedUrl, null, null);
} else { } else {

View File

@ -245,8 +245,9 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
public void onClick(View v) { public void onClick(View v) {
MainActivity mainActivity = mainActivityRef.get(); MainActivity mainActivity = mainActivityRef.get();
if (mainActivity != null) { if (mainActivity != null) {
long[] ids = itemAccess.getItemsIds().toArray(); LongList itemIds = itemAccess.getItemsIds();
mainActivity.loadChildFragment(ItemPagerFragment.newInstance(ids, getAdapterPosition())); long[] ids = itemIds.toArray();
mainActivity.loadChildFragment(ItemPagerFragment.newInstance(ids, itemIds.indexOf(item.getId())));
} }
} }

View File

@ -51,7 +51,7 @@ public class EpisodesApplyActionFragment extends Fragment {
public static final int ACTION_REMOVE_FROM_QUEUE = 2; public static final int ACTION_REMOVE_FROM_QUEUE = 2;
private static final int ACTION_MARK_PLAYED = 4; private static final int ACTION_MARK_PLAYED = 4;
private static final int ACTION_MARK_UNPLAYED = 8; private static final int ACTION_MARK_UNPLAYED = 8;
private static final int ACTION_DOWNLOAD = 16; public static final int ACTION_DOWNLOAD = 16;
public static final int ACTION_DELETE = 32; public static final int ACTION_DELETE = 32;
private static final int ACTION_ALL = ACTION_ADD_TO_QUEUE | ACTION_REMOVE_FROM_QUEUE private static final int ACTION_ALL = ACTION_ADD_TO_QUEUE | ACTION_REMOVE_FROM_QUEUE
| ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED | ACTION_DOWNLOAD | ACTION_DELETE; | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED | ACTION_DOWNLOAD | ACTION_DELETE;
@ -480,7 +480,7 @@ public class EpisodesApplyActionFragment extends Fragment {
// download the check episodes in the same order as they are currently displayed // download the check episodes in the same order as they are currently displayed
List<FeedItem> toDownload = new ArrayList<>(checkedIds.size()); List<FeedItem> toDownload = new ArrayList<>(checkedIds.size());
for(FeedItem episode : episodes) { for(FeedItem episode : episodes) {
if(checkedIds.contains(episode.getId())) { if(checkedIds.contains(episode.getId()) && episode.hasMedia()) {
toDownload.add(episode); toDownload.add(episode);
} }
} }
@ -490,7 +490,7 @@ public class EpisodesApplyActionFragment extends Fragment {
e.printStackTrace(); e.printStackTrace();
DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
} }
close(R.plurals.downloading_batch_label, checkedIds.size()); close(R.plurals.downloading_batch_label, toDownload.size());
} }
private void deleteChecked() { private void deleteChecked() {

View File

@ -1,5 +1,7 @@
package de.danoeh.antennapod.fragment; package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
@ -20,6 +22,8 @@ import de.danoeh.antennapod.dialog.FilterDialog;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -32,12 +36,13 @@ public class AllEpisodesFragment extends EpisodesListFragment {
public static final String TAG = "AllEpisodesFragment"; public static final String TAG = "AllEpisodesFragment";
private static final String PREF_NAME = "PrefAllEpisodesFragment"; private static final String PREF_NAME = "PrefAllEpisodesFragment";
private static final String PREF_FILTER = "filter";
private static final int EPISODES_PER_PAGE = 150; private static final int EPISODES_PER_PAGE = 150;
private static final int VISIBLE_EPISODES_SCROLL_THRESHOLD = 5; private static final int VISIBLE_EPISODES_SCROLL_THRESHOLD = 5;
private static int page = 1; private static int page = 1;
private static FeedItemFilter feedItemFilter = new FeedItemFilter(""); private FeedItemFilter feedItemFilter = new FeedItemFilter("");
@Override @Override
protected boolean showOnlyNewEpisodes() { protected boolean showOnlyNewEpisodes() {
@ -69,6 +74,9 @@ public class AllEpisodesFragment extends EpisodesListFragment {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = super.onCreateView(inflater, container, savedInstanceState); View root = super.onCreateView(inflater, container, savedInstanceState);
SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
feedItemFilter = new FeedItemFilter(prefs.getString(PREF_FILTER, ""));
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
/* Total number of episodes after last load */ /* Total number of episodes after last load */
@ -147,6 +155,8 @@ public class AllEpisodesFragment extends EpisodesListFragment {
@Override @Override
protected void updateFilter(Set<String> filterValues) { protected void updateFilter(Set<String> filterValues) {
feedItemFilter = new FeedItemFilter(filterValues.toArray(new String[0])); feedItemFilter = new FeedItemFilter(filterValues.toArray(new String[0]));
SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
prefs.edit().putString(PREF_FILTER, StringUtils.join(filterValues, ",")).apply();
loadItems(); loadItems();
} }
}; };

View File

@ -50,9 +50,6 @@ public class ItemPagerFragment extends Fragment {
* @return The ItemFragment instance * @return The ItemFragment instance
*/ */
public static ItemPagerFragment newInstance(long[] feeditems, int feedItemPos) { public static ItemPagerFragment newInstance(long[] feeditems, int feedItemPos) {
if (feeditems.length <= feedItemPos) {
throw new IllegalArgumentException("Trying to show a feed item that is out of the list");
}
ItemPagerFragment fragment = new ItemPagerFragment(); ItemPagerFragment fragment = new ItemPagerFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLongArray(ARG_FEEDITEMS, feeditems); args.putLongArray(ARG_FEEDITEMS, feeditems);
@ -62,7 +59,6 @@ public class ItemPagerFragment extends Fragment {
} }
private long[] feedItems; private long[] feedItems;
private int feedItemPos;
private FeedItem item; private FeedItem item;
private Disposable disposable; private Disposable disposable;
@ -70,9 +66,6 @@ public class ItemPagerFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true); setHasOptionsMenu(true);
feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
} }
@Override @Override
@ -81,6 +74,9 @@ public class ItemPagerFragment extends Fragment {
super.onCreateView(inflater, container, savedInstanceState); super.onCreateView(inflater, container, savedInstanceState);
View layout = inflater.inflate(R.layout.feeditem_pager_fragment, container, false); View layout = inflater.inflate(R.layout.feeditem_pager_fragment, container, false);
feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
int feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
ViewPager pager = layout.findViewById(R.id.pager); ViewPager pager = layout.findViewById(R.id.pager);
// FragmentStatePagerAdapter documentation: // FragmentStatePagerAdapter documentation:
// > When using FragmentStatePagerAdapter the host ViewPager must have a valid ID set. // > When using FragmentStatePagerAdapter the host ViewPager must have a valid ID set.

View File

@ -69,6 +69,7 @@ import io.reactivex.schedulers.Schedulers;
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE; import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REMOVE_FROM_QUEUE; import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REMOVE_FROM_QUEUE;
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DOWNLOAD;
/** /**
* Shows all items in the queue * Shows all items in the queue
@ -349,7 +350,7 @@ public class QueueFragment extends Fragment {
return true; return true;
case R.id.episode_actions: case R.id.episode_actions:
((MainActivity) requireActivity()).loadChildFragment( ((MainActivity) requireActivity()).loadChildFragment(
EpisodesApplyActionFragment.newInstance(queue, ACTION_DELETE | ACTION_REMOVE_FROM_QUEUE)); EpisodesApplyActionFragment.newInstance(queue, ACTION_DELETE | ACTION_REMOVE_FROM_QUEUE | ACTION_DOWNLOAD));
return true; return true;
case R.id.queue_sort_episode_title_asc: case R.id.queue_sort_episode_title_asc:
setSortOrder(SortOrder.EPISODE_TITLE_A_Z); setSortOrder(SortOrder.EPISODE_TITLE_A_Z);

View File

@ -2,21 +2,22 @@ package de.danoeh.antennapod.fragment;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.ListFragment;
import androidx.core.view.MenuItemCompat;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView; import android.widget.ListView;
import android.widget.ProgressBar;
import java.util.ArrayList; import androidx.annotation.NonNull;
import java.util.List; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.core.view.MenuItemCompat;
import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SearchlistAdapter; import de.danoeh.antennapod.adapter.SearchlistAdapter;
@ -26,17 +27,20 @@ import de.danoeh.antennapod.core.feed.FeedComponent;
import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.SearchResult; import de.danoeh.antennapod.core.feed.SearchResult;
import de.danoeh.antennapod.core.storage.FeedSearcher; import de.danoeh.antennapod.core.storage.FeedSearcher;
import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.List;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
/** /**
* Performs a search operation on all feeds or one specific feed and displays the search result. * Performs a search operation on all feeds or one specific feed and displays the search result.
*/ */
public class SearchFragment extends ListFragment { public class SearchFragment extends Fragment implements AdapterView.OnItemClickListener {
private static final String TAG = "SearchFragment"; private static final String TAG = "SearchFragment";
private static final String ARG_QUERY = "query"; private static final String ARG_QUERY = "query";
@ -45,6 +49,9 @@ public class SearchFragment extends ListFragment {
private SearchlistAdapter searchAdapter; private SearchlistAdapter searchAdapter;
private List<SearchResult> searchResults = new ArrayList<>(); private List<SearchResult> searchResults = new ArrayList<>();
private Disposable disposable; private Disposable disposable;
private ListView listView;
private ProgressBar progressBar;
private EmptyViewHandler emptyViewHandler;
/** /**
* Create a new SearchFragment that searches all feeds. * Create a new SearchFragment that searches all feeds.
@ -84,26 +91,30 @@ public class SearchFragment extends ListFragment {
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
if(disposable != null) { if (disposable != null) {
disposable.dispose(); disposable.dispose();
} }
} }
@Nullable
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
super.onViewCreated(view, savedInstanceState); @Nullable Bundle savedInstanceState) {
// add padding
final ListView lv = getListView();
lv.setClipToPadding(false);
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label); ((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label);
View layout = inflater.inflate(R.layout.search_fragment, container, false);
listView = layout.findViewById(R.id.listview);
progressBar = layout.findViewById(R.id.progressBar);
searchAdapter = new SearchlistAdapter(getActivity(), itemAccess); searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
setListAdapter(searchAdapter); listView.setAdapter(searchAdapter);
listView.setOnItemClickListener(this);
emptyViewHandler = new EmptyViewHandler(getContext());
emptyViewHandler.attachToListView(listView);
emptyViewHandler.setIcon(R.attr.action_search);
emptyViewHandler.setTitle(R.string.search_status_no_results);
EventBus.getDefault().register(this); EventBus.getDefault().register(this);
return layout;
} }
@Override @Override
@ -113,9 +124,8 @@ public class SearchFragment extends ListFragment {
} }
@Override @Override
public void onListItemClick(ListView l, View v, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
super.onListItemClick(l, v, position, id); SearchResult result = (SearchResult) listView.getAdapter().getItem(position);
SearchResult result = (SearchResult) l.getAdapter().getItem(position);
FeedComponent comp = result.getComponent(); FeedComponent comp = result.getComponent();
if (comp.getClass() == Feed.class) { if (comp.getClass() == Feed.class) {
((MainActivity) getActivity()).loadFeedFragmentById(comp.getId(), null); ((MainActivity) getActivity()).loadFeedFragmentById(comp.getId(), null);
@ -128,7 +138,7 @@ public class SearchFragment extends ListFragment {
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label); MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
@ -158,10 +168,11 @@ public class SearchFragment extends ListFragment {
} }
private void onSearchResults(List<SearchResult> results) { private void onSearchResults(List<SearchResult> results) {
progressBar.setVisibility(View.GONE);
searchResults = results; searchResults = results;
searchAdapter.notifyDataSetChanged(); searchAdapter.notifyDataSetChanged();
String query = getArguments().getString(ARG_QUERY); String query = getArguments().getString(ARG_QUERY);
setEmptyText(getString(R.string.no_results_for_query, query)); emptyViewHandler.setMessage(getString(R.string.no_results_for_query, query));
} }
private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() { private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() {
@ -181,9 +192,11 @@ public class SearchFragment extends ListFragment {
}; };
private void search() { private void search() {
if(disposable != null) { if (disposable != null) {
disposable.dispose(); disposable.dispose();
} }
progressBar.setVisibility(View.VISIBLE);
emptyViewHandler.hide();
disposable = Observable.fromCallable(this::performSearch) disposable = Observable.fromCallable(this::performSearch)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View File

@ -2,29 +2,28 @@ package de.danoeh.antennapod.fragment.preferences;
import android.app.Activity; import android.app.Activity;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.collection.ArrayMap; import androidx.collection.ArrayMap;
import androidx.preference.ListPreference; import androidx.preference.ListPreference;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceFragmentCompat;
import java.util.Map;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MediaplayerActivity; import de.danoeh.antennapod.activity.MediaplayerActivity;
import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil; import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.dialog.VariableSpeedDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog;
import de.danoeh.antennapod.preferences.PreferenceControllerFlavorHelper; import de.danoeh.antennapod.preferences.PreferenceControllerFlavorHelper;
import java.util.Map;
import org.greenrobot.eventbus.EventBus;
public class PlaybackPreferencesFragment extends PreferenceFragmentCompat { public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher"; private static final String PREF_PLAYBACK_SPEED_LAUNCHER = "prefPlaybackSpeedLauncher";
private static final String PREF_PLAYBACK_REWIND_DELTA_LAUNCHER = "prefPlaybackRewindDeltaLauncher"; private static final String PREF_PLAYBACK_REWIND_DELTA_LAUNCHER = "prefPlaybackRewindDeltaLauncher";
private static final String PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER = "prefPlaybackFastForwardDeltaLauncher"; private static final String PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER = "prefPlaybackFastForwardDeltaLauncher";
private static final String PREF_PLAYBACK_PREFER_STREAMING = "prefStreamOverDownload";
@Override @Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@ -44,26 +43,28 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
private void setupPlaybackScreen() { private void setupPlaybackScreen() {
final Activity activity = getActivity(); final Activity activity = getActivity();
findPreference(PREF_PLAYBACK_SPEED_LAUNCHER) findPreference(PREF_PLAYBACK_SPEED_LAUNCHER).setOnPreferenceClickListener(preference -> {
.setOnPreferenceClickListener(preference -> { VariableSpeedDialog.showDialog(activity);
VariableSpeedDialog.showDialog(activity); return true;
return true; });
}); findPreference(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER).setOnPreferenceClickListener(preference -> {
findPreference(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER) MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_REWIND);
.setOnPreferenceClickListener(preference -> { return true;
MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_REWIND); });
return true; findPreference(PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER).setOnPreferenceClickListener(preference -> {
}); MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_FORWARD);
findPreference(PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER) return true;
.setOnPreferenceClickListener(preference -> { });
MediaplayerActivity.showSkipPreference(activity, MediaplayerActivity.SkipDirection.SKIP_FORWARD);
return true;
});
if (!PictureInPictureUtil.supportsPictureInPicture(activity)) { if (!PictureInPictureUtil.supportsPictureInPicture(activity)) {
ListPreference behaviour = (ListPreference) findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR); ListPreference behaviour = findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR);
behaviour.setEntries(R.array.video_background_behavior_options_without_pip); behaviour.setEntries(R.array.video_background_behavior_options_without_pip);
behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip); behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip);
} }
findPreference(PREF_PLAYBACK_PREFER_STREAMING).setOnPreferenceChangeListener((preference, newValue) -> {
// Update all visible lists to reflect new streaming action button
EventBus.getDefault().post(new UnreadItemsUpdateEvent());
return true;
});
buildEnqueueLocationPreference(); buildEnqueueLocationPreference();
} }

View File

@ -45,6 +45,10 @@ public class EmptyViewHandler {
tvMessage.setText(message); tvMessage.setText(message);
} }
public void setMessage(String message) {
tvMessage.setText(message);
}
public void setIcon(@AttrRes int iconAttr) { public void setIcon(@AttrRes int iconAttr) {
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(iconAttr, typedValue, true); context.getTheme().resolveAttribute(iconAttr, typedValue, true);

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingLeft="@dimen/list_vertical_padding"
android:paddingRight="@dimen/list_vertical_padding" />
</FrameLayout>

View File

@ -167,7 +167,7 @@ public class DownloadService extends Service {
Notification notification = notificationManager.updateNotifications( Notification notification = notificationManager.updateNotifications(
requester.getNumberOfDownloads(), downloads); requester.getNumberOfDownloads(), downloads);
startForeground(NOTIFICATION_ID, notification); startForeground(NOTIFICATION_ID, notification);
onDownloadQueued(intent); syncExecutor.execute(() -> onDownloadQueued(intent));
} else if (numberOfDownloads.get() == 0) { } else if (numberOfDownloads.get() == 0) {
stopSelf(); stopSelf();
} else { } else {
@ -477,13 +477,13 @@ public class DownloadService extends Service {
&& isEnqueued(request, itemsEnqueued)) { && isEnqueued(request, itemsEnqueued)) {
request.setMediaEnqueued(true); request.setMediaEnqueued(true);
} }
downloads.add(downloader); handler.post(() -> {
downloadExecutor.submit(downloader); downloads.add(downloader);
downloadExecutor.submit(downloader);
postDownloaders(); postDownloaders();
});
} }
handler.post(this::queryDownloads);
queryDownloads();
} }
private static boolean isEnqueued(@NonNull DownloadRequest request, private static boolean isEnqueued(@NonNull DownloadRequest request,

View File

@ -3,6 +3,10 @@ package de.danoeh.antennapod.core;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.security.ProviderInstaller;
import de.danoeh.antennapod.core.cast.CastManager; import de.danoeh.antennapod.core.cast.CastManager;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences; import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
@ -57,10 +61,21 @@ public class ClientConfig {
} else { } else {
Log.v(TAG, "Cast is disabled. All Cast-related initialization will be skipped."); Log.v(TAG, "Cast is disabled. All Cast-related initialization will be skipped.");
} }
installSslProvider(context);
SleepTimerPreferences.init(context); SleepTimerPreferences.init(context);
RxJavaErrorHandlerSetup.setupRxJavaErrorHandler(); RxJavaErrorHandlerSetup.setupRxJavaErrorHandler();
NotificationUtils.createChannels(context); NotificationUtils.createChannels(context);
initialized = true; initialized = true;
} }
private static void installSslProvider(Context context) {
try {
ProviderInstaller.installIfNeeded(context);
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
GoogleApiAvailability.getInstance().showErrorNotification(context, e.getConnectionStatusCode());
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}
} }