UI improvements

master
Koitharu 2 years ago
parent 1bf01ca240
commit 7c4b254f08
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -14,6 +14,7 @@ import android.widget.TextView
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.widget.LinearLayoutCompat import androidx.appcompat.widget.LinearLayoutCompat
import androidx.core.content.withStyledAttributes import androidx.core.content.withStyledAttributes
import androidx.core.view.children
import androidx.core.widget.TextViewCompat import androidx.core.widget.TextViewCompat
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.getAnimationDuration import org.koitharu.kotatsu.core.util.ext.getAnimationDuration
@ -100,6 +101,11 @@ class ProgressButton @JvmOverloads constructor(
} }
} }
override fun setEnabled(enabled: Boolean) {
super.setEnabled(enabled)
children.forEach { it.isEnabled = enabled }
}
override fun onAnimationUpdate(animation: ValueAnimator) { override fun onAnimationUpdate(animation: ValueAnimator) {
progress = animation.animatedValue as Float progress = animation.animatedValue as Float
invalidate() invalidate()

@ -54,7 +54,8 @@ class DetailsLoadUseCase @Inject constructor(
} catch (e: IOException) { } catch (e: IOException) {
local?.await()?.manga?.also { localManga -> local?.await()?.manga?.also { localManga ->
send(MangaDetails(localManga, null, localManga.description?.parseAsHtml(withImages = false), true)) send(MangaDetails(localManga, null, localManga.description?.parseAsHtml(withImages = false), true))
} ?: throw e }
throw e
} }
} }

