diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt index bfd8292ae..0cd5301a9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt @@ -36,13 +36,14 @@ class FavouritesListViewModel( when { list.isEmpty() -> listOf( EmptyState( - R.drawable.ic_heart_outline, - R.string.text_empty_holder_primary, - if (categoryId == 0L) { + icon = R.drawable.ic_heart_outline, + textPrimary = R.string.text_empty_holder_primary, + textSecondary = if (categoryId == 0L) { R.string.you_have_not_favourites_yet } else { R.string.favourites_category_empty - } + }, + actionStringRes = 0, ) ) else -> list.toUi(mode, this) diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt index 97664dd2f..b37e01a3c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt @@ -45,7 +45,14 @@ class HistoryListViewModel( createListModeFlow() ) { list, grouped, mode -> when { - list.isEmpty() -> listOf(EmptyState(R.drawable.ic_history, R.string.text_history_holder_primary, R.string.text_history_holder_secondary)) + list.isEmpty() -> listOf( + EmptyState( + icon = R.drawable.ic_history, + textPrimary = R.string.text_history_holder_primary, + textSecondary = R.string.text_history_holder_secondary, + actionStringRes = 0, + ) + ) else -> mapList(list, grouped, mode) } }.onFirst { diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt index 00bd769fd..f2c453db1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt @@ -15,17 +15,18 @@ import kotlinx.coroutines.launch import org.koin.android.ext.android.get import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseFragment -import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.PaginationScrollListener import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.resolve.ResolvableException import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.core.model.MangaTag import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter +import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.main.ui.AppBarOwner import org.koitharu.kotatsu.main.ui.MainActivity @@ -33,7 +34,7 @@ import org.koitharu.kotatsu.utils.RecycledViewPoolHolder import org.koitharu.kotatsu.utils.ext.* abstract class MangaListFragment : BaseFragment(), - PaginationScrollListener.Callback, OnListItemClickListener, + PaginationScrollListener.Callback, MangaListListener, SwipeRefreshLayout.OnRefreshListener { private var listAdapter: MangaListAdapter? = null @@ -62,10 +63,7 @@ abstract class MangaListFragment : BaseFragment(), listAdapter = MangaListAdapter( coil = get(), lifecycleOwner = viewLifecycleOwner, - clickListener = this, - onRetryClick = ::resolveException, - onTagRemoveClick = viewModel::onRemoveFilterTag, - onFilterClickListener = this::onFilterClick, + listener = this, ) paginationListener = PaginationScrollListener(4, this) with(binding.recyclerView) { @@ -192,7 +190,17 @@ abstract class MangaListFragment : BaseFragment(), } } - protected open fun onFilterClick() = Unit + override fun onFilterClick() = Unit + + override fun onEmptyActionClick() = Unit + + override fun onRetryClick(error: Throwable) { + resolveException(error) + } + + override fun onTagRemoveClick(tag: MangaTag) { + viewModel.onRemoveFilterTag(tag) + } private fun onGridScaleChanged(scale: Float) { spanSizeLookup.invalidateCache() diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/CurrentFilterAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/CurrentFilterAD.kt index 4848a27b8..5508f9f9c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/CurrentFilterAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/CurrentFilterAD.kt @@ -1,23 +1,23 @@ package org.koitharu.kotatsu.list.ui.adapter -import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate +import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.widgets.ChipsView import org.koitharu.kotatsu.core.model.MangaTag -import org.koitharu.kotatsu.databinding.ItemCurrentFilterBinding import org.koitharu.kotatsu.list.ui.model.CurrentFilterModel import org.koitharu.kotatsu.list.ui.model.ListModel fun currentFilterAD( - onTagRemoveClick: (MangaTag) -> Unit, -) = adapterDelegateViewBinding( - { inflater, parent -> ItemCurrentFilterBinding.inflate(inflater, parent, false) } -) { + listener: MangaListListener, +) = adapterDelegate(R.layout.item_current_filter) { - binding.chipsTags.onChipCloseClickListener = ChipsView.OnChipCloseClickListener { chip, data -> - onTagRemoveClick(data as? MangaTag ?: return@OnChipCloseClickListener) + val chipGroup = itemView as ChipsView + + chipGroup.onChipCloseClickListener = ChipsView.OnChipCloseClickListener { chip, data -> + listener.onTagRemoveClick(data as? MangaTag ?: return@OnChipCloseClickListener) } bind { - binding.chipsTags.setChips(item.chips) + chipGroup.setChips(item.chips) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/EmptyStateListAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/EmptyStateListAD.kt index 29ecc9b30..8385090ab 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/EmptyStateListAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/EmptyStateListAD.kt @@ -4,20 +4,20 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import org.koitharu.kotatsu.databinding.ItemEmptyStateBinding import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListModel +import org.koitharu.kotatsu.utils.ext.setTextAndVisible -fun emptyStateListAD() = adapterDelegateViewBinding( +fun emptyStateListAD( + listener: MangaListListener, +) = adapterDelegateViewBinding( { inflater, parent -> ItemEmptyStateBinding.inflate(inflater, parent, false) } ) { + binding.buttonRetry.setOnClickListener { listener.onEmptyActionClick() } + bind { - with(binding.icon) { - setImageResource(item.icon) - } - with(binding.textPrimary) { - setText(item.textPrimary) - } - with(binding.textSecondary) { - setText(item.textSecondary) - } + binding.icon.setImageResource(item.icon) + binding.textPrimary.setText(item.textPrimary) + binding.textSecondary.setTextAndVisible(item.textSecondary) + binding.buttonRetry.setTextAndVisible(item.actionStringRes) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorFooterAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorFooterAD.kt index 6e777f36b..52b3db95a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorFooterAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorFooterAD.kt @@ -7,13 +7,13 @@ import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.utils.ext.getDisplayMessage fun errorFooterAD( - onRetryClick: (Throwable) -> Unit + listener: MangaListListener, ) = adapterDelegateViewBinding( { inflater, parent -> ItemErrorFooterBinding.inflate(inflater, parent, false) } ) { binding.root.setOnClickListener { - onRetryClick(item.exception) + listener.onRetryClick(item.exception) } bind { diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorStateListAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorStateListAD.kt index eb78e6700..084c0c28f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorStateListAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ErrorStateListAD.kt @@ -8,13 +8,13 @@ import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.utils.ext.getDisplayMessage fun errorStateListAD( - onRetryClick: (Throwable) -> Unit + listener: MangaListListener, ) = adapterDelegateViewBinding( { inflater, parent -> ItemErrorStateBinding.inflate(inflater, parent, false) } ) { binding.buttonRetry.setOnClickListener { - onRetryClick(item.exception) + listener.onRetryClick(item.exception) } bind { diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeaderAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeaderAD.kt index 53ac01484..df322b010 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeaderAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/ListHeaderAD.kt @@ -24,14 +24,14 @@ fun listHeaderAD() = adapterDelegate( } fun listHeaderWithFilterAD( - onFilterClickListener: () -> Unit, + listener: MangaListListener, ) = adapterDelegateViewBinding( viewBinding = { inflater, parent -> ItemHeaderWithFilterBinding.inflate(inflater, parent, false) }, on = { item, _, _ -> item is ListHeader && item.sortOrder != null }, ) { binding.textViewFilter.setOnClickListener { - onFilterClickListener() + listener.onFilterClick() } bind { diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt index 714f04473..a95612318 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListAdapter.kt @@ -4,9 +4,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter -import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener -import org.koitharu.kotatsu.core.model.Manga -import org.koitharu.kotatsu.core.model.MangaTag import org.koitharu.kotatsu.core.ui.DateTimeAgo import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaGridModel @@ -17,32 +14,29 @@ import kotlin.jvm.internal.Intrinsics class MangaListAdapter( coil: ImageLoader, lifecycleOwner: LifecycleOwner, - clickListener: OnListItemClickListener, - onRetryClick: (Throwable) -> Unit, - onTagRemoveClick: (MangaTag) -> Unit, - onFilterClickListener: () -> Unit, + listener: MangaListListener, ) : AsyncListDifferDelegationAdapter(DiffCallback()) { init { delegatesManager .addDelegate( ITEM_TYPE_MANGA_LIST, - mangaListItemAD(coil, lifecycleOwner, clickListener) + mangaListItemAD(coil, lifecycleOwner, listener) ) .addDelegate( ITEM_TYPE_MANGA_LIST_DETAILED, - mangaListDetailedItemAD(coil, lifecycleOwner, clickListener) + mangaListDetailedItemAD(coil, lifecycleOwner, listener) ) - .addDelegate(ITEM_TYPE_MANGA_GRID, mangaGridItemAD(coil, lifecycleOwner, clickListener)) + .addDelegate(ITEM_TYPE_MANGA_GRID, mangaGridItemAD(coil, lifecycleOwner, listener)) .addDelegate(ITEM_TYPE_LOADING_FOOTER, loadingFooterAD()) .addDelegate(ITEM_TYPE_LOADING_STATE, loadingStateAD()) .addDelegate(ITEM_TYPE_DATE, relatedDateItemAD()) - .addDelegate(ITEM_TYPE_ERROR_STATE, errorStateListAD(onRetryClick)) - .addDelegate(ITEM_TYPE_ERROR_FOOTER, errorFooterAD(onRetryClick)) - .addDelegate(ITEM_TYPE_EMPTY, emptyStateListAD()) + .addDelegate(ITEM_TYPE_ERROR_STATE, errorStateListAD(listener)) + .addDelegate(ITEM_TYPE_ERROR_FOOTER, errorFooterAD(listener)) + .addDelegate(ITEM_TYPE_EMPTY, emptyStateListAD(listener)) .addDelegate(ITEM_TYPE_HEADER, listHeaderAD()) - .addDelegate(ITEM_TYPE_FILTER, currentFilterAD(onTagRemoveClick)) - .addDelegate(ITEM_TYPE_HEADER_FILTER, listHeaderWithFilterAD(onFilterClickListener)) + .addDelegate(ITEM_TYPE_FILTER, currentFilterAD(listener)) + .addDelegate(ITEM_TYPE_HEADER_FILTER, listHeaderWithFilterAD(listener)) } private class DiffCallback : DiffUtil.ItemCallback() { diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListListener.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListListener.kt new file mode 100644 index 000000000..5b372f2f8 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListListener.kt @@ -0,0 +1,13 @@ +package org.koitharu.kotatsu.list.ui.adapter + +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.core.model.MangaTag + +interface MangaListListener : OnListItemClickListener { + + fun onRetryClick(error: Throwable) + fun onTagRemoveClick(tag: MangaTag) + fun onFilterClick() + fun onEmptyActionClick() +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt index 70aef4326..6f7363b39 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterBottomSheet.kt @@ -24,10 +24,15 @@ class FilterBottomSheet : BaseBottomSheet() { ) { parametersOf( requireArguments().getParcelable(ARG_SOURCE), - requireArguments().getParcelable(ARG_STATE), ) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val state = requireArguments().getParcelable(ARG_STATE) + viewModel.updateState(state) + } + override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): SheetFilterBinding { return SheetFilterBinding.inflate(inflater, container, false) } diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterViewModel.kt index 9ce1579ce..0782b27db 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/filter/FilterViewModel.kt @@ -11,28 +11,24 @@ import org.koitharu.kotatsu.base.ui.BaseViewModel import org.koitharu.kotatsu.core.model.MangaTag import org.koitharu.kotatsu.core.model.SortOrder import org.koitharu.kotatsu.core.parser.RemoteMangaRepository +import org.koitharu.kotatsu.utils.ext.replaceWith import java.util.* class FilterViewModel( private val repository: RemoteMangaRepository, dataRepository: MangaDataRepository, - state: FilterState, ) : BaseViewModel(), OnFilterChangedListener { val filter = MutableLiveData>() val result = MutableLiveData() private var job: Job? = null - private var selectedSortOrder: SortOrder? = state.sortOrder - private val selectedTags = HashSet(state.tags) + private var selectedSortOrder: SortOrder? = repository.sortOrders.firstOrNull() + private val selectedTags = HashSet() private val localTagsDeferred = viewModelScope.async(Dispatchers.Default) { dataRepository.findTags(repository.source) } private var availableTagsDeferred = loadTagsAsync() - init { - showFilter() - } - override fun onSortItemClick(item: FilterItem.Sort) { selectedSortOrder = item.order updateFilters() @@ -49,6 +45,18 @@ class FilterViewModel( } } + fun updateState(state: FilterState?) { + if (state != null) { + selectedSortOrder = state.sortOrder + selectedTags.replaceWith(state.tags) + } + if (job == null) { + showFilter() + } else { + updateFilters() + } + } + @AnyThread private fun updateFilters() { val previousJob = job diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt index 0613f2e24..179bb25b5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt @@ -6,5 +6,6 @@ import androidx.annotation.StringRes data class EmptyState( @DrawableRes val icon: Int, @StringRes val textPrimary: Int, - @StringRes val textSecondary: Int + @StringRes val textSecondary: Int, + @StringRes val actionStringRes: Int, ) : ListModel \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt index 94ef2fe21..e30120259 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt @@ -62,6 +62,21 @@ class LocalListFragment : MangaListFragment(), ActivityResultCallback { - try { - importCall.launch(arrayOf("*/*")) - } catch (e: ActivityNotFoundException) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - Snackbar.make( - binding.recyclerView, - R.string.operation_not_supported, - Snackbar.LENGTH_SHORT - ).show() - } + onEmptyActionClick() true } else -> super.onOptionsItemSelected(item) diff --git a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt index b68af3a0a..1050475c2 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListViewModel.kt @@ -45,9 +45,10 @@ class LocalListViewModel( list == null -> listOf(LoadingState) list.isEmpty() -> listOf( EmptyState( - R.drawable.ic_storage, - R.string.text_local_holder_primary, - R.string.text_local_holder_secondary + icon = R.drawable.ic_storage, + textPrimary = R.string.text_local_holder_primary, + textSecondary = R.string.text_local_holder_secondary, + actionStringRes = R.string._import, ) ) else -> ArrayList(list.size + 1).apply { diff --git a/app/src/main/java/org/koitharu/kotatsu/remotelist/RemoteListModule.kt b/app/src/main/java/org/koitharu/kotatsu/remotelist/RemoteListModule.kt index 4d35a857f..91ded9a42 100644 --- a/app/src/main/java/org/koitharu/kotatsu/remotelist/RemoteListModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/remotelist/RemoteListModule.kt @@ -23,7 +23,6 @@ val remoteListModule FilterViewModel( repository = get(named(params.get())) as RemoteMangaRepository, dataRepository = get(), - state = params.get(), ) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt index 04a1ffefe..8d4d22f3a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListFragment.kt @@ -12,6 +12,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.list.ui.filter.FilterBottomSheet +import org.koitharu.kotatsu.list.ui.filter.FilterState import org.koitharu.kotatsu.reader.ui.SimpleSettingsActivity import org.koitharu.kotatsu.utils.ext.parcelableArgument import org.koitharu.kotatsu.utils.ext.withArgs @@ -65,6 +66,10 @@ class RemoteListFragment : MangaListFragment(), FragmentResultListener { FilterBottomSheet.show(childFragmentManager, source, viewModel.filter) } + override fun onEmptyActionClick() { + viewModel.applyFilter(FilterState(viewModel.filter.sortOrder, emptySet())) + } + override fun onFragmentResult(requestKey: String, result: Bundle) { when (requestKey) { FilterBottomSheet.REQUEST_KEY -> viewModel.applyFilter( diff --git a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index c914e709f..a41ed190f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -42,7 +42,7 @@ class RemoteListViewModel( when { list.isNullOrEmpty() && error != null -> listOf(error.toErrorState(canRetry = true)) list == null -> listOf(LoadingState) - list.isEmpty() -> listOf(EmptyState(R.drawable.ic_book_cross, R.string.nothing_found, R.string.empty)) + list.isEmpty() -> createEmptyState() else -> { val result = ArrayList(list.size + 3) result += header @@ -126,4 +126,13 @@ class RemoteListViewModel( CurrentFilterModel(tags.map { ChipsView.ChipModel(0, it.title, it) }) } } + + private fun createEmptyState() = listOf( + EmptyState( + icon = R.drawable.ic_book_cross, + textPrimary = R.string.nothing_found, + textSecondary = 0, + actionStringRes = if (filter.tags.isEmpty()) 0 else R.string.reset_filter, + ) + ) } diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchViewModel.kt index 659e12082..c5c5bdaf6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchViewModel.kt @@ -33,7 +33,14 @@ class SearchViewModel( when { list.isNullOrEmpty() && error != null -> listOf(error.toErrorState(canRetry = true)) list == null -> listOf(LoadingState) - list.isEmpty() -> listOf(EmptyState(R.drawable.ic_book_search, R.string.nothing_found, R.string.text_search_holder_secondary)) + list.isEmpty() -> listOf( + EmptyState( + icon = R.drawable.ic_book_search, + textPrimary = R.string.nothing_found, + textSecondary = R.string.text_search_holder_secondary, + actionStringRes = 0, + ) + ) else -> { val result = ArrayList(list.size + 1) list.toUi(result, mode) diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/global/GlobalSearchViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/global/GlobalSearchViewModel.kt index fff40209e..321ee09f8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/search/ui/global/GlobalSearchViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/search/ui/global/GlobalSearchViewModel.kt @@ -13,7 +13,6 @@ import org.koitharu.kotatsu.list.ui.model.* import org.koitharu.kotatsu.search.domain.MangaSearchRepository import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.ext.onFirst -import java.util.* class GlobalSearchViewModel( private val query: String, @@ -35,7 +34,14 @@ class GlobalSearchViewModel( when { list.isNullOrEmpty() && error != null -> listOf(error.toErrorState(canRetry = true)) list == null -> listOf(LoadingState) - list.isEmpty() -> listOf(EmptyState(R.drawable.ic_book_search, R.string.nothing_found, R.string.text_search_holder_secondary)) + list.isEmpty() -> listOf( + EmptyState( + icon = R.drawable.ic_book_search, + textPrimary = R.string.nothing_found, + textSecondary = R.string.text_search_holder_secondary, + actionStringRes = 0, + ) + ) else -> { val result = ArrayList(list.size + 1) list.toUi(result, mode) diff --git a/app/src/main/java/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt index 21090bf5f..634eeb757 100644 --- a/app/src/main/java/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/suggestions/ui/SuggestionsViewModel.kt @@ -24,11 +24,14 @@ class SuggestionsViewModel( createListModeFlow() ) { list, mode -> when { - list.isEmpty() -> listOf(EmptyState( - icon = R.drawable.ic_book_cross, - textPrimary = R.string.nothing_found, - textSecondary = R.string.text_suggestion_holder, - )) + list.isEmpty() -> listOf( + EmptyState( + icon = R.drawable.ic_book_cross, + textPrimary = R.string.nothing_found, + textSecondary = R.string.text_suggestion_holder, + actionStringRes = 0, + ) + ) else -> buildList(list.size + 1) { add(headerModel) list.toUi(this, mode) diff --git a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedFragment.kt b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedFragment.kt index 3f5d5263a..350979484 100644 --- a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedFragment.kt @@ -10,12 +10,13 @@ import org.koin.android.ext.android.get import org.koin.androidx.viewmodel.ext.android.viewModel import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseFragment -import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.PaginationScrollListener import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.core.model.MangaTag import org.koitharu.kotatsu.databinding.FragmentFeedBinding import org.koitharu.kotatsu.details.ui.DetailsActivity +import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.main.ui.AppBarOwner import org.koitharu.kotatsu.tracker.ui.adapter.FeedAdapter @@ -25,7 +26,7 @@ import org.koitharu.kotatsu.utils.ext.measureHeight import org.koitharu.kotatsu.utils.progress.Progress class FeedFragment : BaseFragment(), PaginationScrollListener.Callback, - OnListItemClickListener { + MangaListListener { private val viewModel by viewModel() @@ -114,6 +115,14 @@ class FeedFragment : BaseFragment(), PaginationScrollListen ) } + override fun onRetryClick(error: Throwable) = Unit + + override fun onTagRemoveClick(tag: MangaTag) = Unit + + override fun onFilterClick() = Unit + + override fun onEmptyActionClick() = Unit + private fun onListChanged(list: List) { feedAdapter?.items = list } diff --git a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt index b86f62919..ef533cdc1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt @@ -37,7 +37,14 @@ class FeedViewModel( hasNextPage ) { list, isHasNextPage -> when { - list.isEmpty() -> listOf(EmptyState(R.drawable.ic_feed, R.string.text_empty_holder_primary, R.string.text_feed_holder)) + list.isEmpty() -> listOf( + EmptyState( + icon = R.drawable.ic_feed, + textPrimary = R.string.text_empty_holder_primary, + textSecondary = R.string.text_feed_holder, + actionStringRes = 0, + ) + ) isHasNextPage -> list + LoadingFooter else -> list } diff --git a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/adapter/FeedAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/adapter/FeedAdapter.kt index 1314267e2..68c66bb3f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/adapter/FeedAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/adapter/FeedAdapter.kt @@ -4,8 +4,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter -import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener -import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.list.ui.adapter.* import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.LoadingFooter @@ -15,17 +13,17 @@ import kotlin.jvm.internal.Intrinsics class FeedAdapter( coil: ImageLoader, lifecycleOwner: LifecycleOwner, - clickListener: OnListItemClickListener + listener: MangaListListener, ) : AsyncListDifferDelegationAdapter(DiffCallback()) { init { delegatesManager - .addDelegate(ITEM_TYPE_FEED, feedItemAD(coil, lifecycleOwner, clickListener)) + .addDelegate(ITEM_TYPE_FEED, feedItemAD(coil, lifecycleOwner, listener)) .addDelegate(ITEM_TYPE_LOADING_FOOTER, loadingFooterAD()) .addDelegate(ITEM_TYPE_LOADING_STATE, loadingStateAD()) - .addDelegate(ITEM_TYPE_ERROR_FOOTER, errorFooterAD {}) - .addDelegate(ITEM_TYPE_ERROR_STATE, errorStateListAD {}) - .addDelegate(ITEM_TYPE_EMPTY, emptyStateListAD()) + .addDelegate(ITEM_TYPE_ERROR_FOOTER, errorFooterAD(listener)) + .addDelegate(ITEM_TYPE_ERROR_STATE, errorStateListAD(listener)) + .addDelegate(ITEM_TYPE_EMPTY, emptyStateListAD(listener)) } private class DiffCallback : DiffUtil.ItemCallback() { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt index 77e71daa5..ba57e667b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/TextViewExt.kt @@ -3,6 +3,7 @@ package org.koitharu.kotatsu.utils.ext import android.graphics.drawable.Drawable import android.view.View import android.widget.TextView +import androidx.annotation.StringRes import androidx.core.view.isGone var TextView.textAndVisible: CharSequence? @@ -17,4 +18,14 @@ var TextView.drawableStart: Drawable? set(value) { val dr = compoundDrawablesRelative setCompoundDrawablesRelativeWithIntrinsicBounds(value, dr[1], dr[2], dr[3]) - } \ No newline at end of file + } + +fun TextView.setTextAndVisible(@StringRes textResId: Int) { + if (textResId == 0) { + text = null + isGone = true + } else { + setText(textResId) + isGone = text.isNullOrEmpty() + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_current_filter.xml b/app/src/main/res/layout/item_current_filter.xml index 1014b0fdd..e15cdcc80 100644 --- a/app/src/main/res/layout/item_current_filter.xml +++ b/app/src/main/res/layout/item_current_filter.xml @@ -1,15 +1,8 @@ - - - - - \ No newline at end of file + android:layout_height="wrap_content" + app:closeIconEnabled="true" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_empty_state.xml b/app/src/main/res/layout/item_empty_state.xml index 5ed96afef..dcdac4e9d 100644 --- a/app/src/main/res/layout/item_empty_state.xml +++ b/app/src/main/res/layout/item_empty_state.xml @@ -34,4 +34,14 @@ android:textAppearance="?attr/textAppearanceBodyMedium" tools:text="@tools:sample/lorem[15]" /> +