summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorByteHamster <ByteHamster@users.noreply.github.com>2024-09-10 20:59:18 +0200
committerGitHub <noreply@github.com>2024-09-10 20:59:18 +0200
commit6cbc58ba78caf311a706823a8784ef4453743024 (patch)
tree7c75a2fcf5e0a267460c1988c8d3f10c08a13621
parent60f6e175a8dc3a6b67655c920a9f70aceeb5b7db (diff)
downloadAntennaPod-6cbc58ba78caf311a706823a8784ef4453743024.zip
Bottom navigation (#7176)
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java200
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/episodeslist/HorizontalItemViewHolder.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/BottomNavigationMoreAdapter.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/DrawerPreferencesDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavListAdapter.java57
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavigationNames.java106
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/view/LiftOnScrollListener.java7
-rw-r--r--app/src/main/res/layout-sw720dp/main.xml79
-rw-r--r--app/src/main/res/layout/addfeed.xml3
-rw-r--r--app/src/main/res/layout/audioplayer_fragment.xml5
-rw-r--r--app/src/main/res/layout/bottom_navigation_more_listitem.xml33
-rw-r--r--app/src/main/res/layout/horizontal_itemlist_item.xml7
-rw-r--r--app/src/main/res/layout/main.xml68
-rw-r--r--app/src/main/res/values/ids.xml12
-rw-r--r--build.gradle2
-rw-r--r--storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java9
-rw-r--r--ui/common/src/main/res/drawable/dots_vertical.xml13
-rw-r--r--ui/common/src/main/res/drawable/ic_pencil.xml13
-rw-r--r--ui/common/src/main/res/values-v23/styles.xml2
-rw-r--r--ui/common/src/main/res/values-v27/styles.xml2
-rw-r--r--ui/common/src/main/res/values/colors.xml3
-rw-r--r--ui/common/src/main/res/values/styles.xml7
-rw-r--r--ui/i18n/src/main/res/values/strings.xml6
-rw-r--r--ui/preferences/src/main/res/xml/preferences_user_interface.xml10
26 files changed, 520 insertions, 171 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
index 57385f62a..d9e1db18d 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
@@ -52,6 +52,7 @@ public class NavigationDrawerTest {
EspressoTestUtils.clearPreferences();
EspressoTestUtils.clearDatabase();
+ UserPreferences.setBottomNavigationEnabled(false);
}
@After
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index 15fa614a4..79ee013bf 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -10,14 +10,19 @@ import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
+import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.view.menu.MenuBuilder;
+import androidx.appcompat.widget.ListPopupWindow;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
@@ -32,48 +37,62 @@ import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import com.bumptech.glide.Glide;
import com.google.android.material.appbar.MaterialToolbar;
+import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.google.android.material.navigation.NavigationBarView;
import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.net.download.service.feed.FeedUpdateManagerImpl;
-import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
-import de.danoeh.antennapod.net.sync.serviceinterface.SynchronizationQueueSink;
-import de.danoeh.antennapod.ui.appstartintent.MediaButtonStarter;
-import de.danoeh.antennapod.ui.common.ThemeSwitcher;
-import de.danoeh.antennapod.ui.screen.rating.RatingDialogManager;
import de.danoeh.antennapod.event.EpisodeDownloadEvent;
import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.event.MessageEvent;
-import de.danoeh.antennapod.ui.screen.AddFeedFragment;
-import de.danoeh.antennapod.ui.screen.AllEpisodesFragment;
-import de.danoeh.antennapod.ui.screen.playback.audio.AudioPlayerFragment;
-import de.danoeh.antennapod.ui.screen.download.CompletedDownloadsFragment;
-import de.danoeh.antennapod.ui.screen.download.DownloadLogFragment;
-import de.danoeh.antennapod.ui.screen.feed.FeedItemlistFragment;
-import de.danoeh.antennapod.ui.screen.InboxFragment;
-import de.danoeh.antennapod.ui.screen.drawer.NavDrawerFragment;
-import de.danoeh.antennapod.ui.screen.PlaybackHistoryFragment;
-import de.danoeh.antennapod.ui.screen.queue.QueueFragment;
-import de.danoeh.antennapod.ui.screen.SearchFragment;
-import de.danoeh.antennapod.ui.screen.subscriptions.SubscriptionFragment;
-import de.danoeh.antennapod.ui.TransitionEffect;
import de.danoeh.antennapod.model.download.DownloadStatus;
+import de.danoeh.antennapod.model.feed.FeedItemFilter;
+import de.danoeh.antennapod.net.download.service.feed.FeedUpdateManagerImpl;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
+import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
+import de.danoeh.antennapod.net.sync.serviceinterface.SynchronizationQueueSink;
import de.danoeh.antennapod.playback.cast.CastEnabledActivity;
+import de.danoeh.antennapod.storage.database.DBReader;
import de.danoeh.antennapod.storage.importexport.AutomaticDatabaseExportWorker;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
+import de.danoeh.antennapod.ui.TransitionEffect;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
+import de.danoeh.antennapod.ui.appstartintent.MediaButtonStarter;
+import de.danoeh.antennapod.ui.common.ThemeSwitcher;
import de.danoeh.antennapod.ui.common.ThemeUtils;
import de.danoeh.antennapod.ui.discovery.DiscoveryFragment;
+import de.danoeh.antennapod.ui.screen.AddFeedFragment;
+import de.danoeh.antennapod.ui.screen.AllEpisodesFragment;
+import de.danoeh.antennapod.ui.screen.InboxFragment;
+import de.danoeh.antennapod.ui.screen.PlaybackHistoryFragment;
+import de.danoeh.antennapod.ui.screen.SearchFragment;
+import de.danoeh.antennapod.ui.screen.download.CompletedDownloadsFragment;
+import de.danoeh.antennapod.ui.screen.download.DownloadLogFragment;
+import de.danoeh.antennapod.ui.screen.drawer.BottomNavigationMoreAdapter;
+import de.danoeh.antennapod.ui.screen.drawer.DrawerPreferencesDialog;
+import de.danoeh.antennapod.ui.screen.drawer.NavDrawerFragment;
+import de.danoeh.antennapod.ui.screen.drawer.NavListAdapter;
+import de.danoeh.antennapod.ui.screen.drawer.NavigationNames;
+import de.danoeh.antennapod.ui.screen.feed.FeedItemlistFragment;
import de.danoeh.antennapod.ui.screen.home.HomeFragment;
+import de.danoeh.antennapod.ui.screen.playback.audio.AudioPlayerFragment;
+import de.danoeh.antennapod.ui.screen.preferences.PreferenceActivity;
+import de.danoeh.antennapod.ui.screen.queue.QueueFragment;
+import de.danoeh.antennapod.ui.screen.rating.RatingDialogManager;
+import de.danoeh.antennapod.ui.screen.subscriptions.SubscriptionFragment;
import de.danoeh.antennapod.ui.view.LockableBottomSheetBehavior;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -94,11 +113,12 @@ public class MainActivity extends CastEnabledActivity {
private @Nullable DrawerLayout drawerLayout;
private @Nullable ActionBarDrawerToggle drawerToggle;
+ private BottomNavigationView bottomNavigationView;
private View navDrawer;
private LockableBottomSheetBehavior sheetBehavior;
private RecyclerView.RecycledViewPool recycledViewPool = new RecyclerView.RecycledViewPool();
private int lastTheme = 0;
- private Insets navigationBarInsets = Insets.NONE;
+ private Insets systemBarInsets = Insets.NONE;
@NonNull
public static Intent getIntentToOpenFeed(@NonNull Context context, long feedId) {
@@ -122,11 +142,24 @@ public class MainActivity extends CastEnabledActivity {
drawerLayout = findViewById(R.id.drawer_layout);
navDrawer = findViewById(R.id.navDrawerFragment);
- setNavDrawerSize();
+ bottomNavigationView = findViewById(R.id.bottomNavigationView);
+ if (UserPreferences.isBottomNavigationEnabled()) {
+ buildBottomNavigationMenu();
+ if (drawerLayout == null) { // Tablet mode
+ navDrawer.setVisibility(View.GONE);
+ } else {
+ drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ }
+ drawerLayout = null;
+ } else {
+ bottomNavigationView.setVisibility(View.GONE);
+ bottomNavigationView = null;
+ setNavDrawerSize();
+ }
// Consume navigation bar insets - we apply them in setPlayerVisible()
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main_view), (v, insets) -> {
- navigationBarInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars());
+ systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
updateInsets();
return new WindowInsetsCompat.Builder(insets)
.setInsets(WindowInsetsCompat.Type.navigationBars(), Insets.NONE)
@@ -320,28 +353,35 @@ public class MainActivity extends CastEnabledActivity {
private void updateInsets() {
setPlayerVisible(findViewById(R.id.audioplayerFragment).getVisibility() == View.VISIBLE);
- int playerHeight = (int) getResources().getDimension(R.dimen.external_player_height);
- sheetBehavior.setPeekHeight(playerHeight + navigationBarInsets.bottom);
}
public void setPlayerVisible(boolean visible) {
getBottomSheet().setLocked(!visible);
+ findViewById(R.id.audioplayerFragment).setVisibility(visible ? View.VISIBLE : View.GONE);
if (visible) {
bottomSheetCallback.onStateChanged(null, getBottomSheet().getState()); // Update toolbar visibility
} else {
getBottomSheet().setState(BottomSheetBehavior.STATE_COLLAPSED);
}
- FragmentContainerView mainView = findViewById(R.id.main_view);
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mainView.getLayoutParams();
+ View bottomPaddingView = findViewById(R.id.bottom_padding);
+ ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) bottomPaddingView.getLayoutParams();
+ params.height = systemBarInsets.bottom;
+ bottomPaddingView.setLayoutParams(params);
+
int externalPlayerHeight = (int) getResources().getDimension(R.dimen.external_player_height);
- params.setMargins(navigationBarInsets.left, 0, navigationBarInsets.right,
- navigationBarInsets.bottom + (visible ? externalPlayerHeight : 0));
+ FragmentContainerView mainView = findViewById(R.id.main_content_view);
+ params = (ViewGroup.MarginLayoutParams) mainView.getLayoutParams();
+ params.setMargins(systemBarInsets.left, 0, systemBarInsets.right, (visible ? externalPlayerHeight : 0));
mainView.setLayoutParams(params);
+ sheetBehavior.setPeekHeight(externalPlayerHeight);
+ sheetBehavior.setGestureInsetBottomIgnored(true);
+
FragmentContainerView playerView = findViewById(R.id.playerFragment);
ViewGroup.MarginLayoutParams playerParams = (ViewGroup.MarginLayoutParams) playerView.getLayoutParams();
- playerParams.setMargins(navigationBarInsets.left, 0, navigationBarInsets.right, 0);
+ playerParams.setMargins(systemBarInsets.left, 0, systemBarInsets.right, 0);
playerView.setLayoutParams(playerParams);
- findViewById(R.id.audioplayerFragment).setVisibility(visible ? View.VISIBLE : View.GONE);
+ RelativeLayout playerContent = findViewById(R.id.playerContent);
+ playerContent.setPadding(systemBarInsets.left, systemBarInsets.top, systemBarInsets.right, 0);
}
public RecyclerView.RecycledViewPool getRecycledViewPool() {
@@ -393,6 +433,15 @@ public class MainActivity extends CastEnabledActivity {
public void loadFragment(String tag, Bundle args) {
NavDrawerFragment.saveLastNavFragment(this, tag);
+ if (bottomNavigationView != null) {
+ int bottomSelectedItem = NavigationNames.getBottomNavigationItemId(tag);
+ if (bottomNavigationView.getMenu().findItem(bottomSelectedItem) == null) {
+ bottomSelectedItem = R.id.bottom_navigation_more;
+ }
+ bottomNavigationView.setOnItemSelectedListener(null);
+ bottomNavigationView.setSelectedItemId(bottomSelectedItem);
+ bottomNavigationView.setOnItemSelectedListener(bottomItemSelectedListener);
+ }
loadFragment(createFragmentInstance(tag, args));
}
@@ -412,7 +461,7 @@ public class MainActivity extends CastEnabledActivity {
fragmentManager.popBackStack();
}
FragmentTransaction t = fragmentManager.beginTransaction();
- t.replace(R.id.main_view, fragment, MAIN_FRAGMENT_TAG);
+ t.replace(R.id.main_content_view, fragment, MAIN_FRAGMENT_TAG);
fragmentManager.popBackStack();
// TODO: we have to allow state loss here
// since this function can get called from an AsyncTask which
@@ -443,7 +492,7 @@ public class MainActivity extends CastEnabledActivity {
transaction
.hide(getSupportFragmentManager().findFragmentByTag(MAIN_FRAGMENT_TAG))
- .add(R.id.main_view, fragment, MAIN_FRAGMENT_TAG)
+ .add(R.id.main_content_view, fragment, MAIN_FRAGMENT_TAG)
.addToBackStack(null)
.commit();
}
@@ -452,6 +501,85 @@ public class MainActivity extends CastEnabledActivity {
loadChildFragment(fragment, TransitionEffect.NONE);
}
+ private void buildBottomNavigationMenu() {
+ List<String> drawerItems = UserPreferences.getVisibleDrawerItemOrder();
+ drawerItems.remove(NavListAdapter.SUBSCRIPTION_LIST_TAG);
+
+ Menu menu = bottomNavigationView.getMenu();
+ menu.clear();
+ for (int i = 0; i < drawerItems.size() && i < bottomNavigationView.getMaxItemCount() - 1; i++) {
+ String tag = drawerItems.get(i);
+ MenuItem item = menu.add(0, NavigationNames.getBottomNavigationItemId(tag),
+ 0, getString(NavigationNames.getLabel(tag)));
+ item.setIcon(NavigationNames.getDrawable(tag));
+ }
+ MenuItem moreItem = menu.add(0, R.id.bottom_navigation_more, 0, getString(R.string.searchpreference_more));
+ moreItem.setIcon(R.drawable.dots_vertical);
+ bottomNavigationView.setOnItemSelectedListener(bottomItemSelectedListener);
+
+ if (bottomNavigationView.getMenu().findItem(R.id.bottom_navigation_inbox) != null) {
+ Observable.fromCallable(() -> DBReader.getTotalEpisodeCount(new FeedItemFilter(FeedItemFilter.NEW)))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result ->
+ bottomNavigationView.getOrCreateBadge(R.id.bottom_navigation_inbox).setNumber(result),
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+ }
+
+ private final NavigationBarView.OnItemSelectedListener bottomItemSelectedListener = item -> {
+ sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
+ if (item.getItemId() == R.id.bottom_navigation_more) {
+ showBottomNavigationMorePopup();
+ return false;
+ } else {
+ loadFragment(NavigationNames.getBottomNavigationFragmentTag(item.getItemId()), null);
+ return true;
+ }
+ };
+
+ private void showBottomNavigationMorePopup() {
+ List<String> drawerItems = UserPreferences.getVisibleDrawerItemOrder();
+ drawerItems.remove(NavListAdapter.SUBSCRIPTION_LIST_TAG);
+
+ final List<MenuItem> popupMenuItems = new ArrayList<>();
+ for (int i = bottomNavigationView.getMaxItemCount() - 1; i < drawerItems.size(); i++) {
+ String tag = drawerItems.get(i);
+ MenuItem item = new MenuBuilder(this).add(0, NavigationNames.getBottomNavigationItemId(tag),
+ 0, getString(NavigationNames.getLabel(tag)));
+ item.setIcon(NavigationNames.getDrawable(tag));
+ popupMenuItems.add(item);
+ }
+ MenuItem customizeItem = new MenuBuilder(this).add(0, R.id.bottom_navigation_settings,
+ 0, getString(R.string.pref_nav_drawer_items_title));
+ customizeItem.setIcon(R.drawable.ic_pencil);
+ popupMenuItems.add(customizeItem);
+
+ MenuItem settingsItem = new MenuBuilder(this).add(0, R.id.bottom_navigation_settings,
+ 0, getString(R.string.settings_label));
+ settingsItem.setIcon(R.drawable.ic_settings);
+ popupMenuItems.add(settingsItem);
+
+ final ListPopupWindow listPopupWindow = new ListPopupWindow(this);
+ listPopupWindow.setWidth((int) (250 * getResources().getDisplayMetrics().density));
+ listPopupWindow.setAnchorView(bottomNavigationView);
+ listPopupWindow.setAdapter(new BottomNavigationMoreAdapter(this, popupMenuItems));
+ listPopupWindow.setOnItemClickListener((parent, view, position, id) -> {
+ if (position == popupMenuItems.size() - 1) {
+ startActivity(new Intent(this, PreferenceActivity.class));
+ } else if (position == popupMenuItems.size() - 2) {
+ new DrawerPreferencesDialog(this, this::buildBottomNavigationMenu).show();
+ } else {
+ loadFragment(NavigationNames.getBottomNavigationFragmentTag(
+ popupMenuItems.get(position).getItemId()), null);
+ }
+ listPopupWindow.dismiss();
+ });
+ listPopupWindow.setDropDownGravity(Gravity.END | Gravity.BOTTOM);
+ listPopupWindow.setModal(true);
+ listPopupWindow.show();
+ }
+
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
@@ -507,7 +635,9 @@ public class MainActivity extends CastEnabledActivity {
super.onResume();
handleNavIntent();
- if (lastTheme != ThemeSwitcher.getNoTitleTheme(this)) {
+ boolean hasBottomNavigation = bottomNavigationView != null;
+ if (lastTheme != ThemeSwitcher.getNoTitleTheme(this)
+ || hasBottomNavigation != UserPreferences.isBottomNavigationEnabled()) {
finish();
startActivity(new Intent(this, MainActivity.class));
}
@@ -566,7 +696,7 @@ public class MainActivity extends CastEnabledActivity {
String toPage = UserPreferences.getDefaultPage();
if (NavDrawerFragment.getLastNavFragment(this).equals(toPage)
|| UserPreferences.DEFAULT_PAGE_REMEMBER.equals(toPage)) {
- if (UserPreferences.backButtonOpensDrawer() && drawerLayout != null) {
+ if (UserPreferences.backButtonOpensDrawer() && drawerLayout != null && bottomNavigationView == null) {
drawerLayout.openDrawer(navDrawer);
} else {
super.onBackPressed();
@@ -644,7 +774,7 @@ public class MainActivity extends CastEnabledActivity {
public Snackbar showSnackbarAbovePlayer(CharSequence text, int duration) {
Snackbar s;
if (getBottomSheet().getState() == BottomSheetBehavior.STATE_COLLAPSED) {
- s = Snackbar.make(findViewById(R.id.main_view), text, duration);
+ s = Snackbar.make(findViewById(R.id.main_content_view), text, duration);
if (findViewById(R.id.audioplayerFragment).getVisibility() == View.VISIBLE) {
s.setAnchorView(findViewById(R.id.audioplayerFragment));
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/HorizontalItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/HorizontalItemViewHolder.java
index c297725b0..d6942fdbd 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/HorizontalItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/episodeslist/HorizontalItemViewHolder.java
@@ -8,7 +8,6 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
-import com.google.android.material.elevation.SurfaceColors;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.ui.CoverLoader;
@@ -56,8 +55,7 @@ public class HorizontalItemViewHolder extends RecyclerView.ViewHolder {
this.item = item;
card.setAlpha(1.0f);
- float density = activity.getResources().getDisplayMetrics().density;
- card.setCardBackgroundColor(SurfaceColors.getColorForElevation(activity, 1 * density));
+ card.setCardBackgroundColor(ThemeUtils.getColorFromAttr(activity, R.attr.colorSurfaceContainer));
new CoverLoader()
.withUri(ImageResourceUtils.getEpisodeListImageLocation(item))
.withFallbackUri(item.getFeed().getImageUrl())
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/BottomNavigationMoreAdapter.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/BottomNavigationMoreAdapter.java
new file mode 100644
index 000000000..f0553f0a9
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/BottomNavigationMoreAdapter.java
@@ -0,0 +1,35 @@
+package de.danoeh.antennapod.ui.screen.drawer;
+
+import android.content.Context;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+
+import java.util.List;
+
+public class BottomNavigationMoreAdapter extends ArrayAdapter<MenuItem> {
+ private final Context context;
+ private final List<MenuItem> listItems;
+
+ public BottomNavigationMoreAdapter(Context context, List<MenuItem> listItems) {
+ super(context, R.layout.bottom_navigation_more_listitem, listItems);
+ this.context = context;
+ this.listItems = listItems;
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ if (view == null) {
+ view = View.inflate(context, R.layout.bottom_navigation_more_listitem, null);
+ }
+
+ MenuItem item = listItems.get(position);
+ ((ImageView) view.findViewById(R.id.coverImage)).setImageDrawable(item.getIcon());
+ ((TextView) view.findViewById(R.id.titleLabel)).setText(item.getTitle());
+ return view;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/DrawerPreferencesDialog.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/DrawerPreferencesDialog.java
index 12bf673f6..d738d8c8c 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/DrawerPreferencesDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/DrawerPreferencesDialog.java
@@ -35,7 +35,7 @@ public class DrawerPreferencesDialog extends ReorderDialog {
final List<String> drawerItemOrder = UserPreferences.getVisibleDrawerItemOrder();
for (String tag : drawerItemOrder) {
settingsDialogItems.add(new ReorderDialogItem(ReorderDialogItem.ViewType.Section,
- tag, context.getString(NavListAdapter.getLabel(tag))));
+ tag, context.getString(NavigationNames.getLabel(tag))));
}
settingsDialogItems.add(new ReorderDialogItem(ReorderDialogItem.ViewType.Header,
@@ -44,7 +44,7 @@ public class DrawerPreferencesDialog extends ReorderDialog {
final List<String> hiddenDrawerItems = UserPreferences.getHiddenDrawerItems();
for (String sectionTag : hiddenDrawerItems) {
settingsDialogItems.add(new ReorderDialogItem(ReorderDialogItem.ViewType.Section,
- sectionTag, context.getString(NavListAdapter.getLabel(sectionTag))));
+ sectionTag, context.getString(NavigationNames.getLabel(sectionTag))));
}
return settingsDialogItems;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavListAdapter.java
index a4ffb7566..7eaebcdc5 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavListAdapter.java
@@ -14,7 +14,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
-import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.preference.PreferenceManager;
@@ -29,12 +28,8 @@ import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.storage.database.NavDrawerData;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.ui.common.ImagePlaceholder;
-import de.danoeh.antennapod.ui.screen.AddFeedFragment;
-import de.danoeh.antennapod.ui.screen.AllEpisodesFragment;
import de.danoeh.antennapod.ui.screen.InboxFragment;
-import de.danoeh.antennapod.ui.screen.PlaybackHistoryFragment;
import de.danoeh.antennapod.ui.screen.download.CompletedDownloadsFragment;
-import de.danoeh.antennapod.ui.screen.home.HomeFragment;
import de.danoeh.antennapod.ui.screen.preferences.PreferenceActivity;
import de.danoeh.antennapod.ui.screen.queue.QueueFragment;
import de.danoeh.antennapod.ui.screen.subscriptions.SubscriptionFragment;
@@ -100,54 +95,6 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
notifyDataSetChanged();
}
- public static @StringRes int getLabel(String tag) {
- switch (tag) {
- case HomeFragment.TAG:
- return R.string.home_label;
- case QueueFragment.TAG:
- return R.string.queue_label;
- case InboxFragment.TAG:
- return R.string.inbox_label;
- case AllEpisodesFragment.TAG:
- return R.string.episodes_label;
- case SubscriptionFragment.TAG:
- return R.string.subscriptions_label;
- case CompletedDownloadsFragment.TAG:
- return R.string.downloads_label;
- case PlaybackHistoryFragment.TAG:
- return R.string.playback_history_label;
- case AddFeedFragment.TAG:
- return R.string.add_feed_label;
- case NavListAdapter.SUBSCRIPTION_LIST_TAG:
- return R.string.subscriptions_list_label;
- default:
- return 0;
- }
- }
-
- private static @DrawableRes int getDrawable(String tag) {
- switch (tag) {
- case HomeFragment.TAG:
- return R.drawable.ic_home;
- case QueueFragment.TAG:
- return R.drawable.ic_playlist_play;
- case InboxFragment.TAG:
- return R.drawable.ic_inbox;
- case AllEpisodesFragment.TAG:
- return R.drawable.ic_feed;
- case CompletedDownloadsFragment.TAG:
- return R.drawable.ic_download;
- case PlaybackHistoryFragment.TAG:
- return R.drawable.ic_history;
- case SubscriptionFragment.TAG:
- return R.drawable.ic_subscriptions;
- case AddFeedFragment.TAG:
- return R.drawable.ic_add;
- default:
- return 0;
- }
- }
-
public List<String> getFragmentTags() {
return Collections.unmodifiableList(fragmentTags);
}
@@ -207,7 +154,7 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
holder.itemView.setOnCreateContextMenuListener(null);
if (viewType == VIEW_TYPE_NAV) {
- bindNavView(getLabel(fragmentTags.get(position)), position, (NavHolder) holder);
+ bindNavView(NavigationNames.getLabel(fragmentTags.get(position)), position, (NavHolder) holder);
} else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
bindSectionDivider((DividerHolder) holder);
} else {
@@ -292,7 +239,7 @@ public class NavListAdapter extends RecyclerView.Adapter<NavListAdapter.Holder>
}
}
- holder.image.setImageResource(getDrawable(fragmentTags.get(position)));
+ holder.image.setImageResource(NavigationNames.getDrawable(fragmentTags.get(position)));
}
private void bindSectionDivider(DividerHolder holder) {
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavigationNames.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavigationNames.java
new file mode 100644
index 000000000..18a2fbb6b
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/drawer/NavigationNames.java
@@ -0,0 +1,106 @@
+package de.danoeh.antennapod.ui.screen.drawer;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.StringRes;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.ui.screen.AddFeedFragment;
+import de.danoeh.antennapod.ui.screen.AllEpisodesFragment;
+import de.danoeh.antennapod.ui.screen.InboxFragment;
+import de.danoeh.antennapod.ui.screen.PlaybackHistoryFragment;
+import de.danoeh.antennapod.ui.screen.download.CompletedDownloadsFragment;
+import de.danoeh.antennapod.ui.screen.home.HomeFragment;
+import de.danoeh.antennapod.ui.screen.queue.QueueFragment;
+import de.danoeh.antennapod.ui.screen.subscriptions.SubscriptionFragment;
+
+public abstract class NavigationNames {
+ public static @DrawableRes int getDrawable(String tag) {
+ switch (tag) {
+ case HomeFragment.TAG:
+ return R.drawable.ic_home;
+ case QueueFragment.TAG:
+ return R.drawable.ic_playlist_play;
+ case InboxFragment.TAG:
+ return R.drawable.ic_inbox;
+ case AllEpisodesFragment.TAG:
+ return R.drawable.ic_feed;
+ case CompletedDownloadsFragment.TAG:
+ return R.drawable.ic_download;
+ case PlaybackHistoryFragment.TAG:
+ return R.drawable.ic_history;
+ case SubscriptionFragment.TAG:
+ return R.drawable.ic_subscriptions;
+ case AddFeedFragment.TAG:
+ return R.drawable.ic_add;
+ default:
+ return 0;
+ }
+ }
+
+ public static @StringRes int getLabel(String tag) {
+ switch (tag) {
+ case HomeFragment.TAG:
+ return R.string.home_label;
+ case QueueFragment.TAG:
+ return R.string.queue_label;
+ case InboxFragment.TAG:
+ return R.string.inbox_label;
+ case AllEpisodesFragment.TAG:
+ return R.string.episodes_label;
+ case SubscriptionFragment.TAG:
+ return R.string.subscriptions_label;
+ case CompletedDownloadsFragment.TAG:
+ return R.string.downloads_label;
+ case PlaybackHistoryFragment.TAG:
+ return R.string.playback_history_label;
+ case AddFeedFragment.TAG:
+ return R.string.add_feed_label;
+ case NavListAdapter.SUBSCRIPTION_LIST_TAG:
+ return R.string.subscriptions_list_label;
+ default:
+ return 0;
+ }
+ }
+
+ public static int getBottomNavigationItemId(String tag) {
+ switch (tag) {
+ case QueueFragment.TAG:
+ return R.id.bottom_navigation_queue;
+ case InboxFragment.TAG:
+ return R.id.bottom_navigation_inbox;
+ case AllEpisodesFragment.TAG:
+ return R.id.bottom_navigation_episodes;
+ case CompletedDownloadsFragment.TAG:
+ return R.id.bottom_navigation_downloads;
+ case PlaybackHistoryFragment.TAG:
+ return R.id.bottom_navigation_history;
+ case AddFeedFragment.TAG:
+ return R.id.bottom_navigation_addfeed;
+ case SubscriptionFragment.TAG:
+ return R.id.bottom_navigation_subscriptions;
+ case HomeFragment.TAG: // fall-through
+ default:
+ return R.id.bottom_navigation_home;
+ }
+ }
+
+ public static String getBottomNavigationFragmentTag(int id) {
+ if (id == R.id.bottom_navigation_queue) {
+ return QueueFragment.TAG;
+ } else if (id == R.id.bottom_navigation_inbox) {
+ return InboxFragment.TAG;
+ } else if (id == R.id.bottom_navigation_episodes) {
+ return AllEpisodesFragment.TAG;
+ } else if (id == R.id.bottom_navigation_downloads) {
+ return CompletedDownloadsFragment.TAG;
+ } else if (id == R.id.bottom_navigation_history) {
+ return PlaybackHistoryFragment.TAG;
+ } else if (id == R.id.bottom_navigation_addfeed) {
+ return AddFeedFragment.TAG;
+ } else if (id == R.id.bottom_navigation_subscriptions) {
+ return SubscriptionFragment.TAG;
+ } else if (id == R.id.bottom_navigation_home) {
+ return HomeFragment.TAG;
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java
index 634f1ecfe..5b561bd30 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/AudioPlayerFragment.java
@@ -23,7 +23,6 @@ import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
-import com.google.android.material.elevation.SurfaceColors;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.playback.service.PlaybackController;
@@ -121,8 +120,6 @@ public class AudioPlayerFragment extends Fragment implements
getChildFragmentManager().beginTransaction()
.replace(R.id.playerFragment, externalPlayerFragment, ExternalPlayerFragment.TAG)
.commit();
- root.findViewById(R.id.playerFragment).setBackgroundColor(
- SurfaceColors.getColorForElevation(getContext(), 8 * getResources().getDisplayMetrics().density));
butPlaybackSpeed = root.findViewById(R.id.butPlaybackSpeed);
txtvPlaybackSpeed = root.findViewById(R.id.txtvPlaybackSpeed);
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/view/LiftOnScrollListener.java b/app/src/main/java/de/danoeh/antennapod/ui/view/LiftOnScrollListener.java
index e046dd43e..d328f77ed 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/view/LiftOnScrollListener.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/view/LiftOnScrollListener.java
@@ -6,6 +6,8 @@ import androidx.annotation.NonNull;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.ui.common.ThemeUtils;
/**
* Workaround for app:liftOnScroll flickering when in SwipeRefreshLayout
@@ -16,8 +18,9 @@ public class LiftOnScrollListener extends RecyclerView.OnScrollListener
private boolean animatingToScrolled = false;
public LiftOnScrollListener(View appBar) {
- animator = ValueAnimator.ofFloat(0, appBar.getContext().getResources().getDisplayMetrics().density * 8);
- animator.addUpdateListener(animation -> appBar.setElevation((float) animation.getAnimatedValue()));
+ int colorLifted = ThemeUtils.getColorFromAttr(appBar.getContext(), R.attr.colorSurfaceContainer);
+ animator = ValueAnimator.ofArgb(colorLifted & 0x00ffffff, colorLifted);
+ animator.addUpdateListener(animation -> appBar.setBackgroundColor((int) animation.getAnimatedValue()));
}
@Override
diff --git a/app/src/main/res/layout-sw720dp/main.xml b/app/src/main/res/layout-sw720dp/main.xml
index e8edc260f..a9984916e 100644
--- a/app/src/main/res/layout-sw720dp/main.xml
+++ b/app/src/main/res/layout-sw720dp/main.xml
@@ -3,45 +3,66 @@
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:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal"
+ android:orientation="vertical"
tools:viewBindingIgnore="true">
- <androidx.fragment.app.FragmentContainerView
- android:id="@+id/navDrawerFragment"
- android:layout_width="300dp"
- android:layout_height="match_parent"
- android:layout_gravity="start"
- android:orientation="vertical" />
-
- <View
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:background="?android:attr/listDivider" />
-
- <androidx.coordinatorlayout.widget.CoordinatorLayout
- android:id="@+id/overview_coordinator_layout"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="0dp"
+ android:orientation="horizontal"
+ android:layout_weight="1">
<androidx.fragment.app.FragmentContainerView
- android:id="@+id/main_view"
- android:layout_width="match_parent"
+ android:id="@+id/navDrawerFragment"
+ android:layout_width="300dp"
android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:foreground="?android:windowContentOverlay"
- tools:background="@android:color/holo_red_dark" />
+ android:layout_gravity="start"
+ android:orientation="vertical" />
- <androidx.fragment.app.FragmentContainerView
- android:id="@+id/audioplayerFragment"
- android:layout_width="match_parent"
+ <View
+ android:layout_width="1dp"
android:layout_height="match_parent"
- android:background="?android:attr/colorBackground"
- android:elevation="8dp"
- android:visibility="gone"
- app:layout_behavior="de.danoeh.antennapod.ui.view.LockableBottomSheetBehavior" />
+ android:background="?android:attr/listDivider" />
+
+ <androidx.coordinatorlayout.widget.CoordinatorLayout
+ android:id="@+id/overview_coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- </androidx.coordinatorlayout.widget.CoordinatorLayout>
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/main_content_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:foreground="?android:windowContentOverlay"
+ tools:background="@android:color/holo_red_dark" />
+
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/audioplayerFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/colorBackground"
+ android:elevation="8dp"
+ android:visibility="gone"
+ app:layout_behavior="de.danoeh.antennapod.ui.view.LockableBottomSheetBehavior" />
+
+ </androidx.coordinatorlayout.widget.CoordinatorLayout>
+
+ </LinearLayout>
+
+ <com.google.android.material.bottomnavigation.BottomNavigationView
+ android:id="@+id/bottomNavigationView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:labelVisibilityMode="labeled" />
+
+ <View
+ android:id="@+id/bottom_padding"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:background="?attr/colorSurfaceContainer" />
</LinearLayout>
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index bc42aba05..15e44f2f9 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -41,6 +41,7 @@
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
app:cardCornerRadius="28dp"
app:cardElevation="0dp">
@@ -49,7 +50,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:background="?attr/colorPrimaryContainer">
+ android:background="?attr/colorSurfaceContainer">
<ImageView
android:id="@+id/searchButton"
diff --git a/app/src/main/res/layout/audioplayer_fragment.xml b/app/src/main/res/layout/audioplayer_fragment.xml
index db109bbd3..3c52daa94 100644
--- a/app/src/main/res/layout/audioplayer_fragment.xml
+++ b/app/src/main/res/layout/audioplayer_fragment.xml
@@ -13,12 +13,13 @@
android:layout_gravity="top"
android:elevation="8dp"
android:outlineProvider="none"
+ android:background="?attr/colorSurfaceContainer"
tools:layout_height="@dimen/external_player_height" />
<RelativeLayout
+ android:id="@+id/playerContent"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true">
+ android:layout_height="match_parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
diff --git a/app/src/main/res/layout/bottom_navigation_more_listitem.xml b/app/src/main/res/layout/bottom_navigation_more_listitem.xml
new file mode 100644
index 000000000..e85ecfce1
--- /dev/null
+++ b/app/src/main/res/layout/bottom_navigation_more_listitem.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ 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:orientation="horizontal"
+ android:paddingHorizontal="16dp"
+ android:paddingVertical="4dp">
+
+ <ImageView
+ android:id="@+id/coverImage"
+ android:layout_width="@dimen/thumbnail_length_navlist"
+ android:layout_height="@dimen/thumbnail_length_navlist"
+ android:importantForAccessibility="no"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
+ android:scaleType="centerInside"
+ tools:src="@drawable/ic_download_black" />
+
+ <TextView
+ android:id="@+id/titleLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:ellipsize="end"
+ android:lines="1"
+ android:singleLine="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_navdrawer"
+ tools:text="Navigation item title" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/horizontal_itemlist_item.xml b/app/src/main/res/layout/horizontal_itemlist_item.xml
index 338409647..edbf7b724 100644
--- a/app/src/main/res/layout/horizontal_itemlist_item.xml
+++ b/app/src/main/res/layout/horizontal_itemlist_item.xml
@@ -6,8 +6,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:clipToPadding="false"
- android:padding="4dp">
+ android:clipToPadding="false">
<androidx.cardview.widget.CardView
android:id="@+id/card"
@@ -15,8 +14,10 @@
android:layout_height="wrap_content"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
+ android:layout_margin="4dp"
+ app:cardBackgroundColor="?attr/colorSurfaceContainer"
app:cardCornerRadius="12dp"
- app:cardElevation="0dp">
+ app:cardElevation="1dp">
<LinearLayout
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
index e205707d5..1249eeaca 100644
--- a/app/src/main/res/layout/main.xml
+++ b/app/src/main/res/layout/main.xml
@@ -1,46 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.drawerlayout.widget.DrawerLayout
+<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:id="@+id/drawer_layout"
+ android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:orientation="vertical"
tools:ignore="InconsistentLayout"
tools:viewBindingIgnore="true">
<!-- InconsistentLayout: Tablet layout does not have a drawer -->
<!-- viewBindingIgnore: Configurations for main.xml must
agree on the root element's ID -->
- <androidx.coordinatorlayout.widget.CoordinatorLayout
- android:id="@+id/overview_coordinator_layout"
+ <androidx.drawerlayout.widget.DrawerLayout
+ android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="0dp"
+ android:layout_weight="1">
- <androidx.fragment.app.FragmentContainerView
- android:id="@+id/main_view"
+ <androidx.coordinatorlayout.widget.CoordinatorLayout
+ android:id="@+id/overview_coordinator_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:foreground="?android:windowContentOverlay"
- tools:background="@android:color/holo_red_dark" />
+ android:layout_height="match_parent">
+
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/main_content_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:foreground="?android:windowContentOverlay"
+ tools:background="@android:color/holo_red_dark" />
+
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/audioplayerFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/colorBackground"
+ android:elevation="8dp"
+ android:visibility="gone"
+ android:fitsSystemWindows="false"
+ app:layout_behavior="de.danoeh.antennapod.ui.view.LockableBottomSheetBehavior" />
+
+ </androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.fragment.app.FragmentContainerView
- android:id="@+id/audioplayerFragment"
+ android:id="@+id/navDrawerFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="?android:attr/colorBackground"
- android:elevation="8dp"
- android:visibility="gone"
- app:layout_behavior="de.danoeh.antennapod.ui.view.LockableBottomSheetBehavior" />
+ android:layout_gravity="start"
+ android:orientation="vertical" />
+
+ </androidx.drawerlayout.widget.DrawerLayout>
- </androidx.coordinatorlayout.widget.CoordinatorLayout>
+ <com.google.android.material.bottomnavigation.BottomNavigationView
+ android:id="@+id/bottomNavigationView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:labelVisibilityMode="labeled" />
- <androidx.fragment.app.FragmentContainerView
- android:id="@+id/navDrawerFragment"
+ <View
+ android:id="@+id/bottom_padding"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="start"
- android:orientation="vertical" />
+ android:layout_height="0dp"
+ android:background="?attr/colorSurfaceContainer" />
-</androidx.drawerlayout.widget.DrawerLayout>
+</LinearLayout>
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index 545e79da7..bdcbd6c0b 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -17,4 +17,16 @@
<item name="view_type_subscription_grid_with_title" type="id"/>
<item name="view_type_subscription_grid_without_title" type="id"/>
<item name="view_type_subscription_list" type="id"/>
+
+ <!-- Bottom navigation -->
+ <item name="bottom_navigation_home" type="id"/>
+ <item name="bottom_navigation_queue" type="id"/>
+ <item name="bottom_navigation_inbox" type="id"/>
+ <item name="bottom_navigation_episodes" type="id"/>
+ <item name="bottom_navigation_downloads" type="id"/>
+ <item name="bottom_navigation_history" type="id"/>
+ <item name="bottom_navigation_addfeed" type="id"/>
+ <item name="bottom_navigation_subscriptions" type="id"/>
+ <item name="bottom_navigation_more" type="id"/>
+ <item name="bottom_navigation_settings" type="id"/>
</resources>
diff --git a/build.gradle b/build.gradle
index 1e9c6e946..69b9f8564 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,7 +21,7 @@ project.ext {
recyclerViewVersion = "1.2.1"
viewPager2Version = "1.1.0-beta01"
workManagerVersion = "2.7.1"
- googleMaterialVersion = "1.7.0"
+ googleMaterialVersion = "1.12.0"
// Third-party
commonslangVersion = "3.6"
diff --git a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
index 771ad5632..608998c00 100644
--- a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
+++ b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
@@ -62,6 +62,7 @@ public abstract class UserPreferences {
public static final String PREF_FILTER_FEED = "prefSubscriptionsFilter";
public static final String PREF_SUBSCRIPTION_TITLE = "prefSubscriptionTitle";
public static final String PREF_BACK_OPENS_DRAWER = "prefBackButtonOpensDrawer";
+ public static final String PREF_BOTTOM_NAVIGATION = "prefBottomNavigation";
public static final String PREF_QUEUE_KEEP_SORTED = "prefQueueKeepSorted";
public static final String PREF_QUEUE_KEEP_SORTED_ORDER = "prefQueueKeepSortedOrder";
@@ -758,6 +759,14 @@ public abstract class UserPreferences {
return prefs.getBoolean(PREF_BACK_OPENS_DRAWER, false);
}
+ public static boolean isBottomNavigationEnabled() {
+ return prefs.getBoolean(PREF_BOTTOM_NAVIGATION, false);
+ }
+
+ public static void setBottomNavigationEnabled(boolean enabled) {
+ prefs.edit().putBoolean(PREF_BOTTOM_NAVIGATION, enabled).apply();
+ }
+
public static boolean timeRespectsSpeed() {
return prefs.getBoolean(PREF_TIME_RESPECTS_SPEED, false);
}
diff --git a/ui/common/src/main/res/drawable/dots_vertical.xml b/ui/common/src/main/res/drawable/dots_vertical.xml
new file mode 100644
index 000000000..4848dde4e
--- /dev/null
+++ b/ui/common/src/main/res/drawable/dots_vertical.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z" />
+
+</vector>
diff --git a/ui/common/src/main/res/drawable/ic_pencil.xml b/ui/common/src/main/res/drawable/ic_pencil.xml
new file mode 100644
index 000000000..5a4838da7
--- /dev/null
+++ b/ui/common/src/main/res/drawable/ic_pencil.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="?attr/action_icon_color"
+ android:pathData="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" />
+
+</vector>
diff --git a/ui/common/src/main/res/values-v23/styles.xml b/ui/common/src/main/res/values-v23/styles.xml
index 95740f648..9475596dc 100644
--- a/ui/common/src/main/res/values-v23/styles.xml
+++ b/ui/common/src/main/res/values-v23/styles.xml
@@ -3,7 +3,5 @@
<style name="Theme.AntennaPod.Dynamic.Light" parent="Theme.Base.AntennaPod.Dynamic.Light">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowLightStatusBar">true</item>
- <!-- To make icons visible -->
- <item name="android:navigationBarColor">@color/grey600</item>
</style>
</resources>
diff --git a/ui/common/src/main/res/values-v27/styles.xml b/ui/common/src/main/res/values-v27/styles.xml
index df4d786be..1266e901f 100644
--- a/ui/common/src/main/res/values-v27/styles.xml
+++ b/ui/common/src/main/res/values-v27/styles.xml
@@ -3,8 +3,6 @@
<style name="Theme.AntennaPod.Dynamic.Light" parent="Theme.Base.AntennaPod.Dynamic.Light">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowLightStatusBar">true</item>
- <item name="android:navigationBarColor">@color/background_light</item>
- <item name="android:navigationBarDividerColor">@color/navigation_bar_divider_light</item>
<item name="android:windowLightNavigationBar">true</item>
</style>
</resources>
diff --git a/ui/common/src/main/res/values/colors.xml b/ui/common/src/main/res/values/colors.xml
index 55ba650e7..e3a3e1451 100644
--- a/ui/common/src/main/res/values/colors.xml
+++ b/ui/common/src/main/res/values/colors.xml
@@ -11,14 +11,13 @@
<color name="feed_text_bg">#55333333</color>
<!-- Theme colors -->
- <color name="background_light">#FFFFFF</color>
+ <color name="background_light">#f9fcff</color>
<color name="background_elevated_light">#EFEEEE</color>
<color name="background_darktheme">#21272b</color>
<color name="background_elevated_darktheme">#2D3337</color>
<color name="non_square_icon_background">#22777777</color>
<color name="seek_background_light">#90000000</color>
<color name="seek_background_dark">#905B5B5B</color>
- <color name="navigation_bar_divider_light">#1F000000</color>
<color name="accent_light">#0078C2</color>
<color name="accent_dark">#3D8BFF</color>
diff --git a/ui/common/src/main/res/values/styles.xml b/ui/common/src/main/res/values/styles.xml
index 2cf3b3997..f2c9a1e27 100644
--- a/ui/common/src/main/res/values/styles.xml
+++ b/ui/common/src/main/res/values/styles.xml
@@ -27,6 +27,7 @@
<item name="android:splitMotionEvents">false</item>
<item name="android:fitsSystemWindows">false</item>
<item name="android:windowContentTransitions">true</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
<item name="toolbarStyle">@style/Style.AntennaPod.Toolbar</item>
<item name="preferenceTheme">@style/AppPreferenceThemeOverlay</item>
</style>
@@ -44,6 +45,8 @@
<item name="android:colorBackground">@color/background_light</item>
<item name="colorSurface">@color/background_light</item>
<item name="colorSurfaceVariant">#D3DCE0</item>
+ <item name="colorSurfaceContainer">#EBEEF3</item>
+ <item name="colorSecondaryContainer">#D3DCE0</item>
</style>
<style name="Theme.AntennaPod.Dynamic.Dark" parent="Theme.Base.AntennaPod.Dynamic.Dark">
@@ -70,7 +73,7 @@
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
<item name="android:windowContentTransitions">true</item>
- <item name="android:navigationBarColor">@color/background_darktheme</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
<item name="toolbarStyle">@style/Style.AntennaPod.Toolbar</item>
<item name="preferenceTheme">@style/AppPreferenceThemeOverlay</item>
</style>
@@ -88,6 +91,8 @@
<item name="android:colorBackground">@color/background_darktheme</item>
<item name="colorSurface">@color/background_darktheme</item>
<item name="colorSurfaceVariant">#2F3B4F</item>
+ <item name="colorSurfaceContainer">#1C2024</item>
+ <item name="colorSecondaryContainer">#2F3B4F</item>
</style>
<style name="Theme.AntennaPod.Dynamic.TrueBlack" parent="Theme.AntennaPod.Dynamic.Dark">
diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml
index 8b0fbf25b..268cd6ed3 100644
--- a/ui/i18n/src/main/res/values/strings.xml
+++ b/ui/i18n/src/main/res/values/strings.xml
@@ -454,8 +454,10 @@
<string name="pref_black_theme_message">Use full black for the dark theme</string>
<string name="pref_tinted_theme_title">Dynamic colors</string>
<string name="pref_tinted_theme_message">Adapt app colors based on the wallpaper</string>
- <string name="pref_nav_drawer_items_title">Set navigation drawer items</string>
- <string name="pref_nav_drawer_items_sum">Change which items appear in the navigation drawer</string>
+ <string name="bottom_navigation">Bottom navigation</string>
+ <string name="bottom_navigation_summary">Beta feature: Access the most important screens from everywhere, in a single tap</string>
+ <string name="pref_nav_drawer_items_title">Customize navigation</string>
+ <string name="pref_nav_drawer_items_sum">Change which items appear in the navigation drawer or bottom navigation</string>
<string name="pref_nav_drawer_feed_order_title">Set subscription order</string>
<string name="pref_nav_drawer_feed_order_sum">Change the order of your subscriptions</string>
<string name="pref_nav_drawer_feed_counter_title">Set subscription counter</string>
diff --git a/ui/preferences/src/main/res/xml/preferences_user_interface.xml b/ui/preferences/src/main/res/xml/preferences_user_interface.xml
index f61447b77..1b3aad476 100644
--- a/ui/preferences/src/main/res/xml/preferences_user_interface.xml
+++ b/ui/preferences/src/main/res/xml/preferences_user_interface.xml
@@ -80,10 +80,14 @@
android:title="@string/pref_default_page"
android:summary="@string/pref_default_page_sum"
android:defaultValue="HomeFragment"/>
+ <SwitchPreferenceCompat
+ android:title="@string/bottom_navigation"
+ android:summary="@string/bottom_navigation_summary"
+ android:key="prefBottomNavigation" />
<Preference
- android:key="prefHiddenDrawerItems"
- android:summary="@string/pref_nav_drawer_items_sum"
- android:title="@string/pref_nav_drawer_items_title"/>
+ android:key="prefHiddenDrawerItems"
+ android:summary="@string/pref_nav_drawer_items_sum"
+ android:title="@string/pref_nav_drawer_items_title"/>
<SwitchPreferenceCompat
android:key="prefBackButtonOpensDrawer"
android:title="@string/pref_back_button_opens_drawer"