diff options
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" |