Add bottom menu

Add a tab menu on the bottom of the screen that can switch between all fragments on the ViewPager.
This commit is contained in:
OxygenCobalt 2020-08-31 18:55:25 -06:00
parent 736e335ccf
commit d5e6b813a9
12 changed files with 161 additions and 30 deletions

View file

@ -66,6 +66,9 @@ dependencies {
// Image loading
implementation 'io.coil-kt:coil:0.12.0'
// Material
implementation 'com.google.android.material:material:1.3.0-alpha02'
// Lint
ktlint "com.pinterest:ktlint:0.37.2"
}

View file

@ -3,7 +3,6 @@ package org.oxycblt.auxio
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
class MainActivity : AppCompatActivity() {
@ -11,7 +10,7 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
Log.d(this::class.simpleName, "Activity Created.")
}

View file

@ -5,13 +5,19 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import org.oxycblt.auxio.databinding.FragmentMainBinding
import org.oxycblt.auxio.library.LibraryFragment
import org.oxycblt.auxio.songs.SongsFragment
import org.oxycblt.auxio.theme.getAccentTransparency
import org.oxycblt.auxio.theme.getDeselectedTransparency
import org.oxycblt.auxio.theme.toColor
class MainFragment : Fragment() {
@ -20,6 +26,21 @@ class MainFragment : Fragment() {
private val libraryFragment: LibraryFragment by lazy { LibraryFragment() }
private val songsFragment: SongsFragment by lazy { SongsFragment() }
private val colorSelected: Int by lazy {
R.color.blue.toColor(requireContext())
}
private val colorDeselected: Int by lazy {
getAccentTransparency(
requireContext(), R.color.blue, getDeselectedTransparency(R.color.blue)
)
}
private val tabIcons = listOf(
R.drawable.ic_library,
R.drawable.ic_music
)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -32,11 +53,54 @@ class MainFragment : Fragment() {
val adapter = PagerAdapter(requireActivity())
binding.viewPager.adapter = adapter
// Link the ViewPager & Tab View
TabLayoutMediator(binding.tabs, binding.viewPager) { tab, position ->
tab.icon = ContextCompat.getDrawable(requireContext(), tabIcons[position])
// Set the icon tint to deselected if its not the default tab
if (position > 0) {
tab.icon?.setTint(colorDeselected)
}
// Init the fragment
fragmentAt(position)
}.attach()
// Set up the selected/deselected colors
binding.tabs.addOnTabSelectedListener(
object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
tab.icon?.setTint(colorSelected)
}
override fun onTabUnselected(tab: TabLayout.Tab) {
tab.icon?.setTint(colorDeselected)
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
}
)
binding.tabs.getTabAt(
binding.viewPager.offscreenPageLimit
)
Log.d(this::class.simpleName, "Fragment Created.")
return binding.root
}
private fun fragmentAt(position: Int): Fragment {
return when (position) {
0 -> libraryFragment
1 -> songsFragment
else -> libraryFragment
}
}
private inner class PagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
override fun getItemCount(): Int = shownFragments.size
@ -44,12 +108,7 @@ class MainFragment : Fragment() {
Log.d(this::class.simpleName, "Switching to fragment $position.")
if (shownFragments.contains(position)) {
return when (position) {
0 -> libraryFragment
1 -> songsFragment
else -> libraryFragment
}
return fragmentAt(position)
}
// Not sure how this would happen but it might

View file

@ -79,7 +79,7 @@ fun ImageView.getCoverArt(any: Any) {
load(uri) {
crossfade(true)
placeholder(android.R.color.transparent)
error(R.drawable.music_icon)
error(R.drawable.ic_music)
}
}

View file

@ -137,6 +137,8 @@ class MusicSorter(
unknownGenre.numArtists = artists.size
genres.add(unknownGenre)
Log.d(
this::class.simpleName,
"${unknownArtists.size} albums were placed into an unknown genre."

View file

@ -1,12 +1,11 @@
package org.oxycblt.auxio.recycler
import android.graphics.drawable.ColorDrawable
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.theme.getAccentTransparency
import org.oxycblt.auxio.theme.getDayNightTransparency
// Apply a custom vertical divider
fun RecyclerView.applyDivider() {
@ -17,21 +16,11 @@ fun RecyclerView.applyDivider() {
div.setDrawable(
ColorDrawable(
getDividerDrawable(this)
getAccentTransparency(
context, R.color.divider_color, getDayNightTransparency()
)
)
)
addItemDecoration(div)
}
private fun getDividerDrawable(recycler: RecyclerView): Int {
val isDark = AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES
// Depending on the theme use a different opacity for the divider
val alpha = if (isDark) 45 else 85
return ColorUtils.setAlphaComponent(
ContextCompat.getColor(recycler.context, R.color.divider_color),
alpha
)
}

View file

@ -0,0 +1,33 @@
package org.oxycblt.auxio.theme
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import org.oxycblt.auxio.R
fun getDayNightTransparency(): Int {
val isDark = AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES
// Depending on the theme use a different opacity for the divider
return if (isDark) 45 else 85
}
fun getDeselectedTransparency(color: Int): Int {
return if (color == R.color.yellow) 100 else 150
}
fun getAccentTransparency(context: Context, color: Int, alpha: Int): Int {
return ColorUtils.setAlphaComponent(
ContextCompat.getColor(context, color),
alpha
)
}
fun Int.toColor(context: Context): Int {
return try {
ContextCompat.getColor(context, this)
} catch (e: Exception) {
ContextCompat.getColor(context, android.R.color.white)
}
}

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorPrimary">
<path
android:fillColor="@android:color/white"
android:pathData="M20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,7h-3v5.5c0,1.38 -1.12,2.5 -2.5,2.5S10,13.88 10,12.5s1.12,-2.5 2.5,-2.5c0.57,0 1.08,0.19 1.5,0.51L14,5h4v2zM4,6L2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6z" />
</vector>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:gravity="center"
android:left="16dp"
android:right="16dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
<corners android:radius="4dp" />
<size android:height="2dp" />
</shape>
</item>
</layer-list>

View file

@ -1,13 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<layout 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">
<FrameLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="@dimen/tab_menu_size"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:tabIndicatorColor="?android:attr/colorPrimary"
app:tabGravity="fill"
app:tabMode="fixed"
app:tabIconTint="?android:attr/colorPrimary"
app:tabIconTintMode="src_in"
app:tabIndicator="@drawable/indicator"
app:tabRippleColor="?android:attr/colorPrimary" />
</LinearLayout>
</layout>

View file

@ -10,5 +10,7 @@
<dimen name="cover_size_compact">44dp</dimen>
<dimen name="cover_size_normal">56dp</dimen>
<dimen name="tab_menu_size">38dp</dimen>
<dimen name="elevation_normal">4dp</dimen>
</resources>