From 0e7960fcedcda8556f07d531a83b357c1b735044 Mon Sep 17 00:00:00 2001 From: Zakhar Timoshenko Date: Sat, 2 Jul 2022 22:13:31 +0300 Subject: [PATCH] Initial adding bottom navigation --- .../koitharu/kotatsu/main/ui/MainActivity.kt | 133 ++++-------------- .../kotatsu/utils/InternalResourceHelper.kt | 27 ++++ .../koitharu/kotatsu/utils/ext/AndroidExt.kt | 18 +++ .../kotatsu/utils/ext/ResourcesExt.kt | 24 +++- .../main/res/drawable/toolbar_background.xml | 2 +- .../res/layout-w720dp-land/activity_main.xml | 96 ------------- app/src/main/res/layout/activity_main.xml | 12 +- app/src/main/res/layout/fragment_explore.xml | 7 + app/src/main/res/layout/fragment_library.xml | 7 + 9 files changed, 115 insertions(+), 211 deletions(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/InternalResourceHelper.kt delete mode 100644 app/src/main/res/layout-w720dp-land/activity_main.xml create mode 100644 app/src/main/res/layout/fragment_explore.xml create mode 100644 app/src/main/res/layout/fragment_library.xml diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt index 55cd36559..e8f54182d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -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(), - NavigationView.OnNavigationItemSelectedListener, AppBarOwner, View.OnClickListener, View.OnFocusChangeListener, @@ -75,6 +75,8 @@ class MainActivity : private val viewModel by viewModel() private val searchSuggestionViewModel by viewModel() + 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 { bottomMargin = insets.bottom + topMargin @@ -335,57 +305,6 @@ class MainActivity : adjustFabVisibility(isResumeEnabled = isEnabled) } - private fun updateSideMenu(remoteSources: List) { - 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) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/InternalResourceHelper.kt b/app/src/main/java/org/koitharu/kotatsu/utils/InternalResourceHelper.kt new file mode 100644 index 000000000..dc6a86a91 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/InternalResourceHelper.kt @@ -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") + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt index bd6ad731b..51e49f24f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt @@ -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, + ) + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ResourcesExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ResourcesExt.kt index 6b5cd4157..8735eb970 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ResourcesExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ResourcesExt.kt @@ -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 \ No newline at end of file +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 +} \ No newline at end of file diff --git a/app/src/main/res/drawable/toolbar_background.xml b/app/src/main/res/drawable/toolbar_background.xml index 301d6bc22..2c38f25fc 100644 --- a/app/src/main/res/drawable/toolbar_background.xml +++ b/app/src/main/res/drawable/toolbar_background.xml @@ -2,6 +2,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout-w720dp-land/activity_main.xml b/app/src/main/res/layout-w720dp-land/activity_main.xml deleted file mode 100644 index 63d11c39b..000000000 --- a/app/src/main/res/layout-w720dp-land/activity_main.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ 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 5697b0d35..0d8fededf 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -24,15 +24,13 @@ android:paddingRight="16dp" android:stateListAnimator="@null"> - + app:contentInsetStartWithNavigation="0dp" + android:layout_marginEnd="6dp" + app:navigationIcon="?attr/actionModeWebSearchDrawable"> - + diff --git a/app/src/main/res/layout/fragment_explore.xml b/app/src/main/res/layout/fragment_explore.xml new file mode 100644 index 000000000..44cb66b71 --- /dev/null +++ b/app/src/main/res/layout/fragment_explore.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml new file mode 100644 index 000000000..44cb66b71 --- /dev/null +++ b/app/src/main/res/layout/fragment_library.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file