SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/api/entity/TootNotification.kt

231 lines
8.5 KiB
Kotlin

package jp.juggler.subwaytooter.api.entity
import android.content.Context
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.TootParser
import jp.juggler.subwaytooter.api.entity.TootAccountRef.Companion.tootAccountRefOrNull
import jp.juggler.subwaytooter.pref.PrefB
import jp.juggler.util.data.JsonObject
import jp.juggler.util.data.notEmpty
import jp.juggler.util.log.LogCategory
class TootNotification(
val json: JsonObject,
val id: EntityId,
// One of: "mention", "reblog", "favourite", "follow"
val type: String,
// The Account sending the notification to the user
val accountRef: TootAccountRef?,
// The Status associated with the notification, if applicable
// 投稿の更新により変更可能になる
var status: TootStatus?,
var reaction: TootReaction? = null,
val reblog_visibility: TootVisibility,
// The time the notification was created
private val created_at: String?,
val time_created_at: Long,
) : TimelineItem() {
val account: TootAccount?
get() = accountRef?.get()
companion object {
@Suppress("unused")
private val log = LogCategory("TootNotification")
// 言及と返信
const val TYPE_MENTION = "mention" // Mastodon,Misskey
const val TYPE_REPLY = "reply" // Misskey (メンションとReplyは別の物らしい
// ブーストとリノート
const val TYPE_REBLOG = "reblog" // Mastodon
const val TYPE_RENOTE = "renote" // Misskey
const val TYPE_QUOTE = "quote" // Misskeyの引用Renote, fedibirdのquote
// フォロー
const val TYPE_FOLLOW = "follow" // Mastodon,Misskey
const val TYPE_UNFOLLOW = "unfollow" // Mastodon,Misskey
const val TYPE_FAVOURITE = "favourite"
const val TYPE_REACTION = "reaction" // misskey
const val TYPE_EMOJI_REACTION_PLEROMA = "pleroma:emoji_reaction" // pleroma
const val TYPE_FOLLOW_REQUEST = "follow_request"
const val TYPE_FOLLOW_REQUEST_MISSKEY = "receiveFollowRequest"
const val TYPE_FOLLOW_REQUEST_ACCEPTED_MISSKEY = "followRequestAccepted"
const val TYPE_POLL_VOTE_MISSKEY = "pollVote"
// 投票
const val TYPE_VOTE = "poll_vote"
// (Mastodon 2.8)投票完了
const val TYPE_POLL = "poll"
const val TYPE_STATUS = "status"
// (Mastodon 3.5.0rc1)
const val TYPE_UPDATE = "update"
const val TYPE_ADMIN_SIGNUP = "admin.sign_up"
// (Mastodon 4.0)
const val TYPE_ADMIN_REPORT = "admin.report"
// (Fedibird)
// https://github.com/fedibird/mastodon/blob/fedibird/app/controllers/api/v1/push/subscriptions_controller.rb#L55
// https://github.com/fedibird/mastodon/blob/fedibird/app/models/notification.rb
const val TYPE_EMOJI_REACTION = "emoji_reaction"
const val TYPE_STATUS_REFERENCE = "status_reference"
const val TYPE_SCHEDULED_STATUS = "scheduled_status"
private fun tootNotificationMisskey(parser: TootParser, src: JsonObject): TootNotification {
// Misskeyの通知APIはページネーションをIDでしか行えない
// これは改善される予定 https://github.com/syuilo/misskey/issues/2275
val created_at: String? = src.string("createdAt")
val accountRef = tootAccountRefOrNull(
parser,
parser.account(src.jsonObject("user"))
)
val reaction: TootReaction? = src.string("reaction")
?.notEmpty()
?.let { TootReaction.parseMisskey(it) }
return TootNotification(
json = src,
id = EntityId.mayDefault(src.string("id")),
type = src.stringOrThrow("type"),
accountRef = accountRef,
status = parser.status(src.jsonObject("note")),
reaction = reaction,
reblog_visibility = TootVisibility.Unknown,
created_at = created_at,
time_created_at = TootStatus.parseTime(created_at),
)
}
private fun tootNotificationMastodon(
parser: TootParser,
src: JsonObject,
): TootNotification {
val created_at: String? = src.string("created_at")
val accountRef: TootAccountRef? =
tootAccountRefOrNull(parser, parser.account(src.jsonObject("account")))
val status: TootStatus? = parser.status(src.jsonObject("status"))
val reaction: TootReaction? = src.jsonObject("emoji_reaction")
?.notEmpty()
?.let { TootReaction.parseFedibird(it) }
?: src.string("emoji")?.let { TootReaction(name = it) } // pleroma unicode emoji
// fedibird
// https://github.com/fedibird/mastodon/blob/7974fd3c7ec11ea9f7bef4ad7f4009fff53f62af/app/serializers/rest/notification_serializer.rb#L9
val visibilityString = when {
src.boolean("limited") == true -> "limited"
else -> src.string("reblog_visibility")
}
val reblog_visibility = TootVisibility.parseMastodon(visibilityString)
?: TootVisibility.Unknown
return TootNotification(
json = src,
id = EntityId.mayDefault(src.string("id")),
type = src.stringOrThrow("type"),
accountRef = accountRef,
status = status,
reaction = reaction,
reblog_visibility = reblog_visibility,
created_at = created_at,
time_created_at = TootStatus.parseTime(created_at),
)
}
fun tootNotification(parser: TootParser, src: JsonObject): TootNotification =
when (parser.serviceType) {
ServiceType.MISSKEY -> tootNotificationMisskey(parser, src)
else -> tootNotificationMastodon(parser, src)
}
}
override fun getOrderId() = id
fun getNotificationLine(context: Context): String {
val name = when (PrefB.bpShowAcctInSystemNotification.value) {
true -> accountRef?.get()?.acct?.pretty?.notEmpty()?.let { "@$it" }
else -> accountRef?.decoded_display_name
} ?: "?"
return when (type) {
TYPE_MENTION,
TYPE_REPLY,
-> context.getString(R.string.display_name_replied_by, name)
TYPE_RENOTE,
TYPE_REBLOG,
-> context.getString(R.string.display_name_boosted_by, name)
TYPE_QUOTE,
-> context.getString(R.string.display_name_quoted_by, name)
TYPE_STATUS,
-> context.getString(R.string.display_name_posted_by, name)
TYPE_UPDATE,
-> context.getString(R.string.display_name_updates_post, name)
TYPE_STATUS_REFERENCE,
-> context.getString(R.string.display_name_references_post, name)
TYPE_FOLLOW,
-> context.getString(R.string.display_name_followed_by, name)
TYPE_UNFOLLOW,
-> context.getString(R.string.display_name_unfollowed_by, name)
TYPE_ADMIN_SIGNUP,
-> context.getString(R.string.display_name_signed_up, name)
TYPE_ADMIN_REPORT,
-> context.getString(R.string.display_name_report, name)
TYPE_FAVOURITE,
-> context.getString(R.string.display_name_favourited_by, name)
TYPE_EMOJI_REACTION_PLEROMA,
TYPE_EMOJI_REACTION,
TYPE_REACTION,
-> arrayOf(
context.getString(R.string.display_name_reaction_by, name),
reaction?.name
).mapNotNull { it.notEmpty() }.joinToString(" ")
TYPE_VOTE,
TYPE_POLL_VOTE_MISSKEY,
-> context.getString(R.string.display_name_voted_by, name)
TYPE_FOLLOW_REQUEST,
TYPE_FOLLOW_REQUEST_MISSKEY,
-> context.getString(R.string.display_name_follow_request_by, name)
TYPE_FOLLOW_REQUEST_ACCEPTED_MISSKEY,
-> context.getString(R.string.display_name_follow_request_accepted_by, name)
TYPE_POLL,
-> context.getString(R.string.end_of_polling_from, name)
else -> context.getString(R.string.unknown_notification_from, name) + " :" + type
}
}
}