Initial adding bottom navigation
This commit is contained in:
@@ -22,6 +22,7 @@ import androidx.transition.TransitionManager
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.appbar.AppBarLayout.LayoutParams.*
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.navigation.NavigationBarView
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -66,7 +67,6 @@ private const val TAG_SEARCH = "search"
|
||||
|
||||
class MainActivity :
|
||||
BaseActivity<ActivityMainBinding>(),
|
||||
NavigationView.OnNavigationItemSelectedListener,
|
||||
AppBarOwner,
|
||||
View.OnClickListener,
|
||||
View.OnFocusChangeListener,
|
||||
@@ -75,6 +75,8 @@ class MainActivity :
|
||||
private val viewModel by viewModel<MainViewModel>()
|
||||
private val searchSuggestionViewModel by viewModel<SearchSuggestionViewModel>()
|
||||
|
||||
private lateinit var nav: NavigationBarView
|
||||
|
||||
private lateinit var navHeaderBinding: NavigationHeaderBinding
|
||||
private var drawerToggle: ActionBarDrawerToggle? = null
|
||||
private var drawer: DrawerLayout? = null
|
||||
@@ -87,6 +89,7 @@ class MainActivity :
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(ActivityMainBinding.inflate(layoutInflater))
|
||||
navHeaderBinding = NavigationHeaderBinding.inflate(layoutInflater)
|
||||
nav = binding.bottomNav
|
||||
drawer = binding.root as? DrawerLayout
|
||||
drawerToggle = drawer?.let {
|
||||
ActionBarDrawerToggle(
|
||||
@@ -108,18 +111,33 @@ class MainActivity :
|
||||
}
|
||||
}
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||
if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) {
|
||||
val elevation = binding.bottomNav.elevation
|
||||
window.setNavigationBarTransparentCompat(this@MainActivity, elevation)
|
||||
}
|
||||
insets
|
||||
}
|
||||
ViewCompat.requestApplyInsets(binding.root)
|
||||
|
||||
with(binding.searchView) {
|
||||
onFocusChangeListener = this@MainActivity
|
||||
searchSuggestionListener = this@MainActivity
|
||||
if (drawer == null) {
|
||||
drawableStart = context.getThemeDrawable(materialR.attr.actionModeWebSearchDrawable)
|
||||
}
|
||||
}
|
||||
|
||||
with(binding.navigationView) {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this, NavigationViewInsetsListener())
|
||||
addHeaderView(navHeaderBinding.root)
|
||||
setNavigationItemSelectedListener(this@MainActivity)
|
||||
nav.setOnItemSelectedListener { item ->
|
||||
when (item.itemId) {
|
||||
R.id.nav_local_storage -> {
|
||||
viewModel.defaultSection = AppSection.HISTORY
|
||||
setPrimaryFragment(HistoryListFragment.newInstance())
|
||||
}
|
||||
R.id.nav_favourites -> {
|
||||
viewModel.defaultSection = AppSection.FAVOURITES
|
||||
setPrimaryFragment(FavouritesContainerFragment.newInstance())
|
||||
}
|
||||
}
|
||||
appBar.setExpanded(true)
|
||||
true
|
||||
}
|
||||
|
||||
binding.fab.setOnClickListener(this@MainActivity)
|
||||
@@ -127,8 +145,6 @@ class MainActivity :
|
||||
|
||||
supportFragmentManager.findFragmentByTag(TAG_PRIMARY)?.let {
|
||||
if (it is HistoryListFragment) binding.fab.show() else binding.fab.hide()
|
||||
} ?: run {
|
||||
openDefaultSection()
|
||||
}
|
||||
if (savedInstanceState == null) {
|
||||
onFirstStart()
|
||||
@@ -138,9 +154,6 @@ class MainActivity :
|
||||
viewModel.onError.observe(this, this::onError)
|
||||
viewModel.isLoading.observe(this, this::onLoadingStateChanged)
|
||||
viewModel.isResumeEnabled.observe(this, this::onResumeEnabledChanged)
|
||||
viewModel.remoteSources.observe(this, this::updateSideMenu)
|
||||
viewModel.isSuggestionsEnabled.observe(this, this::setSuggestionsEnabled)
|
||||
viewModel.isTrackerEnabled.observe(this, this::setTrackerEnabled)
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||
@@ -163,9 +176,6 @@ class MainActivity :
|
||||
val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH)
|
||||
binding.searchView.clearFocus()
|
||||
when {
|
||||
drawer?.isDrawerOpen(binding.navigationView) == true -> {
|
||||
drawer?.closeDrawer(binding.navigationView)
|
||||
}
|
||||
fragment != null -> supportFragmentManager.commit {
|
||||
remove(fragment)
|
||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
@@ -187,46 +197,6 @@ class MainActivity :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||
if (item.groupId == R.id.group_remote_sources) {
|
||||
val source = MangaSource.values().getOrNull(item.itemId) ?: return false
|
||||
setPrimaryFragment(RemoteListFragment.newInstance(source))
|
||||
searchSuggestionViewModel.onSourceChanged(source)
|
||||
} else {
|
||||
searchSuggestionViewModel.onSourceChanged(null)
|
||||
when (item.itemId) {
|
||||
R.id.nav_history -> {
|
||||
viewModel.defaultSection = AppSection.HISTORY
|
||||
setPrimaryFragment(HistoryListFragment.newInstance())
|
||||
}
|
||||
R.id.nav_favourites -> {
|
||||
viewModel.defaultSection = AppSection.FAVOURITES
|
||||
setPrimaryFragment(FavouritesContainerFragment.newInstance())
|
||||
}
|
||||
R.id.nav_local_storage -> {
|
||||
viewModel.defaultSection = AppSection.LOCAL
|
||||
setPrimaryFragment(LocalListFragment.newInstance())
|
||||
}
|
||||
R.id.nav_suggestions -> {
|
||||
viewModel.defaultSection = AppSection.SUGGESTIONS
|
||||
setPrimaryFragment(SuggestionsFragment.newInstance())
|
||||
}
|
||||
R.id.nav_feed -> {
|
||||
viewModel.defaultSection = AppSection.FEED
|
||||
setPrimaryFragment(FeedFragment.newInstance())
|
||||
}
|
||||
R.id.nav_action_settings -> {
|
||||
startActivity(SettingsActivity.newIntent(this))
|
||||
return true
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
drawer?.closeDrawers()
|
||||
appBar.setExpanded(true)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
binding.fab.updateLayoutParams<MarginLayoutParams> {
|
||||
bottomMargin = insets.bottom + topMargin
|
||||
@@ -335,57 +305,6 @@ class MainActivity :
|
||||
adjustFabVisibility(isResumeEnabled = isEnabled)
|
||||
}
|
||||
|
||||
private fun updateSideMenu(remoteSources: List<MangaSource>) {
|
||||
val submenu = binding.navigationView.menu.findItem(R.id.nav_remote_sources).subMenu
|
||||
submenu.removeGroup(R.id.group_remote_sources)
|
||||
remoteSources.forEachIndexed { index, source ->
|
||||
submenu.add(R.id.group_remote_sources, source.ordinal, index, source.title)
|
||||
.setIcon(R.drawable.ic_manga_source)
|
||||
}
|
||||
submenu.setGroupCheckable(R.id.group_remote_sources, true, true)
|
||||
}
|
||||
|
||||
private fun setSuggestionsEnabled(isEnabled: Boolean) {
|
||||
val item = binding.navigationView.menu.findItem(R.id.nav_suggestions) ?: return
|
||||
if (!isEnabled && item.isChecked) {
|
||||
binding.navigationView.setCheckedItem(R.id.nav_history)
|
||||
}
|
||||
item.isVisible = isEnabled
|
||||
}
|
||||
|
||||
private fun setTrackerEnabled(isEnabled: Boolean) {
|
||||
val item = binding.navigationView.menu.findItem(R.id.nav_feed) ?: return
|
||||
if (!isEnabled && item.isChecked) {
|
||||
binding.navigationView.setCheckedItem(R.id.nav_history)
|
||||
}
|
||||
item.isVisible = isEnabled
|
||||
}
|
||||
|
||||
private fun openDefaultSection() {
|
||||
when (viewModel.defaultSection) {
|
||||
AppSection.LOCAL -> {
|
||||
binding.navigationView.setCheckedItem(R.id.nav_local_storage)
|
||||
setPrimaryFragment(LocalListFragment.newInstance())
|
||||
}
|
||||
AppSection.FAVOURITES -> {
|
||||
binding.navigationView.setCheckedItem(R.id.nav_favourites)
|
||||
setPrimaryFragment(FavouritesContainerFragment.newInstance())
|
||||
}
|
||||
AppSection.HISTORY -> {
|
||||
binding.navigationView.setCheckedItem(R.id.nav_history)
|
||||
setPrimaryFragment(HistoryListFragment.newInstance())
|
||||
}
|
||||
AppSection.FEED -> {
|
||||
binding.navigationView.setCheckedItem(R.id.nav_feed)
|
||||
setPrimaryFragment(FeedFragment.newInstance())
|
||||
}
|
||||
AppSection.SUGGESTIONS -> {
|
||||
binding.navigationView.setCheckedItem(R.id.nav_suggestions)
|
||||
setPrimaryFragment(SuggestionsFragment.newInstance())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setPrimaryFragment(fragment: Fragment) {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.container, fragment, TAG_PRIMARY)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
|
||||
object InternalResourceHelper {
|
||||
|
||||
fun getBoolean(context: Context, resName: String, defaultValue: Boolean): Boolean {
|
||||
val id = getResourceId(resName, "bool")
|
||||
return if (id != 0) {
|
||||
context.createPackageContext("android", 0).resources.getBoolean(id)
|
||||
} else {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resource id from system resources
|
||||
* @param resName resource name to get
|
||||
* @param type resource type of [resName] to get
|
||||
* @return 0 if not available
|
||||
*/
|
||||
private fun getResourceId(resName: String, type: String): Int {
|
||||
return Resources.getSystem().getIdentifier(resName, type, "android")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,19 +2,23 @@ package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.graphics.Color
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkRequest
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.view.Window
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.coroutineScope
|
||||
import androidx.work.CoroutineWorker
|
||||
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import org.koitharu.kotatsu.utils.InternalResourceHelper
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
val Context.connectivityManager: ConnectivityManager
|
||||
@@ -66,4 +70,18 @@ fun Lifecycle.postDelayed(runnable: Runnable, delay: Long) {
|
||||
delay(delay)
|
||||
runnable.run()
|
||||
}
|
||||
}
|
||||
|
||||
fun Window.setNavigationBarTransparentCompat(context: Context, elevation: Float = 0F) {
|
||||
navigationBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
|
||||
!InternalResourceHelper.getBoolean(context, "config_navBarNeedsScrim", true)
|
||||
) {
|
||||
Color.TRANSPARENT
|
||||
} else {
|
||||
// Set navbar scrim 70% of navigationBarColor
|
||||
ElevationOverlayProvider(context).compositeOverlayIfNeeded(
|
||||
context.getResourceColor(android.R.attr.navigationBarColor, 0.7F),
|
||||
elevation,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,33 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.Px
|
||||
import androidx.core.graphics.alpha
|
||||
import androidx.core.graphics.blue
|
||||
import androidx.core.graphics.green
|
||||
import androidx.core.graphics.red
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Px
|
||||
fun Resources.resolveDp(dp: Int) = (dp * displayMetrics.density).roundToInt()
|
||||
|
||||
@Px
|
||||
fun Resources.resolveDp(dp: Float) = dp * displayMetrics.density
|
||||
fun Resources.resolveDp(dp: Float) = dp * displayMetrics.density
|
||||
|
||||
@ColorInt
|
||||
fun Context.getResourceColor(@AttrRes resource: Int, alphaFactor: Float = 1f): Int {
|
||||
val typedArray = obtainStyledAttributes(intArrayOf(resource))
|
||||
val color = typedArray.getColor(0, 0)
|
||||
typedArray.recycle()
|
||||
|
||||
if (alphaFactor < 1f) {
|
||||
val alpha = (color.alpha * alphaFactor).roundToInt()
|
||||
return Color.argb(alpha, color.red, color.green, color.blue)
|
||||
}
|
||||
|
||||
return color
|
||||
}
|
||||
@@ -2,6 +2,6 @@
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?attr/colorSurfaceVariant" />
|
||||
<solid android:color="?attr/colorSecondaryContainer" />
|
||||
<corners android:radius="100dp" />
|
||||
</shape>
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/navigationView"
|
||||
android:layout_width="260dp"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="false"
|
||||
app:drawerLayoutCornerSize="0dp"
|
||||
app:elevation="0dp"
|
||||
app:menu="@menu/nav_drawer" />
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
tools:layout="@layout/fragment_list" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
app:elevation="0dp"
|
||||
app:liftOnScroll="false">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/toolbar_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:background="@drawable/toolbar_background"
|
||||
android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true">
|
||||
|
||||
<org.koitharu.kotatsu.search.ui.widget.SearchEditText
|
||||
android:id="@+id/searchView"
|
||||
style="@style/Widget.Kotatsu.SearchView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:background="@null"
|
||||
android:drawablePadding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:hint="@string/search_manga"
|
||||
android:imeOptions="actionSearch"
|
||||
android:importantForAutofill="no"
|
||||
android:singleLine="true"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/_continue"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="?attr/colorContainer"
|
||||
app:icon="@drawable/ic_read"
|
||||
app:layout_anchor="@id/container"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
app:layout_behavior="org.koitharu.kotatsu.base.ui.util.ShrinkOnScrollBehavior"
|
||||
app:layout_dodgeInsetEdges="bottom"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -24,15 +24,13 @@
|
||||
android:paddingRight="16dp"
|
||||
android:stateListAnimator="@null">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<FrameLayout
|
||||
android:id="@+id/toolbar_card"
|
||||
style="@style/Widget.Material3.CardView.Elevated"
|
||||
android:background="@drawable/toolbar_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar"
|
||||
app:cardCornerRadius="50dp"
|
||||
app:cardElevation="2dp"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
@@ -42,7 +40,9 @@
|
||||
android:background="@null"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
app:contentInsetStartWithNavigation="0dp">
|
||||
app:contentInsetStartWithNavigation="0dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
app:navigationIcon="?attr/actionModeWebSearchDrawable">
|
||||
|
||||
<org.koitharu.kotatsu.search.ui.widget.SearchEditText
|
||||
android:id="@+id/searchView"
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</FrameLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
7
app/src/main/res/layout/fragment_explore.xml
Normal file
7
app/src/main/res/layout/fragment_explore.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
7
app/src/main/res/layout/fragment_library.xml
Normal file
7
app/src/main/res/layout/fragment_library.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user