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