fix can't restore reply from drafts
This commit is contained in:
parent
3eccf01edd
commit
3b7b424119
|
@ -344,15 +344,15 @@ class ActMain : AppCompatActivity(),
|
|||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
App1.setActivityTheme(this, noActionBar = true)
|
||||
|
||||
handler = App1.getAppState(this).handler
|
||||
appState = App1.getAppState(this)
|
||||
pref = App1.pref
|
||||
handler = appState.handler
|
||||
pref = appState.pref
|
||||
density = appState.density
|
||||
completionHelper = CompletionHelper(this, pref, appState.handler)
|
||||
|
||||
EmojiDecoder.handleUnicodeEmoji = PrefB.bpInAppUnicodeEmoji(pref)
|
||||
|
||||
density = appState.density
|
||||
acctPadLr = (0.5f + 4f * density).toInt()
|
||||
|
||||
timelineFontSizeSp = PrefF.fpTimelineFontSize(pref).clipFontSize()
|
||||
acctFontSizeSp = PrefF.fpAcctFontSize(pref).clipFontSize()
|
||||
notificationTlFontSizeSp = PrefF.fpNotificationTlFontSize(pref).clipFontSize()
|
||||
|
@ -925,7 +925,6 @@ class ActMain : AppCompatActivity(),
|
|||
initUIQuickToot()
|
||||
|
||||
svColumnStrip.isHorizontalFadingEdgeEnabled = true
|
||||
completionHelper = CompletionHelper(this, pref, appState.handler)
|
||||
|
||||
val dm = resources.displayMetrics
|
||||
val density = dm.density
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.text.SpannableStringBuilder
|
|||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.RawRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||
import jp.juggler.util.*
|
||||
|
@ -101,35 +100,22 @@ fun ActMain.checkPrivacyPolicy() {
|
|||
// 既に表示中かもしれない
|
||||
if (dlgPrivacyPolicy?.get()?.isShowing == true) return
|
||||
|
||||
@RawRes val resId = when (getString(R.string.language_code)) {
|
||||
"ja" -> R.raw.privacy_policy_ja
|
||||
"fr" -> R.raw.privacy_policy_fr
|
||||
else -> R.raw.privacy_policy_en
|
||||
}
|
||||
|
||||
// プライバシーポリシーデータの読み込み
|
||||
val bytes = loadRawResource(resId)
|
||||
if (bytes.isEmpty()) return
|
||||
val checker = PrivacyPolicyChecker(this, pref)
|
||||
|
||||
// 同意ずみなら表示しない
|
||||
val digest = bytes.digestSHA256().encodeBase64Url()
|
||||
if (digest == PrefS.spAgreedPrivacyPolicyDigest(pref)) return
|
||||
if (checker.agreed) return
|
||||
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(R.string.privacy_policy)
|
||||
.setMessage(bytes.decodeUTF8())
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
finish()
|
||||
}
|
||||
.setOnCancelListener {
|
||||
finish()
|
||||
}
|
||||
.setMessage(checker.text)
|
||||
.setOnCancelListener { finish() }
|
||||
.setNegativeButton(R.string.cancel) { _, _ -> finish() }
|
||||
.setPositiveButton(R.string.agree) { _, _ ->
|
||||
pref.edit().put(PrefS.spAgreedPrivacyPolicyDigest, digest).apply()
|
||||
pref.edit().put(PrefS.spAgreedPrivacyPolicyDigest, checker.digest).apply()
|
||||
}
|
||||
.create()
|
||||
dlgPrivacyPolicy = WeakReference(dialog)
|
||||
dialog.show()
|
||||
.also { dlgPrivacyPolicy = WeakReference(it) }
|
||||
.show()
|
||||
}
|
||||
|
||||
fun ActMain.closeListItemPopup() {
|
||||
|
|
|
@ -29,11 +29,14 @@ fun ActMain.handleIntentUri(uri: Uri) {
|
|||
log.d("handleIntentUri $uri")
|
||||
|
||||
when (uri.scheme) {
|
||||
"subwaytooter", "misskeyclientproto" -> return try {
|
||||
handleCustomSchemaUri(uri)
|
||||
} catch (ex: Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(ex, "handleCustomSchemaUri failed.")
|
||||
"subwaytooter", "misskeyclientproto" -> {
|
||||
try {
|
||||
handleCustomSchemaUri(uri)
|
||||
} catch (ex: Throwable) {
|
||||
log.trace(ex)
|
||||
showToast(ex, "handleCustomSchemaUri failed.")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class ActPost : AppCompatActivity(),
|
|||
MyClickableSpanHandler, AttachmentPicker.Callback {
|
||||
|
||||
companion object {
|
||||
internal val log = LogCategory("ActPost")
|
||||
private val log = LogCategory("ActPost")
|
||||
|
||||
var refActPost: WeakReference<ActPost>? = null
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import jp.juggler.subwaytooter.table.SavedAccount
|
|||
import jp.juggler.util.*
|
||||
import org.jetbrains.anko.textColor
|
||||
|
||||
private val log = LogCategory("ActPostAccount")
|
||||
|
||||
fun ActPost.selectAccount(a: SavedAccount?) {
|
||||
this.account = a
|
||||
|
||||
|
@ -95,7 +97,7 @@ internal fun ActPost.setAccountWithVisibilityConversion(a: SavedAccount) {
|
|||
states.visibility = a.visibility
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
showVisibility()
|
||||
showQuotedRenote()
|
||||
|
|
|
@ -30,7 +30,7 @@ fun ActPost.decodeAttachments(sv: String) {
|
|||
try {
|
||||
attachmentList.add(PostAttachment(TootAttachment.decodeJson(it)))
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
|
@ -126,22 +126,22 @@ fun ActPost.onPostAttachmentCompleteImpl(pa: PostAttachment) {
|
|||
|
||||
when (pa.status) {
|
||||
PostAttachment.Status.Error -> {
|
||||
ActPost.log.w("onPostAttachmentComplete: upload failed.")
|
||||
log.w("onPostAttachmentComplete: upload failed.")
|
||||
attachmentList.remove(pa)
|
||||
showMediaAttachment()
|
||||
}
|
||||
|
||||
PostAttachment.Status.Progress -> {
|
||||
// アップロード中…?
|
||||
ActPost.log.w("onPostAttachmentComplete: ?? status=${pa.status}")
|
||||
log.w("onPostAttachmentComplete: ?? status=${pa.status}")
|
||||
}
|
||||
|
||||
PostAttachment.Status.Ok -> {
|
||||
when (val a = pa.attachment) {
|
||||
null -> ActPost.log.e("onPostAttachmentComplete: upload complete, but missing attachment entity.")
|
||||
null -> log.e("onPostAttachmentComplete: upload complete, but missing attachment entity.")
|
||||
else -> {
|
||||
// アップロード完了
|
||||
ActPost.log.i("onPostAttachmentComplete: upload complete.")
|
||||
log.i("onPostAttachmentComplete: upload complete.")
|
||||
|
||||
// 投稿欄の末尾に追記する
|
||||
if (PrefB.bpAppendAttachmentUrlToContent(pref)) {
|
||||
|
|
|
@ -11,6 +11,8 @@ import jp.juggler.subwaytooter.table.SavedAccount
|
|||
import jp.juggler.subwaytooter.util.*
|
||||
import jp.juggler.util.*
|
||||
|
||||
private val log = LogCategory("ActPostExtra")
|
||||
|
||||
fun ActPost.appendContentText(
|
||||
src: String?,
|
||||
selectBefore: Boolean = false,
|
||||
|
@ -246,7 +248,7 @@ fun ActPost.initializeFromSharedIntent(sharedIntent: Intent) {
|
|||
appendContentText(sharedIntent)
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,12 @@ import androidx.annotation.RawRes
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import jp.juggler.subwaytooter.util.DecodeOptions
|
||||
import jp.juggler.subwaytooter.util.LinkHelper
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.decodeUTF8
|
||||
import jp.juggler.util.loadRawResource
|
||||
|
||||
private val log = LogCategory("ActPostMushroom")
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
fun ActPost.showRecommendedPlugin(title: String?) {
|
||||
|
||||
|
@ -89,7 +92,7 @@ fun ActPost.openMushroom() {
|
|||
|
||||
arMushroom.launch(chooser)
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
showRecommendedPlugin(getString(R.string.plugin_not_installed))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import jp.juggler.subwaytooter.util.PostAttachment
|
|||
import jp.juggler.util.*
|
||||
import kotlinx.coroutines.isActive
|
||||
|
||||
private val log = LogCategory("ActPostRedraft")
|
||||
|
||||
// DlgDraftPickerから参照される
|
||||
const val DRAFT_CONTENT = "content"
|
||||
const val DRAFT_CONTENT_WARNING = "content_warning"
|
||||
|
@ -60,7 +62,7 @@ fun ActPost.saveDraft() {
|
|||
}
|
||||
|
||||
if (!hasContent) {
|
||||
ActPost.log.d("saveDraft: dont save empty content")
|
||||
log.d("saveDraft: dont save empty content")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -74,32 +76,29 @@ fun ActPost.saveDraft() {
|
|||
json[DRAFT_CONTENT_WARNING] = contentWarning
|
||||
json[DRAFT_CONTENT_WARNING_CHECK] = cbContentWarning.isChecked
|
||||
json[DRAFT_NSFW_CHECK] = cbNSFW.isChecked
|
||||
states.visibility?.let { json.put(DRAFT_VISIBILITY, it.id.toString()) }
|
||||
json[DRAFT_ACCOUNT_DB_ID] = account?.db_id ?: -1L
|
||||
json[DRAFT_ATTACHMENT_LIST] = tmpAttachmentList
|
||||
states.inReplyToId?.putTo(json, DRAFT_REPLY_ID)
|
||||
json[DRAFT_REPLY_TEXT] = states.inReplyToText
|
||||
json[DRAFT_REPLY_IMAGE] = states.inReplyToImage
|
||||
json[DRAFT_REPLY_URL] = states.inReplyToUrl
|
||||
|
||||
json[DRAFT_QUOTE] = cbQuote.isChecked
|
||||
|
||||
// deprecated. but still used in old draft.
|
||||
// json.put(DRAFT_IS_ENQUETE, isEnquete)
|
||||
|
||||
json[DRAFT_POLL_TYPE] = spPollType.selectedItemPosition.toPollTypeString()
|
||||
|
||||
json[DRAFT_POLL_MULTIPLE] = cbMultipleChoice.isChecked
|
||||
json[DRAFT_POLL_HIDE_TOTALS] = cbHideTotals.isChecked
|
||||
json[DRAFT_POLL_EXPIRE_DAY] = etExpireDays.text.toString()
|
||||
json[DRAFT_POLL_EXPIRE_HOUR] = etExpireHours.text.toString()
|
||||
json[DRAFT_POLL_EXPIRE_MINUTE] = etExpireMinutes.text.toString()
|
||||
|
||||
json[DRAFT_ENQUETE_ITEMS] = strChoice.toJsonArray()
|
||||
|
||||
states.visibility?.id?.toString()?.let { json.put(DRAFT_VISIBILITY, it) }
|
||||
states.inReplyToId?.putTo(json, DRAFT_REPLY_ID)
|
||||
|
||||
// deprecated. but still used in old draft.
|
||||
// json.put(DRAFT_IS_ENQUETE, isEnquete)
|
||||
|
||||
PostDraft.save(System.currentTimeMillis(), json)
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,98 +110,94 @@ fun ActPost.restoreDraft(draft: JsonObject) {
|
|||
launchMain {
|
||||
val listWarning = ArrayList<String>()
|
||||
var targetAccount: SavedAccount? = null
|
||||
runWithProgress(
|
||||
"restore from draft",
|
||||
doInBackground = { progress ->
|
||||
fun isTaskCancelled() = !this.coroutineContext.isActive
|
||||
runWithProgress("restore from draft", doInBackground = { progress ->
|
||||
|
||||
var content = draft.string(DRAFT_CONTENT) ?: ""
|
||||
val accountDbId = draft.long(DRAFT_ACCOUNT_DB_ID) ?: -1L
|
||||
val tmpAttachmentList =
|
||||
draft.jsonArray(DRAFT_ATTACHMENT_LIST)?.objectList()?.toMutableList()
|
||||
fun isTaskCancelled() = !this.coroutineContext.isActive
|
||||
|
||||
val account = SavedAccount.loadAccount(this@restoreDraft, accountDbId)
|
||||
if (account == null) {
|
||||
listWarning.add(getString(R.string.account_in_draft_is_lost))
|
||||
try {
|
||||
if (tmpAttachmentList != null) {
|
||||
// 本文からURLを除去する
|
||||
tmpAttachmentList.forEach {
|
||||
val textUrl = TootAttachment.decodeJson(it).text_url
|
||||
if (textUrl?.isNotEmpty() == true) {
|
||||
content = content.replace(textUrl, "")
|
||||
}
|
||||
}
|
||||
tmpAttachmentList.clear()
|
||||
draft[DRAFT_ATTACHMENT_LIST] = tmpAttachmentList.toJsonArray()
|
||||
draft[DRAFT_CONTENT] = content
|
||||
draft.remove(DRAFT_REPLY_ID)
|
||||
draft.remove(DRAFT_REPLY_TEXT)
|
||||
draft.remove(DRAFT_REPLY_IMAGE)
|
||||
draft.remove(DRAFT_REPLY_URL)
|
||||
}
|
||||
} catch (ignored: JsonException) {
|
||||
}
|
||||
|
||||
return@runWithProgress "OK"
|
||||
}
|
||||
|
||||
targetAccount = account
|
||||
|
||||
// アカウントがあるなら基本的にはすべての情報を復元できるはずだが、いくつか確認が必要だ
|
||||
val apiClient = TootApiClient(this@restoreDraft, callback = object : TootApiCallback {
|
||||
|
||||
override val isApiCancelled: Boolean
|
||||
get() = isTaskCancelled()
|
||||
|
||||
override suspend fun publishApiProgress(s: String) {
|
||||
progress.setMessageEx(s)
|
||||
}
|
||||
})
|
||||
|
||||
apiClient.account = account
|
||||
|
||||
states.inReplyToId?.let { inReplyToId ->
|
||||
val result = apiClient.request("/api/v1/statuses/$inReplyToId")
|
||||
if (isTaskCancelled()) return@runWithProgress null
|
||||
val jsonObject = result?.jsonObject
|
||||
if (jsonObject == null) {
|
||||
listWarning.add(getString(R.string.reply_to_in_draft_is_lost))
|
||||
draft.remove(DRAFT_REPLY_ID)
|
||||
draft.remove(DRAFT_REPLY_TEXT)
|
||||
draft.remove(DRAFT_REPLY_IMAGE)
|
||||
}
|
||||
}
|
||||
var content = draft.string(DRAFT_CONTENT) ?: ""
|
||||
val tmpAttachmentList = draft.jsonArray(DRAFT_ATTACHMENT_LIST)?.objectList()?.toMutableList()
|
||||
|
||||
val accountDbId = draft.long(DRAFT_ACCOUNT_DB_ID) ?: -1L
|
||||
val account = SavedAccount.loadAccount(this@restoreDraft, accountDbId)
|
||||
if (account == null) {
|
||||
listWarning.add(getString(R.string.account_in_draft_is_lost))
|
||||
try {
|
||||
if (tmpAttachmentList != null) {
|
||||
// 添付メディアの存在確認
|
||||
var isSomeAttachmentRemoved = false
|
||||
val it = tmpAttachmentList.iterator()
|
||||
while (it.hasNext()) {
|
||||
if (isTaskCancelled()) return@runWithProgress null
|
||||
val ta = TootAttachment.decodeJson(it.next())
|
||||
if (ActPost.checkExist(ta.url)) continue
|
||||
it.remove()
|
||||
isSomeAttachmentRemoved = true
|
||||
// 本文からURLを除去する
|
||||
val textUrl = ta.text_url
|
||||
// 本文からURLを除去する
|
||||
tmpAttachmentList.forEach {
|
||||
val textUrl = TootAttachment.decodeJson(it).text_url
|
||||
if (textUrl?.isNotEmpty() == true) {
|
||||
content = content.replace(textUrl, "")
|
||||
}
|
||||
}
|
||||
if (isSomeAttachmentRemoved) {
|
||||
listWarning.add(getString(R.string.attachment_in_draft_is_lost))
|
||||
draft[DRAFT_ATTACHMENT_LIST] = tmpAttachmentList.toJsonArray()
|
||||
draft[DRAFT_CONTENT] = content
|
||||
}
|
||||
tmpAttachmentList.clear()
|
||||
draft[DRAFT_ATTACHMENT_LIST] = tmpAttachmentList.toJsonArray()
|
||||
draft[DRAFT_CONTENT] = content
|
||||
draft.remove(DRAFT_REPLY_ID)
|
||||
draft.remove(DRAFT_REPLY_TEXT)
|
||||
draft.remove(DRAFT_REPLY_IMAGE)
|
||||
draft.remove(DRAFT_REPLY_URL)
|
||||
}
|
||||
} catch (ex: JsonException) {
|
||||
ActPost.log.trace(ex)
|
||||
} catch (ignored: JsonException) {
|
||||
}
|
||||
|
||||
"OK"
|
||||
},
|
||||
return@runWithProgress "OK"
|
||||
}
|
||||
|
||||
targetAccount = account
|
||||
|
||||
// アカウントがあるなら基本的にはすべての情報を復元できるはずだが、いくつか確認が必要だ
|
||||
val apiClient = TootApiClient(this@restoreDraft, callback = object : TootApiCallback {
|
||||
override val isApiCancelled: Boolean
|
||||
get() = isTaskCancelled()
|
||||
|
||||
override suspend fun publishApiProgress(s: String) {
|
||||
progress.setMessageEx(s)
|
||||
}
|
||||
})
|
||||
apiClient.account = account
|
||||
|
||||
// 返信ステータスが存在するかどうか
|
||||
EntityId.from(draft, DRAFT_REPLY_ID)?.let { inReplyToId ->
|
||||
val result = apiClient.request("/api/v1/statuses/$inReplyToId")
|
||||
if (isTaskCancelled()) return@runWithProgress null
|
||||
if (result?.jsonObject == null) {
|
||||
listWarning.add(getString(R.string.reply_to_in_draft_is_lost))
|
||||
draft.remove(DRAFT_REPLY_ID)
|
||||
draft.remove(DRAFT_REPLY_TEXT)
|
||||
draft.remove(DRAFT_REPLY_IMAGE)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (tmpAttachmentList != null) {
|
||||
// 添付メディアの存在確認
|
||||
var isSomeAttachmentRemoved = false
|
||||
val it = tmpAttachmentList.iterator()
|
||||
while (it.hasNext()) {
|
||||
if (isTaskCancelled()) return@runWithProgress null
|
||||
val ta = TootAttachment.decodeJson(it.next())
|
||||
if (ActPost.checkExist(ta.url)) continue
|
||||
it.remove()
|
||||
isSomeAttachmentRemoved = true
|
||||
// 本文からURLを除去する
|
||||
val textUrl = ta.text_url
|
||||
if (textUrl?.isNotEmpty() == true) {
|
||||
content = content.replace(textUrl, "")
|
||||
}
|
||||
}
|
||||
if (isSomeAttachmentRemoved) {
|
||||
listWarning.add(getString(R.string.attachment_in_draft_is_lost))
|
||||
draft[DRAFT_ATTACHMENT_LIST] = tmpAttachmentList.toJsonArray()
|
||||
draft[DRAFT_CONTENT] = content
|
||||
}
|
||||
}
|
||||
} catch (ex: JsonException) {
|
||||
log.trace(ex)
|
||||
}
|
||||
|
||||
"OK"
|
||||
},
|
||||
afterProc = { result ->
|
||||
// cancelled.
|
||||
if (result == null) return@runWithProgress
|
||||
|
@ -213,16 +208,12 @@ fun ActPost.restoreDraft(draft: JsonObject) {
|
|||
val nsfwChecked = draft.optBoolean(DRAFT_NSFW_CHECK)
|
||||
val tmpAttachmentList = draft.jsonArray(DRAFT_ATTACHMENT_LIST)
|
||||
val replyId = EntityId.from(draft, DRAFT_REPLY_ID)
|
||||
val replyText = draft.string(DRAFT_REPLY_TEXT)
|
||||
val replyImage = draft.string(DRAFT_REPLY_IMAGE)
|
||||
val replyUrl = draft.string(DRAFT_REPLY_URL)
|
||||
val draftVisibility = TootVisibility
|
||||
.parseSavedVisibility(draft.string(DRAFT_VISIBILITY))
|
||||
|
||||
val evEmoji = DecodeOptions(
|
||||
this@restoreDraft,
|
||||
decodeEmoji = true
|
||||
).decodeEmoji(content)
|
||||
val draftVisibility = TootVisibility.parseSavedVisibility(draft.string(DRAFT_VISIBILITY))
|
||||
|
||||
val evEmoji = DecodeOptions(this@restoreDraft, decodeEmoji = true)
|
||||
.decodeEmoji(content)
|
||||
|
||||
etContent.setText(evEmoji)
|
||||
etContent.setSelection(evEmoji.length)
|
||||
etContentWarning.setText(contentWarning)
|
||||
|
@ -274,9 +265,9 @@ fun ActPost.restoreDraft(draft: JsonObject) {
|
|||
|
||||
if (replyId != null) {
|
||||
states.inReplyToId = replyId
|
||||
states.inReplyToText = replyText
|
||||
states.inReplyToImage = replyImage
|
||||
states.inReplyToUrl = replyUrl
|
||||
states.inReplyToText = draft.string(DRAFT_REPLY_TEXT)
|
||||
states.inReplyToImage = draft.string(DRAFT_REPLY_IMAGE)
|
||||
states.inReplyToUrl = draft.string(DRAFT_REPLY_URL)
|
||||
}
|
||||
|
||||
showContentWarningEnabled()
|
||||
|
@ -327,7 +318,7 @@ fun ActPost.initializeFromRedraftStatus(account: SavedAccount, jsonText: String)
|
|||
}
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,6 +391,6 @@ fun ActPost.initializeFromRedraftStatus(account: SavedAccount, jsonText: String)
|
|||
}
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,13 @@ import jp.juggler.subwaytooter.api.runApiTask
|
|||
import jp.juggler.subwaytooter.api.syncStatus
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.subwaytooter.util.DecodeOptions
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.decodeJsonObject
|
||||
import jp.juggler.util.launchMain
|
||||
import jp.juggler.util.showToast
|
||||
|
||||
private val log = LogCategory("ActPostReply")
|
||||
|
||||
fun ActPost.showQuotedRenote() {
|
||||
cbQuote.visibility = if (states.inReplyToId != null) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
@ -102,6 +105,7 @@ fun ActPost.initializeFromReplyStatus(account: SavedAccount, jsonText: String) {
|
|||
}
|
||||
|
||||
// リプライ表示をつける
|
||||
states.inReplyToId = replyStatus.id
|
||||
states.inReplyToText = replyStatus.content
|
||||
states.inReplyToImage = replyStatus.account.avatar_static
|
||||
states.inReplyToUrl = replyStatus.url
|
||||
|
@ -127,18 +131,15 @@ fun ActPost.initializeFromReplyStatus(account: SavedAccount, jsonText: String) {
|
|||
if (TootVisibility.WebSetting == states.visibility) {
|
||||
// 「Web設定に合わせる」だった場合は無条件にリプライ元の公開範囲に変更する
|
||||
states.visibility = sample
|
||||
} else if (TootVisibility.isVisibilitySpoilRequired(
|
||||
states.visibility, sample
|
||||
)
|
||||
) {
|
||||
} else if (TootVisibility.isVisibilitySpoilRequired(states.visibility, sample)) {
|
||||
// デフォルトの方が公開範囲が大きい場合、リプライ元に合わせて公開範囲を狭める
|
||||
states.visibility = sample
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,13 @@ import jp.juggler.subwaytooter.api.entity.parseItem
|
|||
import jp.juggler.subwaytooter.dialog.DlgDateTime
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.subwaytooter.util.PostAttachment
|
||||
import jp.juggler.util.LogCategory
|
||||
import jp.juggler.util.cast
|
||||
import jp.juggler.util.decodeJsonObject
|
||||
import jp.juggler.util.notEmpty
|
||||
|
||||
private val log = LogCategory("ActPostSchedule")
|
||||
|
||||
fun ActPost.showSchedule() {
|
||||
tvSchedule.text = when (states.timeSchedule) {
|
||||
0L -> getString(R.string.unspecified)
|
||||
|
@ -37,7 +40,7 @@ fun ActPost.initializeFromScheduledStatus(account: SavedAccount, jsonText: Strin
|
|||
::TootScheduled,
|
||||
TootParser(this, account),
|
||||
jsonText.decodeJsonObject(),
|
||||
ActPost.log
|
||||
log
|
||||
) ?: error("initializeFromScheduledStatus: parse failed.")
|
||||
|
||||
scheduledStatus = item
|
||||
|
@ -67,6 +70,6 @@ fun ActPost.initializeFromScheduledStatus(account: SavedAccount, jsonText: Strin
|
|||
this.attachmentList.addAll(it)
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ class ActText : AppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun search() {
|
||||
selection.trim().notEmpty()?.let {
|
||||
selection.trim().notEmpty()?.also {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_WEB_SEARCH)
|
||||
intent.putExtra(SearchManager.QUERY, it)
|
||||
|
|
|
@ -18,14 +18,15 @@ import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
|
|||
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
|
||||
import com.bumptech.glide.load.engine.executor.GlideExecutor
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import jp.juggler.subwaytooter.emoji.EmojiMap
|
||||
import jp.juggler.subwaytooter.api.TootApiClient
|
||||
import jp.juggler.subwaytooter.emoji.EmojiMap
|
||||
import jp.juggler.subwaytooter.table.*
|
||||
import jp.juggler.subwaytooter.util.CustomEmojiCache
|
||||
import jp.juggler.subwaytooter.util.CustomEmojiLister
|
||||
import jp.juggler.subwaytooter.util.ProgressResponseBody
|
||||
import jp.juggler.util.*
|
||||
import okhttp3.*
|
||||
import okhttp3.OkHttpClient
|
||||
import org.conscrypt.Conscrypt
|
||||
import ru.gildor.coroutines.okhttp.await
|
||||
import java.io.File
|
||||
|
@ -36,6 +37,8 @@ import java.net.CookiePolicy
|
|||
import java.security.Security
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.logging.Level
|
||||
import java.util.logging.Logger
|
||||
import kotlin.math.max
|
||||
|
||||
class App1 : Application() {
|
||||
|
@ -370,6 +373,9 @@ class App1 : Application() {
|
|||
|
||||
log.d("create okhttp client")
|
||||
run {
|
||||
|
||||
Logger.getLogger(OkHttpClient::class.java.name).level = Level.FINE
|
||||
|
||||
// API用のHTTP設定はキャッシュを使わない
|
||||
ok_http_client = prepareOkHttp(60, 60)
|
||||
.build()
|
||||
|
@ -540,19 +546,19 @@ class App1 : Application() {
|
|||
val call = ok_http_client2.newCall(request_builder.build())
|
||||
response = call.await()
|
||||
} catch (ex: Throwable) {
|
||||
log.e(ex, "getHttp network error.")
|
||||
log.e(ex, "getHttp network error. $url")
|
||||
return null
|
||||
}
|
||||
|
||||
if (!response.isSuccessful) {
|
||||
log.e(TootApiClient.formatResponse(response, "getHttp response error."))
|
||||
log.e(TootApiClient.formatResponse(response, "getHttp response error. $url"))
|
||||
return null
|
||||
}
|
||||
|
||||
return try {
|
||||
response.body?.bytes()
|
||||
} catch (ex: Throwable) {
|
||||
log.e(ex, "getHttp content error.")
|
||||
log.e(ex, "getHttp content error. $url")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -579,19 +585,19 @@ class App1 : Application() {
|
|||
val call = ok_http_client2.newCall(request_builder.build())
|
||||
response = call.await()
|
||||
} catch (ex: Throwable) {
|
||||
log.e(ex, "getHttp network error.")
|
||||
log.e(ex, "getHttp network error. $url")
|
||||
return null
|
||||
}
|
||||
|
||||
if (!response.isSuccessful) {
|
||||
log.e(TootApiClient.formatResponse(response, "getHttp response error."))
|
||||
log.e(TootApiClient.formatResponse(response, "getHttp response error. $url"))
|
||||
return null
|
||||
}
|
||||
|
||||
return try {
|
||||
response.body?.string()
|
||||
} catch (ex: Throwable) {
|
||||
log.e(ex, "getHttp content error.")
|
||||
log.e(ex, "getHttp content error. $url")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.*
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import jp.juggler.subwaytooter.action.*
|
||||
import jp.juggler.subwaytooter.api.entity.*
|
||||
|
@ -43,38 +44,20 @@ internal class DlgContextMenu(
|
|||
private val dialog: Dialog
|
||||
|
||||
private val viewRoot = activity.layoutInflater.inflate(R.layout.dlg_context_menu, null, false)
|
||||
private fun <T : View> fv(@IdRes id: Int): T = viewRoot.findViewById(id)
|
||||
|
||||
private val btnCrossAccountActionsForStatus: Button =
|
||||
viewRoot.findViewById(R.id.btnCrossAccountActionsForStatus)
|
||||
private val llCrossAccountActionsForStatus: View =
|
||||
viewRoot.findViewById(R.id.llCrossAccountActionsForStatus)
|
||||
|
||||
private val btnCrossAccountActionsForAccount: Button =
|
||||
viewRoot.findViewById(R.id.btnCrossAccountActionsForAccount)
|
||||
private val llCrossAccountActionsForAccount: View =
|
||||
viewRoot.findViewById(R.id.llCrossAccountActionsForAccount)
|
||||
|
||||
private val btnAroundThisToot: Button =
|
||||
viewRoot.findViewById(R.id.btnAroundThisToot)
|
||||
private val llAroundThisToot: View =
|
||||
viewRoot.findViewById(R.id.llAroundThisToot)
|
||||
|
||||
private val btnYourToot: Button =
|
||||
viewRoot.findViewById(R.id.btnYourToot)
|
||||
private val llYourToot: View =
|
||||
viewRoot.findViewById(R.id.llYourToot)
|
||||
|
||||
private val btnStatusExtraAction: Button =
|
||||
viewRoot.findViewById(R.id.btnStatusExtraAction)
|
||||
private val llStatusExtraAction: View =
|
||||
viewRoot.findViewById(R.id.llStatusExtraAction)
|
||||
|
||||
private val btnAccountExtraAction: Button =
|
||||
viewRoot.findViewById(R.id.btnAccountExtraAction)
|
||||
private val llAccountExtraAction: View =
|
||||
viewRoot.findViewById(R.id.llAccountExtraAction)
|
||||
|
||||
private val btnPostNotification: Button = viewRoot.findViewById(R.id.btnPostNotification)
|
||||
private val btnGroupStatusCrossAccount: Button = fv(R.id.btnGroupStatusCrossAccount)
|
||||
private val llGroupStatusCrossAccount: View = fv(R.id.llGroupStatusCrossAccount)
|
||||
private val btnGroupStatusAround: Button = fv(R.id.btnGroupStatusAround)
|
||||
private val llGroupStatusAround: View = fv(R.id.llGroupStatusAround)
|
||||
private val btnGroupStatusByMe: Button = fv(R.id.btnGroupStatusByMe)
|
||||
private val llGroupStatusByMe: View = fv(R.id.llGroupStatusByMe)
|
||||
private val btnGroupStatusExtra: Button = fv(R.id.btnGroupStatusExtra)
|
||||
private val llGroupStatusExtra: View = fv(R.id.llGroupStatusExtra)
|
||||
private val btnGroupUserCrossAccount: Button = fv(R.id.btnGroupUserCrossAccount)
|
||||
private val llGroupUserCrossAccount: View = fv(R.id.llGroupUserCrossAccount)
|
||||
private val btnGroupUserExtra: Button = fv(R.id.btnGroupUserExtra)
|
||||
private val llGroupUserExtra: View = fv(R.id.llGroupUserExtra)
|
||||
|
||||
init {
|
||||
val columnType = column.type
|
||||
|
@ -93,136 +76,121 @@ internal class DlgContextMenu(
|
|||
dialog.setCancelable(true)
|
||||
dialog.setCanceledOnTouchOutside(true)
|
||||
|
||||
val llStatus: View = viewRoot.findViewById(R.id.llStatus)
|
||||
val btnStatusWebPage: View = viewRoot.findViewById(R.id.btnStatusWebPage)
|
||||
val btnText: View = viewRoot.findViewById(R.id.btnText)
|
||||
val btnFavouriteAnotherAccount: View =
|
||||
viewRoot.findViewById(R.id.btnFavouriteAnotherAccount)
|
||||
val btnBookmarkAnotherAccount: View =
|
||||
viewRoot.findViewById(R.id.btnBookmarkAnotherAccount)
|
||||
val btnBoostAnotherAccount: View = viewRoot.findViewById(R.id.btnBoostAnotherAccount)
|
||||
val btnReactionAnotherAccount: View = viewRoot.findViewById(R.id.btnReactionAnotherAccount)
|
||||
val btnReplyAnotherAccount: View = viewRoot.findViewById(R.id.btnReplyAnotherAccount)
|
||||
val btnQuoteAnotherAccount: View = viewRoot.findViewById(R.id.btnQuoteAnotherAccount)
|
||||
val btnQuoteTootBT: View = viewRoot.findViewById(R.id.btnQuoteTootBT)
|
||||
val btnDelete: View = viewRoot.findViewById(R.id.btnDelete)
|
||||
val btnRedraft: View = viewRoot.findViewById(R.id.btnRedraft)
|
||||
|
||||
val btnReportStatus: View = viewRoot.findViewById(R.id.btnReportStatus)
|
||||
val btnReportUser: View = viewRoot.findViewById(R.id.btnReportUser)
|
||||
val btnMuteApp: Button = viewRoot.findViewById(R.id.btnMuteApp)
|
||||
val llAccountActionBar: View = viewRoot.findViewById(R.id.llAccountActionBar)
|
||||
val btnFollow: ImageButton = viewRoot.findViewById(R.id.btnFollow)
|
||||
|
||||
val btnMute: ImageView = viewRoot.findViewById(R.id.btnMute)
|
||||
val btnBlock: ImageView = viewRoot.findViewById(R.id.btnBlock)
|
||||
val btnProfile: View = viewRoot.findViewById(R.id.btnProfile)
|
||||
val btnSendMessage: View = viewRoot.findViewById(R.id.btnSendMessage)
|
||||
val btnAccountWebPage: View = viewRoot.findViewById(R.id.btnAccountWebPage)
|
||||
val btnFollowRequestOK: View = viewRoot.findViewById(R.id.btnFollowRequestOK)
|
||||
val btnFollowRequestNG: View = viewRoot.findViewById(R.id.btnFollowRequestNG)
|
||||
val btnDeleteSuggestion: View = viewRoot.findViewById(R.id.btnDeleteSuggestion)
|
||||
val btnFollowFromAnotherAccount: View =
|
||||
viewRoot.findViewById(R.id.btnFollowFromAnotherAccount)
|
||||
val btnSendMessageFromAnotherAccount: View =
|
||||
viewRoot.findViewById(R.id.btnSendMessageFromAnotherAccount)
|
||||
val btnOpenProfileFromAnotherAccount: View =
|
||||
viewRoot.findViewById(R.id.btnOpenProfileFromAnotherAccount)
|
||||
val btnDomainBlock: Button = viewRoot.findViewById(R.id.btnDomainBlock)
|
||||
val btnInstanceInformation: Button = viewRoot.findViewById(R.id.btnInstanceInformation)
|
||||
val btnProfileDirectory: Button = viewRoot.findViewById(R.id.btnProfileDirectory)
|
||||
val ivFollowedBy: ImageView = viewRoot.findViewById(R.id.ivFollowedBy)
|
||||
val btnOpenTimeline: Button = viewRoot.findViewById(R.id.btnOpenTimeline)
|
||||
val btnConversationAnotherAccount: View =
|
||||
viewRoot.findViewById(R.id.btnConversationAnotherAccount)
|
||||
val btnAvatarImage: View = viewRoot.findViewById(R.id.btnAvatarImage)
|
||||
|
||||
val llNotification: View = viewRoot.findViewById(R.id.llNotification)
|
||||
val btnNotificationDelete: View = viewRoot.findViewById(R.id.btnNotificationDelete)
|
||||
val btnConversationMute: Button = viewRoot.findViewById(R.id.btnConversationMute)
|
||||
|
||||
val btnHideBoost: View = viewRoot.findViewById(R.id.btnHideBoost)
|
||||
val btnShowBoost: View = viewRoot.findViewById(R.id.btnShowBoost)
|
||||
val btnHideFavourite: View = viewRoot.findViewById(R.id.btnHideFavourite)
|
||||
val btnShowFavourite: View = viewRoot.findViewById(R.id.btnShowFavourite)
|
||||
|
||||
val btnListMemberAddRemove: View = viewRoot.findViewById(R.id.btnListMemberAddRemove)
|
||||
val btnEndorse: Button = viewRoot.findViewById(R.id.btnEndorse)
|
||||
|
||||
val btnAroundAccountTL: View = viewRoot.findViewById(R.id.btnAroundAccountTL)
|
||||
val btnAroundLTL: View = viewRoot.findViewById(R.id.btnAroundLTL)
|
||||
val btnAroundFTL: View = viewRoot.findViewById(R.id.btnAroundFTL)
|
||||
val btnCopyAccountId: Button = viewRoot.findViewById(R.id.btnCopyAccountId)
|
||||
val btnOpenAccountInAdminWebUi: Button =
|
||||
viewRoot.findViewById(R.id.btnOpenAccountInAdminWebUi)
|
||||
val btnOpenInstanceInAdminWebUi: Button =
|
||||
viewRoot.findViewById(R.id.btnOpenInstanceInAdminWebUi)
|
||||
val btnBoostWithVisibility: Button = viewRoot.findViewById(R.id.btnBoostWithVisibility)
|
||||
val llLinks: LinearLayout = viewRoot.findViewById(R.id.llLinks)
|
||||
|
||||
val btnNotificationFrom: Button = viewRoot.findViewById(R.id.btnNotificationFrom)
|
||||
val btnProfilePin = viewRoot.findViewById<View>(R.id.btnProfilePin)
|
||||
val btnProfileUnpin = viewRoot.findViewById<View>(R.id.btnProfileUnpin)
|
||||
val btnBoostedBy = viewRoot.findViewById<View>(R.id.btnBoostedBy)
|
||||
val btnFavouritedBy = viewRoot.findViewById<View>(R.id.btnFavouritedBy)
|
||||
|
||||
val btnDomainTimeline = viewRoot.findViewById<View>(R.id.btnDomainTimeline)
|
||||
val btnAccountWebPage: View = fv(R.id.btnAccountWebPage)
|
||||
val btnAroundAccountTL: View = fv(R.id.btnAroundAccountTL)
|
||||
val btnAroundFTL: View = fv(R.id.btnAroundFTL)
|
||||
val btnAroundLTL: View = fv(R.id.btnAroundLTL)
|
||||
val btnAvatarImage: View = fv(R.id.btnAvatarImage)
|
||||
val btnBlock: ImageView = fv(R.id.btnBlock)
|
||||
val btnBookmarkAnotherAccount: View = fv(R.id.btnBookmarkAnotherAccount)
|
||||
val btnBoostAnotherAccount: View = fv(R.id.btnBoostAnotherAccount)
|
||||
val btnBoostedBy: View = fv(R.id.btnBoostedBy)
|
||||
val btnBoostWithVisibility: Button = fv(R.id.btnBoostWithVisibility)
|
||||
val btnConversationAnotherAccount: View = fv(R.id.btnConversationAnotherAccount)
|
||||
val btnConversationMute: Button = fv(R.id.btnConversationMute)
|
||||
val btnCopyAccountId: Button = fv(R.id.btnCopyAccountId)
|
||||
val btnDelete: View = fv(R.id.btnDelete)
|
||||
val btnDeleteSuggestion: View = fv(R.id.btnDeleteSuggestion)
|
||||
val btnDomainBlock: Button = fv(R.id.btnDomainBlock)
|
||||
val btnDomainTimeline: View = fv(R.id.btnDomainTimeline)
|
||||
val btnEndorse: Button = fv(R.id.btnEndorse)
|
||||
val btnFavouriteAnotherAccount: View = fv(R.id.btnFavouriteAnotherAccount)
|
||||
val btnFavouritedBy: View = fv(R.id.btnFavouritedBy)
|
||||
val btnFollow: ImageButton = fv(R.id.btnFollow)
|
||||
val btnFollowFromAnotherAccount: View = fv(R.id.btnFollowFromAnotherAccount)
|
||||
val btnFollowRequestNG: View = fv(R.id.btnFollowRequestNG)
|
||||
val btnFollowRequestOK: View = fv(R.id.btnFollowRequestOK)
|
||||
val btnHideBoost: View = fv(R.id.btnHideBoost)
|
||||
val btnHideFavourite: View = fv(R.id.btnHideFavourite)
|
||||
val btnInstanceInformation: Button = fv(R.id.btnInstanceInformation)
|
||||
val btnListMemberAddRemove: View = fv(R.id.btnListMemberAddRemove)
|
||||
val btnMute: ImageView = fv(R.id.btnMute)
|
||||
val btnMuteApp: Button = fv(R.id.btnMuteApp)
|
||||
val btnNotificationDelete: View = fv(R.id.btnNotificationDelete)
|
||||
val btnNotificationFrom: Button = fv(R.id.btnNotificationFrom)
|
||||
val btnOpenAccountInAdminWebUi: Button = fv(R.id.btnOpenAccountInAdminWebUi)
|
||||
val btnOpenInstanceInAdminWebUi: Button = fv(R.id.btnOpenInstanceInAdminWebUi)
|
||||
val btnOpenProfileFromAnotherAccount: View = fv(R.id.btnOpenProfileFromAnotherAccount)
|
||||
val btnOpenTimeline: Button = fv(R.id.btnOpenTimeline)
|
||||
val btnProfile: View = fv(R.id.btnProfile)
|
||||
val btnProfileDirectory: Button = fv(R.id.btnProfileDirectory)
|
||||
val btnProfilePin: View = fv(R.id.btnProfilePin)
|
||||
val btnProfileUnpin: View = fv(R.id.btnProfileUnpin)
|
||||
val btnQuoteAnotherAccount: View = fv(R.id.btnQuoteAnotherAccount)
|
||||
val btnQuoteTootBT: View = fv(R.id.btnQuoteTootBT)
|
||||
val btnReactionAnotherAccount: View = fv(R.id.btnReactionAnotherAccount)
|
||||
val btnRedraft: View = fv(R.id.btnRedraft)
|
||||
val btnReplyAnotherAccount: View = fv(R.id.btnReplyAnotherAccount)
|
||||
val btnReportStatus: View = fv(R.id.btnReportStatus)
|
||||
val btnReportUser: View = fv(R.id.btnReportUser)
|
||||
val btnSendMessage: View = fv(R.id.btnSendMessage)
|
||||
val btnSendMessageFromAnotherAccount: View = fv(R.id.btnSendMessageFromAnotherAccount)
|
||||
val btnShowBoost: View = fv(R.id.btnShowBoost)
|
||||
val btnShowFavourite: View = fv(R.id.btnShowFavourite)
|
||||
val btnStatusWebPage: View = fv(R.id.btnStatusWebPage)
|
||||
val btnText: View = fv(R.id.btnText)
|
||||
val ivFollowedBy: ImageView = fv(R.id.ivFollowedBy)
|
||||
val llAccountActionBar: View = fv(R.id.llAccountActionBar)
|
||||
val llLinks: LinearLayout = fv(R.id.llLinks)
|
||||
val llNotification: View = fv(R.id.llNotification)
|
||||
val llStatus: View = fv(R.id.llStatus)
|
||||
val btnStatusNotification: Button = fv(R.id.btnStatusNotification)
|
||||
|
||||
arrayOf(
|
||||
btnNotificationFrom,
|
||||
btnAccountWebPage,
|
||||
btnAroundAccountTL,
|
||||
btnAroundLTL,
|
||||
btnAroundFTL,
|
||||
btnStatusWebPage,
|
||||
btnText,
|
||||
btnFavouriteAnotherAccount,
|
||||
btnAroundLTL,
|
||||
btnAvatarImage,
|
||||
btnBlock,
|
||||
btnBookmarkAnotherAccount,
|
||||
btnBoostAnotherAccount,
|
||||
btnReactionAnotherAccount,
|
||||
btnReplyAnotherAccount,
|
||||
btnQuoteAnotherAccount,
|
||||
btnQuoteTootBT,
|
||||
btnReportStatus,
|
||||
btnReportUser,
|
||||
btnMuteApp,
|
||||
btnDelete,
|
||||
btnRedraft,
|
||||
btnFollow,
|
||||
btnMute,
|
||||
btnBlock,
|
||||
btnProfile,
|
||||
btnSendMessage,
|
||||
btnAccountWebPage,
|
||||
btnFollowRequestOK,
|
||||
btnFollowRequestNG,
|
||||
btnDeleteSuggestion,
|
||||
btnFollowFromAnotherAccount,
|
||||
btnSendMessageFromAnotherAccount,
|
||||
btnOpenProfileFromAnotherAccount,
|
||||
btnOpenTimeline,
|
||||
btnBoostedBy,
|
||||
btnBoostWithVisibility,
|
||||
btnConversationAnotherAccount,
|
||||
btnAvatarImage,
|
||||
btnNotificationDelete,
|
||||
btnConversationMute,
|
||||
btnHideBoost,
|
||||
btnShowBoost,
|
||||
btnHideFavourite,
|
||||
btnShowFavourite,
|
||||
btnListMemberAddRemove,
|
||||
btnInstanceInformation,
|
||||
btnProfileDirectory,
|
||||
btnDomainBlock,
|
||||
btnEndorse,
|
||||
btnCopyAccountId,
|
||||
btnDelete,
|
||||
btnDeleteSuggestion,
|
||||
btnDomainBlock,
|
||||
btnDomainTimeline,
|
||||
btnEndorse,
|
||||
btnFavouriteAnotherAccount,
|
||||
btnFavouritedBy,
|
||||
btnFollow,
|
||||
btnFollowFromAnotherAccount,
|
||||
btnFollowRequestNG,
|
||||
btnFollowRequestOK,
|
||||
btnHideBoost,
|
||||
btnHideFavourite,
|
||||
btnInstanceInformation,
|
||||
btnListMemberAddRemove,
|
||||
btnMute,
|
||||
btnMuteApp,
|
||||
btnNotificationDelete,
|
||||
btnNotificationFrom,
|
||||
btnOpenAccountInAdminWebUi,
|
||||
btnOpenInstanceInAdminWebUi,
|
||||
btnBoostWithVisibility,
|
||||
btnOpenProfileFromAnotherAccount,
|
||||
btnOpenTimeline,
|
||||
btnProfile,
|
||||
btnProfileDirectory,
|
||||
btnProfilePin,
|
||||
btnProfileUnpin,
|
||||
btnBoostedBy,
|
||||
btnFavouritedBy,
|
||||
btnDomainTimeline,
|
||||
btnPostNotification,
|
||||
btnQuoteAnotherAccount,
|
||||
btnQuoteTootBT,
|
||||
btnReactionAnotherAccount,
|
||||
btnRedraft,
|
||||
btnReplyAnotherAccount,
|
||||
btnReportStatus,
|
||||
btnReportUser,
|
||||
btnSendMessage,
|
||||
btnSendMessageFromAnotherAccount,
|
||||
btnShowBoost,
|
||||
btnShowFavourite,
|
||||
btnStatusNotification,
|
||||
btnStatusWebPage,
|
||||
btnText,
|
||||
|
||||
viewRoot.findViewById(R.id.btnQuoteUrlStatus),
|
||||
viewRoot.findViewById(R.id.btnTranslate),
|
||||
|
@ -231,21 +199,17 @@ internal class DlgContextMenu(
|
|||
viewRoot.findViewById(R.id.btnShareUrlAccount),
|
||||
viewRoot.findViewById(R.id.btnQuoteName)
|
||||
|
||||
).forEach {
|
||||
it.setOnClickListener(this@DlgContextMenu)
|
||||
}
|
||||
).forEach { it.setOnClickListener(this) }
|
||||
|
||||
arrayOf(
|
||||
btnFollow,
|
||||
btnProfile,
|
||||
btnMute,
|
||||
btnBlock,
|
||||
btnSendMessage,
|
||||
btnFollow,
|
||||
btnMute,
|
||||
btnProfile,
|
||||
btnQuoteAnotherAccount,
|
||||
btnQuoteTootBT,
|
||||
).forEach {
|
||||
it.setOnLongClickListener(this)
|
||||
}
|
||||
btnSendMessage,
|
||||
).forEach { it.setOnLongClickListener(this) }
|
||||
|
||||
val accountList = SavedAccount.loadAccountList(activity)
|
||||
// final ArrayList< SavedAccount > account_list_non_pseudo_same_instance = new ArrayList<>();
|
||||
|
@ -305,7 +269,7 @@ internal class DlgContextMenu(
|
|||
}
|
||||
llLinks.vg(llLinks.childCount > 1)
|
||||
|
||||
btnYourToot.vg(statusByMe)
|
||||
btnGroupStatusByMe.vg(statusByMe)
|
||||
|
||||
btnQuoteTootBT.vg(status.reblogParent != null)
|
||||
|
||||
|
@ -448,7 +412,7 @@ internal class DlgContextMenu(
|
|||
|
||||
btnReportUser.vg(!(accessInfo.isPseudo || accessInfo.isMe(who)))
|
||||
|
||||
btnPostNotification.vg(!accessInfo.isPseudo && accessInfo.isMastodon && relation.following)
|
||||
btnStatusNotification.vg(!accessInfo.isPseudo && accessInfo.isMastodon && relation.following)
|
||||
?.let {
|
||||
it.text = when (relation.notifying) {
|
||||
true -> activity.getString(R.string.stop_notify_posts_from_this_user)
|
||||
|
@ -522,12 +486,12 @@ internal class DlgContextMenu(
|
|||
|
||||
btnListMemberAddRemove.visibility = View.VISIBLE
|
||||
|
||||
updateGroup(btnCrossAccountActionsForStatus, llCrossAccountActionsForStatus)
|
||||
updateGroup(btnCrossAccountActionsForAccount, llCrossAccountActionsForAccount)
|
||||
updateGroup(btnAroundThisToot, llAroundThisToot)
|
||||
updateGroup(btnYourToot, llYourToot)
|
||||
updateGroup(btnStatusExtraAction, llStatusExtraAction)
|
||||
updateGroup(btnAccountExtraAction, llAccountExtraAction)
|
||||
updateGroup(btnGroupStatusCrossAccount, llGroupStatusCrossAccount)
|
||||
updateGroup(btnGroupUserCrossAccount, llGroupUserCrossAccount)
|
||||
updateGroup(btnGroupStatusAround, llGroupStatusAround)
|
||||
updateGroup(btnGroupStatusByMe, llGroupStatusByMe)
|
||||
updateGroup(btnGroupStatusExtra, llGroupStatusExtra)
|
||||
updateGroup(btnGroupUserExtra, llGroupUserExtra)
|
||||
}
|
||||
|
||||
fun show() {
|
||||
|
@ -585,35 +549,35 @@ internal class DlgContextMenu(
|
|||
}
|
||||
|
||||
fun onClickUpdateGroup(v: View): Boolean = when (v.id) {
|
||||
R.id.btnCrossAccountActionsForStatus -> updateGroup(
|
||||
btnCrossAccountActionsForStatus,
|
||||
llCrossAccountActionsForStatus,
|
||||
R.id.btnGroupStatusCrossAccount -> updateGroup(
|
||||
btnGroupStatusCrossAccount,
|
||||
llGroupStatusCrossAccount,
|
||||
toggle = true
|
||||
)
|
||||
|
||||
R.id.btnCrossAccountActionsForAccount -> updateGroup(
|
||||
btnCrossAccountActionsForAccount,
|
||||
llCrossAccountActionsForAccount,
|
||||
R.id.btnGroupUserCrossAccount -> updateGroup(
|
||||
btnGroupUserCrossAccount,
|
||||
llGroupUserCrossAccount,
|
||||
toggle = true
|
||||
)
|
||||
R.id.btnAroundThisToot -> updateGroup(
|
||||
btnAroundThisToot,
|
||||
llAroundThisToot,
|
||||
R.id.btnGroupStatusAround -> updateGroup(
|
||||
btnGroupStatusAround,
|
||||
llGroupStatusAround,
|
||||
toggle = true
|
||||
)
|
||||
R.id.btnYourToot -> updateGroup(
|
||||
btnYourToot,
|
||||
llYourToot,
|
||||
R.id.btnGroupStatusByMe -> updateGroup(
|
||||
btnGroupStatusByMe,
|
||||
llGroupStatusByMe,
|
||||
toggle = true
|
||||
)
|
||||
R.id.btnStatusExtraAction -> updateGroup(
|
||||
btnStatusExtraAction,
|
||||
llStatusExtraAction,
|
||||
R.id.btnGroupStatusExtra -> updateGroup(
|
||||
btnGroupStatusExtra,
|
||||
llGroupStatusExtra,
|
||||
toggle = true
|
||||
)
|
||||
R.id.btnAccountExtraAction -> updateGroup(
|
||||
btnAccountExtraAction,
|
||||
llAccountExtraAction,
|
||||
R.id.btnGroupUserExtra -> updateGroup(
|
||||
btnGroupUserExtra,
|
||||
llGroupUserExtra,
|
||||
toggle = true
|
||||
)
|
||||
else -> false
|
||||
|
@ -671,7 +635,7 @@ internal class DlgContextMenu(
|
|||
R.id.btnOpenAccountInAdminWebUi -> openBrowser("https://${accessInfo.apiHost.ascii}/admin/accounts/${who.id}")
|
||||
R.id.btnOpenInstanceInAdminWebUi -> openBrowser("https://${accessInfo.apiHost.ascii}/admin/instances/${who.apDomain.ascii}")
|
||||
R.id.btnNotificationFrom -> clickNotificationFrom(pos, accessInfo, who)
|
||||
R.id.btnPostNotification -> clickStatusNotification(accessInfo, who, relation)
|
||||
R.id.btnStatusNotification -> clickStatusNotification(accessInfo, who, relation)
|
||||
R.id.btnQuoteUrlAccount -> openPost(who.url?.notEmpty())
|
||||
R.id.btnShareUrlAccount -> shareText(who.url?.notEmpty())
|
||||
else -> return false
|
||||
|
@ -740,36 +704,33 @@ internal class DlgContextMenu(
|
|||
override fun onLongClick(v: View): Boolean {
|
||||
val whoRef = this.whoRef
|
||||
val who = whoRef?.get()
|
||||
when (v.id) {
|
||||
R.id.btnFollow -> {
|
||||
dialog.dismissSafe()
|
||||
activity.followFromAnotherAccount(
|
||||
activity.nextPosition(column),
|
||||
accessInfo,
|
||||
who
|
||||
)
|
||||
|
||||
with(activity) {
|
||||
val pos = nextPosition(column)
|
||||
|
||||
when (v.id) {
|
||||
// events don't close dialog
|
||||
R.id.btnMute -> userMuteFromAnotherAccount(who, accessInfo)
|
||||
R.id.btnBlock -> userBlockFromAnotherAccount(who, accessInfo)
|
||||
R.id.btnQuoteAnotherAccount -> quoteFromAnotherAccount(accessInfo, status)
|
||||
R.id.btnQuoteTootBT -> quoteFromAnotherAccount(accessInfo, status?.reblogParent)
|
||||
|
||||
// events close dialog before action
|
||||
R.id.btnFollow -> {
|
||||
dialog.dismissSafe()
|
||||
followFromAnotherAccount(pos, accessInfo, who)
|
||||
}
|
||||
R.id.btnProfile -> {
|
||||
dialog.dismissSafe()
|
||||
userProfileFromAnotherAccount(pos, accessInfo, who)
|
||||
}
|
||||
R.id.btnSendMessage -> {
|
||||
dialog.dismissSafe()
|
||||
mentionFromAnotherAccount(accessInfo, who)
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
|
||||
R.id.btnProfile -> {
|
||||
dialog.dismissSafe()
|
||||
activity.userProfileFromAnotherAccount(
|
||||
activity.nextPosition(column),
|
||||
accessInfo,
|
||||
who
|
||||
)
|
||||
}
|
||||
|
||||
R.id.btnSendMessage -> {
|
||||
dialog.dismissSafe()
|
||||
activity.mentionFromAnotherAccount(accessInfo, who)
|
||||
}
|
||||
|
||||
R.id.btnMute -> activity.userMuteFromAnotherAccount(who, accessInfo)
|
||||
R.id.btnBlock -> activity.userBlockFromAnotherAccount(who, accessInfo)
|
||||
R.id.btnQuoteAnotherAccount -> activity.quoteFromAnotherAccount(accessInfo, status)
|
||||
R.id.btnQuoteTootBT -> activity.quoteFromAnotherAccount(accessInfo, status?.reblogParent)
|
||||
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package jp.juggler.subwaytooter
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.annotation.RawRes
|
||||
import jp.juggler.util.decodeUTF8
|
||||
import jp.juggler.util.digestSHA256
|
||||
import jp.juggler.util.encodeBase64Url
|
||||
import jp.juggler.util.loadRawResource
|
||||
|
||||
// 利用規約
|
||||
// 同意済みかどうか調べる
|
||||
// 関連データを提供する
|
||||
class PrivacyPolicyChecker(
|
||||
val context: Context,
|
||||
val pref: SharedPreferences = context.pref(),
|
||||
) {
|
||||
val bytes by lazy {
|
||||
@RawRes val resId = when (context.getString(R.string.language_code)) {
|
||||
"ja" -> R.raw.privacy_policy_ja
|
||||
"fr" -> R.raw.privacy_policy_fr
|
||||
else -> R.raw.privacy_policy_en
|
||||
}
|
||||
context.loadRawResource(resId)
|
||||
}
|
||||
|
||||
val text by lazy { bytes.decodeUTF8() }
|
||||
val digest by lazy { bytes.digestSHA256().encodeBase64Url() }
|
||||
|
||||
val agreed: Boolean
|
||||
get() = when {
|
||||
bytes.isEmpty() -> true
|
||||
else -> digest == PrefS.spAgreedPrivacyPolicyDigest(pref)
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ fun ActPost.saveWindowSize() {
|
|||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
// WindowMetrics#getBounds() the window size including all system bar areas
|
||||
windowManager?.currentWindowMetrics?.bounds?.let { bounds ->
|
||||
ActPost.log.d("API=${Build.VERSION.SDK_INT}, WindowMetrics#getBounds() $bounds")
|
||||
log.d("API=${Build.VERSION.SDK_INT}, WindowMetrics#getBounds() $bounds")
|
||||
PrefDevice.savePostWindowBound(this, bounds.width(), bounds.height())
|
||||
}
|
||||
} else {
|
||||
|
@ -40,7 +40,7 @@ fun ActPost.saveWindowSize() {
|
|||
windowManager.defaultDisplay?.let { display ->
|
||||
val dm = DisplayMetrics()
|
||||
display.getMetrics(dm)
|
||||
ActPost.log.d("API=${Build.VERSION.SDK_INT}, displayMetrics=${dm.widthPixels},${dm.heightPixels}")
|
||||
log.d("API=${Build.VERSION.SDK_INT}, displayMetrics=${dm.widthPixels},${dm.heightPixels}")
|
||||
PrefDevice.savePostWindowBound(this, dm.widthPixels, dm.heightPixels)
|
||||
}
|
||||
}
|
||||
|
@ -265,17 +265,15 @@ fun ActMain.shareText(text: String?) {
|
|||
}
|
||||
|
||||
fun ActMain.clickReply(accessInfo: SavedAccount, status: TootStatus) {
|
||||
if (!accessInfo.isPseudo) {
|
||||
reply(accessInfo, status)
|
||||
} else {
|
||||
replyFromAnotherAccount(accessInfo, status)
|
||||
when {
|
||||
accessInfo.isPseudo -> replyFromAnotherAccount(accessInfo, status)
|
||||
else -> reply(accessInfo, status)
|
||||
}
|
||||
}
|
||||
|
||||
fun ActMain.clickQuote(accessInfo: SavedAccount, status: TootStatus) {
|
||||
if (!accessInfo.isPseudo) {
|
||||
reply(accessInfo, status, quote = true)
|
||||
} else {
|
||||
quoteFromAnotherAccount(accessInfo, status)
|
||||
when {
|
||||
accessInfo.isPseudo -> quoteFromAnotherAccount(accessInfo, status)
|
||||
else -> reply(accessInfo, status, quote = true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -302,7 +302,6 @@ fun ActMain.bookmark(
|
|||
)
|
||||
) {
|
||||
bookmark(
|
||||
|
||||
accessInfo,
|
||||
statusArg,
|
||||
crossAccountMode,
|
||||
|
|
|
@ -142,15 +142,11 @@ enum class TootVisibility(
|
|||
fun parseSavedVisibility(sv: String?): TootVisibility? {
|
||||
sv ?: return null
|
||||
|
||||
// 新しい方式ではenumのID
|
||||
for (v in values()) {
|
||||
if (v.id.toString() == sv) return v
|
||||
}
|
||||
// 新しい方式ではenumのidの文字列表現
|
||||
values().find { it.id.toString() == sv }?.let { return it }
|
||||
|
||||
// 古い方式ではマストドンの公開範囲文字列かweb_setting
|
||||
for (v in values()) {
|
||||
if (v.strMastodon == sv) return v
|
||||
}
|
||||
values().find { it.strMastodon == sv }?.let { return it }
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -42,9 +42,6 @@ class PollingWorker private constructor(contextArg: Context) {
|
|||
|
||||
val log = LogCategory("PollingWorker")
|
||||
|
||||
// private const val FCM_SENDER_ID = "433682361381"
|
||||
// private const val FCM_SCOPE = "FCM"
|
||||
|
||||
const val NOTIFICATION_ID = 1
|
||||
const val NOTIFICATION_ID_ERROR = 3
|
||||
|
||||
|
@ -72,6 +69,7 @@ class PollingWorker private constructor(contextArg: Context) {
|
|||
|
||||
suspend fun getFirebaseMessagingToken(context: Context): String? {
|
||||
val prefDevice = PrefDevice.from(context)
|
||||
|
||||
// 設定ファイルに保持されていたらそれを使う
|
||||
prefDevice
|
||||
.getString(PrefDevice.KEY_DEVICE_TOKEN, null)
|
||||
|
@ -103,20 +101,22 @@ class PollingWorker private constructor(contextArg: Context) {
|
|||
// インストールIDを生成する前に、各データの通知登録キャッシュをクリアする
|
||||
// トークンがまだ生成されていない場合、このメソッドは null を返します。
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun prepareInstallId(
|
||||
context: Context,
|
||||
job: JobItem? = null,
|
||||
): String? {
|
||||
suspend fun prepareInstallId(context: Context, job: JobItem? = null): String? {
|
||||
if (!PrivacyPolicyChecker(context).agreed) {
|
||||
log.w("prepareInstallId: PrivacyPolicy not agreed.")
|
||||
return null
|
||||
}
|
||||
|
||||
val prefDevice = PrefDevice.from(context)
|
||||
|
||||
var sv = prefDevice.getString(PrefDevice.KEY_INSTALL_ID, null)
|
||||
if (sv?.isNotEmpty() == true) return sv
|
||||
prefDevice.getString(PrefDevice.KEY_INSTALL_ID, null)
|
||||
?.notEmpty()?.let { return it }
|
||||
|
||||
SavedAccount.clearRegistrationCache()
|
||||
|
||||
try {
|
||||
return try {
|
||||
val device_token = getFirebaseMessagingToken(context)
|
||||
?: return null
|
||||
?: error("getFirebaseMessagingToken returns null")
|
||||
|
||||
val request = Request.Builder()
|
||||
.url("$APP_SERVER/counter")
|
||||
|
@ -124,28 +124,21 @@ class PollingWorker private constructor(contextArg: Context) {
|
|||
|
||||
val call = App1.ok_http_client.newCall(request)
|
||||
job?.currentCall = WeakReference(call)
|
||||
val response = call.await()
|
||||
call.await().use { response ->
|
||||
val body = response.body?.string()
|
||||
|
||||
val body = response.body?.string()
|
||||
if (!response.isSuccessful || body?.isEmpty() != false) {
|
||||
log.e(TootApiClient.formatResponse(response, "getInstallId: get/counter failed."))
|
||||
return null
|
||||
}
|
||||
|
||||
if (!response.isSuccessful || body?.isEmpty() != false) {
|
||||
log.e(
|
||||
TootApiClient.formatResponse(
|
||||
response,
|
||||
"getInstallId: get/counter failed."
|
||||
)
|
||||
)
|
||||
return null
|
||||
(device_token + UUID.randomUUID() + body).digestSHA256Base64Url()
|
||||
.also { prefDevice.edit().putString(PrefDevice.KEY_INSTALL_ID, it).apply() }
|
||||
}
|
||||
|
||||
sv = (device_token + UUID.randomUUID() + body).digestSHA256Base64Url()
|
||||
prefDevice.edit().putString(PrefDevice.KEY_INSTALL_ID, sv).apply()
|
||||
|
||||
return sv
|
||||
} catch (ex: Throwable) {
|
||||
log.trace(ex, "prepareInstallId failed.")
|
||||
null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.net.Uri
|
|||
import android.os.Handler
|
||||
import android.os.SystemClock
|
||||
import androidx.annotation.WorkerThread
|
||||
import jp.juggler.subwaytooter.ActPost
|
||||
import jp.juggler.subwaytooter.R
|
||||
import jp.juggler.subwaytooter.api.TootApiCallback
|
||||
import jp.juggler.subwaytooter.api.TootApiClient
|
||||
|
@ -477,7 +476,7 @@ class AttachmentUploader(
|
|||
val isJpeg = MIME_TYPE_JPEG == mimeType
|
||||
val isPng = MIME_TYPE_PNG == mimeType
|
||||
if (!isJpeg && !isPng) {
|
||||
ActPost.log.d("createOpener: source is not jpeg or png")
|
||||
log.d("createOpener: source is not jpeg or png")
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -525,7 +524,7 @@ class AttachmentUploader(
|
|||
}
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
ActPost.log.trace(ex)
|
||||
log.trace(ex)
|
||||
context.showToast(ex, "Resizing image failed.")
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import jp.juggler.util.*
|
|||
import java.util.*
|
||||
import kotlin.math.min
|
||||
|
||||
// 入力補完機能
|
||||
class CompletionHelper(
|
||||
private val activity: AppCompatActivity,
|
||||
private val pref: SharedPreferences,
|
||||
|
@ -36,38 +37,14 @@ class CompletionHelper(
|
|||
private val reCharsNotEmoji = "[^0-9A-Za-z_-]".asciiPattern()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 投稿機能はPostImplに移動した
|
||||
// var content: String? = null
|
||||
// var spoilerText: String? = null
|
||||
// var visibility: TootVisibility = TootVisibility.Public
|
||||
// var bNSFW = false
|
||||
// var inReplyToId: EntityId? = null
|
||||
// var attachmentList: ArrayList<PostAttachment>? = null
|
||||
// var enqueteItems: ArrayList<String>? = null
|
||||
// var pollType: TootPollsType? = null
|
||||
// var pollExpireSeconds = 0
|
||||
// var pollHideTotals = false
|
||||
// var pollMultipleChoice = false
|
||||
//
|
||||
// var emojiMapCustom: HashMap<String, CustomEmoji>? = null
|
||||
// var redraftStatusId: EntityId? = null
|
||||
// var useQuoteToot = false
|
||||
// var scheduledAt = 0L
|
||||
// var scheduledId: EntityId? = null
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 入力補完機能
|
||||
interface Callback2 {
|
||||
fun onTextUpdate()
|
||||
fun canOpenPopup(): Boolean
|
||||
}
|
||||
|
||||
private val pickerCaptionEmoji: String by lazy {
|
||||
activity.getString(R.string.open_picker_emoji)
|
||||
}
|
||||
// private val picker_caption_tag : String by lazy {
|
||||
// activity.getString(R.string.open_picker_tag)
|
||||
// }
|
||||
// private val picker_caption_mention : String by lazy {
|
||||
// activity.getString(R.string.open_picker_mention)
|
||||
// }
|
||||
|
||||
private var callback2: Callback2? = null
|
||||
private var et: MyEditText? = null
|
||||
|
@ -77,11 +54,9 @@ class CompletionHelper(
|
|||
|
||||
private var accessInfo: SavedAccount? = null
|
||||
|
||||
private val onEmojiListLoad: (list: ArrayList<CustomEmoji>) -> Unit =
|
||||
{
|
||||
val popup = this@CompletionHelper.popup
|
||||
if (popup?.isShowing == true) procTextChanged.run()
|
||||
}
|
||||
private val onEmojiListLoad: (list: ArrayList<CustomEmoji>) -> Unit = {
|
||||
if (popup?.isShowing == true) procTextChanged.run()
|
||||
}
|
||||
|
||||
private val procTextChanged = object : Runnable {
|
||||
|
||||
|
@ -320,24 +295,10 @@ class CompletionHelper(
|
|||
return popup
|
||||
}
|
||||
|
||||
interface Callback2 {
|
||||
|
||||
fun onTextUpdate()
|
||||
|
||||
fun canOpenPopup(): Boolean
|
||||
}
|
||||
|
||||
fun setInstance(accessInfo: SavedAccount?) {
|
||||
this.accessInfo = accessInfo
|
||||
|
||||
if (accessInfo != null) {
|
||||
App1.custom_emoji_lister.getList(accessInfo, onEmojiListLoad)
|
||||
}
|
||||
|
||||
val popup = this.popup
|
||||
if (popup?.isShowing == true) {
|
||||
procTextChanged.run()
|
||||
}
|
||||
accessInfo?.let { App1.custom_emoji_lister.getList(it, onEmojiListLoad) }
|
||||
if (popup?.isShowing == true) procTextChanged.run()
|
||||
}
|
||||
|
||||
fun closeAcctPopup() {
|
||||
|
@ -346,9 +307,7 @@ class CompletionHelper(
|
|||
}
|
||||
|
||||
fun onScrollChanged() {
|
||||
if (popup?.isShowing == true) {
|
||||
popup?.updatePosition()
|
||||
}
|
||||
popup?.takeIf { it.isShowing }?.updatePosition()
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
|
|
|
@ -30,7 +30,6 @@ import jp.juggler.util.clipRange
|
|||
class MyNetworkImageView : AppCompatImageView {
|
||||
|
||||
companion object {
|
||||
|
||||
internal val log = LogCategory("MyNetworkImageView")
|
||||
}
|
||||
|
||||
|
@ -264,7 +263,7 @@ class MyNetworkImageView : AppCompatImageView {
|
|||
}
|
||||
// その他のDrawable
|
||||
// たとえばInstanceTickerのアイコンにSVGが使われていたらPictureDrawableになる
|
||||
log.w("cornerRadius=$mCornerRadius,drawable=$resource,url=$urlLoading")
|
||||
// log.w("cornerRadius=$mCornerRadius,drawable=$resource,url=$urlLoading")
|
||||
}
|
||||
|
||||
setImageDrawable(resource)
|
||||
|
|
|
@ -10,7 +10,7 @@ object ToastUtils {
|
|||
private val log = LogCategory("ToastUtils")
|
||||
private var refToast: WeakReference<Toast>? = null
|
||||
|
||||
internal fun showToastImpl(context: Context, bLong: Boolean, message: String) {
|
||||
internal fun showToastImpl(context: Context, bLong: Boolean, message: String): Boolean {
|
||||
runOnMainLooper {
|
||||
|
||||
// 前回のトーストの表示を終了する
|
||||
|
@ -41,21 +41,18 @@ object ToastUtils {
|
|||
// at android.widget.Toast$TN.handleShow (Toast.java:435)
|
||||
// at android.widget.Toast$TN$2.handleMessage (Toast.java:345)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.showToast(bLong: Boolean, caption: String?) {
|
||||
fun Context.showToast(bLong: Boolean, caption: String?): Boolean =
|
||||
ToastUtils.showToastImpl(this, bLong, caption ?: "(null)")
|
||||
}
|
||||
|
||||
fun Context.showToast(ex: Throwable, caption: String) {
|
||||
fun Context.showToast(ex: Throwable, caption: String): Boolean =
|
||||
ToastUtils.showToastImpl(this, true, ex.withCaption(caption))
|
||||
}
|
||||
|
||||
fun Context.showToast(bLong: Boolean, stringId: Int, vararg args: Any) {
|
||||
fun Context.showToast(bLong: Boolean, stringId: Int, vararg args: Any): Boolean =
|
||||
ToastUtils.showToastImpl(this, bLong, getString(stringId, *args))
|
||||
}
|
||||
|
||||
fun Context.showToast(ex: Throwable, stringId: Int, vararg args: Any) {
|
||||
fun Context.showToast(ex: Throwable, stringId: Int, vararg args: Any): Boolean =
|
||||
ToastUtils.showToastImpl(this, true, ex.withCaption(resources, stringId, *args))
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCrossAccountActionsForStatus"
|
||||
android:id="@+id/btnGroupStatusCrossAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
|
@ -140,7 +140,7 @@
|
|||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llCrossAccountActionsForStatus"
|
||||
android:id="@+id/llGroupStatusCrossAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
|
@ -262,7 +262,7 @@
|
|||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnAroundThisToot"
|
||||
android:id="@+id/btnGroupStatusAround"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
|
@ -279,7 +279,7 @@
|
|||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llAroundThisToot"
|
||||
android:id="@+id/llGroupStatusAround"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
|
@ -332,7 +332,7 @@
|
|||
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnYourToot"
|
||||
android:id="@+id/btnGroupStatusByMe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
|
@ -349,7 +349,7 @@
|
|||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llYourToot"
|
||||
android:id="@+id/llGroupStatusByMe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
|
@ -420,7 +420,7 @@
|
|||
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnStatusExtraAction"
|
||||
android:id="@+id/btnGroupStatusExtra"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
|
@ -437,7 +437,7 @@
|
|||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llStatusExtraAction"
|
||||
android:id="@+id/llGroupStatusExtra"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
|
@ -810,7 +810,7 @@
|
|||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCrossAccountActionsForAccount"
|
||||
android:id="@+id/btnGroupUserCrossAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
|
@ -827,7 +827,7 @@
|
|||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llCrossAccountActionsForAccount"
|
||||
android:id="@+id/llGroupUserCrossAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
|
@ -880,7 +880,7 @@
|
|||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnAccountExtraAction"
|
||||
android:id="@+id/btnGroupUserExtra"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
|
@ -897,7 +897,7 @@
|
|||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llAccountExtraAction"
|
||||
android:id="@+id/llGroupUserExtra"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
|
@ -906,7 +906,7 @@
|
|||
tools:ignore="RtlSymmetry">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnPostNotification"
|
||||
android:id="@+id/btnStatusNotification"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent_round6dp"
|
||||
|
|
Loading…
Reference in New Issue