diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/activity/MainActivity.java b/app/src/main/java/com/cappielloantonio/tempo/ui/activity/MainActivity.java index 3509175f..f872b403 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/activity/MainActivity.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/activity/MainActivity.java @@ -3,7 +3,6 @@ package com.cappielloantonio.tempo.ui.activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; -import android.graphics.Rect; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -11,12 +10,16 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; -import android.util.Log; +import android.view.Gravity; import android.view.View; -import android.view.ViewGroup; +import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.core.splashscreen.SplashScreen; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; +import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; import androidx.media3.common.MediaItem; @@ -48,6 +51,7 @@ import com.cappielloantonio.tempo.viewmodel.MainViewModel; import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.color.DynamicColors; +import com.google.android.material.navigation.NavigationView; import com.google.common.util.concurrent.MoreExecutors; import java.util.Objects; @@ -63,9 +67,12 @@ public class MainActivity extends BaseActivity { private FragmentManager fragmentManager; private NavHostFragment navHostFragment; private BottomNavigationView bottomNavigationView; + private FrameLayout bottomNavigationViewFrame; public NavController navController; + private DrawerLayout drawerLayout; + private NavigationView navigationView; private BottomSheetBehavior bottomSheetBehavior; - private boolean isLandscape = false; + public boolean isLandscape = false; private AssetLinkNavigator assetLinkNavigator; private AssetLinkUtil.AssetLink pendingAssetLink; @@ -111,6 +118,7 @@ public class MainActivity extends BaseActivity { protected void onResume() { super.onResume(); pingServer(); + toggleNavigationDrawerLockOnOrientationChange(); } @Override @@ -148,14 +156,8 @@ public class MainActivity extends BaseActivity { goToLogin(); } - // Set bottom navigation height - if (isLandscape) { - ViewGroup.LayoutParams layoutParams = bottomNavigationView.getLayoutParams(); - Rect windowRect = new Rect(); - bottomNavigationView.getWindowVisibleDisplayFrame(windowRect); - layoutParams.width = windowRect.height(); - bottomNavigationView.setLayoutParams(layoutParams); - } + toggleNavigationDrawerLockOnOrientationChange(); + } // BOTTOM SHEET/NAVIGATION @@ -259,8 +261,12 @@ public class MainActivity extends BaseActivity { private void initNavigation() { bottomNavigationView = findViewById(R.id.bottom_navigation); + bottomNavigationViewFrame = findViewById(R.id.bottom_navigation_frame); navHostFragment = (NavHostFragment) fragmentManager.findFragmentById(R.id.nav_host_fragment); navController = Objects.requireNonNull(navHostFragment).getNavController(); + // This is the lateral slide-in drawer + drawerLayout = findViewById(R.id.drawer_layout); + navigationView = findViewById(R.id.nav_view); /* * In questo modo intercetto il cambio schermata tramite navbar e se il bottom sheet รจ aperto, @@ -277,16 +283,90 @@ public class MainActivity extends BaseActivity { }); NavigationUI.setupWithNavController(bottomNavigationView, navController); + NavigationUI.setupWithNavController(navigationView, navController); } public void setBottomNavigationBarVisibility(boolean visibility) { if (visibility) { bottomNavigationView.setVisibility(View.VISIBLE); + bottomNavigationViewFrame.setVisibility(View.VISIBLE); } else { bottomNavigationView.setVisibility(View.GONE); + bottomNavigationViewFrame.setVisibility(View.GONE); } } + public void toggleBottomNavigationBarVisibilityOnOrientationChange() { + // Ignore orientation change, bottom navbar always hidden + if (Preferences.getHideBottomNavbarOnPortrait()) { + setBottomNavigationBarVisibility(false); + setPortraitPlayerBottomSheetPeekHeight(56); + setSystemBarsVisibility(!isLandscape); + return; + } + + if (!isLandscape) { + // Show app navbar + show system bars + setPortraitPlayerBottomSheetPeekHeight(136); + setBottomNavigationBarVisibility(true); + setSystemBarsVisibility(true); + } else { + // Hide app navbar + hide system bars + setPortraitPlayerBottomSheetPeekHeight(56); + setBottomNavigationBarVisibility(false); + setSystemBarsVisibility(false); + } + } + + public void setNavigationDrawerLock(boolean locked) { + int mode = locked + ? DrawerLayout.LOCK_MODE_LOCKED_CLOSED + : DrawerLayout.LOCK_MODE_UNLOCKED; + drawerLayout.setDrawerLockMode(mode); + } + + public void toggleNavigationDrawerLockOnOrientationChange() { + // Ignore orientation check, drawer always unlocked + if (Preferences.getEnableDrawerOnPortrait()) { + setNavigationDrawerLock(false); + return; + } + if (!isLandscape) { + setNavigationDrawerLock(true); + } else { + setNavigationDrawerLock(false); + } + } + + public void setSystemBarsVisibility(boolean visibility) { + WindowInsetsControllerCompat insetsController; + View decorView = getWindow().getDecorView(); + insetsController = new WindowInsetsControllerCompat(getWindow(), decorView); + + if (visibility) { + WindowCompat.setDecorFitsSystemWindows(getWindow(), true); + insetsController.show(WindowInsetsCompat.Type.navigationBars()); + insetsController.show(WindowInsetsCompat.Type.statusBars()); + insetsController.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_DEFAULT); + } else { + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + insetsController.hide(WindowInsetsCompat.Type.navigationBars()); + insetsController.hide(WindowInsetsCompat.Type.statusBars()); + insetsController.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); + } + } + + private void setPortraitPlayerBottomSheetPeekHeight(int peekHeight) { + FrameLayout bottomSheet = findViewById(R.id.player_bottom_sheet); + BottomSheetBehavior behavior = + BottomSheetBehavior.from(bottomSheet); + + int newPeekPx = (int) (peekHeight * getResources().getDisplayMetrics().density); + behavior.setPeekHeight(newPeekPx); + } + private void initService() { MediaManager.check(getMediaBrowserListenableFuture()); @@ -570,4 +650,4 @@ public class MainActivity extends BaseActivity { MediaManager.playDownloadedMediaItem(getMediaBrowserListenableFuture(), mediaItem); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/DownloadFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/DownloadFragment.java index 12ca2434..72d1e0f3 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/DownloadFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/DownloadFragment.java @@ -83,7 +83,7 @@ public class DownloadFragment extends Fragment implements ClickCallback { super.onStart(); initializeMediaBrowser(); - activity.setBottomNavigationBarVisibility(true); + activity.toggleBottomNavigationBarVisibilityOnOrientationChange(); activity.setBottomSheetVisibility(true); } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/EqualizerFragment.kt b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/EqualizerFragment.kt index ac6608c7..04aae67c 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/EqualizerFragment.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/EqualizerFragment.kt @@ -21,18 +21,26 @@ import com.cappielloantonio.tempo.R import com.cappielloantonio.tempo.service.EqualizerManager import com.cappielloantonio.tempo.service.BaseMediaService import com.cappielloantonio.tempo.service.MediaService +import com.cappielloantonio.tempo.ui.activity.MainActivity import com.cappielloantonio.tempo.util.Preferences class EqualizerFragment : Fragment() { + private lateinit var activity: MainActivity private var equalizerManager: EqualizerManager? = null private lateinit var eqBandsContainer: LinearLayout private lateinit var eqSwitch: Switch private lateinit var resetButton: Button private lateinit var safeSpace: Space private val bandSeekBars = mutableListOf() - private var receiverRegistered = false + + @OptIn(UnstableApi::class) + override fun onAttach(context: Context) { + super.onAttach(context) + activity = requireActivity() as MainActivity + } + private val equalizerUpdatedReceiver = object : BroadcastReceiver() { @OptIn(UnstableApi::class) override fun onReceive(context: Context?, intent: Intent?) { @@ -73,6 +81,8 @@ class EqualizerFragment : Fragment() { ) receiverRegistered = true } + val showBottomBar = !Preferences.getHideBottomNavbarOnPortrait() + activity.setBottomNavigationBarVisibility(showBottomBar) } override fun onStop() { diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java index a0d0380c..7697c01f 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java @@ -53,7 +53,7 @@ public class HomeFragment extends Fragment { public void onStart() { super.onStart(); - activity.setBottomNavigationBarVisibility(true); + activity.toggleBottomNavigationBarVisibilityOnOrientationChange(); activity.setBottomSheetVisibility(true); } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/LibraryFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/LibraryFragment.java index b50ee60f..daa5d412 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/LibraryFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/LibraryFragment.java @@ -87,7 +87,7 @@ public class LibraryFragment extends Fragment implements ClickCallback { public void onStart() { super.onStart(); initializeMediaBrowser(); - activity.setBottomNavigationBarVisibility(true); + activity.toggleBottomNavigationBarVisibilityOnOrientationChange(); } @Override diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java index aab61593..2981fa7c 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java @@ -130,6 +130,8 @@ public class SettingsFragment extends PreferenceFragmentCompat { super.onStart(); activity.setBottomNavigationBarVisibility(false); activity.setBottomSheetVisibility(false); + activity.setNavigationDrawerLock(true); + activity.setSystemBarsVisibility(!activity.isLandscape); } @Override @@ -167,6 +169,8 @@ public class SettingsFragment extends PreferenceFragmentCompat { public void onStop() { super.onStop(); activity.setBottomSheetVisibility(true); + activity.toggleNavigationDrawerLockOnOrientationChange(); + activity.setSystemBarsVisibility(!activity.isLandscape); } @Override diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt index a95c84ae..47c30cc0 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt @@ -30,6 +30,8 @@ object Preferences { private const val IMAGE_CACHE_SIZE = "image_cache_size" private const val STREAMING_CACHE_SIZE = "streaming_cache_size" private const val LANDSCAPE_ITEMS_PER_ROW = "landscape_items_per_row" + private const val ENABLE_DRAWER_ON_PORTRAIT = "enable_drawer_on_portrait" + private const val HIDE_BOTTOM_NAVBAR_ON_PORTRAIT = "hide_bottom_navbar_on_portrait" private const val IMAGE_SIZE = "image_size" private const val MAX_BITRATE_WIFI = "max_bitrate_wifi" private const val MAX_BITRATE_MOBILE = "max_bitrate_mobile" @@ -310,6 +312,16 @@ object Preferences { return App.getInstance().preferences.getString(LANDSCAPE_ITEMS_PER_ROW, "4")!!.toInt() } + @JvmStatic + fun getEnableDrawerOnPortrait(): Boolean { + return App.getInstance().preferences.getBoolean(ENABLE_DRAWER_ON_PORTRAIT, false) + } + + @JvmStatic + fun getHideBottomNavbarOnPortrait(): Boolean { + return App.getInstance().preferences.getBoolean(HIDE_BOTTOM_NAVBAR_ON_PORTRAIT, false) + } + @JvmStatic fun getImageSize(): Int { return App.getInstance().preferences.getString(IMAGE_SIZE, "-1")!!.toInt() diff --git a/app/src/main/res/drawable/ic_albums.xml b/app/src/main/res/drawable/ic_albums.xml new file mode 100644 index 00000000..4c1c697d --- /dev/null +++ b/app/src/main/res/drawable/ic_albums.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_artists.xml b/app/src/main/res/drawable/ic_artists.xml new file mode 100644 index 00000000..03d8308f --- /dev/null +++ b/app/src/main/res/drawable/ic_artists.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_genres.xml b/app/src/main/res/drawable/ic_genres.xml new file mode 100644 index 00000000..3e7b6679 --- /dev/null +++ b/app/src/main/res/drawable/ic_genres.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable/ic_playlist.xml b/app/src/main/res/drawable/ic_playlist.xml new file mode 100644 index 00000000..08225cc9 --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist.xml @@ -0,0 +1,33 @@ + + + + + + diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml index 581aa4ce..1b6d2e9c 100644 --- a/app/src/main/res/layout-land/activity_main.xml +++ b/app/src/main/res/layout-land/activity_main.xml @@ -1,16 +1,15 @@ - + android:background="?attr/colorSurface"> + android:layout_height="match_parent"> - - - + + - - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 01edf7f5..15a8d99c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,16 +1,16 @@ - + android:background="?attr/colorSurface"> + + android:layout_height="match_parent"> + + + + + + - - + diff --git a/app/src/main/res/layout/nav_drawer_header.xml b/app/src/main/res/layout/nav_drawer_header.xml new file mode 100644 index 00000000..b6ff546c --- /dev/null +++ b/app/src/main/res/layout/nav_drawer_header.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/nav_drawer.xml b/app/src/main/res/menu/nav_drawer.xml new file mode 100644 index 00000000..a01dfced --- /dev/null +++ b/app/src/main/res/menu/nav_drawer.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index c6aba5ab..d234d544 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -220,6 +220,10 @@ + If enabled, show the shuffle button, remove the heart in the mini player Show radio If enabled, show the radio section. Restart the app for it to take full effect. + Enable drawer on portrait [Experimental] + Unlocks the lateral landscape menu drawer on portrait. The changes will take effect on restart. + Hide bottom navbar on portrait [Experimental] + Experimental.Increases vertical space by removing the bottom navbar. The changes will take effect on restart. Auto download lyrics Automatically save lyrics when they are available so they can be shown while offline. Set replay gain mode diff --git a/app/src/main/res/xml/global_preferences.xml b/app/src/main/res/xml/global_preferences.xml index 4ee034e5..cdb875a9 100644 --- a/app/src/main/res/xml/global_preferences.xml +++ b/app/src/main/res/xml/global_preferences.xml @@ -54,6 +54,16 @@ android:defaultValue="false" android:key="always_on_display" /> + + + +