diff options
Diffstat (limited to 'app')
21 files changed, 232 insertions, 163 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java index 647ab911f..666cd845e 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java @@ -267,11 +267,11 @@ public class DBReaderTest { for (int i = 0; i < newItems.size(); i++) { unreadIds[i] = newItems.get(i).getId(); } - List<FeedItem> newItemsSaved = DBReader.getNewItemsList(); + List<FeedItem> newItemsSaved = DBReader.getNewItemsList(0, Integer.MAX_VALUE); assertNotNull(newItemsSaved); assertTrue(newItems.size() == newItemsSaved.size()); - for(int i=0; i < newItemsSaved.size(); i++) { - long savedId = newItemsSaved.get(i).getId(); + for (FeedItem feedItem : newItemsSaved) { + long savedId = feedItem.getId(); boolean found = false; for (long id : unreadIds) { if (id == savedId) { @@ -368,7 +368,6 @@ public class DBReaderTest { @Test public void testGetFeedItemlistCheckChaptersFalse() throws Exception { - Context context = InstrumentationRegistry.getTargetContext(); List<Feed> feeds = DBTestUtils.saveFeedlist(10, 10, false, false, 0); for (Feed feed : feeds) { for (FeedItem item : feed.getItems()) { diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java index a68afbc2e..7d3972378 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java @@ -164,7 +164,7 @@ public class PreferencesTest { @Test public void testHeadPhonesDisconnect() { - onView(withText(R.string.playback_pref)).perform(click()); + clickPreference(R.string.playback_pref); final boolean pauseOnHeadsetDisconnect = UserPreferences.isPauseOnHeadsetDisconnect(); onView(withText(R.string.pref_pauseOnHeadsetDisconnect_title)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) @@ -176,7 +176,7 @@ public class PreferencesTest { @Test public void testHeadPhonesReconnect() { - onView(withText(R.string.playback_pref)).perform(click()); + clickPreference(R.string.playback_pref); if (!UserPreferences.isPauseOnHeadsetDisconnect()) { onView(withText(R.string.pref_pauseOnHeadsetDisconnect_title)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) @@ -193,7 +193,7 @@ public class PreferencesTest { @Test public void testBluetoothReconnect() { - onView(withText(R.string.playback_pref)).perform(click()); + clickPreference(R.string.playback_pref); if (!UserPreferences.isPauseOnHeadsetDisconnect()) { onView(withText(R.string.pref_pauseOnHeadsetDisconnect_title)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) @@ -222,7 +222,7 @@ public class PreferencesTest { @Test public void testAutoDelete() { - onView(withText(R.string.storage_pref)).perform(click()); + clickPreference(R.string.storage_pref); final boolean autoDelete = UserPreferences.isAutoDelete(); onView(withText(R.string.pref_auto_delete_title)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) @@ -245,7 +245,7 @@ public class PreferencesTest { @Test public void testPauseForInterruptions() { - onView(withText(R.string.playback_pref)).perform(click()); + clickPreference(R.string.playback_pref); final boolean pauseForFocusLoss = UserPreferences.shouldPauseForFocusLoss(); clickPreference(R.string.pref_pausePlaybackForFocusLoss_title); Awaitility.await().atMost(1000, MILLISECONDS) @@ -257,7 +257,7 @@ public class PreferencesTest { @Test public void testDisableUpdateInterval() { - onView(withText(R.string.network_pref)).perform(click()); + clickPreference(R.string.network_pref); onView(withText(R.string.pref_autoUpdateIntervallOrTime_title)).perform(click()); onView(withText(R.string.pref_autoUpdateIntervallOrTime_Disable)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) @@ -385,7 +385,7 @@ public class PreferencesTest { @Test public void testEpisodeCleanupQueueOnly() { - onView(withText(R.string.network_pref)).perform(click()); + clickPreference(R.string.network_pref); onView(withText(R.string.pref_automatic_download_title)).perform(click()); onView(withText(R.string.pref_episode_cleanup_title)).perform(click()); onView(isRoot()).perform(waitForView(withText(R.string.episode_cleanup_queue_removal), 1000)); @@ -396,7 +396,7 @@ public class PreferencesTest { @Test public void testEpisodeCleanupNeverAlg() { - onView(withText(R.string.network_pref)).perform(click()); + clickPreference(R.string.network_pref); onView(withText(R.string.pref_automatic_download_title)).perform(click()); onView(withText(R.string.pref_episode_cleanup_title)).perform(click()); onView(withId(R.id.select_dialog_listview)).perform(swipeUp()); @@ -407,7 +407,7 @@ public class PreferencesTest { @Test public void testEpisodeCleanupClassic() { - onView(withText(R.string.network_pref)).perform(click()); + clickPreference(R.string.network_pref); onView(withText(R.string.pref_automatic_download_title)).perform(click()); onView(withText(R.string.pref_episode_cleanup_title)).perform(click()); onView(isRoot()).perform(waitForView(withText(R.string.episode_cleanup_after_listening), 1000)); diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java index 8e16d1a3b..4365fa0ae 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java @@ -98,15 +98,6 @@ public class UITestUtils { return String.format("%s/files/%d", server.getBaseUrl(), id); } - private File newBitmapFile(String name) throws IOException { - File imgFile = new File(destDir, name); - Bitmap bitmap = Bitmap.createBitmap(128, 128, Bitmap.Config.ARGB_8888); - FileOutputStream out = new FileOutputStream(imgFile); - bitmap.compress(Bitmap.CompressFormat.PNG, 1, out); - out.close(); - return imgFile; - } - private File newMediaFile(String name) throws IOException { File mediaFile = new File(hostedMediaDir, name); if (mediaFile.exists()) { @@ -201,7 +192,7 @@ public class UITestUtils { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - adapter.setCompleteFeed(hostedFeeds.toArray(new Feed[hostedFeeds.size()])); + adapter.setCompleteFeed(hostedFeeds.toArray(new Feed[0])); adapter.setQueue(queue); adapter.close(); EventBus.getDefault().post(new FeedListUpdateEvent(hostedFeeds)); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 086206dcd..ad68fcfe3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -236,7 +236,6 @@ android:value="de.danoeh.antennapod.activity.MainActivity"/> <!-- URLs ending with '.xml' or '.rss' --> - <intent-filter> <action android:name="android.intent.action.VIEW"/> @@ -252,7 +251,6 @@ </intent-filter> <!-- Feedburner URLs --> - <intent-filter> <action android:name="android.intent.action.VIEW"/> @@ -268,7 +266,6 @@ </intent-filter> <!-- Files with mimeType rss/xml/atom --> - <intent-filter> <action android:name="android.intent.action.VIEW"/> @@ -284,7 +281,6 @@ </intent-filter> <!-- Podcast protocols --> - <intent-filter> <action android:name="android.intent.action.VIEW"/> @@ -297,6 +293,21 @@ <data android:scheme="antennapod-subscribe"/> </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> <action android:name="android.intent.action.SEND"/> diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index a0530fb95..50a8d0965 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -134,6 +134,10 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } else { Log.d(TAG, "Activity was started with url " + feedUrl); 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) { startFeedDownload(feedUrl, null, null); } else { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java index 45cb4af87..ad23478d6 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java @@ -93,10 +93,7 @@ public class SearchlistAdapter extends BaseAdapter { } else if (component.getClass() == FeedItem.class) { final FeedItem item = (FeedItem) component; holder.title.setText(item.getTitle()); - if (result.getSubtitle() != null) { - holder.subtitle.setVisibility(View.VISIBLE); - holder.subtitle.setText(result.getSubtitle()); - } + holder.subtitle.setText(result.getLocation().getDescription()); convertView.setAlpha(item.isPlayed() ? 0.5f : 1.0f); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 96f350569..34b102ca8 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -492,7 +492,7 @@ public class EpisodesApplyActionFragment extends Fragment { } } try { - DownloadRequester.getInstance().downloadMedia(getActivity(), toDownload.toArray(new FeedItem[toDownload.size()])); + DownloadRequester.getInstance().downloadMedia(getActivity(), toDownload.toArray(new FeedItem[0])); } catch (DownloadRequestException e) { e.printStackTrace(); DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index fdb74fa64..e4276b3b9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -3,26 +3,18 @@ package de.danoeh.antennapod.fragment; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import android.util.Log; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.joanzapata.iconify.Iconify; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedItemFilter; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.dialog.FilterDialog; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import java.util.List; @@ -33,16 +25,18 @@ import java.util.Set; * supports swiping to mark as read. */ public class AllEpisodesFragment extends EpisodesListFragment { - public static final String TAG = "AllEpisodesFragment"; 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 VISIBLE_EPISODES_SCROLL_THRESHOLD = 5; - private static int page = 1; + private static FeedItemFilter feedItemFilter = new FeedItemFilter(""); - private FeedItemFilter feedItemFilter = new FeedItemFilter(""); + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + feedItemFilter = new FeedItemFilter(prefs.getString(PREF_FILTER, "")); + } @Override protected boolean showOnlyNewEpisodes() { @@ -69,53 +63,6 @@ public class AllEpisodesFragment extends EpisodesListFragment { } } - @NonNull - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle 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() { - - /* Total number of episodes after last load */ - private int previousTotalEpisodes = 0; - - /* True if loading more episodes is still in progress */ - private boolean isLoadingMore = true; - - @Override - public void onScrolled(RecyclerView recyclerView, int deltaX, int deltaY) { - super.onScrolled(recyclerView, deltaX, deltaY); - - int visibleEpisodeCount = recyclerView.getChildCount(); - int totalEpisodeCount = recyclerView.getLayoutManager().getItemCount(); - int firstVisibleEpisode = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition(); - - /* Determine if loading more episodes has finished */ - if (isLoadingMore) { - if (totalEpisodeCount > previousTotalEpisodes) { - isLoadingMore = false; - previousTotalEpisodes = totalEpisodeCount; - } - } - - /* Determine if the user scrolled to the bottom and loading more episodes is not already in progress */ - if (!isLoadingMore && (totalEpisodeCount - visibleEpisodeCount) - <= (firstVisibleEpisode + VISIBLE_EPISODES_SCROLL_THRESHOLD)) { - - /* The end of the list has been reached. Load more data. */ - page++; - loadMoreItems(); - isLoadingMore = true; - } - } - }); - - return root; - } - @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); @@ -136,20 +83,6 @@ public class AllEpisodesFragment extends EpisodesListFragment { } } - private void loadMoreItems() { - if (disposable != null) { - disposable.dispose(); - } - disposable = Observable.fromCallable(this::loadMoreData) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(data -> { - progLoading.setVisibility(View.GONE); - episodes.addAll(data); - onFragmentLoaded(episodes); - }, error -> Log.e(TAG, Log.getStackTraceString(error))); - } - private void showFilterDialog() { FilterDialog filterDialog = new FilterDialog(getContext(), feedItemFilter) { @Override @@ -167,10 +100,13 @@ public class AllEpisodesFragment extends EpisodesListFragment { @NonNull @Override protected List<FeedItem> loadData() { - return feedItemFilter.filter( DBReader.getRecentlyPublishedEpisodes(0, page * EPISODES_PER_PAGE)); + return feedItemFilter.filter(DBReader.getRecentlyPublishedEpisodes(0, page * EPISODES_PER_PAGE)); } - List<FeedItem> loadMoreData() { - return feedItemFilter.filter( DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE)); + @NonNull + @Override + protected List<FeedItem> loadMoreData() { + return feedItemFilter.filter(DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, + EPISODES_PER_PAGE)); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 5dbb703b7..b6d6dd9bb 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -70,9 +70,14 @@ public abstract class EpisodesListFragment extends Fragment { private static final String PREF_SCROLL_POSITION = "scroll_position"; private static final String PREF_SCROLL_OFFSET = "scroll_offset"; + protected static final int EPISODES_PER_PAGE = 150; + private static final int VISIBLE_EPISODES_SCROLL_THRESHOLD = 5; + protected int page = 1; + RecyclerView recyclerView; AllEpisodesRecycleAdapter listAdapter; ProgressBar progLoading; + View loadingMore; EmptyViewHandler emptyView; @NonNull @@ -264,6 +269,7 @@ public abstract class EpisodesListFragment extends Fragment { recyclerView.setHasFixedSize(true); recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); recyclerView.setVisibility(View.GONE); + setupLoadMoreScrollListener(); RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator(); if (animator instanceof SimpleItemAnimator) { @@ -272,6 +278,7 @@ public abstract class EpisodesListFragment extends Fragment { progLoading = root.findViewById(R.id.progLoading); progLoading.setVisibility(View.VISIBLE); + loadingMore = root.findViewById(R.id.loadingMore); emptyView = new EmptyViewHandler(getContext()); emptyView.attachToRecyclerView(recyclerView); @@ -285,6 +292,60 @@ public abstract class EpisodesListFragment extends Fragment { return root; } + private void setupLoadMoreScrollListener() { + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + + /* Total number of episodes after last load */ + private int previousTotalEpisodes = 0; + + /* True if loading more episodes is still in progress */ + private boolean isLoadingMore = true; + + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int deltaX, int deltaY) { + super.onScrolled(recyclerView, deltaX, deltaY); + + int visibleEpisodeCount = recyclerView.getChildCount(); + int totalEpisodeCount = recyclerView.getLayoutManager().getItemCount(); + int firstVisibleEpisode = layoutManager.findFirstVisibleItemPosition(); + + /* Determine if loading more episodes has finished */ + if (isLoadingMore) { + if (totalEpisodeCount > previousTotalEpisodes) { + isLoadingMore = false; + previousTotalEpisodes = totalEpisodeCount; + } + } + + /* Determine if the user scrolled to the bottom and loading more episodes is not already in progress */ + if (!isLoadingMore && (totalEpisodeCount - visibleEpisodeCount) + <= (firstVisibleEpisode + VISIBLE_EPISODES_SCROLL_THRESHOLD)) { + + /* The end of the list has been reached. Load more data. */ + page++; + loadMoreItems(); + isLoadingMore = true; + } + } + }); + } + + private void loadMoreItems() { + if (disposable != null) { + disposable.dispose(); + } + loadingMore.setVisibility(View.VISIBLE); + disposable = Observable.fromCallable(this::loadMoreData) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(data -> { + loadingMore.setVisibility(View.GONE); + progLoading.setVisibility(View.GONE); + episodes.addAll(data); + onFragmentLoaded(episodes); + }, error -> Log.e(TAG, Log.getStackTraceString(error))); + } + protected void onFragmentLoaded(List<FeedItem> episodes) { listAdapter.notifyDataSetChanged(); @@ -453,4 +514,7 @@ public abstract class EpisodesListFragment extends Fragment { @NonNull protected abstract List<FeedItem> loadData(); + + @NonNull + protected abstract List<FeedItem> loadMoreData(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java index f73735658..87a555cfd 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -88,6 +88,12 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { @NonNull @Override protected List<FeedItem> loadData() { - return DBReader.getFavoriteItemsList(); + return DBReader.getFavoriteItemsList(0, page * EPISODES_PER_PAGE); + } + + @NonNull + @Override + protected List<FeedItem> loadMoreData() { + return DBReader.getFavoriteItemsList((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java index 2bfdd040b..bd3fd06b0 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -104,6 +104,12 @@ public class NewEpisodesFragment extends EpisodesListFragment { @NonNull @Override protected List<FeedItem> loadData() { - return DBReader.getNewItemsList(); + return DBReader.getNewItemsList(0, page * EPISODES_PER_PAGE); + } + + @NonNull + @Override + protected List<FeedItem> loadMoreData() { + return DBReader.getNewItemsList((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java index 1214edf2c..6befa7e18 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java @@ -2,21 +2,22 @@ package de.danoeh.antennapod.fragment; import android.content.Context; 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.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.ListView; - -import java.util.ArrayList; -import java.util.List; - +import android.widget.ProgressBar; +import androidx.annotation.NonNull; +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.activity.MainActivity; 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.SearchResult; import de.danoeh.antennapod.core.storage.FeedSearcher; +import de.danoeh.antennapod.view.EmptyViewHandler; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import java.util.ArrayList; +import java.util.List; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; /** * 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 ARG_QUERY = "query"; @@ -45,6 +49,9 @@ public class SearchFragment extends ListFragment { private SearchlistAdapter searchAdapter; private List<SearchResult> searchResults = new ArrayList<>(); private Disposable disposable; + private ListView listView; + private ProgressBar progressBar; + private EmptyViewHandler emptyViewHandler; /** * Create a new SearchFragment that searches all feeds. @@ -84,26 +91,30 @@ public class SearchFragment extends ListFragment { @Override public void onStop() { super.onStop(); - if(disposable != null) { + if (disposable != null) { disposable.dispose(); } } + @Nullable @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, 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); - + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { ((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); - 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); + return layout; } @Override @@ -113,9 +124,8 @@ public class SearchFragment extends ListFragment { } @Override - public void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - SearchResult result = (SearchResult) l.getAdapter().getItem(position); + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + SearchResult result = (SearchResult) listView.getAdapter().getItem(position); FeedComponent comp = result.getComponent(); if (comp.getClass() == Feed.class) { ((MainActivity) getActivity()).loadFeedFragmentById(comp.getId(), null); @@ -128,7 +138,7 @@ public class SearchFragment extends ListFragment { } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); 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); @@ -158,10 +168,11 @@ public class SearchFragment extends ListFragment { } private void onSearchResults(List<SearchResult> results) { + progressBar.setVisibility(View.GONE); searchResults = results; searchAdapter.notifyDataSetChanged(); 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() { @@ -181,9 +192,11 @@ public class SearchFragment extends ListFragment { }; private void search() { - if(disposable != null) { + if (disposable != null) { disposable.dispose(); } + progressBar.setVisibility(View.VISIBLE); + emptyViewHandler.hide(); disposable = Observable.fromCallable(this::performSearch) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index fa17fed0a..469697e23 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -131,9 +131,7 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { prefValuesList.add(key); } - UserPreferences.setAutodownloadSelectedNetworks( - prefValuesList.toArray(new String[prefValuesList.size()]) - ); + UserPreferences.setAutodownloadSelectedNetworks(prefValuesList.toArray(new String[0])); return true; } else { return false; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java index 191999cf7..0acfe60bf 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java @@ -33,19 +33,6 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { } private void setupInterfaceScreen() { - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - // disable expanded notification option on unsupported android versions - findPreference(PREF_EXPANDED_NOTIFICATION).setEnabled(false); - findPreference(PREF_EXPANDED_NOTIFICATION).setOnPreferenceClickListener( - preference -> { - Toast toast = Toast.makeText(getActivity(), - R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT); - toast.show(); - return true; - } - ); - } findPreference(UserPreferences.PREF_THEME) .setOnPreferenceChangeListener( (preference, newValue) -> { diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java index e32deba27..44b6453e5 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java @@ -108,7 +108,7 @@ public class FeedMenuHandler { FilterDialog filterDialog = new FilterDialog(context, selectedFeed.getItemFilter()) { @Override protected void updateFilter(Set<String> filterValues) { - selectedFeed.setItemFilter(filterValues.toArray(new String[filterValues.size()])); + selectedFeed.setItemFilter(filterValues.toArray(new String[0])); DBWriter.setFeedItemsFilter(selectedFeed.getId(), filterValues); } }; diff --git a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java index a2d8ec091..9471db0a1 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java @@ -45,6 +45,10 @@ public class EmptyViewHandler { tvMessage.setText(message);
}
+ public void setMessage(String message) {
+ tvMessage.setText(message);
+ }
+
public void setIcon(@AttrRes int iconAttr) {
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(iconAttr, typedValue, true);
diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml index 9160998ac..784e7a1c8 100644 --- a/app/src/main/res/layout/all_episodes_fragment.xml +++ b/app/src/main/res/layout/all_episodes_fragment.xml @@ -27,6 +27,7 @@ android:clipToPadding="false" android:paddingTop="@dimen/list_vertical_padding" android:paddingBottom="@dimen/list_vertical_padding" + android:layout_above="@id/loadingMore" app:fastScrollEnabled="true" app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable" app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable" @@ -43,9 +44,36 @@ android:indeterminateOnly="true" android:visibility="gone" android:layout_centerInParent="true" - tools:visibility="gone" - tools:layout_width="match_parent" - tools:layout_height="64dp" tools:background="@android:color/holo_red_light"/> + <LinearLayout + android:id="@+id/loadingMore" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:orientation="horizontal" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingTop="4dp" + android:paddingBottom="4dp" + android:visibility="gone" + android:gravity="center"> + + <ProgressBar + android:layout_width="16dp" + android:layout_height="16dp" + android:gravity="center_horizontal" + android:indeterminateOnly="true" + android:layout_centerInParent="true" + tools:background="@android:color/holo_red_light" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="4dp" + android:layout_marginStart="4dp" + android:text="@string/loading_more" /> + + </LinearLayout> + </RelativeLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml index 5049db215..25e914c55 100644 --- a/app/src/main/res/layout/audio_controls.xml +++ b/app/src/main/res/layout/audio_controls.xml @@ -43,7 +43,7 @@ android:textStyle="bold" android:textColor="@color/status_progress" android:textSize="24sp" - android:background="@drawable/borderless_button_dark"/> + android:background="?android:attr/selectableItemBackground"/> <Button android:id="@+id/butIncSpeed" @@ -57,7 +57,7 @@ android:textStyle="bold" android:textColor="@color/status_progress" android:textSize="24sp" - android:background="@drawable/borderless_button_dark"/> + android:background="?android:attr/selectableItemBackground"/> <SeekBar android:id="@+id/playback_speed" diff --git a/app/src/main/res/layout/search_fragment.xml b/app/src/main/res/layout/search_fragment.xml new file mode 100644 index 000000000..6f455a056 --- /dev/null +++ b/app/src/main/res/layout/search_fragment.xml @@ -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>
\ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 37707ead6..6e734f789 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -12,26 +12,31 @@ <Preference android:key="prefScreenInterface" android:title="@string/user_interface_label" + android:summary="@string/user_interface_sum" android:icon="?attr/ic_cellphone_text" /> <Preference android:key="prefScreenPlayback" android:title="@string/playback_pref" + android:summary="@string/playback_pref_sum" android:icon="?attr/av_play" /> <Preference android:key="prefScreenNetwork" android:title="@string/network_pref" + android:summary="@string/network_pref_sum" android:icon="?attr/ic_swap" /> <Preference android:key="prefScreenIntegrations" android:title="@string/integrations_label" + android:summary="@string/integrations_sum" android:icon="?attr/ic_unfav" /> <Preference android:key="prefScreenStorage" android:title="@string/storage_pref" + android:summary="@string/storage_sum" android:icon="?attr/storage" /> <Preference diff --git a/app/src/play/res/layout/media_router_controller.xml b/app/src/play/res/layout/media_router_controller.xml index 9489173a3..bdb1b1cc2 100644 --- a/app/src/play/res/layout/media_router_controller.xml +++ b/app/src/play/res/layout/media_router_controller.xml @@ -17,7 +17,7 @@ android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:contentDescription="@string/mr_controller_play" - android:background="?attr/selectableItemBackgroundBorderless"/> + android:background="?android:attr/selectableItemBackground"/> <LinearLayout android:id="@+id/mrc_control_title_container" android:orientation="vertical" |