mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-24 13:48:55 +03:00
Merge pull request #5 from tachiyomiorg/master
This commit is contained in:
commit
9c812e3d54
20 changed files with 168 additions and 159 deletions
2
.github/workflows/issue_closer.yml
vendored
2
.github/workflows/issue_closer.yml
vendored
|
@ -8,7 +8,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Autoclose issues
|
||||
uses: arkon/issue-closer-action@v3.0
|
||||
uses: arkon/issue-closer-action@v3.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
rules: |
|
||||
|
|
|
@ -52,6 +52,9 @@ open class App : Application(), LifecycleObserver {
|
|||
LocaleHelper.updateConfiguration(this, resources.configuration)
|
||||
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
|
||||
// Reset Incognito Mode on relaunch
|
||||
preferences.incognitoMode().set(false)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
|
|
|
@ -81,15 +81,14 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
|
|||
|
||||
private fun showPopupMenu(view: View) {
|
||||
view.popupMenu(
|
||||
R.menu.download_single,
|
||||
{
|
||||
menuRes = R.menu.download_single,
|
||||
initMenu = {
|
||||
findItem(R.id.move_to_top).isVisible = bindingAdapterPosition != 0
|
||||
findItem(R.id.move_to_bottom).isVisible =
|
||||
bindingAdapterPosition != adapter.itemCount - 1
|
||||
},
|
||||
{
|
||||
onMenuItemClick = {
|
||||
adapter.downloadItemListener.onMenuItemClick(bindingAdapterPosition, this)
|
||||
true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -727,8 +727,7 @@ class MangaController :
|
|||
|
||||
fun onChapterDownloadUpdate(download: Download) {
|
||||
chaptersAdapter?.currentItems?.find { it.id == download.chapter.id }?.let {
|
||||
chaptersAdapter?.updateItem(it)
|
||||
chaptersAdapter?.notifyDataSetChanged()
|
||||
chaptersAdapter?.updateItem(it, it.status)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,42 +6,38 @@ import android.util.AttributeSet
|
|||
import android.view.LayoutInflater
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.databinding.ChapterDownloadViewBinding
|
||||
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
||||
|
||||
class ChapterDownloadView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
FrameLayout(context, attrs) {
|
||||
|
||||
private val binding: ChapterDownloadViewBinding
|
||||
private val binding: ChapterDownloadViewBinding =
|
||||
ChapterDownloadViewBinding.inflate(LayoutInflater.from(context), this, false)
|
||||
|
||||
private var state = Download.State.NOT_DOWNLOADED
|
||||
private var progress = 0
|
||||
|
||||
private var downloadIconAnimator: ObjectAnimator? = null
|
||||
private var isAnimating = false
|
||||
|
||||
init {
|
||||
binding = ChapterDownloadViewBinding.inflate(LayoutInflater.from(context), this, false)
|
||||
addView(binding.root)
|
||||
}
|
||||
|
||||
fun setState(state: Download.State, progress: Int = 0) {
|
||||
val isDirty = this.state.value != state.value || this.progress != progress
|
||||
|
||||
this.state = state
|
||||
this.progress = progress
|
||||
|
||||
if (isDirty) {
|
||||
updateLayout()
|
||||
updateLayout(state, progress)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLayout() {
|
||||
binding.downloadIconBorder.isVisible = state == Download.State.NOT_DOWNLOADED
|
||||
|
||||
binding.downloadIcon.isVisible = state == Download.State.NOT_DOWNLOADED || state == Download.State.DOWNLOADING
|
||||
if (state == Download.State.DOWNLOADING) {
|
||||
if (!isAnimating) {
|
||||
private fun updateLayout(state: Download.State, progress: Int) {
|
||||
binding.downloadIcon.isVisible = state == Download.State.NOT_DOWNLOADED ||
|
||||
state == Download.State.DOWNLOADING || state == Download.State.QUEUE
|
||||
if (state == Download.State.DOWNLOADING || state == Download.State.QUEUE) {
|
||||
if (downloadIconAnimator == null) {
|
||||
downloadIconAnimator =
|
||||
ObjectAnimator.ofFloat(binding.downloadIcon, "alpha", 1f, 0f).apply {
|
||||
duration = 1000
|
||||
|
@ -49,22 +45,36 @@ class ChapterDownloadView @JvmOverloads constructor(context: Context, attrs: Att
|
|||
repeatMode = ObjectAnimator.REVERSE
|
||||
}
|
||||
downloadIconAnimator?.start()
|
||||
isAnimating = true
|
||||
}
|
||||
} else {
|
||||
downloadIconAnimator?.currentPlayTime = System.currentTimeMillis() % 2000
|
||||
} else if (downloadIconAnimator != null) {
|
||||
downloadIconAnimator?.cancel()
|
||||
downloadIconAnimator = null
|
||||
binding.downloadIcon.alpha = 1f
|
||||
isAnimating = false
|
||||
}
|
||||
|
||||
binding.downloadQueued.isVisible = state == Download.State.QUEUE
|
||||
|
||||
binding.downloadProgress.isVisible = state == Download.State.DOWNLOADING ||
|
||||
(state == Download.State.QUEUE && progress > 0)
|
||||
binding.downloadProgress.progress = progress
|
||||
state == Download.State.NOT_DOWNLOADED || state == Download.State.QUEUE
|
||||
if (state == Download.State.DOWNLOADING) {
|
||||
binding.downloadProgress.setProgressCompat(progress, true)
|
||||
} else {
|
||||
binding.downloadProgress.setProgressCompat(100, true)
|
||||
}
|
||||
|
||||
binding.downloadedIcon.isVisible = state == Download.State.DOWNLOADED
|
||||
binding.downloadStatusIcon.apply {
|
||||
if (state == Download.State.DOWNLOADED || state == Download.State.ERROR) {
|
||||
isVisible = true
|
||||
if (state == Download.State.DOWNLOADED) {
|
||||
setVectorCompat(R.drawable.ic_check_circle_24dp, android.R.attr.textColorPrimary)
|
||||
} else {
|
||||
setVectorCompat(R.drawable.ic_error_outline_24dp, R.attr.colorError)
|
||||
}
|
||||
} else {
|
||||
isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
binding.errorIcon.isVisible = state == Download.State.ERROR
|
||||
this.state = state
|
||||
this.progress = progress
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,16 +51,12 @@ class ChaptersSettingsSheet(
|
|||
|
||||
private fun showPopupMenu(view: View) {
|
||||
view.popupMenu(
|
||||
R.menu.default_chapter_filter,
|
||||
{
|
||||
},
|
||||
{
|
||||
when (this.itemId) {
|
||||
menuRes = R.menu.default_chapter_filter,
|
||||
onMenuItemClick = {
|
||||
when (itemId) {
|
||||
R.id.set_as_default -> {
|
||||
SetChapterSettingsDialog(presenter.manga).showDialog(router)
|
||||
true
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -29,7 +29,6 @@ open class BaseChapterHolder(
|
|||
},
|
||||
onMenuItemClick = {
|
||||
adapter.clickListener.deleteChapter(position)
|
||||
true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ import eu.kanade.tachiyomi.util.system.toast
|
|||
import eu.kanade.tachiyomi.util.view.defaultBar
|
||||
import eu.kanade.tachiyomi.util.view.hideBar
|
||||
import eu.kanade.tachiyomi.util.view.isDefaultBar
|
||||
import eu.kanade.tachiyomi.util.view.popupMenu
|
||||
import eu.kanade.tachiyomi.util.view.setTooltip
|
||||
import eu.kanade.tachiyomi.util.view.showBar
|
||||
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
|
||||
|
@ -356,13 +357,18 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||
setTooltip(R.string.viewer)
|
||||
|
||||
setOnClickListener {
|
||||
val newReadingMode =
|
||||
ReadingModeType.getNextReadingMode(presenter.getMangaViewer(resolveDefault = false))
|
||||
presenter.setMangaViewer(newReadingMode.prefValue)
|
||||
popupMenu(
|
||||
items = ReadingModeType.values().map { it.prefValue to it.stringRes },
|
||||
selectedItemId = presenter.getMangaViewer(resolveDefault = false),
|
||||
) {
|
||||
val newReadingMode = ReadingModeType.fromPreference(itemId)
|
||||
|
||||
menuToggleToast?.cancel()
|
||||
if (!preferences.showReadingMode()) {
|
||||
menuToggleToast = toast(newReadingMode.stringRes)
|
||||
presenter.setMangaViewer(newReadingMode.prefValue)
|
||||
|
||||
menuToggleToast?.cancel()
|
||||
if (!preferences.showReadingMode()) {
|
||||
menuToggleToast = toast(newReadingMode.stringRes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -372,13 +378,18 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||
setTooltip(R.string.pref_rotation_type)
|
||||
|
||||
setOnClickListener {
|
||||
val newOrientation = OrientationType.getNextOrientation(preferences.rotation().get())
|
||||
popupMenu(
|
||||
items = OrientationType.values().map { it.prefValue to it.stringRes },
|
||||
selectedItemId = preferences.rotation().get(),
|
||||
) {
|
||||
val newOrientation = OrientationType.fromPreference(itemId)
|
||||
|
||||
preferences.rotation().set(newOrientation.prefValue)
|
||||
setOrientation(newOrientation.flag)
|
||||
preferences.rotation().set(newOrientation.prefValue)
|
||||
setOrientation(newOrientation.flag)
|
||||
|
||||
menuToggleToast?.cancel()
|
||||
menuToggleToast = toast(newOrientation.stringRes)
|
||||
menuToggleToast?.cancel()
|
||||
menuToggleToast = toast(newOrientation.stringRes)
|
||||
}
|
||||
}
|
||||
}
|
||||
preferences.rotation().asImmediateFlow { updateRotationShortcut(it) }
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.pm.ActivityInfo
|
|||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.lang.next
|
||||
|
||||
enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) {
|
||||
FREE(1, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp),
|
||||
|
@ -17,10 +16,5 @@ enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val str
|
|||
companion object {
|
||||
fun fromPreference(preference: Int): OrientationType =
|
||||
values().find { it.prefValue == preference } ?: FREE
|
||||
|
||||
fun getNextOrientation(preference: Int): OrientationType {
|
||||
val current = fromPreference(preference)
|
||||
return current.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class ReaderSettingsSheet(
|
|||
init {
|
||||
val sheetBehavior = BottomSheetBehavior.from(binding.root.parent as ViewGroup)
|
||||
sheetBehavior.isFitToContents = false
|
||||
sheetBehavior.halfExpandedRatio = 0.5f
|
||||
sheetBehavior.halfExpandedRatio = 0.25f
|
||||
|
||||
val filterTabIndex = getTabViews().indexOf(colorFilterSettings)
|
||||
binding.tabs.addOnTabSelectedListener(object : SimpleTabSelectedListener() {
|
||||
|
@ -36,11 +36,6 @@ class ReaderSettingsSheet(
|
|||
if (activity.menuVisible != !isFilterTab) {
|
||||
activity.setMenuVisibility(!isFilterTab)
|
||||
}
|
||||
|
||||
// Partially collapse the sheet for better preview
|
||||
if (isFilterTab) {
|
||||
sheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.reader.setting
|
|||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.lang.next
|
||||
|
||||
enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) {
|
||||
DEFAULT(0, R.string.default_viewer, R.drawable.ic_reader_default_24dp),
|
||||
|
@ -17,11 +16,6 @@ enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @D
|
|||
companion object {
|
||||
fun fromPreference(preference: Int): ReadingModeType = values().find { it.prefValue == preference } ?: DEFAULT
|
||||
|
||||
fun getNextReadingMode(preference: Int): ReadingModeType {
|
||||
val current = fromPreference(preference)
|
||||
return current.next()
|
||||
}
|
||||
|
||||
fun isPagerType(preference: Int): Boolean {
|
||||
val mode = fromPreference(preference)
|
||||
return mode == LEFT_TO_RIGHT || mode == RIGHT_TO_LEFT || mode == VERTICAL
|
||||
|
|
|
@ -235,16 +235,13 @@ class PagerPageHolder(
|
|||
readImageHeaderSubscription = Observable
|
||||
.fromCallable {
|
||||
val stream = streamFn().buffered(16)
|
||||
openStream = stream
|
||||
openStream = process(stream)
|
||||
|
||||
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext { isAnimated ->
|
||||
if (viewer.config.dualPageSplit) {
|
||||
openStream = processDualPageSplit(openStream!!)
|
||||
}
|
||||
if (!isAnimated) {
|
||||
initSubsamplingImageView().setImage(ImageSource.inputStream(openStream!!))
|
||||
} else {
|
||||
|
@ -257,21 +254,31 @@ class PagerPageHolder(
|
|||
.subscribe({}, {})
|
||||
}
|
||||
|
||||
private fun processDualPageSplit(openStream: InputStream): InputStream {
|
||||
var inputStream = openStream
|
||||
val (isDoublePage, stream) = when (page) {
|
||||
is InsertPage -> Pair(true, inputStream)
|
||||
else -> ImageUtil.isDoublePage(inputStream)
|
||||
private fun process(imageStream: InputStream): InputStream {
|
||||
if (!viewer.config.dualPageSplit) {
|
||||
return imageStream
|
||||
}
|
||||
inputStream = stream
|
||||
|
||||
if (!isDoublePage) return inputStream
|
||||
if (page is InsertPage) {
|
||||
return splitInHalf(imageStream)
|
||||
}
|
||||
|
||||
val isDoublePage = ImageUtil.isDoublePage(imageStream)
|
||||
if (!isDoublePage) {
|
||||
return imageStream
|
||||
}
|
||||
|
||||
onPageSplit()
|
||||
|
||||
return splitInHalf(imageStream)
|
||||
}
|
||||
|
||||
private fun splitInHalf(imageStream: InputStream): InputStream {
|
||||
var side = when {
|
||||
viewer is L2RPagerViewer && page is InsertPage -> ImageUtil.Side.RIGHT
|
||||
(viewer is R2LPagerViewer || viewer is VerticalPagerViewer) && page is InsertPage -> ImageUtil.Side.LEFT
|
||||
viewer !is L2RPagerViewer && page is InsertPage -> ImageUtil.Side.LEFT
|
||||
viewer is L2RPagerViewer && page !is InsertPage -> ImageUtil.Side.LEFT
|
||||
(viewer is R2LPagerViewer || viewer is VerticalPagerViewer) && page !is InsertPage -> ImageUtil.Side.RIGHT
|
||||
viewer !is L2RPagerViewer && page !is InsertPage -> ImageUtil.Side.RIGHT
|
||||
else -> error("We should choose a side!")
|
||||
}
|
||||
|
||||
|
@ -282,11 +289,7 @@ class PagerPageHolder(
|
|||
}
|
||||
}
|
||||
|
||||
if (page !is InsertPage) {
|
||||
onPageSplit()
|
||||
}
|
||||
|
||||
return ImageUtil.splitInHalf(inputStream, side)
|
||||
return ImageUtil.splitInHalf(imageStream, side)
|
||||
}
|
||||
|
||||
private fun onPageSplit() {
|
||||
|
|
|
@ -385,7 +385,10 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
|||
}
|
||||
|
||||
fun onPageSplit(currentPage: ReaderPage, newPage: InsertPage) {
|
||||
adapter.onPageSplit(currentPage, newPage, this::class.java)
|
||||
activity.runOnUiThread {
|
||||
// Need to insert on UI thread else images will go blank
|
||||
adapter.onPageSplit(currentPage, newPage, this::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanupPageSplit() {
|
||||
|
|
|
@ -281,22 +281,13 @@ class WebtoonPageHolder(
|
|||
readImageHeaderSubscription = Observable
|
||||
.fromCallable {
|
||||
val stream = streamFn().buffered(16)
|
||||
openStream = stream
|
||||
openStream = process(stream)
|
||||
|
||||
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext { isAnimated ->
|
||||
if (viewer.config.dualPageSplit) {
|
||||
val (isDoublePage, stream) = ImageUtil.isDoublePage(openStream!!)
|
||||
openStream = if (!isDoublePage) {
|
||||
stream
|
||||
} else {
|
||||
val upperSide = if (viewer.config.dualPageInvert) ImageUtil.Side.LEFT else ImageUtil.Side.RIGHT
|
||||
ImageUtil.splitAndMerge(stream, upperSide)
|
||||
}
|
||||
}
|
||||
if (!isAnimated) {
|
||||
val subsamplingView = initSubsamplingImageView()
|
||||
subsamplingView.isVisible = true
|
||||
|
@ -315,6 +306,20 @@ class WebtoonPageHolder(
|
|||
addSubscription(readImageHeaderSubscription)
|
||||
}
|
||||
|
||||
private fun process(imageStream: InputStream): InputStream {
|
||||
if (!viewer.config.dualPageSplit) {
|
||||
return imageStream
|
||||
}
|
||||
|
||||
val isDoublePage = ImageUtil.isDoublePage(imageStream)
|
||||
if (!isDoublePage) {
|
||||
return imageStream
|
||||
}
|
||||
|
||||
val upperSide = if (viewer.config.dualPageInvert) ImageUtil.Side.LEFT else ImageUtil.Side.RIGHT
|
||||
return ImageUtil.splitAndMerge(imageStream, upperSide)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page has an error.
|
||||
*/
|
||||
|
|
|
@ -242,8 +242,7 @@ class UpdatesController :
|
|||
adapter?.currentItems
|
||||
?.filterIsInstance<UpdatesItem>()
|
||||
?.find { it.chapter.id == download.chapter.id }?.let {
|
||||
adapter?.updateItem(it)
|
||||
adapter?.notifyDataSetChanged()
|
||||
adapter?.updateItem(it, it.status)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package eu.kanade.tachiyomi.util.lang
|
||||
|
||||
inline fun <reified T : Enum<T>> T.next(): T {
|
||||
val values = enumValues<T>()
|
||||
val nextOrdinal = (ordinal + 1) % values.size
|
||||
return values[nextOrdinal]
|
||||
}
|
|
@ -77,15 +77,20 @@ object ImageUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check whether the image is a double image (width > height), return the result and original stream
|
||||
* Check whether the image is a double-page spread
|
||||
* @return true if the width is greater than the height
|
||||
*/
|
||||
fun isDoublePage(imageStream: InputStream): Pair<Boolean, InputStream> {
|
||||
fun isDoublePage(imageStream: InputStream): Boolean {
|
||||
imageStream.mark(imageStream.available() + 1)
|
||||
|
||||
val imageBytes = imageStream.readBytes()
|
||||
|
||||
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size, options)
|
||||
|
||||
return Pair(options.outWidth > options.outHeight, ByteArrayInputStream(imageBytes))
|
||||
imageStream.reset()
|
||||
|
||||
return options.outWidth > options.outHeight
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
package eu.kanade.tachiyomi.util.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Point
|
||||
import android.view.Gravity
|
||||
import android.view.Menu
|
||||
|
@ -9,14 +10,18 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import androidx.annotation.MenuRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.view.menu.MenuBuilder
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.appcompat.widget.TooltipCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
|
||||
/**
|
||||
* Returns coordinates of view.
|
||||
|
@ -63,7 +68,7 @@ inline fun View.setTooltip(@StringRes stringRes: Int) {
|
|||
inline fun View.popupMenu(
|
||||
@MenuRes menuRes: Int,
|
||||
noinline initMenu: (Menu.() -> Unit)? = null,
|
||||
noinline onMenuItemClick: MenuItem.() -> Boolean
|
||||
noinline onMenuItemClick: MenuItem.() -> Unit
|
||||
): PopupMenu {
|
||||
val popup = PopupMenu(context, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0)
|
||||
popup.menuInflater.inflate(menuRes, popup.menu)
|
||||
|
@ -71,7 +76,50 @@ inline fun View.popupMenu(
|
|||
if (initMenu != null) {
|
||||
popup.menu.initMenu()
|
||||
}
|
||||
popup.setOnMenuItemClickListener { it.onMenuItemClick() }
|
||||
popup.setOnMenuItemClickListener {
|
||||
it.onMenuItemClick()
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
return popup
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a popup menu on top of this view.
|
||||
*
|
||||
* @param items menu item names to inflate the menu with. List of itemId to stringRes pairs.
|
||||
* @param selectedItemId optionally show a checkmark beside an item with this itemId.
|
||||
* @param onMenuItemClick function to execute when a menu item is clicked.
|
||||
*/
|
||||
@SuppressLint("RestrictedApi")
|
||||
inline fun View.popupMenu(
|
||||
items: List<Pair<Int, Int>>,
|
||||
selectedItemId: Int? = null,
|
||||
noinline onMenuItemClick: MenuItem.() -> Unit
|
||||
): PopupMenu {
|
||||
val popup = PopupMenu(context, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0)
|
||||
items.forEach { (id, stringRes) ->
|
||||
popup.menu.add(0, id, 0, stringRes)
|
||||
}
|
||||
|
||||
if (selectedItemId != null) {
|
||||
(popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)
|
||||
val emptyIcon = ContextCompat.getDrawable(context, R.drawable.ic_blank_24dp)
|
||||
popup.menu.forEach { item ->
|
||||
item.icon = when (item.itemId) {
|
||||
selectedItemId -> ContextCompat.getDrawable(context, R.drawable.ic_check_24dp)?.mutate()?.apply {
|
||||
setTint(context.getResourceColor(android.R.attr.textColorPrimary))
|
||||
}
|
||||
else -> emptyIcon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
popup.setOnMenuItemClickListener {
|
||||
it.onMenuItemClick()
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
return popup
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
android:thicknessRatio="2">
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<size
|
||||
android:width="25dp"
|
||||
android:height="25dp" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="?colorAccent" />
|
||||
</shape>
|
|
@ -7,16 +7,6 @@
|
|||
android:padding="8dp"
|
||||
android:background="?selectableItemBackgroundBorderless">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download_icon_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="2dp"
|
||||
android:scaleType="fitXY"
|
||||
app:srcCompat="@drawable/border_circle"
|
||||
app:tint="?android:attr/textColorHint"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download_icon"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -32,42 +22,17 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="1dp"
|
||||
android:visibility="gone"
|
||||
app:indicatorColor="?android:attr/textColorHint"
|
||||
app:indicatorInset="0dp"
|
||||
app:indicatorSize="24dp"
|
||||
app:trackThickness="2dp" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/download_queued"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:indeterminate="true"
|
||||
android:padding="1dp"
|
||||
android:visibility="gone"
|
||||
android:progress="100"
|
||||
app:indicatorColor="?android:attr/textColorHint"
|
||||
app:indicatorInset="0dp"
|
||||
app:indicatorSize="24dp"
|
||||
app:trackThickness="2dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/downloaded_icon"
|
||||
android:id="@+id/download_status_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_check_circle_24dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/error_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_error_outline_24dp"
|
||||
app:tint="?attr/colorError"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</FrameLayout>
|
||||
|
|
Loading…
Reference in a new issue