@ -16,7 +16,6 @@ import android.view.ViewTreeObserver
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.content.ContextCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.text.buildSpannedString import androidx.core.text.buildSpannedString
import androidx.core.text.inSpans import androidx.core.text.inSpans
@ -57,7 +56,6 @@ import org.koitharu.kotatsu.core.ui.widgets.ChipsView
import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.FileSize
import org.koitharu.kotatsu.core.util.ViewBadge import org.koitharu.kotatsu.core.util.ViewBadge
import org.koitharu.kotatsu.core.util.ext.crossfade import org.koitharu.kotatsu.core.util.ext.crossfade
import org.koitharu.kotatsu.core.util.ext.drawableStart
import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.getThemeColor import org.koitharu.kotatsu.core.util.ext.getThemeColor
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
@ -67,7 +65,6 @@ import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.parentView import org.koitharu.kotatsu.core.util.ext.parentView
import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
import org.koitharu.kotatsu.core.util.ext.showDistinct
import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.core.util.ext.source
import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.core.util.ext.textAndVisible
import org.koitharu.kotatsu.databinding.ActivityDetailsNewBinding import org.koitharu.kotatsu.databinding.ActivityDetailsNewBinding
@ -486,14 +483,14 @@ class DetailsActivity2 :
ratingBar.isVisible = false ratingBar.isVisible = false
} }
textViewState.apply { manga.state?.let { state ->
manga.state?.let { state -> textViewState.textAndVisible = resources.getString(state.titleResId)
textAndVisible = resources.getString(state.titleResId) imageViewState.setImageResource(state.iconResId)
drawableStart = ContextCompat.getDrawable(context, state.iconResId) } ?: run {
} ?: run { textViewState.isVisible = false
isVisible = false imageViewState.isVisible = false
}
} }
if (manga.source == MangaSource.LOCAL || manga.source == MangaSource.DUMMY) { if (manga.source == MangaSource.LOCAL || manga.source == MangaSource.DUMMY) {
infoLayout.chipSource.isVisible = false infoLayout.chipSource.isVisible = false
} else { } else {

@ -10,8 +10,8 @@ import android.view.ViewGroup
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import coil.ImageLoader import coil.ImageLoader
import coil.request.CachePolicy import coil.request.CachePolicy
import coil.request.ErrorResult import coil.request.ErrorResult
@ -21,6 +21,7 @@ import coil.target.ViewTarget
import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.getDisplayIcon import org.koitharu.kotatsu.core.util.ext.getDisplayIcon
@ -42,27 +43,25 @@ class ImageActivity : BaseActivity<ActivityImageBinding>(), ImageRequest.Listene
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(ActivityImageBinding.inflate(layoutInflater)) setContentView(ActivityImageBinding.inflate(layoutInflater))
supportActionBar?.run { viewBinding.buttonBack.setOnClickListener(this)
setDisplayHomeAsUpEnabled(true)
setDisplayShowTitleEnabled(false)
}
loadImage(intent.data) loadImage(intent.data)
} }
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {
with(viewBinding.toolbar) { with(viewBinding.buttonBack) {
updatePadding(
left = insets.left,
right = insets.right,
)
updateLayoutParams<ViewGroup.MarginLayoutParams> { updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top topMargin = insets.top + marginBottom
leftMargin = insets.left + marginBottom
rightMargin = insets.right + marginBottom
} }
} }
} }
override fun onClick(v: View?) { override fun onClick(v: View) {
loadImage(intent.data) when (v.id) {
R.id.button_back -> dispatchNavigateUp()
else -> loadImage(intent.data)
}
} }
override fun onError(request: ImageRequest, result: ErrorResult) { override fun onError(request: ImageRequest, result: ErrorResult) {

@ -31,6 +31,7 @@ import org.koitharu.kotatsu.core.ui.list.ListSelectionController
import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
import org.koitharu.kotatsu.core.ui.widgets.TipView
import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ShareHelper
import org.koitharu.kotatsu.core.util.ext.addMenuProvider import org.koitharu.kotatsu.core.util.ext.addMenuProvider
import org.koitharu.kotatsu.core.util.ext.findAppCompatDelegate import org.koitharu.kotatsu.core.util.ext.findAppCompatDelegate
@ -231,6 +232,10 @@ abstract class MangaListFragment :
override fun onListHeaderClick(item: ListHeader, view: View) = Unit override fun onListHeaderClick(item: ListHeader, view: View) = Unit
override fun onPrimaryButtonClick(tipView: TipView) = Unit
override fun onSecondaryButtonClick(tipView: TipView) = Unit
override fun onRetryClick(error: Throwable) { override fun onRetryClick(error: Throwable) {
resolveException(error) resolveException(error)
} }

@ -24,5 +24,6 @@ open class MangaListAdapter(
addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, lifecycleOwner, listener)) addDelegate(ListItemType.STATE_EMPTY, emptyStateListAD(coil, lifecycleOwner, listener))
addDelegate(ListItemType.HINT_EMPTY, emptyHintAD(coil, lifecycleOwner, listener)) addDelegate(ListItemType.HINT_EMPTY, emptyHintAD(coil, lifecycleOwner, listener))
addDelegate(ListItemType.HEADER, listHeaderAD(listener)) addDelegate(ListItemType.HEADER, listHeaderAD(listener))
addDelegate(ListItemType.TIP, tipAD(listener))
} }
} }

