SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/action/Action_ListMember.kt

212 lines
8.1 KiB
Kotlin

package jp.juggler.subwaytooter.action
import android.app.AlertDialog
import jp.juggler.subwaytooter.ActMain
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.*
import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.dialog.DlgConfirm
import jp.juggler.subwaytooter.onListMemberUpdated
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.util.*
import okhttp3.Request
import java.util.regex.Pattern
private val reFollowError422 = "follow".asciiPattern(Pattern.CASE_INSENSITIVE)
private val reFollowError404 = "Record not found".asciiPattern(Pattern.CASE_INSENSITIVE)
fun ActMain.listMemberAdd(
accessInfo: SavedAccount,
listId: EntityId,
localWho: TootAccount,
bFollow: Boolean = false,
onListMemberUpdated: (willRegistered: Boolean, bSuccess: Boolean) -> Unit = { _, _ -> },
) {
launchMain {
runApiTask(accessInfo) { client ->
val parser = TootParser(this, accessInfo)
var userId = localWho.id
if (accessInfo.isMisskey) {
// misskeyのリストはフォロー無関係
client.request(
"/api/users/lists/push",
accessInfo.putMisskeyApiToken().apply {
put("listId", listId)
put("userId", localWho.id)
}.toPostRequestBuilder()
)
// 204 no content
} else {
val isMe = accessInfo.isMe(localWho)
if (isMe) {
val (ti, ri) = TootInstance.get(client)
ti ?: return@runApiTask ri
if (!ti.versionGE(TootInstance.VERSION_3_1_0_rc1)) {
return@runApiTask TootApiResult(getString(R.string.it_is_you))
}
} else if (bFollow) {
// リモートユーザの解決
if (!accessInfo.isLocalUser(localWho)) {
val (r2, ar) = client.syncAccountByAcct(accessInfo, localWho.acct)
val user = ar?.get() ?: return@runApiTask r2
userId = user.id
}
val result = client.request(
"/api/v1/accounts/$userId/follow",
"".toFormRequestBody().toPost()
) ?: return@runApiTask null
val relation = accessInfo.saveUserRelation(
parseItem(::TootRelationShip, parser, result.jsonObject)
) ?: return@runApiTask TootApiResult("parse error.")
if (!relation.following) {
@Suppress("ControlFlowWithEmptyBody")
if (relation.requested) {
return@runApiTask TootApiResult(getString(R.string.cant_add_list_follow_requesting))
} else {
// リモートフォローの場合、正常ケースでもここを通る場合がある
// 何もしてはいけない…
}
}
}
// リストメンバー追加
client.request(
"/api/v1/lists/$listId/accounts",
jsonObject {
put(
"account_ids",
jsonArray {
add(userId.toString())
}
)
}
.toPostRequestBuilder()
)
}
}.let { result -> // may null
var bSuccess = false
try {
val response = result?.response
val error = result?.error
fun isNotFollowed(): Boolean {
response ?: return false
error ?: return false
return when {
response.code == 422 && reFollowError422.matcher(error).find() -> true
response.code == 404 && reFollowError404.matcher(error).find() -> true
else -> false
}
}
when {
// cancelled.
result == null -> {
}
result.jsonObject != null -> {
for (column in appState.columnList) {
// リストメンバー追加イベントをカラムに伝達
column.onListMemberUpdated(accessInfo, listId, localWho, true)
}
// フォロー状態の更新を表示に反映させる
if (bFollow) showColumnMatchAccount(accessInfo)
showToast(false, R.string.list_member_added)
bSuccess = true
}
isNotFollowed() -> {
if (!bFollow) {
DlgConfirm.openSimple(
this@listMemberAdd,
getString(
R.string.list_retry_with_follow,
accessInfo.getFullAcct(localWho)
)
) {
listMemberAdd(
accessInfo,
listId,
localWho,
bFollow = true,
onListMemberUpdated = onListMemberUpdated
)
}
} else {
AlertDialog.Builder(this@listMemberAdd)
.setCancelable(true)
.setMessage(R.string.cant_add_list_follow_requesting)
.setNeutralButton(R.string.close, null)
.show()
}
}
else -> showToast(true, error)
}
} finally {
onListMemberUpdated(true, bSuccess)
}
}
}
}
fun ActMain.listMemberDelete(
accessInfo: SavedAccount,
listId: EntityId,
localWho: TootAccount,
onListMemberDeleted: (willRegistered: Boolean, bSuccess: Boolean) -> Unit = { _, _ -> },
) {
launchMain {
runApiTask(accessInfo) { client ->
if (accessInfo.isMisskey) {
client.request(
"/api/users/lists/pull",
accessInfo.putMisskeyApiToken().apply {
put("listId", listId.toString())
put("userId", localWho.id.toString())
}
.toPostRequestBuilder()
)
} else {
client.request(
"/api/v1/lists/$listId/accounts?account_ids[]=${localWho.id}",
Request.Builder().delete()
)
}
}.let { result -> //may null
var bSuccess = false
try {
when {
result == null -> {
// cancelled.
}
result.jsonObject == null ->
showToast(false, result.error)
else -> {
for (column in appState.columnList) {
column.onListMemberUpdated(accessInfo, listId, localWho, false)
}
showToast(false, R.string.delete_succeeded)
bSuccess = true
}
}
} finally {
onListMemberDeleted(false, bSuccess)
}
}
}
}