2021-05-27 04:15:59 +02:00
|
|
|
package jp.juggler.subwaytooter.action
|
|
|
|
|
|
|
|
import android.content.Intent
|
2021-06-01 00:07:16 +02:00
|
|
|
import android.os.Build
|
|
|
|
import android.util.DisplayMetrics
|
|
|
|
import androidx.core.app.ActivityOptionsCompat
|
2021-06-21 05:03:09 +02:00
|
|
|
import androidx.core.app.ShareCompat
|
2021-06-01 00:07:16 +02:00
|
|
|
import jp.juggler.subwaytooter.*
|
2021-06-28 09:09:00 +02:00
|
|
|
import jp.juggler.subwaytooter.actmain.currentPostTarget
|
|
|
|
import jp.juggler.subwaytooter.actmain.quickPostText
|
|
|
|
import jp.juggler.subwaytooter.actpost.updateText
|
2021-05-27 04:15:59 +02:00
|
|
|
import jp.juggler.subwaytooter.api.entity.TootAccount
|
|
|
|
import jp.juggler.subwaytooter.api.entity.TootScheduled
|
|
|
|
import jp.juggler.subwaytooter.api.entity.TootStatus
|
|
|
|
import jp.juggler.subwaytooter.api.runApiTask
|
|
|
|
import jp.juggler.subwaytooter.api.syncStatus
|
|
|
|
import jp.juggler.subwaytooter.dialog.pickAccount
|
2021-11-06 04:00:29 +01:00
|
|
|
import jp.juggler.subwaytooter.pref.PrefB
|
|
|
|
import jp.juggler.subwaytooter.pref.PrefS
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.subwaytooter.pref.prefDevice
|
2021-05-27 04:15:59 +02:00
|
|
|
import jp.juggler.subwaytooter.table.SavedAccount
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.subwaytooter.table.accountListCanQuote
|
|
|
|
import jp.juggler.subwaytooter.table.accountListNonPseudo
|
2021-05-27 04:15:59 +02:00
|
|
|
import jp.juggler.subwaytooter.util.matchHost
|
2023-02-04 21:52:26 +01:00
|
|
|
import jp.juggler.util.coroutine.launchAndShowError
|
2023-01-13 13:22:25 +01:00
|
|
|
import jp.juggler.util.coroutine.launchMain
|
|
|
|
import jp.juggler.util.log.LogCategory
|
|
|
|
import jp.juggler.util.log.showToast
|
|
|
|
import jp.juggler.util.ui.isLiveActivity
|
2021-06-21 05:03:09 +02:00
|
|
|
import java.util.*
|
2021-05-27 04:15:59 +02:00
|
|
|
|
2021-06-01 00:07:16 +02:00
|
|
|
private val log = LogCategory("Action_OpenPost")
|
|
|
|
|
|
|
|
fun ActPost.saveWindowSize() {
|
|
|
|
|
|
|
|
// 最大化状態で起動することはできないので、最大化状態のサイズは覚えない
|
|
|
|
if (!isInMultiWindowMode) return
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 30) {
|
|
|
|
// WindowMetrics#getBounds() the window size including all system bar areas
|
|
|
|
windowManager?.currentWindowMetrics?.bounds?.let { bounds ->
|
2021-06-27 12:05:04 +02:00
|
|
|
log.d("API=${Build.VERSION.SDK_INT}, WindowMetrics#getBounds() $bounds")
|
2023-02-04 21:52:26 +01:00
|
|
|
prefDevice.savePostWindowBound(bounds.width(), bounds.height())
|
2021-06-01 00:07:16 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
@Suppress("DEPRECATION")
|
|
|
|
windowManager.defaultDisplay?.let { display ->
|
|
|
|
val dm = DisplayMetrics()
|
|
|
|
display.getMetrics(dm)
|
2021-06-27 12:05:04 +02:00
|
|
|
log.d("API=${Build.VERSION.SDK_INT}, displayMetrics=${dm.widthPixels},${dm.heightPixels}")
|
2023-02-04 21:52:26 +01:00
|
|
|
prefDevice.savePostWindowBound(dm.widthPixels, dm.heightPixels)
|
2021-06-01 00:07:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
fun ActMain.openActPostImpl(
|
2021-06-20 15:12:25 +02:00
|
|
|
accountDbId: Long,
|
2021-05-27 04:15:59 +02:00
|
|
|
|
|
|
|
// 再編集する投稿。アカウントと同一のタンスであること
|
2021-06-20 15:12:25 +02:00
|
|
|
redraftStatus: TootStatus? = null,
|
2021-05-27 04:15:59 +02:00
|
|
|
|
2022-03-15 12:39:37 +01:00
|
|
|
// 編集する投稿。アカウントと同一のタンスであること
|
|
|
|
editStatus: TootStatus? = null,
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
// 返信対象の投稿。同一タンス上に同期済みであること
|
2021-06-20 15:12:25 +02:00
|
|
|
replyStatus: TootStatus? = null,
|
2021-05-27 04:15:59 +02:00
|
|
|
|
|
|
|
//初期テキスト
|
2021-06-20 15:12:25 +02:00
|
|
|
initialText: String? = null,
|
2021-05-27 04:15:59 +02:00
|
|
|
|
|
|
|
// 外部アプリから共有されたインテント
|
2021-06-20 15:12:25 +02:00
|
|
|
sharedIntent: Intent? = null,
|
2021-05-27 04:15:59 +02:00
|
|
|
|
|
|
|
// 返信ではなく引用トゥートを作成する
|
|
|
|
quote: Boolean = false,
|
|
|
|
|
|
|
|
//(Mastodon) 予約投稿の編集
|
2021-06-20 15:12:25 +02:00
|
|
|
scheduledStatus: TootScheduled? = null,
|
2021-05-30 04:01:12 +02:00
|
|
|
) {
|
|
|
|
|
2023-02-04 21:52:26 +01:00
|
|
|
val useManyWindow = PrefB.bpManyWindowPost.value
|
|
|
|
val useMultiWindow = useManyWindow || PrefB.bpMultiWindowPost.value
|
2021-05-30 04:01:12 +02:00
|
|
|
|
|
|
|
val intent = ActPost.createIntent(
|
2021-06-27 20:25:21 +02:00
|
|
|
context = this,
|
2021-06-20 15:12:25 +02:00
|
|
|
accountDbId = accountDbId,
|
|
|
|
redraftStatus = redraftStatus,
|
2022-03-15 12:39:37 +01:00
|
|
|
editStatus = editStatus,
|
2021-06-20 15:12:25 +02:00
|
|
|
replyStatus = replyStatus,
|
|
|
|
initialText = initialText,
|
|
|
|
sharedIntent = sharedIntent,
|
2021-05-27 04:15:59 +02:00
|
|
|
quote = quote,
|
|
|
|
scheduledStatus = scheduledStatus,
|
2021-05-30 04:01:12 +02:00
|
|
|
multiWindowMode = useMultiWindow
|
2021-05-27 04:15:59 +02:00
|
|
|
)
|
2021-05-30 04:01:12 +02:00
|
|
|
|
|
|
|
if (!useMultiWindow) {
|
|
|
|
arActPost.launch(intent)
|
|
|
|
} else {
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
if (!useManyWindow) {
|
2021-05-30 04:01:12 +02:00
|
|
|
ActPost.refActPost?.get()
|
|
|
|
?.takeIf { it.isLiveActivity }
|
|
|
|
?.let {
|
2023-02-04 21:52:26 +01:00
|
|
|
launchAndShowError {
|
|
|
|
it.updateText(intent)
|
|
|
|
}
|
2021-05-30 04:01:12 +02:00
|
|
|
return
|
|
|
|
}
|
2021-06-20 15:12:25 +02:00
|
|
|
}
|
2021-05-30 04:01:12 +02:00
|
|
|
// fall thru
|
2021-06-01 00:07:16 +02:00
|
|
|
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
|
|
|
|
|
|
|
|
var options = ActivityOptionsCompat.makeBasic()
|
2023-02-04 21:52:26 +01:00
|
|
|
prefDevice.loadPostWindowBound()?.let {
|
|
|
|
log.d("ActPost launchBounds $it")
|
|
|
|
options = options.setLaunchBounds(it)
|
|
|
|
}
|
2021-06-01 00:07:16 +02:00
|
|
|
|
|
|
|
arActPost.launch(intent, options)
|
2021-05-30 04:01:12 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-27 04:15:59 +02:00
|
|
|
|
|
|
|
// 投稿画面を開く。初期テキストを指定する
|
|
|
|
fun ActMain.openPost(
|
2021-06-28 09:09:00 +02:00
|
|
|
initialText: String? = quickPostText,
|
2021-05-27 04:15:59 +02:00
|
|
|
) {
|
2021-06-21 05:03:09 +02:00
|
|
|
initialText ?: return
|
|
|
|
|
2021-05-27 04:15:59 +02:00
|
|
|
launchMain {
|
2021-06-21 05:03:09 +02:00
|
|
|
completionHelper.closeAcctPopup()
|
2021-05-27 04:15:59 +02:00
|
|
|
|
|
|
|
val account = currentPostTarget
|
|
|
|
?.takeIf { it.db_id != -1L && !it.isPseudo }
|
|
|
|
?: pickAccount(
|
|
|
|
bAllowPseudo = false,
|
|
|
|
bAuto = true,
|
|
|
|
message = getString(R.string.account_picker_toot)
|
|
|
|
)
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
account?.db_id?.let { openActPostImpl(it, initialText = initialText) }
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// メンションを含むトゥートを作る
|
|
|
|
private fun ActMain.mention(
|
|
|
|
account: SavedAccount,
|
2021-06-20 15:12:25 +02:00
|
|
|
initialText: String,
|
|
|
|
) = openActPostImpl(account.db_id, initialText = initialText)
|
2021-05-27 04:15:59 +02:00
|
|
|
|
|
|
|
// メンションを含むトゥートを作る
|
|
|
|
fun ActMain.mention(
|
|
|
|
account: SavedAccount,
|
2021-06-20 15:12:25 +02:00
|
|
|
who: TootAccount,
|
2021-05-27 04:15:59 +02:00
|
|
|
) = mention(account, "@${account.getFullAcct(who).ascii} ")
|
|
|
|
|
|
|
|
// メンションを含むトゥートを作る
|
|
|
|
fun ActMain.mentionFromAnotherAccount(
|
2021-06-20 15:12:25 +02:00
|
|
|
accessInfo: SavedAccount,
|
|
|
|
who: TootAccount?,
|
2021-06-01 00:07:16 +02:00
|
|
|
) {
|
2021-05-27 04:15:59 +02:00
|
|
|
launchMain {
|
|
|
|
who ?: return@launchMain
|
|
|
|
|
2021-06-20 15:12:25 +02:00
|
|
|
val initialText = "@${accessInfo.getFullAcct(who).ascii} "
|
2021-05-27 04:15:59 +02:00
|
|
|
pickAccount(
|
|
|
|
bAllowPseudo = false,
|
|
|
|
bAuto = false,
|
|
|
|
message = getString(R.string.account_picker_toot),
|
2021-06-01 00:07:16 +02:00
|
|
|
accountListArg = accountListNonPseudo(who.apDomain)
|
2021-06-20 15:12:25 +02:00
|
|
|
)?.let { mention(it, initialText) }
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun ActMain.reply(
|
2021-06-20 15:12:25 +02:00
|
|
|
accessInfo: SavedAccount,
|
2021-05-27 04:15:59 +02:00
|
|
|
status: TootStatus,
|
2021-06-20 15:12:25 +02:00
|
|
|
quote: Boolean = false,
|
2021-05-27 04:15:59 +02:00
|
|
|
) = openActPostImpl(
|
2021-06-20 15:12:25 +02:00
|
|
|
accessInfo.db_id,
|
|
|
|
replyStatus = status,
|
2021-05-27 04:15:59 +02:00
|
|
|
quote = quote
|
|
|
|
)
|
|
|
|
|
|
|
|
private fun ActMain.replyRemote(
|
2021-06-20 15:12:25 +02:00
|
|
|
accessInfo: SavedAccount,
|
|
|
|
remoteStatusUrl: String?,
|
|
|
|
quote: Boolean = false,
|
2021-05-27 04:15:59 +02:00
|
|
|
) {
|
2021-06-20 15:12:25 +02:00
|
|
|
if (remoteStatusUrl.isNullOrEmpty()) return
|
2021-05-27 04:15:59 +02:00
|
|
|
launchMain {
|
2021-06-20 15:12:25 +02:00
|
|
|
var localStatus: TootStatus? = null
|
2021-05-27 04:15:59 +02:00
|
|
|
runApiTask(
|
2021-06-20 15:12:25 +02:00
|
|
|
accessInfo,
|
2021-05-27 04:15:59 +02:00
|
|
|
progressPrefix = getString(R.string.progress_synchronize_toot)
|
|
|
|
) { client ->
|
2021-06-20 15:12:25 +02:00
|
|
|
val (result, status) = client.syncStatus(accessInfo, remoteStatusUrl)
|
|
|
|
localStatus = status
|
2021-05-27 04:15:59 +02:00
|
|
|
result
|
|
|
|
}?.let { result ->
|
2021-06-20 15:12:25 +02:00
|
|
|
when (val ls = localStatus) {
|
2021-05-27 04:15:59 +02:00
|
|
|
null -> showToast(true, result.error)
|
2021-06-20 15:12:25 +02:00
|
|
|
else -> reply(accessInfo, ls, quote = quote)
|
2021-05-27 04:15:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun ActMain.replyFromAnotherAccount(
|
2021-06-20 15:12:25 +02:00
|
|
|
timelineAccount: SavedAccount,
|
|
|
|
status: TootStatus?,
|
2021-05-27 04:15:59 +02:00
|
|
|
) {
|
|
|
|
status ?: return
|
|
|
|
launchMain {
|
|
|
|
pickAccount(
|
|
|
|
bAllowPseudo = false,
|
|
|
|
bAuto = false,
|
|
|
|
message = getString(R.string.account_picker_reply),
|
2021-06-20 15:12:25 +02:00
|
|
|
accountListArg = accountListNonPseudo(timelineAccount.apDomain),
|
2021-05-27 04:15:59 +02:00
|
|
|
)?.let { ai ->
|
|
|
|
if (ai.matchHost(status.readerApDomain)) {
|
|
|
|
// アクセス元ホストが同じならステータスIDを使って返信できる
|
|
|
|
reply(ai, status, quote = false)
|
|
|
|
} else {
|
|
|
|
// それ以外の場合、ステータスのURLを検索APIに投げることで返信できる
|
|
|
|
replyRemote(ai, status.url, quote = false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun ActMain.quoteFromAnotherAccount(
|
2021-06-20 15:12:25 +02:00
|
|
|
timelineAccount: SavedAccount,
|
2021-05-27 04:15:59 +02:00
|
|
|
status: TootStatus?,
|
|
|
|
) {
|
|
|
|
status ?: return
|
|
|
|
launchMain {
|
|
|
|
pickAccount(
|
|
|
|
bAllowPseudo = false,
|
|
|
|
bAllowMisskey = true,
|
|
|
|
bAllowMastodon = true,
|
|
|
|
bAuto = true,
|
|
|
|
message = getString(R.string.account_picker_quote_toot),
|
2021-06-20 15:12:25 +02:00
|
|
|
accountListArg = accountListCanQuote(timelineAccount.apDomain)
|
2021-05-27 04:15:59 +02:00
|
|
|
)?.let { ai ->
|
|
|
|
if (ai.matchHost(status.readerApDomain)) {
|
|
|
|
// アクセス元ホストが同じならステータスIDを使って返信できる
|
|
|
|
reply(ai, status, quote = true)
|
|
|
|
} else {
|
|
|
|
// それ以外の場合、ステータスのURLを検索APIに投げることで返信できる
|
|
|
|
replyRemote(ai, status.url, quote = true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-21 05:03:09 +02:00
|
|
|
|
|
|
|
fun ActMain.quoteName(who: TootAccount) {
|
|
|
|
var sv = who.display_name
|
|
|
|
try {
|
2023-02-04 21:52:26 +01:00
|
|
|
val fmt = PrefS.spQuoteNameFormat.value
|
2021-06-21 05:03:09 +02:00
|
|
|
if (fmt.contains("%1\$s")) {
|
|
|
|
sv = String.format(Locale.getDefault(), fmt, sv)
|
|
|
|
}
|
|
|
|
} catch (ex: Throwable) {
|
2022-12-27 03:54:52 +01:00
|
|
|
log.e(ex, "quoteName failed.")
|
2021-06-21 05:03:09 +02:00
|
|
|
}
|
|
|
|
openPost(sv)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun ActMain.shareText(text: String?) {
|
|
|
|
text ?: return
|
|
|
|
ShareCompat.IntentBuilder(this)
|
|
|
|
.setText(text)
|
|
|
|
.setType("text/plain")
|
|
|
|
.startChooser()
|
|
|
|
}
|
2021-06-22 10:31:51 +02:00
|
|
|
|
|
|
|
fun ActMain.clickReply(accessInfo: SavedAccount, status: TootStatus) {
|
2021-06-27 12:05:04 +02:00
|
|
|
when {
|
|
|
|
accessInfo.isPseudo -> replyFromAnotherAccount(accessInfo, status)
|
|
|
|
else -> reply(accessInfo, status)
|
2021-06-22 10:31:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun ActMain.clickQuote(accessInfo: SavedAccount, status: TootStatus) {
|
2021-06-27 12:05:04 +02:00
|
|
|
when {
|
|
|
|
accessInfo.isPseudo -> quoteFromAnotherAccount(accessInfo, status)
|
|
|
|
else -> reply(accessInfo, status, quote = true)
|
2021-06-22 10:31:51 +02:00
|
|
|
}
|
|
|
|
}
|