Application update indicator

pull/421/head
Koitharu 3 years ago
parent 4c201bf950
commit 2d670418c7
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -0,0 +1,38 @@
package org.koitharu.kotatsu.core.ui.util
import androidx.annotation.IdRes
import androidx.appcompat.widget.Toolbar
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.badge.BadgeUtils
import com.google.android.material.badge.ExperimentalBadgeUtils
@androidx.annotation.OptIn(ExperimentalBadgeUtils::class)
class OptionsMenuBadgeHelper(
private val toolbar: Toolbar,
@IdRes private val itemId: Int,
) {
private var badge: BadgeDrawable? = null
fun setBadgeVisible(isVisible: Boolean) {
if (isVisible) {
showBadge()
} else {
hideBadge()
}
}
private fun hideBadge() {
badge?.let {
BadgeUtils.detachBadgeDrawable(it, toolbar, itemId)
}
badge = null
}
private fun showBadge() {
val badgeDrawable = badge ?: BadgeDrawable.create(toolbar.context).also {
badge = it
}
BadgeUtils.attachBadgeDrawable(badgeDrawable, toolbar, itemId)
}
}

@ -40,6 +40,7 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.ui.util.OptionsMenuBadgeHelper
import org.koitharu.kotatsu.core.ui.widgets.SlidingBottomNavigationView import org.koitharu.kotatsu.core.ui.widgets.SlidingBottomNavigationView
import org.koitharu.kotatsu.core.util.ext.hideKeyboard import org.koitharu.kotatsu.core.util.ext.hideKeyboard
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
@ -63,6 +64,7 @@ import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionFragment
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.settings.about.AppUpdateDialog
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
import javax.inject.Inject import javax.inject.Inject
@ -81,6 +83,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
private val searchSuggestionViewModel by viewModels<SearchSuggestionViewModel>() private val searchSuggestionViewModel by viewModels<SearchSuggestionViewModel>()
private val closeSearchCallback = CloseSearchCallback() private val closeSearchCallback = CloseSearchCallback()
private lateinit var navigationDelegate: MainNavigationDelegate private lateinit var navigationDelegate: MainNavigationDelegate
private lateinit var appUpdateBadge: OptionsMenuBadgeHelper
override val appBar: AppBarLayout override val appBar: AppBarLayout
get() = viewBinding.appbar get() = viewBinding.appbar
@ -119,6 +122,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
navigationDelegate.addOnFragmentChangedListener(this) navigationDelegate.addOnFragmentChangedListener(this)
navigationDelegate.onCreate() navigationDelegate.onCreate()
appUpdateBadge = OptionsMenuBadgeHelper(viewBinding.toolbar, R.id.action_app_update)
onBackPressedDispatcher.addCallback(ExitCallback(this, viewBinding.container)) onBackPressedDispatcher.addCallback(ExitCallback(this, viewBinding.container))
onBackPressedDispatcher.addCallback(navigationDelegate) onBackPressedDispatcher.addCallback(navigationDelegate)
onBackPressedDispatcher.addCallback(closeSearchCallback) onBackPressedDispatcher.addCallback(closeSearchCallback)
@ -132,6 +137,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
viewModel.isLoading.observe(this, this::onLoadingStateChanged) viewModel.isLoading.observe(this, this::onLoadingStateChanged)
viewModel.isResumeEnabled.observe(this, this::onResumeEnabledChanged) viewModel.isResumeEnabled.observe(this, this::onResumeEnabledChanged)
viewModel.counters.observe(this, ::onCountersChanged) viewModel.counters.observe(this, ::onCountersChanged)
viewModel.appUpdate.observe(this) { invalidateMenu() }
viewModel.isFeedAvailable.observe(this, ::onFeedAvailabilityChanged) viewModel.isFeedAvailable.observe(this, ::onFeedAvailabilityChanged)
searchSuggestionViewModel.isIncognitoModeEnabled.observe(this, this::onIncognitoModeChanged) searchSuggestionViewModel.isIncognitoModeEnabled.observe(this, this::onIncognitoModeChanged)
} }
@ -158,6 +164,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
menu?.findItem(R.id.action_incognito)?.isChecked = searchSuggestionViewModel.isIncognitoModeEnabled.value menu?.findItem(R.id.action_incognito)?.isChecked = searchSuggestionViewModel.isIncognitoModeEnabled.value
val hasAppUpdate = viewModel.appUpdate.value != null
menu?.findItem(R.id.action_app_update)?.isVisible = hasAppUpdate
appUpdateBadge.setBadgeVisible(hasAppUpdate)
return super.onPrepareOptionsMenu(menu) return super.onPrepareOptionsMenu(menu)
} }
@ -179,6 +188,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
true true
} }
R.id.action_app_update -> {
viewModel.appUpdate.value?.also {
AppUpdateDialog(this)
.show(it)
} != null
}
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }

@ -7,6 +7,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@ -46,12 +47,14 @@ class MainViewModel @Inject constructor(
valueProducer = { isTrackerEnabled }, valueProducer = { isTrackerEnabled },
) )
val appUpdate = appUpdateRepository.observeAvailableUpdate()
val counters = combine( val counters = combine(
appUpdateRepository.observeAvailableUpdate(),
trackingRepository.observeUpdatedMangaCount(), trackingRepository.observeUpdatedMangaCount(),
) { appUpdate, tracks -> flow { emit(settings.newSources) },
) { tracks, newSources ->
val a = SparseIntArray(2) val a = SparseIntArray(2)
// a[R.id.nav_tools] = if (appUpdate != null) 1 else 0 a[R.id.nav_explore] = newSources.size
a[R.id.nav_feed] = tracks a[R.id.nav_feed] = tracks
a a
}.stateIn( }.stateIn(

@ -3,6 +3,14 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_app_update"
android:icon="@drawable/ic_app_update"
android:orderInCategory="1"
android:title="@string/update"
android:visible="false"
app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_incognito" android:id="@+id/action_incognito"
android:checkable="true" android:checkable="true"

Loading…
Cancel
Save