Misskeyで同一の添付データが複数あると投稿に失敗して、なぜかジョブが残り続ける問題の対策。Misskeyでも添付データの説明文を指定できるようにする。
This commit is contained in:
parent
7ba02264cc
commit
e182127494
|
@ -1,8 +1,8 @@
|
|||
package jp.juggler.subwaytooter.api.entity
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import jp.juggler.subwaytooter.pref.PrefB
|
||||
import jp.juggler.subwaytooter.api.TootParser
|
||||
import jp.juggler.subwaytooter.pref.PrefB
|
||||
import jp.juggler.util.*
|
||||
|
||||
class TootAttachment : TootAttachmentLike {
|
||||
|
@ -120,12 +120,9 @@ class TootAttachment : TootAttachmentLike {
|
|||
remote_url = url
|
||||
text_url = url
|
||||
|
||||
description = arrayOf(
|
||||
src.string("name"),
|
||||
src.string("comment")
|
||||
)
|
||||
.filterNotNull()
|
||||
.joinToString(" / ")
|
||||
|
||||
description = src.string("comment")?.notBlank()
|
||||
?: src.string("name")?.notBlank()
|
||||
|
||||
focusX = 0f
|
||||
focusY = 0f
|
||||
|
|
|
@ -909,15 +909,28 @@ class AttachmentUploader(
|
|||
var resultAttachment: TootAttachment? = null
|
||||
val result = try {
|
||||
context.runApiTask(account) { client ->
|
||||
client.request(
|
||||
"/api/v1/media/$attachmentId",
|
||||
jsonObject {
|
||||
put("description", description)
|
||||
if( account.isMisskey){
|
||||
client.request(
|
||||
"/api/drive/files/update",
|
||||
account.putMisskeyApiToken().apply {
|
||||
put("fileId", attachmentId.toString())
|
||||
put("comment",description)
|
||||
}.toPostRequestBuilder()
|
||||
)?.also { result ->
|
||||
resultAttachment =
|
||||
parseItem(::TootAttachment, ServiceType.MISSKEY, result.jsonObject)
|
||||
}
|
||||
}else {
|
||||
client.request(
|
||||
"/api/v1/media/$attachmentId",
|
||||
jsonObject {
|
||||
put("description", description)
|
||||
}
|
||||
.toPutRequestBuilder()
|
||||
)?.also { result ->
|
||||
resultAttachment =
|
||||
parseItem(::TootAttachment, ServiceType.MASTODON, result.jsonObject)
|
||||
}
|
||||
.toPutRequestBuilder()
|
||||
)?.also { result ->
|
||||
resultAttachment =
|
||||
parseItem(::TootAttachment, ServiceType.MASTODON, result.jsonObject)
|
||||
}
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
|
|
|
@ -78,53 +78,19 @@ class PostImpl(
|
|||
else -> 25 // TootPollsType.Mastodon
|
||||
}
|
||||
|
||||
private fun preCheckPollItemOne(list: List<String>, idx: Int, item: String): Boolean {
|
||||
private fun preCheckPollItemOne(list: List<String>, idx: Int, item: String) {
|
||||
|
||||
// 選択肢が長すぎる
|
||||
val cpCount = item.codePointCount(0, item.length)
|
||||
if (cpCount > choiceMaxChars) {
|
||||
val over = cpCount - choiceMaxChars
|
||||
activity.showToast(true, R.string.enquete_item_too_long, idx + 1, over)
|
||||
return false
|
||||
activity.errorString(R.string.enquete_item_too_long, idx + 1, over)
|
||||
}
|
||||
|
||||
// 他の項目と重複している
|
||||
if ((0 until idx).any { list[it] == item }) {
|
||||
activity.showToast(true, R.string.enquete_item_duplicate, idx + 1)
|
||||
return false
|
||||
activity.errorString(R.string.enquete_item_duplicate, idx + 1)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun preCheck(): Boolean {
|
||||
if (content.isEmpty() && attachmentList == null) {
|
||||
activity.showToast(true, R.string.post_error_contents_empty)
|
||||
return false
|
||||
}
|
||||
|
||||
// nullはCWチェックなしを示す // nullじゃなくてカラならエラー
|
||||
if (spoilerText != null && spoilerText.isEmpty()) {
|
||||
activity.showToast(true, R.string.post_error_contents_warning_empty)
|
||||
return false
|
||||
}
|
||||
|
||||
if (enqueteItems != null) {
|
||||
if (enqueteItems.size < 2) {
|
||||
activity.showToast(true, R.string.enquete_item_is_empty, enqueteItems.size + 1)
|
||||
return false
|
||||
}
|
||||
enqueteItems.forEachIndexed { i, v ->
|
||||
if (!preCheckPollItemOne(enqueteItems, i, v)) return false
|
||||
}
|
||||
}
|
||||
|
||||
if (scheduledAt != 0L && account.isMisskey) {
|
||||
activity.showToast(true, "misskey has no scheduled status API")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private var resultStatus: TootStatus? = null
|
||||
|
@ -401,7 +367,39 @@ class PostImpl(
|
|||
}
|
||||
|
||||
suspend fun runSuspend(): PostResult {
|
||||
if (!preCheck()) throw CancellationException("preCheck failed.")
|
||||
|
||||
if (account.isMisskey){
|
||||
val duplicateCheck = buildMap {
|
||||
attachmentList?.forEach {
|
||||
put( it.id.toString(), (get(it.id.toString())?:0)+1)
|
||||
}
|
||||
}
|
||||
if( duplicateCheck.values.all { it >=2 }){
|
||||
activity.errorString(R.string.post_error_attachments_duplicated)
|
||||
}
|
||||
}
|
||||
|
||||
if (content.isEmpty() && attachmentList == null) {
|
||||
activity.errorString(R.string.post_error_contents_empty)
|
||||
}
|
||||
|
||||
// nullはCWチェックなしを示す // nullじゃなくてカラならエラー
|
||||
if (spoilerText != null && spoilerText.isEmpty()) {
|
||||
activity.errorString(R.string.post_error_contents_warning_empty)
|
||||
}
|
||||
|
||||
if (!enqueteItems.isNullOrEmpty()) {
|
||||
if (enqueteItems.size < 2) {
|
||||
activity.errorString(R.string.enquete_item_is_empty, enqueteItems.size + 1)
|
||||
}
|
||||
enqueteItems.forEachIndexed { i, v ->
|
||||
preCheckPollItemOne(enqueteItems, i, v)
|
||||
}
|
||||
}
|
||||
|
||||
if (scheduledAt != 0L && account.isMisskey) {
|
||||
error("misskey has no scheduled status API")
|
||||
}
|
||||
|
||||
if (PrefB.bpWarnHashtagAsciiAndNonAscii()) {
|
||||
TootTag.findHashtags(content, account.isMisskey)
|
||||
|
@ -449,6 +447,7 @@ class PostImpl(
|
|||
|
||||
// 投稿中に再度投稿ボタンが押された
|
||||
if (postJob?.get()?.isActive == true) {
|
||||
log.e("other postJob is active!")
|
||||
activity.showToast(false, R.string.post_button_tapped_repeatly)
|
||||
throw CancellationException("preCheck failed.")
|
||||
}
|
||||
|
@ -458,6 +457,7 @@ class PostImpl(
|
|||
val delta = now - lastPostTapped
|
||||
lastPostTapped = now
|
||||
if (delta < 1000L) {
|
||||
log.e("lastPostTapped within 1 sec!")
|
||||
activity.showToast(false, R.string.post_button_tapped_repeatly)
|
||||
throw CancellationException("post_button_tapped_repeatly")
|
||||
}
|
||||
|
@ -576,7 +576,7 @@ class PostImpl(
|
|||
status != null ->
|
||||
PostResult.Normal(account, status)
|
||||
|
||||
else -> error( result.error ?: "(result.error is null)")
|
||||
else -> error(result.error ?: "(result.error is null)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,17 +31,6 @@ fun launchMain(block: suspend CoroutineScope.() -> Unit): Job =
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun AppCompatActivity.launchAndShowError(block: suspend CoroutineScope.() -> Unit): Job =
|
||||
lifecycleScope.launch() {
|
||||
try {
|
||||
block()
|
||||
} catch (ex: Throwable) {
|
||||
showError(ex)
|
||||
}
|
||||
}
|
||||
|
||||
// Default Dispatcherで動作するコルーチンを起動して、終了を待たずにリターンする。
|
||||
// 起動されたアクティビティのライフサイクルに関わらず中断しない。
|
||||
fun launchDefault(block: suspend CoroutineScope.() -> Unit): Job =
|
||||
|
@ -71,6 +60,17 @@ fun launchIO(block: suspend CoroutineScope.() -> Unit): Job =
|
|||
fun <T : Any?> asyncIO(block: suspend CoroutineScope.() -> T): Deferred<T> =
|
||||
EndlessScope.async(block = block, context = Dispatchers.IO)
|
||||
|
||||
fun AppCompatActivity.launchAndShowError(
|
||||
errorCaption: String? = null,
|
||||
block: suspend CoroutineScope.() -> Unit,
|
||||
): Job = lifecycleScope.launch() {
|
||||
try {
|
||||
block()
|
||||
} catch (ex: Throwable) {
|
||||
showError(ex, errorCaption)
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
suspend fun <T : Any?> AppCompatActivity.runWithProgress(
|
||||
|
@ -79,7 +79,7 @@ suspend fun <T : Any?> AppCompatActivity.runWithProgress(
|
|||
afterProc: suspend CoroutineScope.(result: T) -> Unit = {},
|
||||
progressInitializer: suspend CoroutineScope.(ProgressDialogEx) -> Unit = {},
|
||||
preProc: suspend CoroutineScope.() -> Unit = {},
|
||||
postProc: suspend CoroutineScope.() -> Unit = {}
|
||||
postProc: suspend CoroutineScope.() -> Unit = {},
|
||||
) {
|
||||
coroutineScope {
|
||||
if (!isMainThread) error("runWithProgress: not main thread.")
|
||||
|
|
|
@ -4,8 +4,11 @@ import android.content.res.Resources
|
|||
import android.util.Log
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
fun Throwable.withCaption(caption: String) =
|
||||
"$caption :${javaClass.simpleName} $message"
|
||||
fun Throwable.withCaption(caption: String?=null) =
|
||||
when {
|
||||
caption.isNullOrBlank() -> "${javaClass.simpleName} $message"
|
||||
else -> "$caption :${javaClass.simpleName} $message"
|
||||
}
|
||||
|
||||
fun Throwable.withCaption(resources: Resources, stringId: Int, vararg args: Any) =
|
||||
"${resources.getString(stringId, *args)}: ${javaClass.simpleName} $message"
|
||||
|
@ -58,7 +61,7 @@ class LogCategory(category: String) {
|
|||
///////////////////////////////
|
||||
// Throwable + string
|
||||
|
||||
private fun msg(priority: Int, ex: Throwable, caption: String = "exception.") =
|
||||
private fun msg(priority: Int, ex: Throwable, caption: String? =null) =
|
||||
msg(priority, ex.withCaption(caption))
|
||||
|
||||
fun e(ex: Throwable, caption: String = "exception") = msg(Log.ERROR, ex, caption)
|
||||
|
|
|
@ -2,6 +2,7 @@ package jp.juggler.util
|
|||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import jp.juggler.subwaytooter.R
|
||||
|
@ -49,7 +50,7 @@ internal fun showToastImpl(context: Context, bLong: Boolean, message: String): B
|
|||
fun Context.showToast(bLong: Boolean, caption: String?): Boolean =
|
||||
showToastImpl(this, bLong, caption ?: "(null)")
|
||||
|
||||
fun Context.showToast(ex: Throwable, caption: String = "error."): Boolean =
|
||||
fun Context.showToast(ex: Throwable, caption: String? = null): Boolean =
|
||||
showToastImpl(this, true, ex.withCaption(caption))
|
||||
|
||||
fun Context.showToast(bLong: Boolean, stringId: Int, vararg args: Any): Boolean =
|
||||
|
@ -58,8 +59,9 @@ fun Context.showToast(bLong: Boolean, stringId: Int, vararg args: Any): Boolean
|
|||
fun Context.showToast(ex: Throwable, stringId: Int, vararg args: Any): Boolean =
|
||||
showToastImpl(this, true, ex.withCaption(resources, stringId, *args))
|
||||
|
||||
fun AppCompatActivity.showError(ex: Throwable, caption: String = "error.") {
|
||||
log.e(ex)
|
||||
fun AppCompatActivity.showError(ex: Throwable, caption: String? = null) {
|
||||
log.e(ex, caption ?: "(showError)")
|
||||
|
||||
// キャンセル例外はUIに表示しない
|
||||
if (ex is CancellationException) return
|
||||
|
||||
|
@ -70,10 +72,8 @@ fun AppCompatActivity.showError(ex: Throwable, caption: String = "error.") {
|
|||
listOf(
|
||||
caption,
|
||||
when (ex) {
|
||||
is IllegalStateException ->
|
||||
null
|
||||
else ->
|
||||
ex.javaClass.simpleName
|
||||
is IllegalStateException -> null
|
||||
else -> ex.javaClass.simpleName
|
||||
},
|
||||
ex.message,
|
||||
)
|
||||
|
@ -81,8 +81,11 @@ fun AppCompatActivity.showError(ex: Throwable, caption: String = "error.") {
|
|||
.joinToString("\n")
|
||||
)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
} catch (ex: Throwable) {
|
||||
log.e(ex)
|
||||
.show()
|
||||
} catch (ignored: Throwable) {
|
||||
showToast(ex, caption)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.errorString(@StringRes stringId: Int, vararg args: Any?): Nothing =
|
||||
error(getString(stringId, args))
|
||||
|
|
|
@ -557,7 +557,7 @@
|
|||
<string name="not_blocked">No blocada.</string>
|
||||
<string name="not_muted">No silenciada.</string>
|
||||
<string name="media_description">(adjunció %1$d) %2$s</string>
|
||||
<string name="set_description">crea una descripció (Mastodont 2.0+)</string>
|
||||
<string name="set_description">crea una descripció</string>
|
||||
<string name="attachment_description_cant_edit_while_uploading">La descripció de l\'adjunció no es pot editar mentre es carrega.</string>
|
||||
<string name="attachment_description">descripció d\'adjunció</string>
|
||||
<string name="description_empty">no hi ha descripció.</string>
|
||||
|
|
|
@ -939,7 +939,7 @@
|
|||
<string name="description_empty">未指定描述.</string>
|
||||
<string name="attachment_description">附件描述</string>
|
||||
<string name="attachment_description_cant_edit_while_uploading">正在上传时无法编辑附件描述.</string>
|
||||
<string name="set_description">设置描述(Mastodon 2.0+)</string>
|
||||
<string name="set_description">设置描述</string>
|
||||
<string name="media_description">(附件%1$d)%2$s</string>
|
||||
<string name="not_muted">未被静音.</string>
|
||||
<string name="not_blocked">未被阻止.</string>
|
||||
|
|
|
@ -332,7 +332,7 @@
|
|||
<string name="emoji">Emoji</string>
|
||||
<string name="not_blocked">Heb ei flocio.</string>
|
||||
<string name="not_muted">Heb ei dawelu.</string>
|
||||
<string name="set_description">gosod disgrifiad(Mastodon 2.0 neu hwyrach)</string>
|
||||
<string name="set_description">gosod disgrifiad</string>
|
||||
<string name="attachment_description_cant_edit_while_uploading">Ni ellir golygu disgrfiad yr atodiad tra\'n uwchlwytho.</string>
|
||||
<string name="attachment_description">disgrifiad atodiad</string>
|
||||
<string name="description_empty">disgrifiad heb ei bennu.</string>
|
||||
|
|
|
@ -845,7 +845,7 @@
|
|||
<string name="lists">Listen</string>
|
||||
<string name="operation_succeeded">Fertig.</string>
|
||||
<string name="attachment_description_sending">sende Beschreibung des Anhangs…</string>
|
||||
<string name="set_description">Beschreibung festlegen (Mastodon 2.0 und später)</string>
|
||||
<string name="set_description">Beschreibung festlegen</string>
|
||||
<string name="attachment_description">Beschreibung des Anhangs</string>
|
||||
<string name="attachment_description_cant_edit_while_uploading">Die Beschreibung des Anhangs kann beim Hochladen nicht mehr geändert werden.</string>
|
||||
<string name="media_description">(Anhang %1$d) %2$s</string>
|
||||
|
|
|
@ -524,7 +524,7 @@
|
|||
<string name="not_blocked">Non bloqué.</string>
|
||||
<string name="not_muted">Pas mis en sourdine.</string>
|
||||
<string name="media_description">(pièce jointe %1$d) %2$s</string>
|
||||
<string name="set_description">ajouter une description (Mastodon 2.0+)</string>
|
||||
<string name="set_description">ajouter une description</string>
|
||||
<string name="attachment_description_cant_edit_while_uploading">La description de la pièce jointe ne peut être modifiée pendant le téléversement.</string>
|
||||
<string name="attachment_description">description de la pièce jointe</string>
|
||||
<string name="description_empty">aucune description.</string>
|
||||
|
|
|
@ -664,7 +664,7 @@
|
|||
<string name="sensitive_content_default_open">NSFWな添付データを隠さない</string>
|
||||
<string name="cw_default_open">CWされたコンテンツを隠さない</string>
|
||||
<string name="server_confirmed">サーバを確認しました</string>
|
||||
<string name="set_description">説明文を設定(マストドン2.0以降)</string>
|
||||
<string name="set_description">説明文を設定</string>
|
||||
<string name="set_focus_point">焦点を設定 (マストドン2.3以降)</string>
|
||||
<string name="setting">設定</string>
|
||||
<string name="share_url">URLを共有</string>
|
||||
|
@ -1146,4 +1146,5 @@
|
|||
<string name="error">エラー</string>
|
||||
<string name="emoji_picker_custom_of">カスタム: %1$s</string>
|
||||
<string name="others" >その他</string>
|
||||
<string name="post_error_attachments_duplicated">Misskeyは添付データの重複を許可していません。</string>
|
||||
</resources>
|
||||
|
|
|
@ -535,7 +535,7 @@
|
|||
<string name="not_blocked">차단 안 됨.</string>
|
||||
<string name="not_muted">음소거 안 됨.</string>
|
||||
<string name="media_description">(첨부 %1$d) %2$s</string>
|
||||
<string name="set_description">설명을 설정 (마스토돈 2.0 이상)</string>
|
||||
<string name="set_description">설명을 설정</string>
|
||||
<string name="attachment_description_cant_edit_while_uploading">첨부파일 설명은 올리는 중에는 편집할 수 없습니다.</string>
|
||||
<string name="attachment_description">첨부파일 설명</string>
|
||||
<string name="description_empty">설명이 지정되지 않았습니다.</string>
|
||||
|
|
|
@ -418,7 +418,7 @@
|
|||
<string name="not_blocked">Ikke blokkert.</string>
|
||||
<string name="not_muted">Ikke forstummet.</string>
|
||||
<string name="media_description">(vedlegg %1$d) %2$s</string>
|
||||
<string name="set_description">sett beskrivelse (Mastodon 2.0 eller senere)</string>
|
||||
<string name="set_description">sett beskrivelse</string>
|
||||
<string name="attachment_description">vedleggsbeskrivelse</string>
|
||||
<string name="description_empty">beskrivelsen er ikke angitt.</string>
|
||||
<string name="attachment_description_sending">sender vedleggsbeskrivelse…</string>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="app_name" translatable="false">Subway Tooter</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="account_add">Add an account</string>
|
||||
|
@ -553,7 +553,7 @@
|
|||
<string name="not_blocked">Not blocked.</string>
|
||||
<string name="not_muted">Not muted.</string>
|
||||
<string name="media_description">(attachment %1$d) %2$s</string>
|
||||
<string name="set_description">set description (Mastodon 2.0+)</string>
|
||||
<string name="set_description">set description</string>
|
||||
<string name="attachment_description_cant_edit_while_uploading">Attachment description can\'t be edit while uploading.</string>
|
||||
<string name="attachment_description">attachment description</string>
|
||||
<string name="description_empty">description is not specified.</string>
|
||||
|
@ -669,11 +669,11 @@
|
|||
<string name="unfavourite">Unfavourite</string>
|
||||
<string name="unboost">Unboost</string>
|
||||
<string name="dont_retrieve_preview_card">Don\'t retrieve preview card</string>
|
||||
<string name="field_name1">label1</string>
|
||||
<string name="field_name1" tools:ignore="Typos">label1</string>
|
||||
<string name="field_name2">label2</string>
|
||||
<string name="field_name3">label3</string>
|
||||
<string name="field_name4">label4</string>
|
||||
<string name="field_value1">value1</string>
|
||||
<string name="field_value1" tools:ignore="Typos">value1</string>
|
||||
<string name="field_value2">value2</string>
|
||||
<string name="field_value3">value3</string>
|
||||
<string name="field_value4">value4</string>
|
||||
|
@ -1154,5 +1154,6 @@
|
|||
<string name="categories">Categories</string>
|
||||
<string name="error">Error</string>
|
||||
<string name="emoji_picker_custom_of">Custom: %1$s</string>
|
||||
<string name="others" >Others</string>
|
||||
<string name="others">Others</string>
|
||||
<string name="post_error_attachments_duplicated">Misskey does not allow duplicate in attachments.</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue