Merge pull request #3923 from ByteHamster/toolbar

Moved Toolbar to individual Fragments
This commit is contained in:
H. Lehmann 2020-03-16 18:50:00 +01:00 committed by GitHub
commit 15b1afa38b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 1499 additions and 1154 deletions

View File

@ -141,6 +141,7 @@ dependencies {
implementation "androidx.preference:preference:1.1.0"
implementation "androidx.gridlayout:gridlayout:1.0.0"
implementation "androidx.recyclerview:recyclerview:1.0.0"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "androidx.media:media:1.1.0"
implementation "com.google.android.material:material:1.0.0"
annotationProcessor "androidx.annotation:annotation:1.1.0"

View File

@ -1,7 +1,7 @@
package de.danoeh.antennapod.activity;
import android.annotation.TargetApi;
import android.app.ProgressDialog;
import android.app.ActionBar;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -11,18 +11,7 @@ import android.database.DataSetObserver;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.google.android.material.snackbar.Snackbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
@ -31,25 +20,25 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.bumptech.glide.Glide;
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@ -77,6 +66,13 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
/**
* The activity that is shown when the user launches the app.
@ -96,7 +92,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
private static final String EXTRA_FEED_ID = "fragment_feed_id";
private static final String SAVE_BACKSTACK_COUNT = "backstackCount";
private static final String SAVE_TITLE = "title";
public static final String[] NAV_DRAWER_TAGS = {
QueueFragment.TAG,
@ -108,15 +103,11 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
NavListAdapter.SUBSCRIPTION_LIST_TAG
};
private Toolbar toolbar;
private ExternalPlayerFragment externalPlayerFragment;
private DrawerLayout drawerLayout;
private View navDrawer;
private ListView navList;
private NavListAdapter navAdapter;
private int mPosition = -1;
private ActionBarDrawerToggle drawerToggle;
private CharSequence currentTitle;
private Disposable disposable;
private long lastBackButtonPressTime = 0;
@ -135,35 +126,13 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
StorageUtils.checkStorageAvailability(this);
setContentView(R.layout.main);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
findViewById(R.id.shadow).setVisibility(View.GONE);
int elevation = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
getResources().getDisplayMetrics());
getSupportActionBar().setElevation(elevation);
}
currentTitle = getTitle();
drawerLayout = findViewById(R.id.drawer_layout);
navList = findViewById(R.id.nav_list);
ListView navList = findViewById(R.id.nav_list);
navDrawer = findViewById(R.id.nav_layout);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close);
if (savedInstanceState != null) {
int backstackCount = savedInstanceState.getInt(SAVE_BACKSTACK_COUNT, 0);
drawerToggle.setDrawerIndicatorEnabled(backstackCount == 0);
}
drawerLayout.setDrawerListener(drawerToggle);
final FragmentManager fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(() -> drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
fm.addOnBackStackChangedListener(() ->
drawerToggle.setDrawerIndicatorEnabled(fm.getBackStackEntryCount() == 0));
navAdapter = new NavListAdapter(itemAccess, this);
navList.setAdapter(navAdapter);
@ -203,7 +172,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
}
}
}
externalPlayerFragment = new ExternalPlayerFragment();
ExternalPlayerFragment externalPlayerFragment = new ExternalPlayerFragment();
transaction.replace(R.id.playerFragment, externalPlayerFragment, ExternalPlayerFragment.TAG);
transaction.commit();
@ -211,11 +180,21 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
PreferenceUpgrader.checkUpgrades(this);
}
@Override
public void setSupportActionBar(@Nullable Toolbar toolbar) {
drawerLayout.removeDrawerListener(drawerToggle);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
R.string.drawer_open, R.string.drawer_close);
drawerLayout.addDrawerListener(drawerToggle);
drawerToggle.syncState();
super.setSupportActionBar(toolbar);
}
private void saveLastNavFragment(String tag) {
Log.d(TAG, "saveLastNavFragment(tag: " + tag +")");
Log.d(TAG, "saveLastNavFragment(tag: " + tag + ")");
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
if(tag != null) {
if (tag != null) {
edit.putString(PREF_LAST_FRAGMENT_TAG, tag);
} else {
edit.remove(PREF_LAST_FRAGMENT_TAG);
@ -315,8 +294,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
args = null;
break;
}
currentTitle = navAdapter.getLabel(tag);
getSupportActionBar().setTitle(currentTitle);
saveLastNavFragment(tag);
if (args != null) {
fragment.setArguments(args);
@ -338,8 +315,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
fragment.setArguments(args);
}
saveLastNavFragment(String.valueOf(feedId));
currentTitle = "";
getSupportActionBar().setTitle(currentTitle);
loadFragment(fragment);
}
@ -392,10 +367,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
loadChildFragment(fragment, TransitionEffect.NONE);
}
public void dismissChildFragment() {
getSupportFragmentManager().popBackStack();
}
private int getSelectedNavListIndex() {
String currentFragment = getLastNavFragment();
if(currentFragment == null) {
@ -452,10 +423,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
if (savedInstanceState != null) {
currentTitle = savedInstanceState.getString(SAVE_TITLE);
if (!drawerLayout.isDrawerOpen(navDrawer)) {
getSupportActionBar().setTitle(currentTitle);
}
selectedNavListIndex = getSelectedNavListIndex();
}
}
@ -469,7 +436,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVE_TITLE, getSupportActionBar().getTitle().toString());
outState.putInt(SAVE_BACKSTACK_COUNT, getSupportFragmentManager().getBackStackEntryCount());
}
@ -552,7 +518,7 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
return true;
} else if (item.getItemId() == android.R.id.home) {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
dismissChildFragment();
getSupportFragmentManager().popBackStack();
}
return true;
} else {

View File

@ -368,8 +368,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
ImageView cover = findViewById(R.id.imgvCover);
ImageView headerBackground = findViewById(R.id.imgvBackground);
findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE);
findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE);
headerBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
TextView title = findViewById(R.id.txtvTitle);
TextView author = findViewById(R.id.txtvAuthor);

View File

@ -13,26 +13,17 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.PluralsRes;
import androidx.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.collection.ArrayMap;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import com.google.android.material.snackbar.Snackbar;
import com.leinardi.android.speeddial.SpeedDialView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.FeedItem;
@ -43,6 +34,12 @@ import de.danoeh.antennapod.core.util.FeedItemPermutors;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.SortOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class EpisodesApplyActionFragment extends Fragment {
public static final String TAG = "EpisodeActionFragment";
@ -55,6 +52,7 @@ public class EpisodesApplyActionFragment extends Fragment {
public static final int ACTION_DELETE = 32;
private static final int ACTION_ALL = ACTION_ADD_TO_QUEUE | ACTION_REMOVE_FROM_QUEUE
| ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED | ACTION_DOWNLOAD | ACTION_DELETE;
private Toolbar toolbar;
/**
* Specify an action (defined by #flag) 's UI bindings.
@ -76,20 +74,15 @@ public class EpisodesApplyActionFragment extends Fragment {
}
private final List<? extends ActionBinding> actionBindings;
private ListView mListView;
private ArrayAdapter<String> mAdapter;
private SpeedDialView mSpeedDialView;
@NonNull
private CharSequence actionBarTitleOriginal = "";
private final Map<Long,FeedItem> idMap = new ArrayMap<>();
private final Map<Long, FeedItem> idMap = new ArrayMap<>();
private final List<FeedItem> episodes = new ArrayList<>();
private int actions;
private final List<String> titles = new ArrayList<>();
private final LongList checkedIds = new LongList();
private ListView mListView;
private ArrayAdapter<String> mAdapter;
private SpeedDialView mSpeedDialView;
private MenuItem mSelectToggle;
public EpisodesApplyActionFragment() {
@ -137,7 +130,7 @@ public class EpisodesApplyActionFragment extends Fragment {
mListView = view.findViewById(android.R.id.list);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
mListView.setOnItemClickListener((ListView, view1, position, rowId) -> {
mListView.setOnItemClickListener((listView, view1, position, rowId) -> {
long id = episodes.get(position).getId();
if (checkedIds.contains(id)) {
checkedIds.remove(id);
@ -177,8 +170,8 @@ public class EpisodesApplyActionFragment extends Fragment {
mAdapter = new ArrayAdapter<>(getActivity(),
R.layout.simple_list_item_multiple_choice_on_start, titles);
mListView.setAdapter(mAdapter);
saveActionBarTitle(); // needed when we dynamically change the title based on selection
toolbar = view.findViewById(R.id.toolbar);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
// Init action UI (via a FAB Speed Dial)
mSpeedDialView = view.findViewById(R.id.fabSD);
@ -206,18 +199,10 @@ public class EpisodesApplyActionFragment extends Fragment {
}
return true;
});
showSpeedDialIfAnyChecked();
refreshCheckboxes();
return view;
}
@Override
public void onStop() {
restoreActionBarTitle(); // it might have been changed to "N selected". Restore original.
super.onStop();
}
private void showSpeedDialIfAnyChecked() {
if (checkedIds.size() > 0) {
if (!mSpeedDialView.isShown()) {
@ -327,7 +312,7 @@ public class EpisodesApplyActionFragment extends Fragment {
return true;
}
}
if(resId != 0) {
if (resId != 0) {
Snackbar.make(getActivity().findViewById(R.id.content), resId, Snackbar.LENGTH_SHORT)
.show();
return true;
@ -345,7 +330,7 @@ public class EpisodesApplyActionFragment extends Fragment {
private void checkAll() {
for (FeedItem episode : episodes) {
if(!checkedIds.contains(episode.getId())) {
if (!checkedIds.contains(episode.getId())) {
checkedIds.add(episode.getId());
}
}
@ -359,12 +344,12 @@ public class EpisodesApplyActionFragment extends Fragment {
private void checkPlayed(boolean isPlayed) {
for (FeedItem episode : episodes) {
if(episode.isPlayed() == isPlayed) {
if(!checkedIds.contains(episode.getId())) {
if (episode.isPlayed() == isPlayed) {
if (!checkedIds.contains(episode.getId())) {
checkedIds.add(episode.getId());
}
} else {
if(checkedIds.contains(episode.getId())) {
if (checkedIds.contains(episode.getId())) {
checkedIds.remove(episode.getId());
}
}
@ -374,12 +359,12 @@ public class EpisodesApplyActionFragment extends Fragment {
private void checkDownloaded(boolean isDownloaded) {
for (FeedItem episode : episodes) {
if(episode.hasMedia() && episode.getMedia().isDownloaded() == isDownloaded) {
if(!checkedIds.contains(episode.getId())) {
if (episode.hasMedia() && episode.getMedia().isDownloaded() == isDownloaded) {
if (!checkedIds.contains(episode.getId())) {
checkedIds.add(episode.getId());
}
} else {
if(checkedIds.contains(episode.getId())) {
if (checkedIds.contains(episode.getId())) {
checkedIds.remove(episode.getId());
}
}
@ -389,7 +374,7 @@ public class EpisodesApplyActionFragment extends Fragment {
private void checkQueued(boolean isQueued) {
for (FeedItem episode : episodes) {
if(episode.isTagged(FeedItem.TAG_QUEUE) == isQueued) {
if (episode.isTagged(FeedItem.TAG_QUEUE) == isQueued) {
checkedIds.add(episode.getId());
} else {
checkedIds.remove(episode.getId());
@ -400,7 +385,7 @@ public class EpisodesApplyActionFragment extends Fragment {
private void checkWithMedia() {
for (FeedItem episode : episodes) {
if(episode.hasMedia()) {
if (episode.hasMedia()) {
checkedIds.add(episode.getId());
} else {
checkedIds.remove(episode.getId());
@ -425,35 +410,7 @@ public class EpisodesApplyActionFragment extends Fragment {
}
ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity());
showSpeedDialIfAnyChecked();
updateActionBarTitle();
}
private void saveActionBarTitle() {
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
CharSequence title = actionBar.getTitle();
if (title == null) {
title = "";
}
actionBarTitleOriginal = title;
}
}
private void restoreActionBarTitle() {
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(actionBarTitleOriginal);
}
}
private void updateActionBarTitle() {
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
CharSequence title = checkedIds.size() > 0 ?
getString(R.string.num_selected_label, checkedIds.size()) :
actionBarTitleOriginal;
actionBar.setTitle(title);
}
toolbar.setTitle(getString(R.string.num_selected_label, checkedIds.size()));
}
private void queueChecked() {
@ -487,7 +444,7 @@ public class EpisodesApplyActionFragment extends Fragment {
// download the check episodes in the same order as they are currently displayed
List<FeedItem> toDownload = new ArrayList<>(checkedIds.size());
for (FeedItem episode : episodes) {
if(checkedIds.contains(episode.getId()) && episode.hasMedia()) {
if (checkedIds.contains(episode.getId()) && episode.hasMedia()) {
toDownload.add(episode);
}
}
@ -503,7 +460,7 @@ public class EpisodesApplyActionFragment extends Fragment {
private void deleteChecked() {
for (long id : checkedIds.toArray()) {
FeedItem episode = idMap.get(id);
if(episode.hasMedia()) {
if (episode.hasMedia()) {
DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId());
}
}
@ -516,7 +473,7 @@ public class EpisodesApplyActionFragment extends Fragment {
getResources().getQuantityString(msgId, numItems, numItems),
Snackbar.LENGTH_LONG
)
.setAction(android.R.string.ok, v -> {})
.setAction(android.R.string.ok, v -> { })
.show();
}
getActivity().getSupportFragmentManager().popBackStack();

View File

@ -6,6 +6,7 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@ -41,9 +42,8 @@ public class AddFeedFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.addfeed, container, false);
activity = (MainActivity) getActivity();
activity.getSupportActionBar().setTitle(R.string.add_feed_label);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
setupAdvancedSearchButtons(root);
setupSeachBox(root);

View File

@ -2,6 +2,7 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.core.view.MenuItemCompat;
import androidx.appcompat.widget.SearchView;
@ -66,6 +67,7 @@ public class CombinedSearchFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);

View File

@ -4,6 +4,8 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.tabs.TabLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@ -37,6 +39,9 @@ public class DownloadsFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.pager_fragment, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
toolbar.setTitle(R.string.downloads_label);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
viewPager = root.findViewById(R.id.viewpager);
DownloadsPagerAdapter pagerAdapter = new DownloadsPagerAdapter(getChildFragmentManager(), getResources());

View File

@ -2,20 +2,18 @@ package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import androidx.annotation.NonNull;
import com.google.android.material.tabs.TabLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
public class EpisodesFragment extends Fragment {
@ -38,22 +36,21 @@ public class EpisodesFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
setHasOptionsMenu(true);
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.episodes_label);
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
Toolbar toolbar = rootView.findViewById(R.id.toolbar);
toolbar.setTitle(R.string.episodes_label);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
viewPager = rootView.findViewById(R.id.viewpager);
viewPager.setAdapter(new EpisodesPagerAdapter());
// Give the TabLayout the ViewPager
tabLayout = rootView.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
return rootView;
}

View File

@ -168,23 +168,7 @@ public abstract class EpisodesListFragment extends Fragment {
}
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.episodes, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
sv.setQueryHint(getString(R.string.search_label));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
((MainActivity) requireActivity()).loadChildFragment(SearchFragment.newInstance(s));
return true;
}
@Override
public boolean onQueryTextChange(String s) {
return false;
}
});
MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), 0);
isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}

View File

@ -8,6 +8,8 @@ import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
@ -22,6 +24,9 @@ import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.snackbar.Snackbar;
import com.joanzapata.iconify.Iconify;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
@ -33,8 +38,10 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.LangUtils;
import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.view.ToolbarIconTintManager;
import io.reactivex.Maybe;
import io.reactivex.MaybeOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -64,6 +71,8 @@ public class FeedInfoFragment extends Fragment {
private TextView txtvUrl;
private TextView txtvAuthorHeader;
private ImageView imgvBackground;
private Menu optionsMenu;
private ToolbarIconTintManager iconTintManager;
public static FeedInfoFragment newInstance(Feed feed) {
FeedInfoFragment fragment = new FeedInfoFragment();
@ -82,23 +91,33 @@ public class FeedInfoFragment extends Fragment {
android.content.ClipboardManager cm = (android.content.ClipboardManager) getContext()
.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(clipData);
Toast t = Toast.makeText(getContext(), R.string.copied_url_msg, Toast.LENGTH_SHORT);
t.show();
Snackbar.make(getView(), R.string.copied_url_msg, Snackbar.LENGTH_SHORT).show();
}
}
};
@Override
public void onResume() {
super.onResume();
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_info_label);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.feedinfo, null);
Toolbar toolbar = root.findViewById(R.id.toolbar);
toolbar.setTitle("");
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
AppBarLayout appBar = root.findViewById(R.id.appBar);
CollapsingToolbarLayout collapsingToolbar = root.findViewById(R.id.collapsing_toolbar);
iconTintManager = new ToolbarIconTintManager(getContext(), toolbar, collapsingToolbar) {
@Override
protected void doTint(Context themedContext) {
if (optionsMenu == null) {
return;
}
optionsMenu.findItem(R.id.visit_website_item)
.setIcon(ThemeUtils.getDrawableFromAttr(themedContext, R.attr.location_web_site));
}
};
appBar.addOnOffsetChangedListener(iconTintManager);
setHasOptionsMenu(true);
imgvCover = root.findViewById(R.id.imgvCover);
@ -110,7 +129,6 @@ public class FeedInfoFragment extends Fragment {
// https://github.com/bumptech/glide/issues/529
imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
txtvDescription = root.findViewById(R.id.txtvDescription);
lblLanguage = root.findViewById(R.id.lblLanguage);
txtvLanguage = root.findViewById(R.id.txtvLanguage);
@ -201,6 +219,8 @@ public class FeedInfoFragment extends Fragment {
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.feedinfo, menu);
optionsMenu = menu;
iconTintManager.updateTint();
}
@Override

View File

@ -1,6 +1,5 @@
package de.danoeh.antennapod.fragment;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.LightingColorFilter;
@ -12,31 +11,28 @@ 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.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.MenuItemCompat;
import androidx.fragment.app.ListFragment;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconTextView;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
@ -46,45 +42,47 @@ import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.event.PlayerStatusEvent;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.FeedItemPermutors;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.Optional;
import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.dialog.RenameFeedDialog;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.view.ToolbarIconTintManager;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
/**
* Displays a list of FeedItems.
*/
@SuppressLint("ValidFragment")
public class FeedItemlistFragment extends ListFragment {
public class FeedItemlistFragment extends Fragment implements AdapterView.OnItemClickListener {
private static final String TAG = "ItemlistFragment";
private static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
@ -92,17 +90,23 @@ public class FeedItemlistFragment extends ListFragment {
private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
private MoreContentListFooterUtil listFooter;
private long feedID;
private Feed feed;
private boolean headerCreated = false;
private boolean isUpdatingFeed;
private ProgressBar progressBar;
private ListView listView;
private TextView txtvTitle;
private IconTextView txtvFailure;
private ImageView imgvBackground;
private ImageView imgvCover;
private TextView txtvInformation;
private TextView txtvAuthor;
private ImageButton butShowInfo;
private ImageButton butShowSettings;
private Menu optionsMenu;
private ToolbarIconTintManager iconTintManager;
private long feedID;
private Feed feed;
private boolean headerCreated = false;
private boolean isUpdatingFeed;
private Disposable disposable;
/**
@ -131,22 +135,50 @@ public class FeedItemlistFragment extends ListFragment {
feedID = args.getLong(ARGUMENT_FEED_ID);
}
@Nullable
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (!hidden && getActivity() != null) {
((MainActivity) getActivity()).getSupportActionBar().setTitle("");
}
}
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.feed_item_list_fragment, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
toolbar.setTitle("");
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
registerForContextMenu(getListView());
listView = root.findViewById(android.R.id.list);
listView.setOnItemClickListener(this);
registerForContextMenu(listView);
progressBar = root.findViewById(R.id.progLoading);
txtvTitle = root.findViewById(R.id.txtvTitle);
txtvAuthor = root.findViewById(R.id.txtvAuthor);
imgvBackground = root.findViewById(R.id.imgvBackground);
imgvCover = root.findViewById(R.id.imgvCover);
butShowInfo = root.findViewById(R.id.butShowInfo);
butShowSettings = root.findViewById(R.id.butShowSettings);
txtvInformation = root.findViewById(R.id.txtvInformation);
txtvFailure = root.findViewById(R.id.txtvFailure);
AppBarLayout appBar = root.findViewById(R.id.appBar);
CollapsingToolbarLayout collapsingToolbar = root.findViewById(R.id.collapsing_toolbar);
iconTintManager = new ToolbarIconTintManager(getContext(), toolbar, collapsingToolbar) {
@Override
protected void doTint(Context themedContext) {
if (optionsMenu == null) {
return;
}
optionsMenu.findItem(R.id.sort_items)
.setIcon(ThemeUtils.getDrawableFromAttr(themedContext, R.attr.ic_sort));
optionsMenu.findItem(R.id.filter_items)
.setIcon(ThemeUtils.getDrawableFromAttr(themedContext, R.attr.ic_filter));
optionsMenu.findItem(R.id.refresh_item)
.setIcon(ThemeUtils.getDrawableFromAttr(themedContext, R.attr.navigation_refresh));
optionsMenu.findItem(R.id.action_search)
.setIcon(ThemeUtils.getDrawableFromAttr(themedContext, R.attr.action_search));
}
};
appBar.addOnOffsetChangedListener(iconTintManager);
EventBus.getDefault().register(this);
loadItems();
return root;
}
@Override
@ -174,43 +206,10 @@ public class FeedItemlistFragment extends ListFragment {
return;
}
super.onCreateOptionsMenu(menu, inflater);
optionsMenu = menu;
FeedMenuHandler.onCreateOptionsMenu(inflater, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
sv.setQueryHint(getString(R.string.search_label));
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
menu.findItem(R.id.sort_items).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.filter_items).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.episode_actions).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.refresh_item).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
getActivity().invalidateOptionsMenu();
return true;
}
});
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
if (feed != null) {
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s, feed.getId()));
}
return true;
}
@Override
public boolean onQueryTextChange(String s) {
return false;
}
});
iconTintManager.updateTint();
MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), feedID);
if (feed == null || feed.getLink() == null) {
menu.findItem(R.id.share_link_item).setVisible(false);
menu.findItem(R.id.visit_website_item).setVisible(false);
@ -288,9 +287,7 @@ public class FeedItemlistFragment extends ListFragment {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
// because of addHeaderView(), positions are increased by 1!
FeedItem item = (FeedItem) itemAccess.getItem(adapterInfo.position - 1);
FeedItem item = (FeedItem) itemAccess.getItem(adapterInfo.position);
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.feeditemlist_context, menu);
@ -308,8 +305,7 @@ public class FeedItemlistFragment extends ListFragment {
if (menuInfo == null) {
menuInfo = lastMenuInfo;
}
// because of addHeaderView(), positions are increased by 1!
FeedItem selectedItem = feed.getItemAtIndex(menuInfo.position - 1);
FeedItem selectedItem = feed.getItemAtIndex(menuInfo.position);
if (selectedItem == null) {
Log.i(TAG, "Selected item at position " + menuInfo.position + " was null, ignoring selection");
@ -320,21 +316,19 @@ public class FeedItemlistFragment extends ListFragment {
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
if(adapter == null) {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (adapter == null) {
return;
}
position -= l.getHeaderViewsCount();
MainActivity activity = (MainActivity) getActivity();
long[] ids = FeedItemUtil.getIds(feed.getItems());
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
activity.getSupportActionBar().setTitle(feed.getTitle());
}
@Subscribe
public void onEvent(FeedEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
if(event.feedId == feedID) {
if (event.feedId == feedID) {
loadItems();
}
}
@ -342,12 +336,12 @@ public class FeedItemlistFragment extends ListFragment {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if(feed == null || feed.getItems() == null || adapter == null) {
if (feed == null || feed.getItems() == null || adapter == null) {
return;
}
for(FeedItem item : event.items) {
for (FeedItem item : event.items) {
int pos = FeedItemUtil.indexOfItemWithId(feed.getItems(), item.getId());
if(pos >= 0) {
if (pos >= 0) {
loadItems();
return;
}
@ -369,12 +363,11 @@ public class FeedItemlistFragment extends ListFragment {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(PlaybackPositionEvent event) {
if (adapter != null) {
adapter.notifyCurrentlyPlayingItemChanged(event, getListView());
adapter.notifyCurrentlyPlayingItemChanged(event, listView);
}
}
private void updateUi() {
refreshHeaderView();
loadItems();
updateProgressBarVisibility();
}
@ -392,6 +385,7 @@ public class FeedItemlistFragment extends ListFragment {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onFeedListChanged(FeedListUpdateEvent event) {
if (event.contains(feed)) {
refreshHeaderView();
updateUi();
}
}
@ -403,7 +397,6 @@ public class FeedItemlistFragment extends ListFragment {
if (listFooter != null) {
listFooter.setLoadingState(DownloadRequester.getInstance().isDownloadingFeeds());
}
}
private void displayList() {
@ -412,39 +405,39 @@ public class FeedItemlistFragment extends ListFragment {
return;
}
if (adapter == null) {
setListAdapter(null);
setupHeaderView();
listView.setAdapter(null);
setupFooterView();
adapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, false, true);
setListAdapter(adapter);
listView.setAdapter(adapter);
}
refreshHeaderView();
setListShown(true);
listView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
adapter.notifyDataSetChanged();
getActivity().supportInvalidateOptionsMenu();
if (feed != null && feed.getNextPageLink() == null && listFooter != null) {
getListView().removeFooterView(listFooter.getRoot());
listView.removeFooterView(listFooter.getRoot());
}
}
private void refreshHeaderView() {
if (getListView() == null || feed == null || !headerCreated) {
if (listView == null || feed == null || !headerCreated) {
Log.e(TAG, "Unable to refresh header view");
return;
}
loadFeedImage();
if(feed.hasLastUpdateFailed()) {
if (feed.hasLastUpdateFailed()) {
txtvFailure.setVisibility(View.VISIBLE);
} else {
txtvFailure.setVisibility(View.GONE);
}
txtvTitle.setText(feed.getTitle());
if(feed.getItemFilter() != null) {
txtvAuthor.setText(feed.getAuthor());
if (feed.getItemFilter() != null) {
FeedItemFilter filter = feed.getItemFilter();
if(filter.getValues().length > 0) {
if(feed.hasLastUpdateFailed()) {
if (filter.getValues().length > 0) {
if (feed.hasLastUpdateFailed()) {
RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) txtvInformation.getLayoutParams();
p.addRule(RelativeLayout.BELOW, R.id.txtvFailure);
}
@ -460,34 +453,16 @@ public class FeedItemlistFragment extends ListFragment {
}
private void setupHeaderView() {
if (getListView() == null || feed == null) {
if (listView == null || feed == null) {
Log.e(TAG, "Unable to setup listview: recyclerView = null or feed = null");
return;
}
ListView lv = getListView();
LayoutInflater inflater = (LayoutInflater)
getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View header = inflater.inflate(R.layout.feeditemlist_header, lv, false);
lv.addHeaderView(header);
txtvTitle = header.findViewById(R.id.txtvTitle);
TextView txtvAuthor = header.findViewById(R.id.txtvAuthor);
imgvBackground = header.findViewById(R.id.imgvBackground);
imgvCover = header.findViewById(R.id.imgvCover);
ImageButton butShowInfo = header.findViewById(R.id.butShowInfo);
ImageButton butShowSettings = header.findViewById(R.id.butShowSettings);
txtvInformation = header.findViewById(R.id.txtvInformation);
txtvFailure = header.findViewById(R.id.txtvFailure);
txtvTitle.setText(feed.getTitle());
txtvAuthor.setText(feed.getAuthor());
if (headerCreated) {
return;
}
// https://github.com/bumptech/glide/issues/529
imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
loadFeedImage();
imgvBackground.setColorFilter(new LightingColorFilter(0xff666666, 0x000000));
butShowInfo.setOnClickListener(v -> showFeedInfo());
imgvCover.setOnClickListener(v -> showFeedInfo());
butShowSettings.setOnClickListener(v -> {
@ -497,6 +472,7 @@ public class FeedItemlistFragment extends ListFragment {
}
});
headerCreated = true;
refreshHeaderView();
}
private void showFeedInfo() {
@ -530,16 +506,15 @@ public class FeedItemlistFragment extends ListFragment {
private void setupFooterView() {
if (getListView() == null || feed == null) {
if (listView == null || feed == null) {
Log.e(TAG, "Unable to setup listview: recyclerView = null or feed = null");
return;
}
if (feed.isPaged() && feed.getNextPageLink() != null) {
ListView lv = getListView();
LayoutInflater inflater = (LayoutInflater)
getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View header = inflater.inflate(R.layout.more_content_list_footer, lv, false);
lv.addFooterView(header);
View header = inflater.inflate(R.layout.more_content_list_footer, listView, false);
listView.addFooterView(header);
listFooter = new MoreContentListFooterUtil(header);
listFooter.setClickListener(() -> {
if (feed != null) {
@ -573,7 +548,7 @@ public class FeedItemlistFragment extends ListFragment {
};
private void loadItems() {
if(disposable != null) {
if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(this::loadData)
@ -581,6 +556,7 @@ public class FeedItemlistFragment extends ListFragment {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result.orElse(null);
setupHeaderView();
displayList();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@ -600,5 +576,4 @@ public class FeedItemlistFragment extends ListFragment {
}
return Optional.ofNullable(feed);
}
}

View File

@ -4,11 +4,18 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.settings.SpeedPresetChangedEvent;
import de.danoeh.antennapod.core.event.settings.VolumeAdaptionChangedEvent;
@ -34,17 +41,11 @@ import java.util.Locale;
import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
public class FeedSettingsFragment extends PreferenceFragmentCompat {
private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter";
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
private static final DecimalFormat SPEED_FORMAT =
new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
public class FeedSettingsFragment extends Fragment {
private static final String TAG = "FeedSettingsFragment";
private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
private Feed feed;
private Disposable disposable;
private FeedPreferences feedPreferences;
public static FeedSettingsFragment newInstance(Feed feed) {
FeedSettingsFragment fragment = new FeedSettingsFragment();
@ -54,13 +55,20 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
return fragment;
}
@Nullable
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.feed_settings);
setupAutoDownloadGlobalPreference(); // To prevent transition animation because of summary update
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.feedsettings, container, false);
long feedId = getArguments().getLong(EXTRA_FEED_ID);
Toolbar toolbar = root.findViewById(R.id.toolbar);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
getFragmentManager().beginTransaction()
.replace(R.id.settings_fragment_container,
FeedSettingsPreferenceFragment.newInstance(feedId), "settings_fragment")
.commitAllowingStateLoss();
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
Feed feed = DBReader.getFeed(feedId);
if (feed != null) {
@ -71,39 +79,12 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result;
feedPreferences = feed.getPreferences();
((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle());
.subscribe(result -> toolbar.setSubtitle(result.getTitle()),
error -> Log.d(TAG, Log.getStackTraceString(error)),
() -> { });
setupAutoDownloadPreference();
setupKeepUpdatedPreference();
setupAutoDeletePreference();
setupVolumeReductionPreferences();
setupAuthentificationPreference();
setupEpisodeFilterPreference();
setupPlaybackSpeedPreference();
updateAutoDeleteSummary();
updateVolumeReductionValue();
updateAutoDownloadEnabled();
updatePlaybackSpeedPreference();
}, error -> Log.d(TAG, Log.getStackTraceString(error)), () -> { });
}
@Override
public void onResume() {
super.onResume();
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_settings_label);
if (feed != null) {
((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle());
}
}
@Override
public void onStop() {
super.onStop();
((MainActivity) getActivity()).getSupportActionBar().setSubtitle(null);
return root;
}
@Override
@ -114,212 +95,275 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
}
}
private void setupPlaybackSpeedPreference() {
ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
public static class FeedSettingsPreferenceFragment extends PreferenceFragmentCompat {
private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter";
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
private static final DecimalFormat SPEED_FORMAT =
new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
final String[] speeds = getResources().getStringArray(R.array.playback_speed_values);
String[] values = new String[speeds.length + 1];
values[0] = SPEED_FORMAT.format(SPEED_USE_GLOBAL);
private Feed feed;
private Disposable disposable;
private FeedPreferences feedPreferences;
String[] entries = new String[speeds.length + 1];
entries[0] = getString(R.string.feed_auto_download_global);
System.arraycopy(speeds, 0, values, 1, speeds.length);
System.arraycopy(speeds, 0, entries, 1, speeds.length);
feedPlaybackSpeedPreference.setEntryValues(values);
feedPlaybackSpeedPreference.setEntries(entries);
feedPlaybackSpeedPreference.setOnPreferenceChangeListener((preference, newValue) -> {
feedPreferences.setFeedPlaybackSpeed(Float.parseFloat((String) newValue));
feed.savePreferences();
updatePlaybackSpeedPreference();
EventBus.getDefault().post(
new SpeedPresetChangedEvent(feedPreferences.getFeedPlaybackSpeed(), feed.getId()));
return false;
});
}
private void setupEpisodeFilterPreference() {
findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> {
new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) {
@Override
protected void onConfirmed(FeedFilter filter) {
feedPreferences.setFilter(filter);
feed.savePreferences();
}
}.show();
return false;
});
}
private void setupAuthentificationPreference() {
findPreference("authentication").setOnPreferenceClickListener(preference -> {
new AuthenticationDialog(getContext(),
R.string.authentication_label, true, false,
feedPreferences.getUsername(), feedPreferences.getPassword()) {
@Override
protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
feedPreferences.setUsername(username);
feedPreferences.setPassword(password);
feed.savePreferences();
}
}.show();
return false;
});
}
private void setupAutoDeletePreference() {
ListPreference autoDeletePreference = (ListPreference) findPreference("autoDelete");
autoDeletePreference.setOnPreferenceChangeListener((preference, newValue) -> {
switch ((String) newValue) {
case "global":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.GLOBAL);
break;
case "always":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.YES);
break;
case "never":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.NO);
break;
}
feed.savePreferences();
updateAutoDeleteSummary();
return false;
});
}
private void updatePlaybackSpeedPreference() {
ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
float speedValue = feedPreferences.getFeedPlaybackSpeed();
feedPlaybackSpeedPreference.setValue(SPEED_FORMAT.format(speedValue));
}
private void updateAutoDeleteSummary() {
ListPreference autoDeletePreference = findPreference("autoDelete");
switch (feedPreferences.getAutoDeleteAction()) {
case GLOBAL:
autoDeletePreference.setSummary(R.string.feed_auto_download_global);
autoDeletePreference.setValue("global");
break;
case YES:
autoDeletePreference.setSummary(R.string.feed_auto_download_always);
autoDeletePreference.setValue("always");
break;
case NO:
autoDeletePreference.setSummary(R.string.feed_auto_download_never);
autoDeletePreference.setValue("never");
break;
}
}
private void setupVolumeReductionPreferences() {
ListPreference volumeReductionPreference = (ListPreference) findPreference("volumeReduction");
volumeReductionPreference.setOnPreferenceChangeListener((preference, newValue) -> {
switch ((String) newValue) {
case "off":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.OFF);
break;
case "light":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.LIGHT_REDUCTION);
break;
case "heavy":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.HEAVY_REDUCTION);
break;
}
feed.savePreferences();
updateVolumeReductionValue();
EventBus.getDefault().post(
new VolumeAdaptionChangedEvent(feedPreferences.getVolumeAdaptionSetting(), feed.getId()));
return false;
});
}
private void updateVolumeReductionValue() {
ListPreference volumeReductionPreference = (ListPreference) findPreference("volumeReduction");
switch (feedPreferences.getVolumeAdaptionSetting()) {
case OFF:
volumeReductionPreference.setValue("off");
break;
case LIGHT_REDUCTION:
volumeReductionPreference.setValue("light");
break;
case HEAVY_REDUCTION:
volumeReductionPreference.setValue("heavy");
break;
}
}
private void setupKeepUpdatedPreference() {
SwitchPreference pref = (SwitchPreference) findPreference("keepUpdated");
pref.setChecked(feedPreferences.getKeepUpdated());
pref.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = newValue == Boolean.TRUE;
feedPreferences.setKeepUpdated(checked);
feed.savePreferences();
pref.setChecked(checked);
return false;
});
}
private void setupAutoDownloadGlobalPreference() {
if (!UserPreferences.isEnableAutodownload()) {
SwitchPreference autodl = findPreference("autoDownload");
autodl.setChecked(false);
autodl.setEnabled(false);
autodl.setSummary(R.string.auto_download_disabled_globally);
findPreference(PREF_EPISODE_FILTER).setEnabled(false);
}
}
private void setupAutoDownloadPreference() {
SwitchPreference pref = (SwitchPreference) findPreference("autoDownload");
pref.setEnabled(UserPreferences.isEnableAutodownload());
if (UserPreferences.isEnableAutodownload()) {
pref.setChecked(feedPreferences.getAutoDownload());
} else {
pref.setChecked(false);
pref.setSummary(R.string.auto_download_disabled_globally);
}
pref.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = newValue == Boolean.TRUE;
feedPreferences.setAutoDownload(checked);
feed.savePreferences();
updateAutoDownloadEnabled();
ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(getActivity(), checked);
dialog.createNewDialog().show();
pref.setChecked(checked);
return false;
});
}
private void updateAutoDownloadEnabled() {
if (feed != null && feed.getPreferences() != null) {
boolean enabled = feed.getPreferences().getAutoDownload() && UserPreferences.isEnableAutodownload();
findPreference(PREF_EPISODE_FILTER).setEnabled(enabled);
}
}
private class ApplyToEpisodesDialog extends ConfirmationDialog {
private final boolean autoDownload;
ApplyToEpisodesDialog(Context context, boolean autoDownload) {
super(context, R.string.auto_download_apply_to_items_title,
R.string.auto_download_apply_to_items_message);
this.autoDownload = autoDownload;
setPositiveText(R.string.yes);
setNegativeText(R.string.no);
public static FeedSettingsPreferenceFragment newInstance(long feedId) {
FeedSettingsPreferenceFragment fragment = new FeedSettingsPreferenceFragment();
Bundle arguments = new Bundle();
arguments.putLong(EXTRA_FEED_ID, feedId);
fragment.setArguments(arguments);
return fragment;
}
@Override
public void onConfirmButtonPressed(DialogInterface dialog) {
DBWriter.setFeedsItemsAutoDownload(feed, autoDownload);
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.feed_settings);
setupAutoDownloadGlobalPreference(); // To prevent transition animation because of summary update
long feedId = getArguments().getLong(EXTRA_FEED_ID);
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
Feed feed = DBReader.getFeed(feedId);
if (feed != null) {
emitter.onSuccess(feed);
} else {
emitter.onComplete();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result;
feedPreferences = feed.getPreferences();
setupAutoDownloadPreference();
setupKeepUpdatedPreference();
setupAutoDeletePreference();
setupVolumeReductionPreferences();
setupAuthentificationPreference();
setupEpisodeFilterPreference();
setupPlaybackSpeedPreference();
updateAutoDeleteSummary();
updateVolumeReductionValue();
updateAutoDownloadEnabled();
updatePlaybackSpeedPreference();
}, error -> Log.d(TAG, Log.getStackTraceString(error)), () -> { });
}
@Override
public void onDestroy() {
super.onDestroy();
if (disposable != null) {
disposable.dispose();
}
}
private void setupPlaybackSpeedPreference() {
ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
final String[] speeds = getResources().getStringArray(R.array.playback_speed_values);
String[] values = new String[speeds.length + 1];
values[0] = SPEED_FORMAT.format(SPEED_USE_GLOBAL);
String[] entries = new String[speeds.length + 1];
entries[0] = getString(R.string.feed_auto_download_global);
System.arraycopy(speeds, 0, values, 1, speeds.length);
System.arraycopy(speeds, 0, entries, 1, speeds.length);
feedPlaybackSpeedPreference.setEntryValues(values);
feedPlaybackSpeedPreference.setEntries(entries);
feedPlaybackSpeedPreference.setOnPreferenceChangeListener((preference, newValue) -> {
feedPreferences.setFeedPlaybackSpeed(Float.parseFloat((String) newValue));
feed.savePreferences();
updatePlaybackSpeedPreference();
EventBus.getDefault().post(
new SpeedPresetChangedEvent(feedPreferences.getFeedPlaybackSpeed(), feed.getId()));
return false;
});
}
private void setupEpisodeFilterPreference() {
findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> {
new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) {
@Override
protected void onConfirmed(FeedFilter filter) {
feedPreferences.setFilter(filter);
feed.savePreferences();
}
}.show();
return false;
});
}
private void setupAuthentificationPreference() {
findPreference("authentication").setOnPreferenceClickListener(preference -> {
new AuthenticationDialog(getContext(),
R.string.authentication_label, true, false,
feedPreferences.getUsername(), feedPreferences.getPassword()) {
@Override
protected void onConfirmed(String username, String password, boolean saveUsernamePassword) {
feedPreferences.setUsername(username);
feedPreferences.setPassword(password);
feed.savePreferences();
}
}.show();
return false;
});
}
private void setupAutoDeletePreference() {
ListPreference autoDeletePreference = findPreference("autoDelete");
autoDeletePreference.setOnPreferenceChangeListener((preference, newValue) -> {
switch ((String) newValue) {
case "global":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.GLOBAL);
break;
case "always":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.YES);
break;
case "never":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.NO);
break;
}
feed.savePreferences();
updateAutoDeleteSummary();
return false;
});
}
private void updatePlaybackSpeedPreference() {
ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
float speedValue = feedPreferences.getFeedPlaybackSpeed();
feedPlaybackSpeedPreference.setValue(SPEED_FORMAT.format(speedValue));
}
private void updateAutoDeleteSummary() {
ListPreference autoDeletePreference = findPreference("autoDelete");
switch (feedPreferences.getAutoDeleteAction()) {
case GLOBAL:
autoDeletePreference.setSummary(R.string.feed_auto_download_global);
autoDeletePreference.setValue("global");
break;
case YES:
autoDeletePreference.setSummary(R.string.feed_auto_download_always);
autoDeletePreference.setValue("always");
break;
case NO:
autoDeletePreference.setSummary(R.string.feed_auto_download_never);
autoDeletePreference.setValue("never");
break;
}
}
private void setupVolumeReductionPreferences() {
ListPreference volumeReductionPreference = findPreference("volumeReduction");
volumeReductionPreference.setOnPreferenceChangeListener((preference, newValue) -> {
switch ((String) newValue) {
case "off":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.OFF);
break;
case "light":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.LIGHT_REDUCTION);
break;
case "heavy":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.HEAVY_REDUCTION);
break;
}
feed.savePreferences();
updateVolumeReductionValue();
EventBus.getDefault().post(
new VolumeAdaptionChangedEvent(feedPreferences.getVolumeAdaptionSetting(), feed.getId()));
return false;
});
}
private void updateVolumeReductionValue() {
ListPreference volumeReductionPreference = findPreference("volumeReduction");
switch (feedPreferences.getVolumeAdaptionSetting()) {
case OFF:
volumeReductionPreference.setValue("off");
break;
case LIGHT_REDUCTION:
volumeReductionPreference.setValue("light");
break;
case HEAVY_REDUCTION:
volumeReductionPreference.setValue("heavy");
break;
}
}
private void setupKeepUpdatedPreference() {
SwitchPreference pref = findPreference("keepUpdated");
pref.setChecked(feedPreferences.getKeepUpdated());
pref.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = newValue == Boolean.TRUE;
feedPreferences.setKeepUpdated(checked);
feed.savePreferences();
pref.setChecked(checked);
return false;
});
}
private void setupAutoDownloadGlobalPreference() {
if (!UserPreferences.isEnableAutodownload()) {
SwitchPreference autodl = findPreference("autoDownload");
autodl.setChecked(false);
autodl.setEnabled(false);
autodl.setSummary(R.string.auto_download_disabled_globally);
findPreference(PREF_EPISODE_FILTER).setEnabled(false);
}
}
private void setupAutoDownloadPreference() {
SwitchPreference pref = findPreference("autoDownload");
pref.setEnabled(UserPreferences.isEnableAutodownload());
if (UserPreferences.isEnableAutodownload()) {
pref.setChecked(feedPreferences.getAutoDownload());
} else {
pref.setChecked(false);
pref.setSummary(R.string.auto_download_disabled_globally);
}
pref.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = newValue == Boolean.TRUE;
feedPreferences.setAutoDownload(checked);
feed.savePreferences();
updateAutoDownloadEnabled();
ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(getActivity(), checked);
dialog.createNewDialog().show();
pref.setChecked(checked);
return false;
});
}
private void updateAutoDownloadEnabled() {
if (feed != null && feed.getPreferences() != null) {
boolean enabled = feed.getPreferences().getAutoDownload() && UserPreferences.isEnableAutodownload();
findPreference(PREF_EPISODE_FILTER).setEnabled(enabled);
}
}
private class ApplyToEpisodesDialog extends ConfirmationDialog {
private final boolean autoDownload;
ApplyToEpisodesDialog(Context context, boolean autoDownload) {
super(context, R.string.auto_download_apply_to_items_title,
R.string.auto_download_apply_to_items_message);
this.autoDownload = autoDownload;
setPositiveText(R.string.yes);
setNegativeText(R.string.no);
}
@Override
public void onConfirmButtonPressed(DialogInterface dialog) {
DBWriter.setFeedsItemsAutoDownload(feed, autoDownload);
}
}
}
}

View File

@ -2,6 +2,7 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.core.view.MenuItemCompat;
import androidx.appcompat.widget.SearchView;
@ -65,6 +66,7 @@ public class FyydSearchFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);

View File

@ -9,6 +9,8 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentStatePagerAdapter;
@ -77,6 +79,9 @@ public class ItemPagerFragment extends Fragment {
@Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View layout = inflater.inflate(R.layout.feeditem_pager_fragment, container, false);
Toolbar toolbar = layout.findViewById(R.id.toolbar);
toolbar.setTitle("");
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
feedItems = getArguments().getLongArray(ARG_FEEDITEMS);
int feedItemPos = getArguments().getInt(ARG_FEEDITEM_POS);
@ -145,15 +150,12 @@ public class ItemPagerFragment extends Fragment {
((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
inflater.inflate(R.menu.feeditem_options, menu);
if (menu != null && item != null) {
if (item.hasMedia()) {
FeedItemMenuHandler.onPrepareMenu(menu, item);
} else {
// these are already available via button1 and button2
FeedItemMenuHandler.onPrepareMenu(menu, item,
R.id.mark_read_item, R.id.visit_website_item);
}
if (item.hasMedia()) {
FeedItemMenuHandler.onPrepareMenu(menu, item);
} else {
// these are already available via button1 and button2
FeedItemMenuHandler.onPrepareMenu(menu, item,
R.id.mark_read_item, R.id.visit_website_item);
}
}

View File

@ -3,6 +3,7 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.core.view.MenuItemCompat;
import androidx.appcompat.widget.SearchView;
@ -93,6 +94,7 @@ public class ItunesSearchFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_itunes_search, container, false);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
gridView = root.findViewById(R.id.gridView);
adapter = new ItunesAdapter(getActivity(), new ArrayList<>());
gridView.setAdapter(adapter);
@ -172,7 +174,7 @@ public class ItunesSearchFragment extends Fragment {
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
if(searchResults != null) {
if (searchResults != null) {
searchResults = null;
updateData(topList);
}

View File

@ -2,50 +2,50 @@ package de.danoeh.antennapod.fragment;
import android.content.res.TypedArray;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.ListFragment;
import androidx.core.view.MenuItemCompat;
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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
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.FeedItemlistAdapter;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.PlaybackHistoryEvent;
import de.danoeh.antennapod.core.event.PlayerStatusEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
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 org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
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;
public class PlaybackHistoryFragment extends ListFragment {
public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnItemClickListener {
public static final String TAG = "PlaybackHistoryFragment";
private List<FeedItem> playbackHistory;
private FeedItemlistAdapter adapter;
private List<Downloader> downloaderList;
private Disposable disposable;
private ListView listView;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -55,26 +55,26 @@ public class PlaybackHistoryFragment extends ListFragment {
}
@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) {
View root = inflater.inflate(R.layout.simple_list_fragment, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
toolbar.setTitle(R.string.playback_history_label);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
listView = root.findViewById(android.R.id.list);
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
emptyView.setIcon(R.attr.ic_history);
emptyView.setTitle(R.string.no_history_head_label);
emptyView.setMessage(R.string.no_history_label);
emptyView.attachToListView(getListView());
emptyView.attachToListView(listView);
// played items shoudln't be transparent for this fragment since, *all* items
// in this fragment will, by definition, be played. So it serves no purpose and can make
// it harder to read.
adapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, true, false);
setListAdapter(adapter);
listView.setAdapter(adapter);
return root;
}
@Override
@ -96,15 +96,12 @@ public class PlaybackHistoryFragment extends ListFragment {
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(DownloadEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
adapter.notifyDataSetChanged();
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
position -= l.getHeaderViewsCount();
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
position -= listView.getHeaderViewsCount();
long[] ids = FeedItemUtil.getIds(playbackHistory);
((MainActivity) getActivity()).loadChildFragment(ItemPagerFragment.newInstance(ids, position));
}
@ -149,12 +146,12 @@ public class PlaybackHistoryFragment extends ListFragment {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(FeedItemEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if(playbackHistory == null) {
if (playbackHistory == null) {
return;
}
for(FeedItem item : event.items) {
for (FeedItem item : event.items) {
int pos = FeedItemUtil.indexOfItemWithId(playbackHistory, item.getId());
if(pos >= 0) {
if (pos >= 0) {
loadItems();
return;
}
@ -196,7 +193,7 @@ public class PlaybackHistoryFragment extends ListFragment {
};
private void loadItems() {
if(disposable != null) {
if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(this::loadData)

View File

@ -16,6 +16,7 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.core.view.MenuItemCompat;
import androidx.fragment.app.Fragment;
@ -283,24 +284,7 @@ public class QueueFragment extends Fragment {
super.onCreateOptionsMenu(menu, inflater);
if (queue != null) {
inflater.inflate(R.menu.queue, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem);
sv.setQueryHint(getString(R.string.search_label));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s));
return true;
}
@Override
public boolean onQueryTextChange(String s) {
return false;
}
});
MenuItemUtils.setupSearchItem(menu, (MainActivity) getActivity(), 0);
MenuItemUtils.refreshLockItem(getActivity(), menu);
// Show Lock Item only if queue is sorted manually
@ -495,9 +479,8 @@ public class QueueFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.queue_label);
View root = inflater.inflate(R.layout.queue_fragment, container, false);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
infoBar = root.findViewById(R.id.info_bar);
recyclerView = root.findViewById(R.id.recyclerView);
RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();

View File

@ -16,7 +16,6 @@ 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;
@ -103,9 +102,8 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
@Override
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);
((AppCompatActivity) getActivity()).setSupportActionBar(layout.findViewById(R.id.toolbar));
ListView listView = layout.findViewById(R.id.listview);
progressBar = layout.findViewById(R.id.progressBar);
searchAdapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, true, true);
@ -140,10 +138,12 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
@Override
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);
final SearchView sv = new SearchView(getActivity());
inflater.inflate(R.menu.search, menu);
MenuItem item = menu.findItem(R.id.action_search);
item.expandActionView();
final SearchView sv = (SearchView) item.getActionView();
sv.setQueryHint(getString(R.string.search_label));
sv.clearFocus();
sv.setQuery(getArguments().getString(ARG_QUERY), false);
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
@ -159,7 +159,18 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
return false;
}
});
MenuItemCompat.setActionView(item, sv);
item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
getFragmentManager().popBackStack();
return true;
}
});
}
@Subscribe

View File

@ -6,6 +6,7 @@ import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
@ -85,6 +86,7 @@ public class SubscriptionFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_subscriptions, container, false);
((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid);
subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, 3));
registerForContextMenu(subscriptionGridLayout);
@ -160,10 +162,6 @@ public class SubscriptionFragment extends Fragment {
((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment());
}
});
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.subscriptions_label);
}
}
@Override

View File

@ -1,18 +1,17 @@
package de.danoeh.antennapod.fragment.gpodnet;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import com.google.android.material.tabs.TabLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.material.tabs.TabLayout;
import de.danoeh.antennapod.R;
/**
@ -20,49 +19,25 @@ import de.danoeh.antennapod.R;
*/
public class GpodnetMainFragment extends Fragment {
private static final String TAG = "GpodnetMainFragment";
private static final String PREF_LAST_TAB_POSITION = "tab_position";
private TabLayout tabLayout;
private ViewPager viewPager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.pager_fragment, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
toolbar.setTitle(R.string.gpodnet_main_label);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
viewPager = root.findViewById(R.id.viewpager);
ViewPager viewPager = root.findViewById(R.id.viewpager);
GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager(), getResources());
viewPager.setAdapter(pagerAdapter);
// Give the TabLayout the ViewPager
tabLayout = root.findViewById(R.id.sliding_tabs);
TabLayout tabLayout = root.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
return root;
}
@Override
public void onPause() {
super.onPause();
// save our tab selection
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(PREF_LAST_TAB_POSITION, tabLayout.getSelectedTabPosition());
editor.apply();
}
@Override
public void onStart() {
super.onStart();
// restore our last position
SharedPreferences prefs = getActivity().getSharedPreferences(TAG, Context.MODE_PRIVATE);
int lastPosition = prefs.getInt(PREF_LAST_TAB_POSITION, 0);
viewPager.setCurrentItem(lastPosition);
}
public class GpodnetPagerAdapter extends FragmentPagerAdapter {
@ -80,13 +55,19 @@ public class GpodnetMainFragment extends Fragment {
@Override
public Fragment getItem(int i) {
Bundle arguments = new Bundle();
arguments.putBoolean(PodcastListFragment.ARGUMENT_HIDE_TOOLBAR, true);
switch (i) {
case POS_TAGS:
return new TagListFragment();
case POS_TOPLIST:
return new PodcastTopListFragment();
PodcastListFragment topListFragment = new PodcastTopListFragment();
topListFragment.setArguments(arguments);
return topListFragment;
case POS_SUGGESTIONS:
return new SuggestionListFragment();
PodcastListFragment suggestionsFragment = new SuggestionListFragment();
suggestionsFragment.setArguments(arguments);
return suggestionsFragment;
default:
return null;
}

View File

@ -4,6 +4,8 @@ import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.core.view.MenuItemCompat;
import androidx.appcompat.widget.SearchView;
@ -34,7 +36,7 @@ import de.danoeh.antennapod.menuhandler.MenuItemUtils;
* Displays a list of GPodnetPodcast-Objects in a GridView
*/
public abstract class PodcastListFragment extends Fragment {
public static final String ARGUMENT_HIDE_TOOLBAR = "hideToolbar";
private static final String TAG = "PodcastListFragment";
private GridView gridView;
@ -76,6 +78,13 @@ public abstract class PodcastListFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.gpodnet_podcast_list, container, false);
Toolbar toolbar = root.findViewById(R.id.toolbar);
if (getArguments() == null || !getArguments().getBoolean(ARGUMENT_HIDE_TOOLBAR, false)) {
toolbar.setTitle(R.string.gpodnet_main_label);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
} else {
toolbar.setVisibility(View.GONE);
}
gridView = root.findViewById(R.id.gridView);
progressBar = root.findViewById(R.id.progressBar);

View File

@ -24,8 +24,6 @@ import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
public class TagListFragment extends ListFragment {
private static final String TAG = "TagListFragment";
private static final int COUNT = 50;
@Override
@ -72,12 +70,6 @@ public class TagListFragment extends ListFragment {
startLoadTask();
}
@Override
public void onResume() {
super.onResume();
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.add_feed_label);
}
@Override
public void onDestroyView() {
super.onDestroyView();

View File

@ -49,6 +49,8 @@ public class StatisticsFragment extends Fragment {
tabLayout = rootView.findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
rootView.findViewById(R.id.toolbar).setVisibility(View.GONE);
return rootView;
}

View File

@ -4,7 +4,11 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.widget.SearchView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.fragment.SearchFragment;
/**
* Utilities for menu items
@ -26,4 +30,40 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte
ta.recycle();
}
public static void setupSearchItem(Menu menu, MainActivity activity, long feedId) {
MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView sv = (SearchView) searchItem.getActionView();
sv.setQueryHint(activity.getString(R.string.search_label));
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
activity.loadChildFragment(SearchFragment.newInstance(s, feedId));
searchItem.collapseActionView();
return true;
}
@Override
public boolean onQueryTextChange(String s) {
return false;
}
});
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
for (int i = 0; i < menu.size(); i++) {
if (menu.getItem(i).getItemId() != searchItem.getItemId()) {
menu.getItem(i).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
}
}
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
activity.invalidateOptionsMenu();
return true;
}
});
}
}

View File

@ -0,0 +1,74 @@
package de.danoeh.antennapod.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChildHelper;
/**
* ListView that can be wrapped in NestedScrollView
* Based on https://stackoverflow.com/a/34920961.
*/
public class NestedScrollingListView extends ListView implements NestedScrollingChild {
private final NestedScrollingChildHelper nestedScrollingChildHelper;
public NestedScrollingListView(Context context) {
super(context);
nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
public NestedScrollingListView(Context context, AttributeSet attrs) {
super(context, attrs);
nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
nestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean isNestedScrollingEnabled() {
return nestedScrollingChildHelper.isNestedScrollingEnabled();
}
@Override
public boolean startNestedScroll(int axes) {
return nestedScrollingChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
nestedScrollingChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return nestedScrollingChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow) {
return nestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return nestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
}

View File

@ -0,0 +1,50 @@
package de.danoeh.antennapod.view;
import android.content.Context;
import android.graphics.PorterDuff;
import android.view.ContextThemeWrapper;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.ViewCompat;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import de.danoeh.antennapod.R;
public abstract class ToolbarIconTintManager implements AppBarLayout.OnOffsetChangedListener {
private final Context context;
private final CollapsingToolbarLayout collapsingToolbar;
private final Toolbar toolbar;
private boolean isTinted = false;
public ToolbarIconTintManager(Context context, Toolbar toolbar, CollapsingToolbarLayout collapsingToolbar) {
this.context = context;
this.collapsingToolbar = collapsingToolbar;
this.toolbar = toolbar;
}
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
boolean tint = (collapsingToolbar.getHeight() + offset) > (2 * ViewCompat.getMinimumHeight(collapsingToolbar));
if (isTinted != tint) {
isTinted = tint;
updateTint();
}
}
public void updateTint() {
if (isTinted) {
doTint(new ContextThemeWrapper(context, R.style.Theme_AntennaPod_Dark));
toolbar.getNavigationIcon().setColorFilter(0xffffffff, PorterDuff.Mode.SRC_ATOP);
toolbar.getOverflowIcon().setColorFilter(0xffffffff, PorterDuff.Mode.SRC_ATOP);
} else {
doTint(context);
toolbar.getNavigationIcon().clearColorFilter();
toolbar.getOverflowIcon().clearColorFilter();
}
}
/**
* View expansion was changed. Icons need to be tinted
* @param themedContext ContextThemeWrapper with dark theme while expanded
*/
protected abstract void doTint(Context themedContext);
}

View File

@ -1,182 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
android:layout_height="match_parent" android:layout_width="match_parent"
android:orientation="vertical">
<LinearLayout
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusableInTouchMode="true"
android:padding="8dp">
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:title="@string/add_feed_label"
android:id="@+id/toolbar"/>
<androidx.cardview.widget.CardView
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
android:elevation="16dp"
android:layout_margin="8dp">
android:orientation="vertical"
android:focusableInTouchMode="true"
android:padding="8dp">
<LinearLayout
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
app:cardCornerRadius="4dp"
android:elevation="16dp"
android:layout_margin="8dp">
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:contentDescription="@string/search_podcast_hint"
app:srcCompat="?attr/action_search"
android:id="@+id/search_icon"
android:scaleType="center"/>
<EditText
android:id="@+id/combinedFeedSearchBox"
android:layout_width="0dp"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="text"
android:imeOptions="actionSearch"
android:importantForAutofill="no"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:hint="@string/search_podcast_hint"
android:background="@null"/>
android:orientation="horizontal">
</LinearLayout>
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:contentDescription="@string/search_podcast_hint"
app:srcCompat="?attr/action_search"
android:id="@+id/search_icon"
android:scaleType="center"/>
</androidx.cardview.widget.CardView>
<EditText
android:id="@+id/combinedFeedSearchBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="text"
android:imeOptions="actionSearch"
android:importantForAutofill="no"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:hint="@string/search_podcast_hint"
android:background="@null"/>
<fragment
android:id="@+id/quickFeedDiscovery"
android:name="de.danoeh.antennapod.fragment.QuickFeedDiscoveryFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"/>
</LinearLayout>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
android:elevation="8dp"
android:layout_margin="8dp">
</androidx.cardview.widget.CardView>
<LinearLayout
<fragment
android:id="@+id/quickFeedDiscovery"
android:name="de.danoeh.antennapod.fragment.QuickFeedDiscoveryFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
android:layout_margin="8dp"/>
<TextView
android:id="@+id/txtvFeedurl"
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
android:elevation="8dp"
android:layout_margin="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/txtvfeedurl_label"
android:textSize="18sp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textColor="?android:attr/textColorPrimary"/>
android:padding="16dp"
android:orientation="vertical">
<EditText
android:id="@+id/etxtFeedurl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cursorVisible="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="@string/etxtFeedurlHint"
android:inputType="textUri"/>
<TextView
android:id="@+id/txtvFeedurl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/txtvfeedurl_label"
android:textSize="18sp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textColor="?android:attr/textColorPrimary"/>
<Button
android:id="@+id/butConfirm"
<EditText
android:id="@+id/etxtFeedurl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cursorVisible="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="@string/etxtFeedurlHint"
android:inputType="textUri"/>
<Button
android:id="@+id/butConfirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
style="?android:attr/buttonBarButtonStyle"
android:text="@string/confirm_label"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
android:elevation="8dp"
android:layout_margin="8dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
style="?android:attr/buttonBarButtonStyle"
android:text="@string/confirm_label"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
android:elevation="8dp"
android:layout_margin="8dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:layout_gravity="center_horizontal"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/advanced_search"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="8dp"
android:background="?android:attr/selectableItemBackground">
android:layout_gravity="center_horizontal"
android:orientation="horizontal">
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:contentDescription="@string/advanced_search"
app:srcCompat="?attr/action_search"
android:scaleType="center"
android:layout_marginBottom="4dp"/>
<TextView
android:layout_width="match_parent"
<LinearLayout
android:id="@+id/advanced_search"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:text="@string/advanced_search"
android:textAlignment="center"
android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="8dp"
android:background="?android:attr/selectableItemBackground">
<LinearLayout
android:id="@+id/btn_opml_import"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="8dp"
android:background="?android:attr/selectableItemBackground">
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:contentDescription="@string/advanced_search"
app:srcCompat="?attr/action_search"
android:scaleType="center"
android:layout_marginBottom="4dp"/>
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:contentDescription="@string/opml_import_label"
app:srcCompat="?attr/av_download"
android:scaleType="center"
android:layout_marginBottom="4dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/advanced_search"
android:textAlignment="center"
android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
<LinearLayout
android:id="@+id/btn_opml_import"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:text="@string/opml_import_label"
android:textAlignment="center"
android:textColor="?android:attr/textColorPrimary"/>
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="8dp"
android:background="?android:attr/selectableItemBackground">
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:contentDescription="@string/opml_import_label"
app:srcCompat="?attr/av_download"
android:scaleType="center"
android:layout_marginBottom="4dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/opml_import_label"
android:textAlignment="center"
android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -4,17 +4,27 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
android:layout_alignParentTop="true"
app:navigationIcon="?homeAsUpIndicator"
android:id="@+id/toolbar"/>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_below="@id/toolbar"
android:layout_marginTop="0dp" />
<com.leinardi.android.speeddial.SpeedDialOverlayLayout
android:id="@+id/fabSDOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:layout_below="@id/toolbar" />
<!-- The FAB SpeedDial
1. MUST be placed at the bottom of the layout xml to ensure it is at the front,
clickable on Pre-Lollipop devices (that do not support elevation).

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/imgvBackground"
style="@style/BigBlurryBackground"
android:layout_width="match_parent"
android:layout_height="256dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.6"/>
<include layout="@layout/feeditemlist_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.6" />
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
android:layout_alignParentTop="true"
android:id="@+id/toolbar"
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<de.danoeh.antennapod.view.NestedScrollingListView
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@android:id/list" />
<ProgressBar
android:id="@+id/progLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateOnly="true"
android:visibility="gone"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,132 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent">
<include layout="@layout/feeditemlist_header" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbarStyle="outsideOverlay"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp"
android:clipToPadding="false">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/imgvBackground"
style="@style/BigBlurryBackground"
android:layout_width="match_parent"
android:layout_height="256dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.6"/>
<include layout="@layout/feeditemlist_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.6"/>
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:navigationIcon="?homeAsUpIndicator"
android:layout_alignParentTop="true"
android:id="@+id/toolbar"
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="outsideOverlay"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp"
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.gridlayout.widget.GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:columnCount="2"
app:rowCount="3">
android:orientation="vertical">
<TextView
<TextView
style="@style/AntennaPod.TextView.Heading"
android:id="@+id/lblAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_row="0"
app:layout_column="0"
android:lines="1"
android:text="@string/author_label"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:textColor="?android:attr/textColorPrimary"
tools:background="@android:color/holo_red_light"/>
<TextView
<TextView
android:id="@+id/txtvDetailsAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
app:layout_row="0"
app:layout_column="1"
tools:text="Daniel Oeh"
tools:background="@android:color/holo_green_dark"/>
<TextView
<TextView
style="@style/AntennaPod.TextView.Heading"
android:id="@+id/lblLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_row="1"
app:layout_column="0"
android:lines="1"
android:text="@string/language_label"
android:textColor="?android:attr/textColorPrimary"
tools:background="@android:color/holo_red_light"/>
<TextView
<TextView
android:id="@+id/txtvLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
app:layout_row="1"
app:layout_column="1"
tools:text="English"
tools:background="@android:color/holo_green_dark"/>
<TextView
<TextView
style="@style/AntennaPod.TextView.Heading"
android:id="@+id/lblUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
app:layout_row="2"
app:layout_column="0"
android:lines="1"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp"
android:text="@string/url_label"
android:textColor="?android:attr/textColorPrimary"
tools:background="@android:color/holo_red_light"/>
<TextView
<TextView
android:id="@+id/txtvUrl"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:background="?attr/selectableItemBackground"
app:layout_row="2"
app:layout_column="1"
app:layout_gravity="fill"
android:maxLines="4"
android:paddingTop="4dp"
android:paddingBottom="4dp"
tools:text="http://www.example.com/feed"
tools:background="@android:color/holo_green_dark"/>
</androidx.gridlayout.widget.GridLayout>
<TextView
style="@style/AntennaPod.TextView.Heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="8dp"
android:text="@string/description_label"/>
<TextView
style="@style/AntennaPod.TextView.Heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/description_label"/>
<TextView
android:id="@+id/txtvDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textIsSelectable="true"
android:text="@string/design_time_lorem_ipsum"
tools:background="@android:color/holo_green_dark"/>
android:id="@+id/txtvDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:text="@string/design_time_lorem_ipsum"
tools:background="@android:color/holo_green_dark"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</ScrollView>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -18,7 +18,6 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<ImageView

View File

@ -1,6 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:navigationIcon="?homeAsUpIndicator"
android:id="@+id/toolbar"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -1,137 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/feed_image_bg"
tools:context="de.danoeh.antennapod.activity.MainActivity"
tools:background="@android:color/darker_gray">
<ImageView
android:id="@+id/imgvBackground"
style="@style/BigBlurryBackground"
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/feeditemlist_header_height" />
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/imgvCover"
android:layout_width="@dimen/thumbnail_length_onlinefeedview"
android:layout_height="@dimen/thumbnail_length_onlinefeedview"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_centerVertical="true"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:contentDescription="@string/cover_label"
tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:layout_marginBottom="16dp"
android:gravity="center_vertical">
<ImageButton
android:id="@+id/butShowInfo"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/show_info_label"
android:src="@drawable/ic_info_white_24dp"
tools:background="@android:color/holo_green_dark"/>
<ImageView
android:id="@+id/imgvCover"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/cover_label"
tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
<ImageButton
android:id="@+id/butShowSettings"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/show_feed_settings_label"
android:src="@drawable/ic_settings_white_24dp"
tools:background="@android:color/holo_green_dark"
android:layout_below="@+id/butShowInfo"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.Heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:shadowColor="@color/black"
android:shadowRadius="2"
android:textColor="@color/white"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark"/>
<TextView
android:id="@+id/txtvAuthor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:shadowColor="@color/black"
android:shadowRadius="2"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
tools:text="Podcast author"
tools:background="@android:color/holo_green_dark"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:id="@+id/butShowInfo"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/show_info_label"
android:src="@drawable/ic_info_white_24dp"
tools:background="@android:color/holo_green_dark"
android:layout_marginLeft="-8dp"
android:layout_marginStart="-8dp"
android:scaleType="fitXY"
android:padding="8dp"/>
<ImageButton
android:id="@+id/butShowSettings"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/show_feed_settings_label"
android:src="@drawable/ic_settings_white_24dp"
tools:background="@android:color/holo_green_dark"
android:scaleType="fitXY"
android:padding="8dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.Heading"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_toLeftOf="@id/butShowInfo"
android:layout_toStartOf="@id/butShowInfo"
android:layout_toRightOf="@id/imgvCover"
android:layout_toEndOf="@id/imgvCover"
android:ellipsize="end"
android:maxLines="2"
android:shadowColor="@color/black"
android:shadowRadius="3"
android:textColor="@color/white"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark" />
<TextView
android:id="@+id/txtvAuthor"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_below="@id/txtvTitle"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_toLeftOf="@id/butShowSettings"
android:layout_toStartOf="@id/butShowSettings"
android:layout_toRightOf="@id/imgvCover"
android:layout_toEndOf="@id/imgvCover"
android:ellipsize="end"
android:lines="1"
android:shadowColor="@color/black"
android:shadowRadius="3"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
tools:text="Podcast author"
tools:background="@android:color/holo_green_dark"/>
android:id="@+id/txtvInformation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:background="?attr/colorPrimary"
android:visibility="gone"
android:gravity="center"
tools:visibility="visible"
tools:text="(i) Information"/>
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/txtvFailure"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/imgvBackground"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:background="@color/download_failed_red"
android:gravity="center"
android:textColor="@color/white"
android:visibility="gone"
android:text="@string/refresh_failed_msg"
tools:text="(!) Last refresh failed"
/>
<TextView
android:id="@+id/txtvInformation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/imgvBackground"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:gravity="center"
android:visibility="gone"
tools:text="(i) Information"
/>
</RelativeLayout>
android:id="@+id/txtvFailure"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:background="@color/download_failed_red"
android:gravity="center"
android:textColor="@color/white"
android:visibility="gone"
android:text="@string/refresh_failed_msg"
tools:visibility="visible"
tools:text="(!) Last refresh failed"/>
</LinearLayout>

View File

@ -1,10 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/feeditemlist_header" />
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:title="@string/feed_settings_label"
app:navigationIcon="?homeAsUpIndicator"
android:elevation="4dp"
android:id="@+id/toolbar"/>
<FrameLayout
android:layout_width="match_parent"

View File

@ -1,10 +1,21 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
android:layout_alignParentTop="true"
app:navigationIcon="?homeAsUpIndicator"
app:title="@string/discover"
android:id="@+id/toolbar"/>
<GridView
android:layout_below="@id/toolbar"
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -1,28 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
android:layout_alignParentTop="true"
app:title="@string/subscriptions_label"
android:id="@+id/toolbar"/>
<GridView
android:layout_below="@id/toolbar"
android:id="@+id/subscriptions_grid"
android:layout_width="match_parent"
android:numColumns="3"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:paddingBottom="88dp"
android:clipToPadding="false"/>
<GridView
android:id="@+id/subscriptions_grid"
android:layout_width="match_parent"
android:numColumns="3"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:paddingBottom="88dp"
android:clipToPadding="false">
</GridView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/subscriptions_add"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_margin="16dp"
android:layout_gravity="bottom|end"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/add_feed_label"
android:src="@drawable/ic_add_white_24dp"
/>
</FrameLayout>
android:src="@drawable/ic_add_white_24dp"/>
</RelativeLayout>

View File

@ -1,10 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:navigationIcon="?homeAsUpIndicator"
android:id="@+id/toolbar"/>
<GridView
android:id="@+id/gridView"
android:layout_width="match_parent"
@ -18,6 +27,7 @@
android:paddingTop="@dimen/list_vertical_padding"
android:stretchMode="columnWidth"
android:verticalSpacing="8dp"
android:layout_below="@id/toolbar"
tools:listitem="@layout/gpodnet_podcast_listitem" />
<ProgressBar

View File

@ -19,28 +19,12 @@
tools:layout_height="64dp"
tools:background="@android:color/holo_green_light" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
tools:background="@android:color/holo_blue_dark" />
<View
android:id="@+id/shadow"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_below="@id/toolbar"
android:background="@drawable/shadow" />
<FrameLayout
android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_above="@id/playerFragment"
android:layout_below="@id/toolbar"
android:layout_alignParentTop="true"
android:foreground="?android:windowContentOverlay"
tools:background="@android:color/holo_red_dark" />

View File

@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
@ -30,7 +30,77 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/feeditemlist_header"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/feed_image_bg">
<ImageView
android:id="@+id/imgvBackground"
style="@style/BigBlurryBackground"
android:layout_width="match_parent"
android:layout_height="@dimen/feeditemlist_header_height" />
<ImageView
android:id="@+id/imgvCover"
android:layout_width="@dimen/thumbnail_length_onlinefeedview"
android:layout_height="@dimen/thumbnail_length_onlinefeedview"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_centerVertical="true"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:contentDescription="@string/cover_label"
tools:src="@drawable/ic_antenna"/>
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.Heading"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_toRightOf="@id/imgvCover"
android:layout_toEndOf="@id/imgvCover"
android:ellipsize="end"
android:maxLines="2"
android:shadowColor="@color/black"
android:shadowRadius="3"
android:textColor="@color/white"
tools:text="Podcast title" />
<TextView
android:id="@+id/txtvAuthor"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_below="@id/txtvTitle"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_toRightOf="@id/imgvCover"
android:layout_toEndOf="@id/imgvCover"
android:ellipsize="end"
android:lines="1"
android:shadowColor="@color/black"
android:shadowRadius="3"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
tools:text="Podcast author"/>
</RelativeLayout>
<Spinner
android:id="@+id/spinnerAlternateUrls"

View File

@ -1,22 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:navigationIcon="?homeAsUpIndicator"
android:id="@+id/toolbar"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabMode="fixed" />
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1" />
</LinearLayout>
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -1,17 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
android:layout_alignParentTop="true"
app:title="@string/queue_label"
android:id="@+id/toolbar"/>
<TextView
android:layout_below="@id/toolbar"
android:id="@+id/info_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:gravity="center"
android:textSize="12sp"
android:text=""/>
android:layout_marginTop="-8dp"
android:layout_marginLeft="72dp"
android:layout_marginStart="72dp"
android:layout_marginBottom="4dp"
tools:text="12 Episodes - Time remaining: 12 hours"/>
<View
android:id="@+id/divider"

View File

@ -1,17 +1,30 @@
<?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">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:navigationIcon="?homeAsUpIndicator"
app:title="@string/search_label"
android:id="@+id/toolbar"/>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
android:layout_centerInParent="true"
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" />
</FrameLayout>
android:layout_below="@id/toolbar"
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
android:layout_alignParentTop="true"
android:id="@+id/toolbar"/>
<ListView android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
android:id="@android:id/list"
android:clipToPadding="false"/>
<ProgressBar
android:id="@+id/progLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateOnly="true"
android:visibility="gone"/>
</RelativeLayout>

View File

@ -1,14 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto">
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/episode_actions"
android:menuCategory="container"
android:title="@string/multi_select"
android:icon="?attr/checkbox_multiple"
custom:showAsAction="always">
</item>
android:showAsAction="ifRoom" />
</menu>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_search"
android:icon="?attr/action_search"
app:showAsAction="collapseActionView|always"
app:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/search_label"/>
</menu>

View File

@ -31,6 +31,16 @@ public class FastBlurTransformation extends BitmapTransformation {
return result;
}
@Override
public boolean equals(Object o) {
return o instanceof FastBlurTransformation;
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
messageDigest.update(TAG.getBytes());
}
private static Bitmap fastBlur(Bitmap bitmap, int radius) {
// Stack Blur v1.0 from
@ -269,9 +279,4 @@ public class FastBlurTransformation extends BitmapTransformation {
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return bitmap;
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
messageDigest.update(TAG.getBytes());
}
}
}

View File

@ -13,7 +13,7 @@ public class MenuItemUtils {
/**
* Changes the appearance of a MenuItem depending on whether the given UpdateRefreshMenuItemChecker
* is refreshing or not. If it returns true, the menu item will be replaced by an indeterminate progress
* bar, otherwise nothing will happen.
* bar, otherwise the progress bar will be hidden.
*
* @param menu The menu that the MenuItem belongs to
* @param resId The id of the MenuItem
@ -22,11 +22,12 @@ public class MenuItemUtils {
*/
public static boolean updateRefreshMenuItem(Menu menu, int resId, UpdateRefreshMenuItemChecker checker) {
// expand actionview if feeds are being downloaded, collapse otherwise
MenuItem refreshItem = menu.findItem(resId);
if (checker.isRefreshing()) {
MenuItem refreshItem = menu.findItem(resId);
refreshItem.setActionView(R.layout.refresh_action_view);
return true;
} else {
refreshItem.setActionView(null);
return false;
}
}

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:indeterminateOnly="true">
</ProgressBar>
<ProgressBar
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end"
android:padding="8dp"
android:indeterminateOnly="true"/>