外部アプリからシェアした際に送信先インスタンスのサーバ情報をまだキャッシュできていない場合に対応

This commit is contained in:
tateisu 2023-07-12 09:54:09 +09:00
parent f7d079eef1
commit 7d3715d8b9
2 changed files with 97 additions and 12 deletions

View File

@ -22,6 +22,7 @@ import jp.juggler.subwaytooter.actpost.CompletionHelper
import jp.juggler.subwaytooter.actpost.FeaturedTagCache
import jp.juggler.subwaytooter.actpost.addAttachment
import jp.juggler.subwaytooter.actpost.applyMushroomText
import jp.juggler.subwaytooter.actpost.launchAddAttachmentChannelReader
import jp.juggler.subwaytooter.actpost.onPickCustomThumbnailImpl
import jp.juggler.subwaytooter.actpost.onPostAttachmentCompleteImpl
import jp.juggler.subwaytooter.actpost.openAttachment
@ -197,6 +198,13 @@ class ActPost : AppCompatActivity(),
}
}
class AddAttachmentChannelItem(
val uri: Uri,
val mimeTypeArg: String?,
)
val addAttachmentChannel = Channel<AddAttachmentChannelItem>(capacity = Channel.BUFFERED)
////////////////////////////////////////////////////////////////
override fun onCreate(savedInstanceState: Bundle?) {
@ -220,6 +228,8 @@ class ActPost : AppCompatActivity(),
progressChannel = Channel(capacity = Channel.CONFLATED)
launchAddAttachmentChannelReader()
initUI()
// 進捗表示チャネルの回収コルーチン
@ -255,6 +265,7 @@ class ActPost : AppCompatActivity(),
}
completionHelper.onDestroy()
attachmentUploader.onActivityDestroy()
addAttachmentChannel.close()
super.onDestroy()
}

View File

@ -8,6 +8,8 @@ import androidx.appcompat.app.AlertDialog
import jp.juggler.subwaytooter.ActPost
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.ApiTask
import jp.juggler.subwaytooter.api.TootApiCallback
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.TootApiResult
import jp.juggler.subwaytooter.api.entity.InstanceType
import jp.juggler.subwaytooter.api.entity.ServiceType
@ -44,6 +46,9 @@ import jp.juggler.util.log.withCaption
import jp.juggler.util.network.toPutRequestBuilder
import jp.juggler.util.ui.isLiveActivity
import jp.juggler.util.ui.vg
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.channels.ClosedReceiveChannelException
import java.nio.channels.ClosedChannelException
import kotlin.math.min
private val log = LogCategory("ActPostAttachment")
@ -126,34 +131,77 @@ fun ActPost.openAttachment() {
fun ActPost.addAttachment(
uri: Uri,
mimeTypeArg: String? = null,
// onUploadEnd: () -> Unit = {},
) {
val item = ActPost.AddAttachmentChannelItem(uri = uri, mimeTypeArg = mimeTypeArg)
for (nTry in 1..10) {
try {
val channelResult = addAttachmentChannel.trySend(item)
when {
channelResult.isSuccess -> return
channelResult.isClosed -> return
channelResult.isFailure -> continue
}
} catch (ex: Throwable) {
log.e(ex, "addAttachmentChannel.trySend failed.")
continue
}
}
}
suspend fun ActPost.getInstance(): TootInstance {
val client = TootApiClient(
context = applicationContext,
callback = object : TootApiCallback {
override suspend fun isApiCancelled() = isFinishing || isDestroyed
}
).apply {
this.account = this@getInstance.account
}
val (instance, ri) = TootInstance.get(client = client)
if (instance != null) return instance
when (ri) {
null -> throw CancellationException()
else -> error("missing instance information. ${ri.error}")
}
}
suspend fun ActPost.addAttachmentSuspend(
uri: Uri,
mimeTypeArg: String? = null,
) {
val actPost = this
val account = this.account
if (account == null) {
dialogOrToast(R.string.account_select_please)
return
}
val instance = TootInstance.getCached(account)
if (instance == null) {
dialogOrToast("missing instance imformation.")
return
}
val mimeType = uri.resolveMimeType(mimeTypeArg, this)
?.notEmpty()
val isReply = states.inReplyToId != null
when {
actPost.isFinishing || actPost.isDestroyed -> {
dialogOrToast("actPost is finishing or destroyed.")
return
}
attachmentList.size >= 4 -> {
dialogOrToast(R.string.attachment_too_many)
return
}
account == null -> {
dialogOrToast(R.string.account_select_please)
return
}
mimeType == null -> {
dialogOrToast(R.string.mime_type_missing)
return
}
}
val instance = getInstance()
when {
instance.instanceType == InstanceType.Pixelfed && isReply -> {
AttachmentUploader.log.e("pixelfed_does_not_allow_reply_with_media")
dialogOrToast(R.string.pixelfed_does_not_allow_reply_with_media)
@ -169,10 +217,10 @@ fun ActPost.addAttachment(
attachmentUploader.addRequest(
AttachmentRequest(
context = applicationContext,
account = account,
account = account!!,
pa = pa,
uri = uri,
mimeType = mimeType,
mimeType = mimeType!!,
instance = instance,
mediaConfig = mediaConfig,
serverMaxSqPixel = mediaConfig?.int("image_matrix_limit")?.takeIf { it > 0 },
@ -194,6 +242,32 @@ fun ActPost.addAttachment(
}
}
fun ActPost.launchAddAttachmentChannelReader() {
launchMain {
while (true) {
try {
val item = addAttachmentChannel.receive()
addAttachmentSuspend(item.uri, item.mimeTypeArg)
} catch (ex: Throwable) {
when (ex) {
is CancellationException -> {
log.i("launchAddAttachmentChannelReader: cancelled.")
break
}
is ClosedChannelException, is ClosedReceiveChannelException -> {
log.i("launchAddAttachmentChannelReader: channel closed.")
break
}
else ->
log.e(ex,"launchAddAttachmentChannelReader: addAttachmentSuspend raise error. retry…")
}
}
}
}
}
fun ActPost.onPostAttachmentCompleteImpl(pa: PostAttachment) {
// この添付メディアはリストにない
if (!attachmentList.contains(pa)) {