GIFデータの表示を改善
This commit is contained in:
parent
406d066437
commit
d29cbb1299
|
@ -33,6 +33,7 @@ import jp.juggler.subwaytooter.api.entity.TootAttachment.Companion.tootAttachmen
|
||||||
import jp.juggler.subwaytooter.databinding.ActMediaViewerBinding
|
import jp.juggler.subwaytooter.databinding.ActMediaViewerBinding
|
||||||
import jp.juggler.subwaytooter.dialog.actionsDialog
|
import jp.juggler.subwaytooter.dialog.actionsDialog
|
||||||
import jp.juggler.subwaytooter.drawable.MediaBackgroundDrawable
|
import jp.juggler.subwaytooter.drawable.MediaBackgroundDrawable
|
||||||
|
import jp.juggler.subwaytooter.itemviewholder.reUrlGif
|
||||||
import jp.juggler.subwaytooter.pref.PrefI
|
import jp.juggler.subwaytooter.pref.PrefI
|
||||||
import jp.juggler.subwaytooter.util.permissionSpecMediaDownload
|
import jp.juggler.subwaytooter.util.permissionSpecMediaDownload
|
||||||
import jp.juggler.subwaytooter.util.requester
|
import jp.juggler.subwaytooter.util.requester
|
||||||
|
@ -61,7 +62,7 @@ import javax.microedition.khronos.opengles.GL10
|
||||||
import javax.net.ssl.HttpsURLConnection
|
import javax.net.ssl.HttpsURLConnection
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
@androidx.media3.common.util.UnstableApi
|
@androidx.annotation.OptIn(markerClass = [androidx.media3.common.util.UnstableApi::class])
|
||||||
class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
|
class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -399,6 +400,17 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
|
||||||
setShowNextButton(false)
|
setShowNextButton(false)
|
||||||
setRepeatToggleModes(RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE)
|
setRepeatToggleModes(RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
views.wvOther.apply{
|
||||||
|
scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
|
||||||
|
settings.apply {
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
|
javaScriptEnabled = true
|
||||||
|
loadWithOverviewMode = true
|
||||||
|
useWideViewPort = true
|
||||||
|
setSupportZoom(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun loadDelta(delta: Int) {
|
internal fun loadDelta(delta: Int) {
|
||||||
|
@ -414,6 +426,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
|
||||||
|
|
||||||
// いったんすべて隠す
|
// いったんすべて隠す
|
||||||
views.run {
|
views.run {
|
||||||
|
wvOther.gone()
|
||||||
pbvImage.gone()
|
pbvImage.gone()
|
||||||
pvVideo.gone()
|
pvVideo.gone()
|
||||||
tvError.gone()
|
tvError.gone()
|
||||||
|
@ -434,10 +447,15 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
|
||||||
|
|
||||||
when (ta.type) {
|
when (ta.type) {
|
||||||
TootAttachmentType.Unknown,
|
TootAttachmentType.Unknown,
|
||||||
-> showError(getString(R.string.media_attachment_type_error, ta.type.id))
|
-> loadOther(ta) // showError(getString(R.string.media_attachment_type_error, ta.type.id))
|
||||||
|
|
||||||
TootAttachmentType.Image,
|
TootAttachmentType.Image -> when {
|
||||||
-> loadBitmap(ta)
|
reUrlGif.containsMatchIn(ta.remote_url ?: "") ->
|
||||||
|
loadOther(ta)
|
||||||
|
|
||||||
|
else ->
|
||||||
|
loadBitmap(ta)
|
||||||
|
}
|
||||||
|
|
||||||
TootAttachmentType.Video,
|
TootAttachmentType.Video,
|
||||||
TootAttachmentType.GIFV,
|
TootAttachmentType.GIFV,
|
||||||
|
@ -590,7 +608,21 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
|
||||||
return Pair(bitmap2, null)
|
return Pair(bitmap2, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
private fun loadOther(ta: TootAttachment) {
|
||||||
|
|
||||||
|
val urlList = ta.getLargeUrlList()
|
||||||
|
if (urlList.isEmpty()) {
|
||||||
|
showError("missing media attachment url.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val url = urlList.first()
|
||||||
|
views.run {
|
||||||
|
cbMute.gone()
|
||||||
|
tvStatus.visible().text = "${ta.type.id} ${url.ellipsizeDot3(100)}"
|
||||||
|
wvOther.visible().loadUrl(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadBitmap(ta: TootAttachment) {
|
private fun loadBitmap(ta: TootAttachment) {
|
||||||
|
|
||||||
views.run {
|
views.run {
|
||||||
|
|
|
@ -7,11 +7,9 @@ class TootAttachmentMSP(
|
||||||
val preview_url: String,
|
val preview_url: String,
|
||||||
) : TootAttachmentLike {
|
) : TootAttachmentLike {
|
||||||
|
|
||||||
override val type: TootAttachmentType
|
override val type = TootAttachmentType.Unknown
|
||||||
get() = TootAttachmentType.Unknown
|
|
||||||
|
|
||||||
override val description: String?
|
override val description = null
|
||||||
get() = null
|
|
||||||
|
|
||||||
override fun urlForThumbnail() = preview_url
|
override fun urlForThumbnail() = preview_url
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,35 @@ import android.view.View
|
||||||
import jp.juggler.subwaytooter.ActMain
|
import jp.juggler.subwaytooter.ActMain
|
||||||
import jp.juggler.subwaytooter.ActMediaViewer
|
import jp.juggler.subwaytooter.ActMediaViewer
|
||||||
import jp.juggler.subwaytooter.R
|
import jp.juggler.subwaytooter.R
|
||||||
import jp.juggler.subwaytooter.action.*
|
import jp.juggler.subwaytooter.action.clickCardImage
|
||||||
|
import jp.juggler.subwaytooter.action.clickConversation
|
||||||
|
import jp.juggler.subwaytooter.action.clickDomainBlock
|
||||||
|
import jp.juggler.subwaytooter.action.clickFollowInfo
|
||||||
|
import jp.juggler.subwaytooter.action.clickFollowRequestAccept
|
||||||
|
import jp.juggler.subwaytooter.action.clickListMoreButton
|
||||||
|
import jp.juggler.subwaytooter.action.clickListTl
|
||||||
|
import jp.juggler.subwaytooter.action.clickReplyInfo
|
||||||
|
import jp.juggler.subwaytooter.action.clickScheduledToot
|
||||||
|
import jp.juggler.subwaytooter.action.conversationOtherInstance
|
||||||
|
import jp.juggler.subwaytooter.action.followFromAnotherAccount
|
||||||
|
import jp.juggler.subwaytooter.action.longClickTootTag
|
||||||
|
import jp.juggler.subwaytooter.action.openFilterMenu
|
||||||
|
import jp.juggler.subwaytooter.action.tagDialog
|
||||||
|
import jp.juggler.subwaytooter.action.userProfileLocal
|
||||||
import jp.juggler.subwaytooter.actmain.nextPosition
|
import jp.juggler.subwaytooter.actmain.nextPosition
|
||||||
import jp.juggler.subwaytooter.api.entity.*
|
import jp.juggler.subwaytooter.api.entity.ServiceType
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TimelineItem
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootAccountRef
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootAttachment
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootAttachmentMSP
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootAttachmentType
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootConversationSummary
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootDomainBlock
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootGap
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootNotification
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootScheduled
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootSearchGap
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootTag
|
||||||
import jp.juggler.subwaytooter.column.Column
|
import jp.juggler.subwaytooter.column.Column
|
||||||
import jp.juggler.subwaytooter.column.startGap
|
import jp.juggler.subwaytooter.column.startGap
|
||||||
import jp.juggler.subwaytooter.pref.PrefB
|
import jp.juggler.subwaytooter.pref.PrefB
|
||||||
|
@ -62,6 +88,7 @@ fun ItemViewHolder.onClickImpl(v: View?) {
|
||||||
tvContent
|
tvContent
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
btnFollow -> clickFollowInfo(
|
btnFollow -> clickFollowInfo(
|
||||||
pos,
|
pos,
|
||||||
accessInfo,
|
accessInfo,
|
||||||
|
@ -88,11 +115,13 @@ fun ItemViewHolder.onClickImpl(v: View?) {
|
||||||
followAccount,
|
followAccount,
|
||||||
accept = true
|
accept = true
|
||||||
)
|
)
|
||||||
|
|
||||||
btnFollowRequestDeny -> clickFollowRequestAccept(
|
btnFollowRequestDeny -> clickFollowRequestAccept(
|
||||||
accessInfo,
|
accessInfo,
|
||||||
followAccount,
|
followAccount,
|
||||||
accept = false
|
accept = false
|
||||||
)
|
)
|
||||||
|
|
||||||
llFilter -> openFilterMenu(accessInfo, item.cast())
|
llFilter -> openFilterMenu(accessInfo, item.cast())
|
||||||
ivCardImage -> clickCardImage(pos, accessInfo, statusShowing?.card)
|
ivCardImage -> clickCardImage(pos, accessInfo, statusShowing?.card)
|
||||||
llConversationIcons -> clickConversation(
|
llConversationIcons -> clickConversation(
|
||||||
|
@ -200,7 +229,7 @@ private fun ItemViewHolder.clickMedia(i: Int) {
|
||||||
statusShowing?.media_attachments ?: (item as? TootScheduled)?.mediaAttachments
|
statusShowing?.media_attachments ?: (item as? TootScheduled)?.mediaAttachments
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
when (val item = if (i < mediaAttachments.size) mediaAttachments[i] else return) {
|
when (val item = mediaAttachments.firstOrNull() ?: return) {
|
||||||
is TootAttachmentMSP -> {
|
is TootAttachmentMSP -> {
|
||||||
// マストドン検索ポータルのデータではmedia_attachmentsが簡略化されている
|
// マストドン検索ポータルのデータではmedia_attachmentsが簡略化されている
|
||||||
// 会話の流れを表示する
|
// 会話の流れを表示する
|
||||||
|
@ -212,15 +241,16 @@ private fun ItemViewHolder.clickMedia(i: Int) {
|
||||||
|
|
||||||
is TootAttachment -> when {
|
is TootAttachment -> when {
|
||||||
|
|
||||||
// unknownが1枚だけなら内蔵ビューアを使わずにインテントを投げる
|
// 添付メディアが1枚だけで、unknownまたはファイル拡張子がGIFなら、ブラウザで開く
|
||||||
item.type == TootAttachmentType.Unknown && mediaAttachments.size == 1 -> {
|
// https://github.com/tateisu/SubwayTooter/pull/119
|
||||||
// https://github.com/tateisu/SubwayTooter/pull/119
|
// メディアタイプがunknownの場合、そのほとんどはリモートから来たURLである
|
||||||
// メディアタイプがunknownの場合、そのほとんどはリモートから来たURLである
|
// PrefB.bpPriorLocalURL の状態に関わらずリモートURLがあればそれをブラウザで開く
|
||||||
// PrefB.bpPriorLocalURL の状態に関わらずリモートURLがあればそれをブラウザで開く
|
mediaAttachments.size == 1 &&
|
||||||
when (val remoteUrl = item.remote_url.notEmpty()) {
|
(item.type == TootAttachmentType.Unknown ||
|
||||||
null -> activity.openCustomTab(item)
|
reUrlGif.containsMatchIn(item.remote_url ?: ""))
|
||||||
else -> activity.openCustomTab(remoteUrl)
|
-> when (val remoteUrl = item.remote_url.notEmpty()) {
|
||||||
}
|
null -> activity.openCustomTab(item)
|
||||||
|
else -> activity.openCustomTab(remoteUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内蔵メディアビューアを使う
|
// 内蔵メディアビューアを使う
|
||||||
|
@ -324,9 +354,11 @@ private fun ItemViewHolder.clickTag(pos: Int, item: TimelineItem?) {
|
||||||
item.name,
|
item.name,
|
||||||
tagInfo = item,
|
tagInfo = item,
|
||||||
)
|
)
|
||||||
|
|
||||||
TootTag.TagType.Link ->
|
TootTag.TagType.Link ->
|
||||||
openCustomTab(item.url)
|
openCustomTab(item.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
is TootSearchGap -> column.startGap(item, isHead = true)
|
is TootSearchGap -> column.startGap(item, isHead = true)
|
||||||
is TootConversationSummary -> clickConversation(
|
is TootConversationSummary -> clickConversation(
|
||||||
pos,
|
pos,
|
||||||
|
@ -334,6 +366,7 @@ private fun ItemViewHolder.clickTag(pos: Int, item: TimelineItem?) {
|
||||||
listAdapter,
|
listAdapter,
|
||||||
summary = item
|
summary = item
|
||||||
)
|
)
|
||||||
|
|
||||||
is TootGap -> clickTootGap(column, item)
|
is TootGap -> clickTootGap(column, item)
|
||||||
is TootDomainBlock -> clickDomainBlock(accessInfo, item)
|
is TootDomainBlock -> clickDomainBlock(accessInfo, item)
|
||||||
is TootScheduled -> clickScheduledToot(accessInfo, item, column)
|
is TootScheduled -> clickScheduledToot(accessInfo, item, column)
|
||||||
|
|
|
@ -356,6 +356,8 @@ private fun ItemViewHolder.showAttachments(status: TootStatus) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val reUrlGif = """\.gif(?:\z|\?)""".toRegex(RegexOption.IGNORE_CASE)
|
||||||
|
|
||||||
fun ItemViewHolder.setMedia(
|
fun ItemViewHolder.setMedia(
|
||||||
mediaAttachments: ArrayList<TootAttachmentLike>,
|
mediaAttachments: ArrayList<TootAttachmentLike>,
|
||||||
idx: Int,
|
idx: Int,
|
||||||
|
@ -390,11 +392,28 @@ fun ItemViewHolder.setMedia(
|
||||||
TootAttachmentType.Unknown -> {
|
TootAttachmentType.Unknown -> {
|
||||||
iv.setMediaType(0)
|
iv.setMediaType(0)
|
||||||
iv.setDefaultImage(defaultColorIcon(activity, R.drawable.wide_question))
|
iv.setDefaultImage(defaultColorIcon(activity, R.drawable.wide_question))
|
||||||
iv.setImageUrl(0f, null)
|
if (ta is TootAttachment &&
|
||||||
|
reUrlGif.containsMatchIn(ta.remote_url ?: "") &&
|
||||||
|
PrefB.bpImageAnimationEnable.value
|
||||||
|
) {
|
||||||
|
val url = ta.remote_url!!
|
||||||
|
iv.setImageUrl(0f, url, url)
|
||||||
|
} else {
|
||||||
|
iv.setImageUrl(0f, null)
|
||||||
|
}
|
||||||
showUrl = true
|
showUrl = true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> when (val urlThumbnail = ta.urlForThumbnail()) {
|
else -> if (ta is TootAttachment &&
|
||||||
|
reUrlGif.containsMatchIn(ta.remote_url ?: "") &&
|
||||||
|
PrefB.bpImageAnimationEnable.value
|
||||||
|
) {
|
||||||
|
iv.setMediaType(0)
|
||||||
|
iv.setDefaultImage(null)
|
||||||
|
val url = ta.remote_url!!
|
||||||
|
iv.setImageUrl(0f, url, url)
|
||||||
|
showUrl = false
|
||||||
|
} else when (val urlThumbnail = ta.urlForThumbnail()) {
|
||||||
null, "" -> {
|
null, "" -> {
|
||||||
iv.setMediaType(0)
|
iv.setMediaType(0)
|
||||||
iv.setDefaultImage(defaultColorIcon(activity, R.drawable.wide_question))
|
iv.setDefaultImage(defaultColorIcon(activity, R.drawable.wide_question))
|
||||||
|
|
|
@ -26,6 +26,12 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1">
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/wvOther"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
/>
|
||||||
|
|
||||||
<jp.juggler.subwaytooter.view.PinchBitmapView
|
<jp.juggler.subwaytooter.view.PinchBitmapView
|
||||||
android:id="@+id/pbvImage"
|
android:id="@+id/pbvImage"
|
||||||
|
|
Loading…
Reference in New Issue