diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActMediaViewer.kt b/app/src/main/java/jp/juggler/subwaytooter/ActMediaViewer.kt index 80e4d7bf..043d7d8f 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActMediaViewer.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActMediaViewer.kt @@ -33,6 +33,7 @@ import jp.juggler.subwaytooter.api.entity.TootAttachment.Companion.tootAttachmen import jp.juggler.subwaytooter.databinding.ActMediaViewerBinding import jp.juggler.subwaytooter.dialog.actionsDialog import jp.juggler.subwaytooter.drawable.MediaBackgroundDrawable +import jp.juggler.subwaytooter.itemviewholder.reUrlGif import jp.juggler.subwaytooter.pref.PrefI import jp.juggler.subwaytooter.util.permissionSpecMediaDownload import jp.juggler.subwaytooter.util.requester @@ -61,7 +62,7 @@ import javax.microedition.khronos.opengles.GL10 import javax.net.ssl.HttpsURLConnection import kotlin.math.max -@androidx.media3.common.util.UnstableApi +@androidx.annotation.OptIn(markerClass = [androidx.media3.common.util.UnstableApi::class]) class ActMediaViewer : AppCompatActivity(), View.OnClickListener { companion object { @@ -399,6 +400,17 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener { setShowNextButton(false) 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) { @@ -414,6 +426,7 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener { // いったんすべて隠す views.run { + wvOther.gone() pbvImage.gone() pvVideo.gone() tvError.gone() @@ -434,10 +447,15 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener { when (ta.type) { 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, - -> loadBitmap(ta) + TootAttachmentType.Image -> when { + reUrlGif.containsMatchIn(ta.remote_url ?: "") -> + loadOther(ta) + + else -> + loadBitmap(ta) + } TootAttachmentType.Video, TootAttachmentType.GIFV, @@ -590,7 +608,21 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener { 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) { views.run { diff --git a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAttachmentMSP.kt b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAttachmentMSP.kt index 5d0a5fa9..8451f7c6 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAttachmentMSP.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootAttachmentMSP.kt @@ -7,11 +7,9 @@ class TootAttachmentMSP( val preview_url: String, ) : TootAttachmentLike { - override val type: TootAttachmentType - get() = TootAttachmentType.Unknown + override val type = TootAttachmentType.Unknown - override val description: String? - get() = null + override val description = null override fun urlForThumbnail() = preview_url diff --git a/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderActions.kt b/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderActions.kt index 2287f707..ab41d4d3 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderActions.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderActions.kt @@ -5,9 +5,35 @@ import android.view.View import jp.juggler.subwaytooter.ActMain import jp.juggler.subwaytooter.ActMediaViewer 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.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.startGap import jp.juggler.subwaytooter.pref.PrefB @@ -62,6 +88,7 @@ fun ItemViewHolder.onClickImpl(v: View?) { tvContent ).show() } + btnFollow -> clickFollowInfo( pos, accessInfo, @@ -88,11 +115,13 @@ fun ItemViewHolder.onClickImpl(v: View?) { followAccount, accept = true ) + btnFollowRequestDeny -> clickFollowRequestAccept( accessInfo, followAccount, accept = false ) + llFilter -> openFilterMenu(accessInfo, item.cast()) ivCardImage -> clickCardImage(pos, accessInfo, statusShowing?.card) llConversationIcons -> clickConversation( @@ -200,7 +229,7 @@ private fun ItemViewHolder.clickMedia(i: Int) { statusShowing?.media_attachments ?: (item as? TootScheduled)?.mediaAttachments ?: return - when (val item = if (i < mediaAttachments.size) mediaAttachments[i] else return) { + when (val item = mediaAttachments.firstOrNull() ?: return) { is TootAttachmentMSP -> { // マストドン検索ポータルのデータではmedia_attachmentsが簡略化されている // 会話の流れを表示する @@ -212,15 +241,16 @@ private fun ItemViewHolder.clickMedia(i: Int) { is TootAttachment -> when { - // unknownが1枚だけなら内蔵ビューアを使わずにインテントを投げる - item.type == TootAttachmentType.Unknown && mediaAttachments.size == 1 -> { - // https://github.com/tateisu/SubwayTooter/pull/119 - // メディアタイプがunknownの場合、そのほとんどはリモートから来たURLである - // PrefB.bpPriorLocalURL の状態に関わらずリモートURLがあればそれをブラウザで開く - when (val remoteUrl = item.remote_url.notEmpty()) { - null -> activity.openCustomTab(item) - else -> activity.openCustomTab(remoteUrl) - } + // 添付メディアが1枚だけで、unknownまたはファイル拡張子がGIFなら、ブラウザで開く + // https://github.com/tateisu/SubwayTooter/pull/119 + // メディアタイプがunknownの場合、そのほとんどはリモートから来たURLである + // PrefB.bpPriorLocalURL の状態に関わらずリモートURLがあればそれをブラウザで開く + mediaAttachments.size == 1 && + (item.type == TootAttachmentType.Unknown || + reUrlGif.containsMatchIn(item.remote_url ?: "")) + -> 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, tagInfo = item, ) + TootTag.TagType.Link -> openCustomTab(item.url) } + is TootSearchGap -> column.startGap(item, isHead = true) is TootConversationSummary -> clickConversation( pos, @@ -334,6 +366,7 @@ private fun ItemViewHolder.clickTag(pos: Int, item: TimelineItem?) { listAdapter, summary = item ) + is TootGap -> clickTootGap(column, item) is TootDomainBlock -> clickDomainBlock(accessInfo, item) is TootScheduled -> clickScheduledToot(accessInfo, item, column) diff --git a/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderShowStatus.kt b/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderShowStatus.kt index 751fc7f9..8743ca83 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderShowStatus.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/ItemViewHolderShowStatus.kt @@ -356,6 +356,8 @@ private fun ItemViewHolder.showAttachments(status: TootStatus) { } } +val reUrlGif = """\.gif(?:\z|\?)""".toRegex(RegexOption.IGNORE_CASE) + fun ItemViewHolder.setMedia( mediaAttachments: ArrayList, idx: Int, @@ -390,11 +392,28 @@ fun ItemViewHolder.setMedia( TootAttachmentType.Unknown -> { iv.setMediaType(0) 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 } - 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, "" -> { iv.setMediaType(0) iv.setDefaultImage(defaultColorIcon(activity, R.drawable.wide_question)) diff --git a/app/src/main/res/layout/act_media_viewer.xml b/app/src/main/res/layout/act_media_viewer.xml index 98d60a50..cc12a266 100644 --- a/app/src/main/res/layout/act_media_viewer.xml +++ b/app/src/main/res/layout/act_media_viewer.xml @@ -26,6 +26,12 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> + +