@ -1,9 +1,11 @@
package org.koitharu.kotatsu.list.ui.adapter package org.koitharu.kotatsu.list.ui.adapter
import android.view.View import android.view.View
import org.koitharu.kotatsu.core.ui.widgets.TipView
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
interface MangaListListener : MangaDetailsClickListener, ListStateHolderListener, ListHeaderClickListener { interface MangaListListener : MangaDetailsClickListener, ListStateHolderListener, ListHeaderClickListener,
TipView.OnButtonClickListener {
fun onUpdateFilter(tags: Set<MangaTag>) fun onUpdateFilter(tags: Set<MangaTag>)

@ -1,11 +1,16 @@
package org.koitharu.kotatsu.local.data package org.koitharu.kotatsu.local.data
import android.Manifest
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.StatFs import android.os.StatFs
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.core.content.ContextCompat
import androidx.core.net.toFile import androidx.core.net.toFile
import dagger.Reusable import dagger.Reusable
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
@ -101,6 +106,23 @@ class LocalStorageManager @Inject constructor(
contentResolver.takePersistableUriPermission(uri, flags) contentResolver.takePersistableUriPermission(uri, flags)
} }
fun isOnExternalStorage(file: File): Boolean {
return !file.absolutePath.contains(context.packageName)
}
fun hasExternalStoragePermission(isReadOnly: Boolean): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Environment.isExternalStorageManager()
} else {
val permission = if (isReadOnly) {
Manifest.permission.READ_EXTERNAL_STORAGE
} else {
Manifest.permission.WRITE_EXTERNAL_STORAGE
}
ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
}
}
suspend fun getDirectoryDisplayName(dir: File, isFullPath: Boolean): String = runInterruptible(Dispatchers.IO) { suspend fun getDirectoryDisplayName(dir: File, isFullPath: Boolean): String = runInterruptible(Dispatchers.IO) {
val packageName = context.packageName val packageName = context.packageName
if (dir.absolutePath.contains(packageName)) { if (dir.absolutePath.contains(packageName)) {

@ -1,9 +1,12 @@
package org.koitharu.kotatsu.local.ui package org.koitharu.kotatsu.local.ui
import android.Manifest
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.core.net.toFile import androidx.core.net.toFile
import androidx.core.net.toUri import androidx.core.net.toUri
@ -12,9 +15,11 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.ListSelectionController
import org.koitharu.kotatsu.core.ui.widgets.TipView
import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ShareHelper
import org.koitharu.kotatsu.core.util.ext.addMenuProvider import org.koitharu.kotatsu.core.util.ext.addMenuProvider
import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.tryLaunch
import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.databinding.FragmentListBinding
import org.koitharu.kotatsu.filter.ui.FilterOwner import org.koitharu.kotatsu.filter.ui.FilterOwner
@ -23,9 +28,23 @@ import org.koitharu.kotatsu.filter.ui.sheet.FilterSheetFragment
import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.list.ui.MangaListFragment
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment
import org.koitharu.kotatsu.settings.storage.RequestStorageManagerPermissionContract
import org.koitharu.kotatsu.settings.storage.directories.MangaDirectoriesActivity
class LocalListFragment : MangaListFragment(), FilterOwner { class LocalListFragment : MangaListFragment(), FilterOwner {
private val permissionRequestLauncher = registerForActivityResult(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
RequestStorageManagerPermissionContract()
} else {
ActivityResultContracts.RequestPermission()
},
) {
if (it) {
viewModel.onRefresh()
}
}
init { init {
withArgs(1) { withArgs(1) {
putSerializable( putSerializable(
@ -54,6 +73,16 @@ class LocalListFragment : MangaListFragment(), FilterOwner {
FilterSheetFragment.show(childFragmentManager) FilterSheetFragment.show(childFragmentManager)
} }
override fun onPrimaryButtonClick(tipView: TipView) {
if (!permissionRequestLauncher.tryLaunch(Manifest.permission.READ_EXTERNAL_STORAGE)) {
Snackbar.make(tipView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT).show()
}
}
override fun onSecondaryButtonClick(tipView: TipView) {
startActivity(MangaDirectoriesActivity.newIntent(tipView.context))
}
override fun onScrolledToEnd() = viewModel.loadNextPage() override fun onScrolledToEnd() = viewModel.loadNextPage()
override fun onCreateActionMode( override fun onCreateActionMode(

@ -10,12 +10,18 @@ import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.toFileOrNull
import org.koitharu.kotatsu.core.util.ext.toUriOrNull
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.explore.domain.ExploreRepository
import org.koitharu.kotatsu.filter.ui.FilterCoordinator import org.koitharu.kotatsu.filter.ui.FilterCoordinator
import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.domain.ListExtraProvider
import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.MangaItemModel
import org.koitharu.kotatsu.list.ui.model.TipModel
import org.koitharu.kotatsu.local.data.LocalStorageChanges import org.koitharu.kotatsu.local.data.LocalStorageChanges
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase
import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.local.domain.model.LocalManga
import org.koitharu.kotatsu.remotelist.ui.RemoteListViewModel import org.koitharu.kotatsu.remotelist.ui.RemoteListViewModel
@ -32,6 +38,7 @@ class LocalListViewModel @Inject constructor(
private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase, private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase,
exploreRepository: ExploreRepository, exploreRepository: ExploreRepository,
@LocalStorageChanges private val localStorageChanges: SharedFlow<LocalManga?>, @LocalStorageChanges private val localStorageChanges: SharedFlow<LocalManga?>,
private val localStorageManager: LocalStorageManager,
) : RemoteListViewModel( ) : RemoteListViewModel(
savedStateHandle, savedStateHandle,
mangaRepositoryFactory, mangaRepositoryFactory,
@ -54,6 +61,31 @@ class LocalListViewModel @Inject constructor(
settings.subscribe(this) settings.subscribe(this)
} }
override suspend fun onBuildList(list: MutableList<ListModel>) {
super.onBuildList(list)
if (localStorageManager.hasExternalStoragePermission(isReadOnly = true)) {
return
}
for (item in list) {
if (item !is MangaItemModel) {
continue
}
val file = item.manga.url.toUriOrNull()?.toFileOrNull() ?: continue
if (localStorageManager.isOnExternalStorage(file)) {
val tip = TipModel(
key = "permission",
title = R.string.external_storage,
text = R.string.missing_storage_permission,
icon = R.drawable.ic_storage,
primaryButtonText = R.string.fix,
secondaryButtonText = R.string.settings,
)
list.add(0, tip)
return
}
}
}
override fun onCleared() { override fun onCleared() {
settings.unsubscribe(this) settings.unsubscribe(this)
super.onCleared() super.onCleared()

@ -32,6 +32,7 @@ import org.koitharu.kotatsu.filter.ui.MangaFilter
import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.domain.ListExtraProvider
import org.koitharu.kotatsu.list.ui.MangaListViewModel import org.koitharu.kotatsu.list.ui.MangaListViewModel
import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingFooter import org.koitharu.kotatsu.list.ui.model.LoadingFooter
import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.list.ui.model.toErrorFooter import org.koitharu.kotatsu.list.ui.model.toErrorFooter
@ -89,6 +90,7 @@ open class RemoteListViewModel @Inject constructor(
} }
} }
} }
onBuildList(this)
} }
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
@ -166,6 +168,8 @@ open class RemoteListViewModel @Inject constructor(
actionStringRes = if (canResetFilter) R.string.reset_filter else 0, actionStringRes = if (canResetFilter) R.string.reset_filter else 0,
) )
protected open suspend fun onBuildList(list: MutableList<ListModel>) = Unit
fun openRandom() { fun openRandom() {
if (randomJob?.isActive == true) { if (randomJob?.isActive == true) {
return return

@ -18,6 +18,7 @@ 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.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.ListSelectionController
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.widgets.TipView
import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ShareHelper
import org.koitharu.kotatsu.core.util.ext.invalidateNestedItemDecorations import org.koitharu.kotatsu.core.util.ext.invalidateNestedItemDecorations
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
@ -140,6 +141,10 @@ class MultiSearchActivity :
override fun onListHeaderClick(item: ListHeader, view: View) = Unit override fun onListHeaderClick(item: ListHeader, view: View) = Unit
override fun onPrimaryButtonClick(tipView: TipView) = Unit
override fun onSecondaryButtonClick(tipView: TipView) = Unit
override fun onSelectionChanged(controller: ListSelectionController, count: Int) { override fun onSelectionChanged(controller: ListSelectionController, count: Int) {
viewBinding.recyclerView.invalidateNestedItemDecorations() viewBinding.recyclerView.invalidateNestedItemDecorations()
} }

@ -15,6 +15,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.ui.BaseFragment import org.koitharu.kotatsu.core.ui.BaseFragment
import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener
import org.koitharu.kotatsu.core.ui.widgets.TipView
import org.koitharu.kotatsu.core.util.ext.addMenuProvider import org.koitharu.kotatsu.core.util.ext.addMenuProvider
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.observeEvent
@ -100,6 +101,10 @@ class FeedFragment :
override fun onEmptyActionClick() = Unit override fun onEmptyActionClick() = Unit
override fun onPrimaryButtonClick(tipView: TipView) = Unit
override fun onSecondaryButtonClick(tipView: TipView) = Unit
override fun onListHeaderClick(item: ListHeader, view: View) { override fun onListHeaderClick(item: ListHeader, view: View) {
val context = view.context val context = view.context
context.startActivity(UpdatesActivity.newIntent(context)) context.startActivity(UpdatesActivity.newIntent(context))

@ -1,10 +1,12 @@
package org.koitharu.kotatsu.tracker.ui.feed.adapter package org.koitharu.kotatsu.tracker.ui.feed.adapter
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.drawableStart
import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.newImageRequest import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.core.util.ext.source
@ -20,14 +22,13 @@ fun feedItemAD(
) = adapterDelegateViewBinding<FeedItem, ListModel, ItemFeedBinding>( ) = adapterDelegateViewBinding<FeedItem, ListModel, ItemFeedBinding>(
{ inflater, parent -> ItemFeedBinding.inflate(inflater, parent, false) }, { inflater, parent -> ItemFeedBinding.inflate(inflater, parent, false) },
) { ) {
val indicatorNew = ContextCompat.getDrawable(context, R.drawable.ic_new)
itemView.setOnClickListener { itemView.setOnClickListener {
clickListener.onItemClick(item.manga, it) clickListener.onItemClick(item.manga, it)
} }
bind { bind {
val alpha = if (item.isNew) 1f else 0.5f
binding.textViewTitle.alpha = alpha
binding.textViewSummary.alpha = alpha
binding.imageViewCover.newImageRequest(lifecycleOwner, item.imageUrl)?.run { binding.imageViewCover.newImageRequest(lifecycleOwner, item.imageUrl)?.run {
placeholder(R.drawable.ic_placeholder) placeholder(R.drawable.ic_placeholder)
fallback(R.drawable.ic_placeholder) fallback(R.drawable.ic_placeholder)
@ -42,5 +43,10 @@ fun feedItemAD(
item.count, item.count,
item.count, item.count,
) )
binding.textViewSummary.drawableStart = if (item.isNew) {
indicatorNew
} else {
null
}
} }
} }

@ -2,6 +2,7 @@
<FrameLayout <FrameLayout
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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -9,12 +10,19 @@
android:id="@+id/ssiv" android:id="@+id/ssiv"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:restoreStrategy="deferred" /> app:restoreStrategy="deferred"
tools:background="@tools:sample/backgrounds/scenic" />
<com.google.android.material.appbar.MaterialToolbar <ImageButton
android:id="@+id/toolbar" android:id="@+id/button_back"
android:layout_width="match_parent" android:layout_width="48dp"
android:layout_height="wrap_content" /> android:layout_height="48dp"
android:layout_margin="@dimen/screen_padding"
android:background="@drawable/bg_circle_button"
android:contentDescription="@string/back"
android:elevation="4dp"
android:scaleType="center"
android:src="?homeAsUpIndicator" />
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar" android:id="@+id/progressBar"

@ -43,6 +43,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:drawablePadding="8dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textAppearance="?attr/textAppearanceBodySmall" android:textAppearance="?attr/textAppearanceBodySmall"

@ -649,4 +649,6 @@
<string name="minutes_short">%d m</string> <string name="minutes_short">%d m</string>
<!-- Short hours and minutes format pattern --> <!-- Short hours and minutes format pattern -->
<string name="hours_minutes_short">%1$d h %2$d m</string> <string name="hours_minutes_short">%1$d h %2$d m</string>
<string name="fix">Fix</string>
<string name="missing_storage_permission">There is no permission to access manga on external storage</string>
</resources> </resources>

Loading…
Cancel
Save