diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2605f56f3..7e68eb1f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -122,7 +122,7 @@ android:name="org.koitharu.kotatsu.favourites.ui.FavouritesActivity" android:label="@string/favourites" /> (), AppBarOwner, SnackbarOwner { @@ -35,7 +35,7 @@ class BookmarksActivity : if (fm.findFragmentById(R.id.container) == null) { fm.commit { setReorderingAllowed(true) - replace(R.id.container, BookmarksFragment::class.java, null) + replace(R.id.container, AllBookmarksFragment::class.java, null) } } } @@ -49,6 +49,6 @@ class BookmarksActivity : companion object { - fun newIntent(context: Context) = Intent(context, BookmarksActivity::class.java) + fun newIntent(context: Context) = Intent(context, AllBookmarksActivity::class.java) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksFragment.kt similarity index 97% rename from app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksFragment.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksFragment.kt index 3d3b2b7fc..8ad428eaf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksFragment.kt @@ -17,7 +17,7 @@ import coil.ImageLoader import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark -import org.koitharu.kotatsu.bookmarks.ui.sheet.BookmarksAdapter +import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseFragment @@ -42,7 +42,7 @@ import org.koitharu.kotatsu.reader.ui.ReaderActivity import javax.inject.Inject @AndroidEntryPoint -class BookmarksFragment : +class AllBookmarksFragment : BaseFragment(), ListStateHolderListener, OnListItemClickListener, @@ -55,7 +55,7 @@ class BookmarksFragment : @Inject lateinit var settings: AppSettings - private val viewModel by viewModels() + private val viewModel by viewModels() private var bookmarksAdapter: BookmarksAdapter? = null private var selectionController: ListSelectionController? = null @@ -213,6 +213,6 @@ class BookmarksFragment : "org.koitharu.kotatsu.bookmarks.ui.BookmarksFragment", ), ) - fun newInstance() = BookmarksFragment() + fun newInstance() = AllBookmarksFragment() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksViewModel.kt similarity index 97% rename from app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksViewModel.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksViewModel.kt index f661ce4b2..ffa89b111 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/BookmarksViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksViewModel.kt @@ -25,7 +25,7 @@ import org.koitharu.kotatsu.parsers.model.Manga import javax.inject.Inject @HiltViewModel -class BookmarksViewModel @Inject constructor( +class AllBookmarksViewModel @Inject constructor( private val repository: BookmarksRepository, ) : BaseViewModel() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/sheet/BookmarkLargeAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkLargeAD.kt similarity index 96% rename from app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/sheet/BookmarkLargeAD.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkLargeAD.kt index 57a46c11c..e0aab168f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/sheet/BookmarkLargeAD.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkLargeAD.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.bookmarks.ui.sheet +package org.koitharu.kotatsu.bookmarks.ui.adapter import androidx.lifecycle.LifecycleOwner import coil.ImageLoader diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksAdapter.kt index 9bec3962d..fcc980fd4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksAdapter.kt @@ -1,19 +1,36 @@ package org.koitharu.kotatsu.bookmarks.ui.adapter +import android.content.Context import androidx.lifecycle.LifecycleOwner import coil.ImageLoader import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.core.ui.BaseListAdapter import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller +import org.koitharu.kotatsu.list.ui.adapter.ListHeaderClickListener import org.koitharu.kotatsu.list.ui.adapter.ListItemType +import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD +import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD +import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD +import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD +import org.koitharu.kotatsu.list.ui.model.ListModel class BookmarksAdapter( coil: ImageLoader, lifecycleOwner: LifecycleOwner, clickListener: OnListItemClickListener, -) : BaseListAdapter() { + headerClickListener: ListHeaderClickListener?, +) : BaseListAdapter(), FastScroller.SectionIndexer { init { - addDelegate(ListItemType.PAGE_THUMB, bookmarkListAD(coil, lifecycleOwner, clickListener)) + addDelegate(ListItemType.PAGE_THUMB, bookmarkLargeAD(coil, lifecycleOwner, clickListener)) + addDelegate(ListItemType.HEADER, listHeaderAD(headerClickListener)) + addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD()) + addDelegate(ListItemType.STATE_LOADING, loadingStateAD()) + addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, lifecycleOwner, null)) + } + + override fun getSectionText(context: Context, position: Int): CharSequence? { + return findHeader(position)?.getText(context) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/sheet/BookmarksAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/sheet/BookmarksAdapter.kt deleted file mode 100644 index 250d57f7e..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/sheet/BookmarksAdapter.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.koitharu.kotatsu.bookmarks.ui.sheet - -import android.content.Context -import androidx.lifecycle.LifecycleOwner -import coil.ImageLoader -import org.koitharu.kotatsu.bookmarks.domain.Bookmark -import org.koitharu.kotatsu.core.ui.BaseListAdapter -import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener -import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller -import org.koitharu.kotatsu.list.ui.adapter.ListHeaderClickListener -import org.koitharu.kotatsu.list.ui.adapter.ListItemType -import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD -import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD -import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD -import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD -import org.koitharu.kotatsu.list.ui.model.ListModel - -class BookmarksAdapter( - coil: ImageLoader, - lifecycleOwner: LifecycleOwner, - clickListener: OnListItemClickListener, - headerClickListener: ListHeaderClickListener?, -) : BaseListAdapter(), FastScroller.SectionIndexer { - - init { - addDelegate(ListItemType.PAGE_THUMB, bookmarkLargeAD(coil, lifecycleOwner, clickListener)) - addDelegate(ListItemType.HEADER, listHeaderAD(headerClickListener)) - addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD()) - addDelegate(ListItemType.STATE_LOADING, loadingStateAD()) - addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, lifecycleOwner, null)) - } - - override fun getSectionText(context: Context, position: Int): CharSequence? { - return findHeader(position)?.getText(context) - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesAdapter.kt index aeaa3092b..34a98672f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesAdapter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesAdapter.kt @@ -5,7 +5,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.details.ui.pager.bookmarks.MangaBookmarksFragment +import org.koitharu.kotatsu.details.ui.pager.bookmarks.BookmarksFragment import org.koitharu.kotatsu.details.ui.pager.chapters.ChaptersFragment import org.koitharu.kotatsu.details.ui.pager.pages.PagesFragment @@ -19,8 +19,8 @@ class ChaptersPagesAdapter( override fun createFragment(position: Int): Fragment = when (position) { 0 -> ChaptersFragment() - 1 -> if (isPagesTabEnabled) PagesFragment() else MangaBookmarksFragment() - 2 -> MangaBookmarksFragment() + 1 -> if (isPagesTabEnabled) PagesFragment() else BookmarksFragment() + 2 -> BookmarksFragment() else -> throw IllegalArgumentException("Invalid position $position") } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/MangaBookmarksFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksFragment.kt similarity index 65% rename from app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/MangaBookmarksFragment.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksFragment.kt index bae5c7e1e..ab00346ea 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/MangaBookmarksFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksFragment.kt @@ -2,23 +2,33 @@ package org.koitharu.kotatsu.details.ui.pager.bookmarks import android.os.Bundle import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.appcompat.view.ActionMode import androidx.core.graphics.Insets import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.recyclerview.widget.GridLayoutManager import coil.ImageLoader import dagger.hilt.android.AndroidEntryPoint +import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark -import org.koitharu.kotatsu.bookmarks.ui.sheet.BookmarksAdapter +import org.koitharu.kotatsu.bookmarks.ui.BookmarksSelectionDecoration +import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter +import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseFragment +import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.util.PagerNestedScrollHelper +import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver import org.koitharu.kotatsu.core.util.ext.dismissParentDialog +import org.koitharu.kotatsu.core.util.ext.findAppCompatDelegate import org.koitharu.kotatsu.core.util.ext.findParentCallback import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.databinding.FragmentMangaBookmarksBinding import org.koitharu.kotatsu.details.ui.DetailsViewModel import org.koitharu.kotatsu.list.ui.GridSpanResolver @@ -29,11 +39,11 @@ import org.koitharu.kotatsu.reader.ui.ReaderNavigationCallback import javax.inject.Inject @AndroidEntryPoint -class MangaBookmarksFragment : BaseFragment(), - OnListItemClickListener { +class BookmarksFragment : BaseFragment(), + OnListItemClickListener, ListSelectionController.Callback2 { private val activityViewModel by activityViewModels() - private val viewModel by viewModels() + private val viewModel by viewModels() @Inject lateinit var coil: ImageLoader @@ -43,6 +53,7 @@ class MangaBookmarksFragment : BaseFragment(), private var bookmarksAdapter: BookmarksAdapter? = null private var spanResolver: GridSpanResolver? = null + private var selectionController: ListSelectionController? = null private val spanSizeLookup = SpanSizeLookup() private val listCommitCallback = Runnable { @@ -61,10 +72,16 @@ class MangaBookmarksFragment : BaseFragment(), override fun onViewBindingCreated(binding: FragmentMangaBookmarksBinding, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState) spanResolver = GridSpanResolver(binding.root.resources) + selectionController = ListSelectionController( + appCompatDelegate = checkNotNull(findAppCompatDelegate()), + decoration = BookmarksSelectionDecoration(binding.root.context), + registryOwner = this, + callback = this, + ) bookmarksAdapter = BookmarksAdapter( coil = coil, lifecycleOwner = viewLifecycleOwner, - clickListener = this@MangaBookmarksFragment, + clickListener = this@BookmarksFragment, headerClickListener = null, ) viewModel.gridScale.observe(viewLifecycleOwner, ::onGridScaleChanged) // before rv initialization @@ -78,13 +95,21 @@ class MangaBookmarksFragment : BaseFragment(), it.spanSizeLookup = spanSizeLookup it.spanCount = checkNotNull(spanResolver).spanCount } + selectionController?.attachToRecyclerView(this) } viewModel.content.observe(viewLifecycleOwner) { bookmarksAdapter?.setItems(it, listCommitCallback) } + + viewModel.onError.observeEvent( + viewLifecycleOwner, + SnackbarErrorObserver(binding.recyclerView, this), + ) + viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) } override fun onDestroyView() { spanResolver = null bookmarksAdapter = null + selectionController = null spanSizeLookup.invalidateCache() super.onDestroyView() } @@ -92,6 +117,9 @@ class MangaBookmarksFragment : BaseFragment(), override fun onWindowInsetsChanged(insets: Insets) = Unit override fun onItemClick(item: Bookmark, view: View) { + if (selectionController?.onItemClick(item.pageId) == true) { + return + } val listener = findParentCallback(ReaderNavigationCallback::class.java) if (listener != null && listener.onBookmarkSelected(item)) { dismissParentDialog() @@ -105,6 +133,40 @@ class MangaBookmarksFragment : BaseFragment(), } } + override fun onItemLongClick(item: Bookmark, view: View): Boolean { + return selectionController?.onItemLongClick(item.pageId) ?: false + } + + override fun onSelectionChanged(controller: ListSelectionController, count: Int) { + requireViewBinding().recyclerView.invalidateItemDecorations() + } + + override fun onCreateActionMode( + controller: ListSelectionController, + mode: ActionMode, + menu: Menu, + ): Boolean { + mode.menuInflater.inflate(R.menu.mode_bookmarks, menu) + return true + } + + override fun onActionItemClicked( + controller: ListSelectionController, + mode: ActionMode, + item: MenuItem, + ): Boolean { + return when (item.itemId) { + R.id.action_remove -> { + val ids = selectionController?.snapshot() ?: return false + viewModel.removeBookmarks(ids) + mode.finish() + true + } + + else -> false + } + } + private fun onGridScaleChanged(scale: Float) { spanSizeLookup.invalidateCache() spanResolver?.setGridSize(scale, requireViewBinding().recyclerView) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/MangaBookmarksViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksViewModel.kt similarity index 79% rename from app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/MangaBookmarksViewModel.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksViewModel.kt index b198f1b84..0970f965f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/MangaBookmarksViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksViewModel.kt @@ -18,6 +18,9 @@ import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel +import org.koitharu.kotatsu.core.ui.util.ReversibleAction +import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListModel @@ -26,12 +29,13 @@ import org.koitharu.kotatsu.parsers.model.Manga import javax.inject.Inject @HiltViewModel -class MangaBookmarksViewModel @Inject constructor( - bookmarksRepository: BookmarksRepository, +class BookmarksViewModel @Inject constructor( + private val bookmarksRepository: BookmarksRepository, settings: AppSettings, ) : BaseViewModel(), FlowCollector { private val manga = MutableStateFlow(null) + val onActionDone = MutableEventFlow() val gridScale = settings.observeAsStateFlow( scope = viewModelScope + Dispatchers.Default, @@ -50,7 +54,14 @@ class MangaBookmarksViewModel @Inject constructor( manga.value = value } - private suspend fun mapList(manga: Manga, bookmarks: List): List? { + fun removeBookmarks(ids: Set) { + launchJob(Dispatchers.Default) { + val handle = bookmarksRepository.removeBookmarks(ids) + onActionDone.call(ReversibleAction(R.string.bookmarks_removed, handle)) + } + } + + private fun mapList(manga: Manga, bookmarks: List): List? { val chapters = manga.chapters ?: return null val bookmarksMap = bookmarks.groupBy { it.chapterId } val result = ArrayList(bookmarks.size + bookmarksMap.size) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt index 000191baf..2b5d8bfa0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt @@ -19,7 +19,7 @@ import coil.ImageLoader import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.bookmarks.ui.BookmarksActivity +import org.koitharu.kotatsu.bookmarks.ui.AllBookmarksActivity import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.os.AppShortcutManager import org.koitharu.kotatsu.core.ui.BaseFragment @@ -133,7 +133,7 @@ class ExploreFragment : override fun onClick(v: View) { val intent = when (v.id) { R.id.button_local -> MangaListActivity.newIntent(v.context, MangaSource.LOCAL) - R.id.button_bookmarks -> BookmarksActivity.newIntent(v.context) + R.id.button_bookmarks -> AllBookmarksActivity.newIntent(v.context) R.id.button_more -> SuggestionsActivity.newIntent(v.context) R.id.button_downloads -> DownloadsActivity.newIntent(v.context) R.id.button_random -> { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt index 04cd64f9f..611774e87 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt @@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.bookmarks.ui.BookmarksFragment +import org.koitharu.kotatsu.bookmarks.ui.AllBookmarksFragment import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.NavItem import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner @@ -144,7 +144,7 @@ class MainNavigationDelegate( R.id.nav_feed -> FeedFragment::class.java R.id.nav_local -> LocalListFragment::class.java R.id.nav_suggestions -> SuggestionsFragment::class.java - R.id.nav_bookmarks -> BookmarksFragment::class.java + R.id.nav_bookmarks -> AllBookmarksFragment::class.java R.id.nav_updated -> UpdatesFragment::class.java else -> return false }, @@ -158,7 +158,7 @@ class MainNavigationDelegate( is FeedFragment -> R.id.nav_feed is LocalListFragment -> R.id.nav_local is SuggestionsFragment -> R.id.nav_suggestions - is BookmarksFragment -> R.id.nav_bookmarks + is AllBookmarksFragment -> R.id.nav_bookmarks is UpdatesFragment -> R.id.nav_updated else -> 0 }