Improve scrobbling ui
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,6 +15,7 @@
|
||||
/.idea/deploymentTargetDropDown.xml
|
||||
/.idea/androidTestResultsUserPreferences.xml
|
||||
/.idea/render.experimental.xml
|
||||
/.idea/inspectionProfiles/
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
|
||||
17
.idea/inspectionProfiles/Project_Default.xml
generated
17
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,17 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="BooleanLiteralArgument" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="Destructure" enabled="true" level="INFO" enabled_by_default="true" />
|
||||
<inspection_tool class="FillClass" enabled="true" level="INFORMATION" enabled_by_default="true">
|
||||
<option name="withoutDefaultValues" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="KeySetIterationMayUseEntrySet" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="KotlinFunctionArgumentsHelper" enabled="true" level="INFORMATION" enabled_by_default="true">
|
||||
<option name="withoutDefaultValues" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ReplaceCollectionCountWithSize" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TrailingComma" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
||||
<inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
@@ -9,13 +9,13 @@ import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.R as materialR
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.dialog.AppBottomSheetDialog
|
||||
import org.koitharu.kotatsu.utils.ext.displayCompat
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
|
||||
|
||||
@@ -27,6 +27,9 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
|
||||
protected val behavior: BottomSheetBehavior<*>?
|
||||
get() = (dialog as? BottomSheetDialog)?.behavior
|
||||
|
||||
val isExpanded: Boolean
|
||||
get() = behavior?.state == BottomSheetBehavior.STATE_EXPANDED
|
||||
|
||||
final override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
||||
@@ -42,7 +42,7 @@ class DetailsMenuProvider(
|
||||
menu.findItem(R.id.action_delete).isVisible = manga?.source == MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_browser).isVisible = manga?.source != MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_shortcut).isVisible = ShortcutManagerCompat.isRequestPinShortcutSupported(activity)
|
||||
menu.findItem(R.id.action_shiki_track).isVisible = viewModel.isScrobblingAvailable
|
||||
menu.findItem(R.id.action_scrobbling).isVisible = viewModel.isScrobblingAvailable
|
||||
menu.findItem(R.id.action_favourite).setIcon(
|
||||
if (viewModel.favouriteCategories.value == true) R.drawable.ic_heart else R.drawable.ic_heart_outline,
|
||||
)
|
||||
@@ -60,11 +60,13 @@ class DetailsMenuProvider(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
viewModel.manga.value?.let {
|
||||
FavouriteCategoriesBottomSheet.show(activity.supportFragmentManager, it)
|
||||
}
|
||||
}
|
||||
|
||||
R.id.action_delete -> {
|
||||
val title = viewModel.manga.value?.title.orEmpty()
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
@@ -76,6 +78,7 @@ class DetailsMenuProvider(
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
R.id.action_save -> {
|
||||
viewModel.manga.value?.let {
|
||||
val chaptersCount = it.chapters?.size ?: 0
|
||||
@@ -87,21 +90,25 @@ class DetailsMenuProvider(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R.id.action_browser -> {
|
||||
viewModel.manga.value?.let {
|
||||
activity.startActivity(BrowserActivity.newIntent(activity, it.publicUrl, it.title))
|
||||
}
|
||||
}
|
||||
|
||||
R.id.action_related -> {
|
||||
viewModel.manga.value?.let {
|
||||
activity.startActivity(MultiSearchActivity.newIntent(activity, it.title))
|
||||
}
|
||||
}
|
||||
R.id.action_shiki_track -> {
|
||||
|
||||
R.id.action_scrobbling -> {
|
||||
viewModel.manga.value?.let {
|
||||
ScrobblingSelectorBottomSheet.show(activity.supportFragmentManager, it)
|
||||
ScrobblingSelectorBottomSheet.show(activity.supportFragmentManager, it, null)
|
||||
}
|
||||
}
|
||||
|
||||
R.id.action_shortcut -> {
|
||||
viewModel.manga.value?.let {
|
||||
activity.lifecycleScope.launch {
|
||||
@@ -112,6 +119,7 @@ class DetailsMenuProvider(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -256,29 +256,24 @@ class DetailsViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateScrobbling(rating: Float, status: ScrobblingStatus?) {
|
||||
for (info in scrobblingInfo.value ?: return) {
|
||||
val scrobbler = scrobblers.first { it.scrobblerService == info.scrobbler }
|
||||
if (!scrobbler.isAvailable) continue
|
||||
launchJob(Dispatchers.Default) {
|
||||
scrobbler.updateScrobblingInfo(
|
||||
mangaId = delegate.mangaId,
|
||||
rating = rating,
|
||||
status = status,
|
||||
comment = null,
|
||||
)
|
||||
}
|
||||
fun updateScrobbling(index: Int, rating: Float, status: ScrobblingStatus?) {
|
||||
val scrobbler = getScrobbler(index) ?: return
|
||||
launchJob(Dispatchers.Default) {
|
||||
scrobbler.updateScrobblingInfo(
|
||||
mangaId = delegate.mangaId,
|
||||
rating = rating,
|
||||
status = status,
|
||||
comment = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterScrobbling() {
|
||||
for (scrobbler in scrobblers) {
|
||||
if (!scrobbler.isAvailable) continue
|
||||
launchJob(Dispatchers.Default) {
|
||||
scrobbler.unregisterScrobbling(
|
||||
mangaId = delegate.mangaId,
|
||||
)
|
||||
}
|
||||
fun unregisterScrobbling(index: Int) {
|
||||
val scrobbler = getScrobbler(index) ?: return
|
||||
launchJob(Dispatchers.Default) {
|
||||
scrobbler.unregisterScrobbling(
|
||||
mangaId = delegate.mangaId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +310,19 @@ class DetailsViewModel @AssistedInject constructor(
|
||||
return spannable.trim()
|
||||
}
|
||||
|
||||
private fun getScrobbler(index: Int): Scrobbler? {
|
||||
val info = scrobblingInfo.value?.getOrNull(index)
|
||||
val scrobbler = if (info != null) {
|
||||
scrobblers.find { it.scrobblerService == info.scrobbler && it.isAvailable }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (scrobbler == null) {
|
||||
errorEvent.call(IllegalStateException("Scrobbler [$index] is not available"))
|
||||
}
|
||||
return scrobbler
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
|
||||
@@ -15,9 +15,7 @@ import androidx.core.net.toUri
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import coil.ImageLoader
|
||||
import coil.request.ImageRequest
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.databinding.SheetScrobblingBinding
|
||||
@@ -26,7 +24,12 @@ import org.koitharu.kotatsu.image.ui.ImageActivity
|
||||
import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingInfo
|
||||
import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingStatus
|
||||
import org.koitharu.kotatsu.scrobbling.ui.selector.ScrobblingSelectorBottomSheet
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ScrobblingInfoBottomSheet :
|
||||
@@ -41,6 +44,7 @@ class ScrobblingInfoBottomSheet :
|
||||
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
private var menu: PopupMenu? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -78,6 +82,7 @@ class ScrobblingInfoBottomSheet :
|
||||
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
viewModel.updateScrobbling(
|
||||
index = scrobblerIndex,
|
||||
rating = binding.ratingBar.rating / binding.ratingBar.numStars,
|
||||
status = enumValues<ScrobblingStatus>().getOrNull(position),
|
||||
)
|
||||
@@ -88,6 +93,7 @@ class ScrobblingInfoBottomSheet :
|
||||
override fun onRatingChanged(ratingBar: RatingBar, rating: Float, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
viewModel.updateScrobbling(
|
||||
index = scrobblerIndex,
|
||||
rating = rating / ratingBar.numStars,
|
||||
status = enumValues<ScrobblingStatus>().getOrNull(binding.spinnerStatus.selectedItemPosition),
|
||||
)
|
||||
@@ -115,15 +121,15 @@ class ScrobblingInfoBottomSheet :
|
||||
binding.ratingBar.rating = scrobbling.rating * binding.ratingBar.numStars
|
||||
binding.textViewDescription.text = scrobbling.description
|
||||
binding.spinnerStatus.setSelection(scrobbling.status?.ordinal ?: -1)
|
||||
ImageRequest.Builder(context ?: return)
|
||||
.target(binding.imageViewCover)
|
||||
.data(scrobbling.coverUrl)
|
||||
.crossfade(context)
|
||||
.lifecycle(viewLifecycleOwner)
|
||||
.placeholder(R.drawable.ic_placeholder)
|
||||
.fallback(R.drawable.ic_placeholder)
|
||||
.error(R.drawable.ic_error_placeholder)
|
||||
.enqueueWith(coil)
|
||||
binding.imageViewLogo.contentDescription = getString(scrobbling.scrobbler.titleResId)
|
||||
binding.imageViewLogo.setImageResource(scrobbling.scrobbler.iconResId)
|
||||
binding.imageViewCover.newImageRequest(scrobbling.coverUrl)?.apply {
|
||||
lifecycle(viewLifecycleOwner)
|
||||
placeholder(R.drawable.ic_placeholder)
|
||||
fallback(R.drawable.ic_placeholder)
|
||||
error(R.drawable.ic_error_placeholder)
|
||||
enqueueWith(coil)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
@@ -135,13 +141,16 @@ class ScrobblingInfoBottomSheet :
|
||||
Intent.createChooser(intent, getString(R.string.open_in_browser)),
|
||||
)
|
||||
}
|
||||
|
||||
R.id.action_unregister -> {
|
||||
viewModel.unregisterScrobbling()
|
||||
viewModel.unregisterScrobbling(scrobblerIndex)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
R.id.action_edit -> {
|
||||
val manga = viewModel.manga.value ?: return false
|
||||
ScrobblingSelectorBottomSheet.show(parentFragmentManager, manga)
|
||||
val scrobblerService = viewModel.scrobblingInfo.value?.getOrNull(scrobblerIndex)?.scrobbler
|
||||
ScrobblingSelectorBottomSheet.show(parentFragmentManager, manga, scrobblerService)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,12 @@ import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import coil.ImageLoader
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
@@ -23,11 +22,14 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.base.ui.list.PaginationScrollListener
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.databinding.SheetScrobblingSelectorBinding
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
|
||||
import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerService
|
||||
import org.koitharu.kotatsu.scrobbling.ui.selector.adapter.ShikiMangaSelectionDecoration
|
||||
import org.koitharu.kotatsu.scrobbling.ui.selector.adapter.ShikimoriSelectorAdapter
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.requireParcelable
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
@@ -42,7 +44,8 @@ class ScrobblingSelectorBottomSheet :
|
||||
MenuItem.OnActionExpandListener,
|
||||
SearchView.OnQueryTextListener,
|
||||
DialogInterface.OnKeyListener,
|
||||
AdapterView.OnItemSelectedListener {
|
||||
TabLayout.OnTabSelectedListener,
|
||||
ListStateHolderListener {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ScrobblingSelectorViewModel.Factory
|
||||
@@ -68,7 +71,7 @@ class ScrobblingSelectorBottomSheet :
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val listAdapter = ShikimoriSelectorAdapter(viewLifecycleOwner, coil, this)
|
||||
val listAdapter = ShikimoriSelectorAdapter(viewLifecycleOwner, coil, this, this)
|
||||
val decoration = ShikiMangaSelectionDecoration(view.context)
|
||||
with(binding.recyclerView) {
|
||||
adapter = listAdapter
|
||||
@@ -77,7 +80,7 @@ class ScrobblingSelectorBottomSheet :
|
||||
}
|
||||
binding.buttonDone.setOnClickListener(this)
|
||||
initOptionsMenu()
|
||||
initSpinner()
|
||||
initTabs()
|
||||
|
||||
viewModel.content.observe(viewLifecycleOwner) { listAdapter.items = it }
|
||||
viewModel.selectedItemId.observe(viewLifecycleOwner) {
|
||||
@@ -103,6 +106,12 @@ class ScrobblingSelectorBottomSheet :
|
||||
viewModel.selectedItemId.value = item.id
|
||||
}
|
||||
|
||||
override fun onRetryClick(error: Throwable) = Unit
|
||||
|
||||
override fun onEmptyActionClick() {
|
||||
openSearch()
|
||||
}
|
||||
|
||||
override fun onScrolledToEnd() {
|
||||
viewModel.loadList(append = true)
|
||||
}
|
||||
@@ -143,11 +152,23 @@ class ScrobblingSelectorBottomSheet :
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
viewModel.setScrobblerIndex(position)
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
viewModel.setScrobblerIndex(tab.position)
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) = Unit
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
if (!isExpanded) {
|
||||
setExpanded(isExpanded = true, isLocked = behavior?.isDraggable == false)
|
||||
}
|
||||
binding.recyclerView.firstVisibleItemPosition = 0
|
||||
}
|
||||
|
||||
private fun openSearch() {
|
||||
val menuItem = binding.headerBar.menu.findItem(R.id.action_search) ?: return
|
||||
menuItem.expandActionView()
|
||||
}
|
||||
|
||||
private fun onError(e: Throwable) {
|
||||
Toast.makeText(requireContext(), e.getDisplayMessage(resources), Toast.LENGTH_LONG).show()
|
||||
@@ -166,32 +187,41 @@ class ScrobblingSelectorBottomSheet :
|
||||
searchView.queryHint = searchMenuItem.title
|
||||
}
|
||||
|
||||
private fun initSpinner() {
|
||||
private fun initTabs() {
|
||||
val entries = viewModel.availableScrobblers
|
||||
val tabs = binding.tabs
|
||||
if (entries.size <= 1) {
|
||||
binding.spinnerScrobblers.isVisible = false
|
||||
tabs.isVisible = false
|
||||
return
|
||||
}
|
||||
val adapter = ArrayAdapter(
|
||||
requireContext(),
|
||||
android.R.layout.simple_spinner_item,
|
||||
entries.map { getString(it.scrobblerService.titleResId) },
|
||||
)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
binding.spinnerScrobblers.adapter = adapter
|
||||
viewModel.selectedScrobblerIndex.observe(viewLifecycleOwner) {
|
||||
binding.spinnerScrobblers.setSelection(it)
|
||||
val selectedId = arguments?.getInt(ARG_SCROBBLER, -1) ?: -1
|
||||
tabs.removeAllTabs()
|
||||
tabs.clearOnTabSelectedListeners()
|
||||
tabs.addOnTabSelectedListener(this)
|
||||
for (entry in entries) {
|
||||
val tab = tabs.newTab()
|
||||
tab.tag = entry.scrobblerService
|
||||
tab.setIcon(entry.scrobblerService.iconResId)
|
||||
tab.setText(entry.scrobblerService.titleResId)
|
||||
tabs.addTab(tab)
|
||||
if (entry.scrobblerService.id == selectedId) {
|
||||
tab.select()
|
||||
}
|
||||
}
|
||||
binding.spinnerScrobblers.onItemSelectedListener = this
|
||||
tabs.isVisible = true
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "ScrobblingSelectorBottomSheet"
|
||||
private const val ARG_SCROBBLER = "scrobbler"
|
||||
|
||||
fun show(fm: FragmentManager, manga: Manga) =
|
||||
ScrobblingSelectorBottomSheet().withArgs(1) {
|
||||
fun show(fm: FragmentManager, manga: Manga, scrobblerService: ScrobblerService?) =
|
||||
ScrobblingSelectorBottomSheet().withArgs(2) {
|
||||
putParcelable(MangaIntent.KEY_MANGA, ParcelableManga(manga, withChapters = false))
|
||||
if (scrobblerService != null) {
|
||||
putInt(ARG_SCROBBLER, scrobblerService.id)
|
||||
}
|
||||
}.show(fm, TAG)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.list.ui.model.EmptyHint
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.list.ui.model.LoadingFooter
|
||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||
@@ -46,7 +48,7 @@ class ScrobblingSelectorViewModel @AssistedInject constructor(
|
||||
hasNextPage,
|
||||
) { list, isHasNextPage ->
|
||||
when {
|
||||
list.isEmpty() -> listOf()
|
||||
list.isEmpty() -> listOf(emptyResultsHint())
|
||||
isHasNextPage -> list + LoadingFooter
|
||||
else -> list
|
||||
}
|
||||
@@ -125,6 +127,13 @@ class ScrobblingSelectorViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun emptyResultsHint() = EmptyHint(
|
||||
icon = R.drawable.ic_empty_history,
|
||||
textPrimary = R.string.nothing_found,
|
||||
textSecondary = R.string.text_search_holder_secondary,
|
||||
actionStringRes = R.string.search,
|
||||
)
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
||||
|
||||
fun shikimoriMangaAD(
|
||||
fun scrobblingMangaAD(
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
coil: ImageLoader,
|
||||
clickListener: OnListItemClickListener<ScrobblerManga>,
|
||||
@@ -4,23 +4,27 @@ import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import coil.ImageLoader
|
||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
|
||||
import org.koitharu.kotatsu.list.ui.adapter.emptyHintAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblerManga
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
|
||||
class ShikimoriSelectorAdapter(
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
coil: ImageLoader,
|
||||
clickListener: OnListItemClickListener<ScrobblerManga>,
|
||||
stateHolderListener: ListStateHolderListener,
|
||||
) : AsyncListDifferDelegationAdapter<ListModel>(DiffCallback()) {
|
||||
|
||||
init {
|
||||
delegatesManager.addDelegate(loadingStateAD())
|
||||
.addDelegate(shikimoriMangaAD(lifecycleOwner, coil, clickListener))
|
||||
.addDelegate(scrobblingMangaAD(lifecycleOwner, coil, clickListener))
|
||||
.addDelegate(loadingFooterAD())
|
||||
.addDelegate(emptyHintAD(stateHolderListener))
|
||||
}
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<ListModel>() {
|
||||
@@ -37,4 +41,4 @@ class ShikimoriSelectorAdapter(
|
||||
return Intrinsics.areEqual(oldItem, newItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,8 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
viewLifecycleScope.launch {
|
||||
pref.summary = withContext(Dispatchers.Default) {
|
||||
runCatching {
|
||||
repository.loadUser().nickname
|
||||
val user = repository.loadUser()
|
||||
getString(R.string.logged_in_as, user.nickname)
|
||||
}.getOrElse {
|
||||
it.printStackTraceDebug()
|
||||
it.getDisplayMessage(resources)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -36,6 +36,17 @@
|
||||
tools:background="@sample/covers[9]"
|
||||
tools:ignore="ContentDescription,UnusedAttribute" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_logo"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_margin="@dimen/card_indicator_offset"
|
||||
app:layout_constraintBottom_toBottomOf="@id/imageView_cover"
|
||||
app:layout_constraintEnd_toEndOf="@id/imageView_cover"
|
||||
app:tint="?colorControlLight"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@drawable/ic_shikimori" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="0dp"
|
||||
|
||||
@@ -24,11 +24,13 @@
|
||||
|
||||
</org.koitharu.kotatsu.base.ui.widgets.BottomSheetHeaderBar>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_scrobblers"
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:listitem="@android:layout/simple_spinner_item" />
|
||||
android:visibility="gone"
|
||||
app:tabGravity="start"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
@@ -36,7 +38,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:padding="@dimen/grid_spacing"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_manga_list" />
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shiki_track"
|
||||
android:id="@+id/action_scrobbling"
|
||||
android:orderInCategory="50"
|
||||
android:title="@string/tracking"
|
||||
app:showAsAction="never" />
|
||||
|
||||
Reference in New Issue
Block a user