(Mastodon)add notification type for post from specified followings. アカウント設定でプッシュ購読の更新を手動で行った時は以前の状況に関係なく購読を更新する。

This commit is contained in:
tateisu 2020-09-20 11:51:15 +09:00
parent 5849ae8527
commit 8d47c7d283
21 changed files with 260 additions and 53 deletions

View File

@ -108,6 +108,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
private lateinit var cbNotificationFollowRequest : CheckBox
private lateinit var cbNotificationReaction : CheckBox
private lateinit var cbNotificationVote : CheckBox
private lateinit var cbNotificationPost : CheckBox
private lateinit var cbConfirmFollow : CheckBox
private lateinit var cbConfirmFollowLockedUser : CheckBox
@ -284,6 +285,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
cbNotificationReaction = findViewById(R.id.cbNotificationReaction)
cbNotificationVote = findViewById(R.id.cbNotificationVote)
cbNotificationPost = findViewById(R.id.cbNotificationPost)
cbConfirmFollow = findViewById(R.id.cbConfirmFollow)
cbConfirmFollowLockedUser = findViewById(R.id.cbConfirmFollowLockedUser)
@ -350,8 +352,11 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
cbNotificationFollowRequest.setOnCheckedChangeListener(this)
cbNotificationReaction.setOnCheckedChangeListener(this)
cbNotificationVote.setOnCheckedChangeListener(this)
cbNotificationPost.setOnCheckedChangeListener(this)
cbLocked.setOnCheckedChangeListener(this)
cbConfirmFollow.setOnCheckedChangeListener(this)
cbConfirmFollowLockedUser.setOnCheckedChangeListener(this)
cbConfirmUnfollow.setOnCheckedChangeListener(this)
@ -463,6 +468,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
cbNotificationFollowRequest.isChecked = a.notification_follow_request
cbNotificationReaction.isChecked = a.notification_reaction
cbNotificationVote.isChecked = a.notification_vote
cbNotificationPost.isChecked = a.notification_post
cbConfirmFollow.isChecked = a.confirm_follow
cbConfirmFollowLockedUser.isChecked = a.confirm_follow_locked
@ -500,6 +506,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
cbNotificationFollowRequest.isEnabled = enabled
cbNotificationReaction.isEnabled = enabled
cbNotificationVote.isEnabled = enabled
cbNotificationPost.isEnabled = enabled
cbConfirmFollow.isEnabled = enabled
cbConfirmFollowLockedUser.isEnabled = enabled
@ -542,6 +549,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
account.notification_follow_request = cbNotificationFollowRequest.isChecked
account.notification_reaction = cbNotificationReaction.isChecked
account.notification_vote = cbNotificationVote.isChecked
account.notification_post = cbNotificationPost.isChecked
account.sound_uri = notification_sound_uri ?: ""
@ -1574,7 +1582,7 @@ class ActAccountSetting : AsyncActivity(), View.OnClickListener,
)
override fun background(client : TootApiClient) : TootApiResult? {
return wps.updateSubscription(client)
return wps.updateSubscription(client,true)
}
override fun handleResult(result : TootApiResult?) {

View File

@ -135,8 +135,10 @@ class App1 : Application() {
// 2020/6/8 46 => 54 別ブランチで色々してた。このブランチには影響ないが onDowngrade()を実装してないので上げてしまう
// 2020/7/19 54=>55 UserRelation テーブルに項目追加。
// 2020/9/7 55=>56 SavedAccountテーブルにCOL_DOMAINを追加。
// 2020/9/20 56=>57 SavedAccountテーブルに項目追加
// 2020/9/20 57=>58 UserRelationテーブルに項目追加
internal const val DB_VERSION = 56
internal const val DB_VERSION = 58
private val tableList = arrayOf(
LogData,

View File

@ -772,6 +772,7 @@ val appSettingRoot = AppSettingItem(null, SettingType.Section, R.string.app_sett
Pref.ipConversationMainTootBgColor,
R.string.conversation_main_toot_background_color
)
colorAlpha(Pref.ipEventBgColorStatus, R.string.status)
}
group(R.string.button_accent_color) {

View File

@ -203,6 +203,7 @@ class Column(
internal const val QUICK_FILTER_FOLLOW = 4
internal const val QUICK_FILTER_REACTION = 5
internal const val QUICK_FILTER_VOTE = 6
internal const val QUICK_FILTER_POST = 7
internal const val HASHTAG_ELLIPSIZE = 26
@ -1059,6 +1060,7 @@ class Column(
QUICK_FILTER_FOLLOW -> sb.append(context.getString(R.string.notification_type_follow))
QUICK_FILTER_REACTION -> sb.append(context.getString(R.string.notification_type_reaction))
QUICK_FILTER_VOTE -> sb.append(context.getString(R.string.notification_type_vote))
QUICK_FILTER_POST -> sb.append(context.getString(R.string.notification_type_post))
}
sb.append(")")
@ -1619,6 +1621,8 @@ class Column(
TootNotification.TYPE_VOTE,
TootNotification.TYPE_POLL,
TootNotification.TYPE_POLL_VOTE_MISSKEY -> dont_show_vote
TootNotification.TYPE_STATUS -> dont_show_normal_toot
else -> false
}
@ -1641,6 +1645,8 @@ class Column(
TootNotification.TYPE_VOTE,
TootNotification.TYPE_POLL,
TootNotification.TYPE_POLL_VOTE_MISSKEY -> quick_filter != QUICK_FILTER_VOTE
TootNotification.TYPE_STATUS -> quick_filter != QUICK_FILTER_POST
else -> true
}
}) {
@ -2347,6 +2353,7 @@ class Column(
fun canFilterNormalToot() : Boolean {
return when(type) {
ColumnType.NOTIFICATIONS -> true
ColumnType.HOME, ColumnType.MISSKEY_HYBRID,
ColumnType.LIST_TL, ColumnType.MISSKEY_ANTENNA_TL -> true
ColumnType.LOCAL, ColumnType.FEDERATE, ColumnType.HASHTAG, ColumnType.SEARCH -> isMisskey

View File

@ -208,6 +208,9 @@ internal fun JsonObject.addMisskeyNotificationFilter(column : Column) : JsonObje
if(column.dont_show_vote) {
add("poll_vote")
}
if( column.dont_show_normal_toot){
// FIXME Misskeyには特定フォロー者からの投稿を通知する機能があるのか
}
}
if(excludeList.isNotEmpty()) put("excludeTypes", excludeList)
@ -228,6 +231,9 @@ internal fun JsonObject.addMisskeyNotificationFilter(column : Column) : JsonObje
)
Column.QUICK_FILTER_REACTION -> put("includeTypes", jp.juggler.util.jsonArray("reaction"))
Column.QUICK_FILTER_VOTE -> put("includeTypes", jp.juggler.util.jsonArray("poll_vote"))
Column.QUICK_FILTER_POST ->{
// FIXME Misskeyには特定フォロー者からの投稿を通知する機能があるのか
}
}
return this
@ -360,6 +366,7 @@ internal fun Column.makeNotificationUrl(
if(dont_show_follow) sb.append("&exclude_types[]=follow")
if(dont_show_reply) sb.append("&exclude_types[]=mention")
if(dont_show_vote) sb.append("&exclude_types[]=poll")
if(dont_show_normal_toot) sb.append("&exclude_types[]=status")
}
else -> {
@ -367,6 +374,7 @@ internal fun Column.makeNotificationUrl(
if(quick_filter != Column.QUICK_FILTER_BOOST) sb.append("&exclude_types[]=reblog")
if(quick_filter != Column.QUICK_FILTER_FOLLOW) sb.append("&exclude_types[]=follow")
if(quick_filter != Column.QUICK_FILTER_MENTION) sb.append("&exclude_types[]=mention")
if(quick_filter != Column.QUICK_FILTER_POST) sb.append("&exclude_types[]=status")
}
}

View File

@ -146,6 +146,8 @@ class ColumnViewHolder(
private lateinit var btnQuickFilterFavourite : ImageButton
private lateinit var btnQuickFilterBoost : ImageButton
private lateinit var btnQuickFilterFollow : ImageButton
private lateinit var btnQuickFilterPost : ImageButton
private lateinit var btnQuickFilterReaction : ImageButton
private lateinit var btnQuickFilterVote : ImageButton
@ -337,6 +339,7 @@ class ColumnViewHolder(
btnQuickFilterFavourite.setOnClickListener(this)
btnQuickFilterBoost.setOnClickListener(this)
btnQuickFilterFollow.setOnClickListener(this)
btnQuickFilterPost.setOnClickListener(this)
btnQuickFilterReaction.setOnClickListener(this)
btnQuickFilterVote.setOnClickListener(this)
@ -1158,6 +1161,7 @@ class ColumnViewHolder(
btnQuickFilterFavourite -> clickQuickFilter(Column.QUICK_FILTER_FAVOURITE)
btnQuickFilterBoost -> clickQuickFilter(Column.QUICK_FILTER_BOOST)
btnQuickFilterFollow -> clickQuickFilter(Column.QUICK_FILTER_FOLLOW)
btnQuickFilterPost-> clickQuickFilter(Column.QUICK_FILTER_POST)
btnQuickFilterReaction -> clickQuickFilter(Column.QUICK_FILTER_REACTION)
btnQuickFilterVote -> clickQuickFilter(Column.QUICK_FILTER_VOTE)
@ -1664,6 +1668,12 @@ class ColumnViewHolder(
column.quick_filter == Column.QUICK_FILTER_FOLLOW
)
showQuickFilterButton(
btnQuickFilterPost,
R.drawable.ic_send,
column.quick_filter == Column.QUICK_FILTER_POST
)
showQuickFilterButton(
btnQuickFilterReaction,
R.drawable.ic_add,
@ -2315,6 +2325,13 @@ class ColumnViewHolder(
margin = 0
}
btnQuickFilterPost = imageButton {
backgroundResource = R.drawable.btn_bg_transparent_round6dp
contentDescription = context.getString(R.string.notification_type_post)
}.lparams(dip(40), matchParent) {
margin = 0
}
btnQuickFilterReaction = imageButton {
backgroundResource = R.drawable.btn_bg_transparent_round6dp
contentDescription = context.getString(R.string.reaction)

View File

@ -38,6 +38,7 @@ internal class DlgContextMenu(
) : View.OnClickListener, View.OnLongClickListener {
companion object {
private val log = LogCategory("DlgContextMenu")
}
@ -78,6 +79,8 @@ internal class DlgContextMenu(
private val llAccountExtraAction : View =
viewRoot.findViewById(R.id.llAccountExtraAction)
private val btnPostNotification : Button = viewRoot.findViewById(R.id.btnPostNotification)
init {
this.access_info = column.access_info
@ -226,6 +229,7 @@ internal class DlgContextMenu(
btnBoostedBy,
btnFavouritedBy,
btnDomainTimeline,
btnPostNotification,
viewRoot.findViewById(R.id.btnQuoteUrlStatus),
viewRoot.findViewById(R.id.btnTranslate),
@ -412,7 +416,7 @@ internal class DlgContextMenu(
val whoApiHost = getUserApiHost()
val whoApDomain = getUserApDomain()
viewRoot.findViewById<View>(R.id.llInstance)
.vg(whoApiHost.isValid)
?.let {
@ -449,6 +453,15 @@ internal class DlgContextMenu(
btnOpenInstanceInAdminWebUi.vg(! access_info.isPseudo)
btnReportUser.vg(! (access_info.isPseudo || access_info.isMe(who)))
btnPostNotification.vg(! access_info.isPseudo && access_info.isMastodon && relation.following)
?.let {
it.text = when(relation.notifying) {
true -> activity.getString(R.string.stop_notify_posts_from_this_user)
else -> activity.getString(R.string.notify_posts_from_this_user)
}
}
}
viewRoot.findViewById<View>(R.id.btnAccountText).setOnClickListener(this)
@ -541,14 +554,14 @@ internal class DlgContextMenu(
Host.EMPTY, null -> access_info.apiHost
else -> who_host
}
private fun getUserApDomain() : Host =
when(val who_host = whoRef?.get()?.apDomain) {
Host.UNKNOWN -> Host.parse(column.instance_uri)
Host.EMPTY, null -> access_info.apDomain
else -> who_host
}
private fun updateGroup(btn : Button, group : View, toggle : Boolean = false) {
if(btn.visibility != View.VISIBLE) {
@ -742,17 +755,27 @@ internal class DlgContextMenu(
showToast(activity, false, R.string.domain_block_from_pseudo)
return
} else {
val whoApDomain = who.apDomain
val whoApDomain = who.apDomain
// 自分のドメインではブロックできない
if(access_info.matchHost(whoApDomain)) {
showToast(activity, false, R.string.domain_block_from_local)
return
}
AlertDialog.Builder(activity)
.setMessage(activity.getString(R.string.confirm_block_domain, whoApDomain))
.setMessage(
activity.getString(
R.string.confirm_block_domain,
whoApDomain
)
)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok) { _, _ ->
Action_Instance.blockDomain(activity, access_info, whoApDomain, true)
Action_Instance.blockDomain(
activity,
access_info,
whoApDomain,
true
)
}
.show()
}
@ -837,8 +860,7 @@ internal class DlgContextMenu(
pos,
who.apiHost,
status,
ColumnType.ACCOUNT_AROUND
, allowPseudo = false
ColumnType.ACCOUNT_AROUND, allowPseudo = false
)
R.id.btnAroundLTL -> Action_Instance.timelinePublicAround(
@ -930,6 +952,12 @@ internal class DlgContextMenu(
}
}
}
R.id.btnPostNotification ->
if(! access_info.isPseudo && access_info.isMastodon && relation.following) {
val toggle = ! relation.notifying
Action_User.statusNotification(activity, access_info, who.id, toggle)
}
}
}

View File

@ -935,6 +935,23 @@ internal class ItemViewHolder(
}
}
TootNotification.TYPE_STATUS -> {
val colorBg = Pref.ipEventBgColorStatus(activity.pref)
if(n_account != null) showBoost(
n_accountRef,
n.time_created_at,
if(n_status==null){
R.drawable.ic_question
}else{
Styler.getVisibilityIconId(access_info.isMisskey,n_status.visibility)
},
R.string.display_name_posted_by
)
if(n_status != null) {
showNotificationStatus(n_status, colorBg)
}
}
TootNotification.TYPE_FOLLOW_REQUEST,
TootNotification.TYPE_FOLLOW_REQUEST_MISSKEY -> {
val colorBg = Pref.ipEventBgColorFollowRequest(activity.pref)

View File

@ -1575,7 +1575,10 @@ class PollingWorker private constructor(contextArg : Context) {
TootNotification.TYPE_QUOTE ->
"- " + context.getString(R.string.display_name_quoted_by, name)
TootNotification.TYPE_STATUS->
"- " + context.getString(R.string.display_name_posted_by, name)
TootNotification.TYPE_FOLLOW ->
"- " + context.getString(R.string.display_name_followed_by, name)

View File

@ -531,6 +531,7 @@ object Pref {
val ipEventBgColorQuote = IntPref("EventBgColorQuote", 0)
val ipEventBgColorVote = IntPref("EventBgColorVote", 0)
val ipEventBgColorFollowRequest = IntPref("EventBgColorFollowRequest", 0)
val ipEventBgColorStatus = IntPref("EventBgColorStatus", 0)
val ipCcdHeaderBg = IntPref("ipCcdHeaderBg", 0)
val ipCcdHeaderFg = IntPref("ipCcdHeaderFg", 0)

View File

@ -77,6 +77,7 @@ internal fun addPseudoAccount(
account.notification_mention = false
account.notification_reaction = false
account.notification_vote = false
account.notification_post = false
account.saveSetting()
callback(account)
return

View File

@ -807,4 +807,41 @@ object Action_User {
}
})
}
fun statusNotification(
activity : ActMain,
accessInfo : SavedAccount,
whoId : EntityId,
enabled : Boolean
) {
TootTaskRunner(activity).run(accessInfo, object : TootTask {
override fun background(client : TootApiClient) : TootApiResult? {
return client.request(
"/api/v1/accounts/$whoId/follow",
jsonObject {
put("notify",enabled)
}.toPostRequestBuilder()
)?.also{ result->
val relation = parseItem( ::TootRelationShip, TootParser(activity,accessInfo),result.jsonObject)
if(relation!=null){
UserRelation.save1Mastodon(System.currentTimeMillis(),accessInfo.db_id,relation)
}
}
}
override fun handleResult(result : TootApiResult?) {
// cancelled
result ?: return
// error
val error = result.error
if(error != null) {
showToast(activity, true, result.error)
return
}
showToast(activity, false, R.string.operation_succeeded)
}
})
}
}

View File

@ -37,6 +37,8 @@ class TootNotification(parser : TootParser, src : JsonObject) : TimelineItem() {
// (Mastodon 2.8)投票完了
const val TYPE_POLL = "poll"
const val TYPE_STATUS = "status"
}
val json : JsonObject

View File

@ -40,6 +40,8 @@ class TootRelationShip(parser:TootParser,src : JsonObject) {
// misskey用
val requested_by : Boolean
val notifying : Boolean
// (Mastodon 3.2)
var note : String? = null
@ -55,7 +57,8 @@ class TootRelationShip(parser:TootParser,src : JsonObject) {
blocked_by = src.optBoolean("isBlocked")
requested = src.optBoolean("hasPendingFollowRequestFromYou")
requested_by = src.optBoolean("hasPendingFollowRequestToYou")
notifying = false
endorsed = false
showing_reblogs = UserRelation.REBLOG_UNKNOWN
@ -95,6 +98,7 @@ class TootRelationShip(parser:TootParser,src : JsonObject) {
this.requested = src.optBoolean("requested")
this.endorsed = src.optBoolean("endorsed")
this.note = src.optString( "note")
this.notifying = src.optBoolean("notifying")
// https://github.com/tootsuite/mastodon/commit/9745de883b198375ba23f7fde879f6d75ce2df0f
// Mastodon 2.8.0から

View File

@ -52,6 +52,7 @@ class SavedAccount(
var notification_follow_request : Boolean = false
var notification_reaction : Boolean = false
var notification_vote : Boolean = false
var notification_post : Boolean = false
var sound_uri = ""
var confirm_follow : Boolean = false
@ -131,6 +132,7 @@ class SavedAccount(
notification_follow_request = cursor.getBoolean(COL_NOTIFICATION_FOLLOW_REQUEST)
notification_reaction = cursor.getBoolean(COL_NOTIFICATION_REACTION)
notification_vote = cursor.getBoolean(COL_NOTIFICATION_VOTE)
notification_post = cursor.getBoolean(COL_NOTIFICATION_POST)
dont_hide_nsfw = cursor.getBoolean(COL_DONT_HIDE_NSFW)
dont_show_timeout = cursor.getBoolean(COL_DONT_SHOW_TIMEOUT)
@ -204,6 +206,7 @@ class SavedAccount(
cv.put(COL_NOTIFICATION_FOLLOW_REQUEST, notification_follow_request.b2i())
cv.put(COL_NOTIFICATION_REACTION, notification_reaction.b2i())
cv.put(COL_NOTIFICATION_VOTE, notification_vote.b2i())
cv.put(COL_NOTIFICATION_POST, notification_post.b2i())
cv.put(COL_CONFIRM_FOLLOW, confirm_follow.b2i())
cv.put(COL_CONFIRM_FOLLOW_LOCKED, confirm_follow_locked.b2i())
@ -270,6 +273,8 @@ class SavedAccount(
this.notification_follow_request = b.notification_follow_request
this.notification_reaction = b.notification_reaction
this.notification_vote = b.notification_vote
this.notification_post = b.notification_post
this.notification_tag = b.notification_tag
this.default_text = b.default_text
this.default_sensitive = b.default_sensitive
@ -334,6 +339,7 @@ class SavedAccount(
private const val COL_NOTIFICATION_FOLLOW_REQUEST = "notification_follow_request" // スキーマ44
private const val COL_NOTIFICATION_REACTION = "notification_reaction" // スキーマ33
private const val COL_NOTIFICATION_VOTE = "notification_vote" // スキーマ33
private const val COL_NOTIFICATION_POST = "notification_post" // スキーマ57
private const val COL_CONFIRM_FOLLOW = "confirm_follow" // スキーマ10
private const val COL_CONFIRM_FOLLOW_LOCKED = "confirm_follow_locked" // スキーマ10
@ -459,9 +465,12 @@ class SavedAccount(
// スキーマ46から
+ ",$COL_LAST_PUSH_ENDPOINT text"
// スキーマ66から
// スキーマ56から
+ ",$COL_DOMAIN text"
// スキーマ57から
+ ",$COL_NOTIFICATION_POST integer default 1"
+ ")"
)
db.execSQL("create index if not exists ${table}_user on ${table}(u)")
@ -594,8 +603,8 @@ class SavedAccount(
} catch(ex : Throwable) {
log.trace(ex)
}
}
if(oldVersion < 33 && newVersion >= 33) {
try {
db.execSQL("alter table $table add column $COL_NOTIFICATION_REACTION integer default 1")
@ -607,8 +616,8 @@ class SavedAccount(
} catch(ex : Throwable) {
log.trace(ex)
}
}
if(oldVersion < 38 && newVersion >= 38) {
try {
db.execSQL("alter table $table add column $COL_DEFAULT_SENSITIVE integer default 0")
@ -668,6 +677,14 @@ class SavedAccount(
log.trace(ex)
}
}
if(oldVersion < 57 && newVersion >= 57) {
try {
db.execSQL("alter table $table add column $COL_NOTIFICATION_POST integer default 1")
} catch(ex : Throwable) {
log.trace(ex)
}
}
}
// 横断検索用の、何とも紐ついていないアカウント
@ -681,6 +698,7 @@ class SavedAccount(
dst.notification_mention = false
dst.notification_reaction = false
dst.notification_vote = false
dst.notification_post = false
dst
}
@ -1009,6 +1027,8 @@ class SavedAccount(
TootNotification.TYPE_POLL,
TootNotification.TYPE_POLL_VOTE_MISSKEY -> notification_vote
TootNotification.TYPE_STATUS -> notification_post
else -> false
}

View File

@ -17,16 +17,16 @@ import jp.juggler.util.getStringOrNull
class UserRelation {
var following : Boolean = false // 認証ユーザからのフォロー状態にある
var followed_by : Boolean = false // 認証ユーザは被フォロー状態にある
var blocking : Boolean = false // 認証ユーザからブロックした
var blocked_by : Boolean = false // 認証ユーザからブロックされた(Misskeyのみ。Mastodonでは常にfalse)
var muting : Boolean = false
var requested : Boolean = false // 認証ユーザからのフォローは申請中である
var requested_by : Boolean = false // 相手から認証ユーザへのフォローリクエスト申請中(Misskeyのみ。Mastodonでは常にfalse)
var following_reblogs : Int = 0 // このユーザからのブーストをTLに表示する
var endorsed : Boolean = false // ユーザをプロフィールで紹介する
var following = false // 認証ユーザからのフォロー状態にある
var followed_by = false // 認証ユーザは被フォロー状態にある
var blocking = false // 認証ユーザからブロックした
var blocked_by = false // 認証ユーザからブロックされた(Misskeyのみ。Mastodonでは常にfalse)
var muting = false
var requested = false // 認証ユーザからのフォローは申請中である
var requested_by = false // 相手から認証ユーザへのフォローリクエスト申請中(Misskeyのみ。Mastodonでは常にfalse)
var following_reblogs = 0 // このユーザからのブーストをTLに表示する
var endorsed = false // ユーザをプロフィールで紹介する
var notifying = false // ユーザの投稿を通知する
var note : String? = null
// 認証ユーザからのフォロー状態
@ -66,6 +66,7 @@ class UserRelation {
private const val COL_BLOCKED_BY = "blocked_by"
private const val COL_REQUESTED_BY = "requested_by"
private const val COL_NOTE = "note"
private const val COL_NOTIFYING = "notifying"
private const val DB_ID_PSEUDO = - 2L
@ -88,6 +89,7 @@ class UserRelation {
,$COL_BLOCKED_BY integer default 0
,$COL_REQUESTED_BY integer default 0
,$COL_NOTE text default null
,$COL_NOTIFYING integer default 0
)"""
)
db.execSQL(
@ -131,6 +133,13 @@ class UserRelation {
log.trace(ex)
}
}
if(oldVersion < 58 && newVersion >= 58) {
try {
db.execSQL("alter table $table add column $COL_NOTIFYING integer default 0")
} catch(ex : Throwable) {
log.trace(ex)
}
}
}
fun deleteOld(now : Long) {
@ -167,6 +176,8 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
cv.putOrNull(COL_NOTE, src.note)
App1.database.replaceOrThrow(table, null, cv)
@ -197,6 +208,8 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
cv.putOrNull(COL_NOTE, src.note)
App1.database.replaceOrThrow(table, null, cv)
val key = String.format("%s:%s", db_id, id)
@ -282,6 +295,8 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
cv.putOrNull(COL_NOTE, src.note)
db.replaceOrThrow(table, null, cv)
}
@ -323,6 +338,8 @@ class UserRelation {
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
cv.putOrNull(COL_NOTE, src.note)
db.replace(table, null, cv)
}
@ -382,6 +399,8 @@ class UserRelation {
dst.endorsed = cursor.getBoolean(COL_ENDORSED)
dst.blocked_by = cursor.getBoolean(COL_BLOCKED_BY)
dst.requested_by = cursor.getBoolean(COL_REQUESTED_BY)
dst.notifying = cursor.getBoolean(COL_NOTIFYING)
dst.note = cursor.getStringOrNull(COL_NOTE)
return dst
}

View File

@ -58,7 +58,8 @@ class PushSubscriptionHelper(
account.notification_mention.booleanToInt(8) +
(account.isMisskey && account.notification_reaction).booleanToInt(16) +
account.notification_vote.booleanToInt(32) +
account.notification_follow_request.booleanToInt(64)
account.notification_follow_request.booleanToInt(64) +
account.notification_post.booleanToInt(128)
}
val log : String
@ -224,7 +225,7 @@ class PushSubscriptionHelper(
}
}
private fun updateSubscriptionMastodon(client : TootApiClient) : TootApiResult? {
private fun updateSubscriptionMastodon(client : TootApiClient,force:Boolean) : TootApiResult? {
// 現在の購読状態を取得
// https://github.com/tootsuite/mastodon/pull/7471
// https://github.com/tootsuite/mastodon/pull/7472
@ -315,7 +316,7 @@ class PushSubscriptionHelper(
val endpoint =
"${PollingWorker.APP_SERVER}/webpushcallback/${device_id.encodePercent()}/${account.acct.ascii.encodePercent()}/$flags/$clientIdentifier"
if(oldSubscription?.endpoint == endpoint) {
if(oldSubscription?.endpoint == endpoint && !force) {
// 既に登録済みで、endpointも一致している
subscribed = true
if(verbose) addLog(context.getString(R.string.push_subscription_already_exists))
@ -382,31 +383,33 @@ class PushSubscriptionHelper(
} else {
// 通知設定が空ではないので購読を行いたい
val params = JsonObject().apply {
put("subscription", JsonObject().apply {
put("endpoint", endpoint)
put("keys", JsonObject().apply {
put(
"p256dh",
"BBEUVi7Ehdzzpe_ZvlzzkQnhujNJuBKH1R0xYg7XdAKNFKQG9Gpm0TSGRGSuaU7LUFKX-uz8YW0hAshifDCkPuE"
)
put("auth", "iRdmDrOS6eK6xvG1H6KshQ")
})
})
put("data", JsonObject().apply {
put("alerts", JsonObject().apply {
put("follow", account.notification_follow)
put("favourite", account.notification_favourite)
put("reblog", account.notification_boost)
put("mention", account.notification_mention)
put("poll", account.notification_vote)
put("follow_request", account.notification_follow_request)
put("status",account.notification_post)
})
})
}
r = client.request(
"/api/v1/push/subscription",
JsonObject().apply {
put("subscription", JsonObject().apply {
put("endpoint", endpoint)
put("keys", JsonObject().apply {
put(
"p256dh",
"BBEUVi7Ehdzzpe_ZvlzzkQnhujNJuBKH1R0xYg7XdAKNFKQG9Gpm0TSGRGSuaU7LUFKX-uz8YW0hAshifDCkPuE"
)
put("auth", "iRdmDrOS6eK6xvG1H6KshQ")
})
})
put("data", JsonObject().apply {
put("alerts", JsonObject().apply {
put("follow", account.notification_follow)
put("favourite", account.notification_favourite)
put("reblog", account.notification_boost)
put("mention", account.notification_mention)
put("poll", account.notification_vote)
put("follow_request", account.notification_follow_request)
})
})
}
.toPostRequestBuilder()
params.toPostRequestBuilder()
) ?: return null
res = r.response ?: return r
@ -444,7 +447,7 @@ class PushSubscriptionHelper(
}
}
fun updateSubscription(client : TootApiClient) : TootApiResult? =
fun updateSubscription(client : TootApiClient,force:Boolean = false) : TootApiResult? =
try {
when {
isRecentlyChecked() ->
@ -457,7 +460,7 @@ class PushSubscriptionHelper(
updateSubscriptionMisskey(client)
else ->
updateSubscriptionMastodon(client)
updateSubscriptionMastodon(client,force)
}
} catch(ex : Throwable) {
TootApiResult(ex.withCaption("error."))

View File

@ -592,6 +592,13 @@
android:text="@string/vote_polls" />
</LinearLayout>
<LinearLayout style="@style/setting_row_form">
<CheckBox
android:id="@+id/cbNotificationPost"
style="@style/setting_horizontal_stretch"
android:text="@string/notification_type_post" />
</LinearLayout>
<LinearLayout style="@style/setting_row_form">
<Button

View File

@ -904,6 +904,19 @@
android:visibility="gone"
tools:ignore="RtlSymmetry">
<Button
android:id="@+id/btnPostNotification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/btn_bg_transparent_round6dp"
android:gravity="start|center_vertical"
android:minHeight="32dp"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:paddingBottom="4dp"
android:textAllCaps="false" />
<Button
android:id="@+id/btnNickname"
android:layout_width="match_parent"

View File

@ -207,6 +207,7 @@
<string name="display_name_follow_request_accepted_by">%1$sがあなたのフォローリクエストを承認しました</string>
<string name="display_name_followed_by">%1$sにフォローされました</string>
<string name="display_name_quoted_by">%1$sが引用しました</string>
<string name="display_name_posted_by">%1$sが投稿しました</string>
<string name="display_name_reaction_by">%1$sがリアクション</string>
<string name="display_name_replied_by">%1$sからの返信</string>
<string name="display_name_mentioned_by">%1$sからのメンション</string>
@ -500,6 +501,7 @@
<string name="notification_type_mention">返信</string>
<string name="notification_type_reaction">リアクション</string>
<string name="notification_type_vote">投票</string>
<string name="notification_type_post">投稿</string>
<string name="notifications">通知</string>
<string name="nsfw">NSFW</string>
<string name="ok">OK</string>
@ -1045,4 +1047,6 @@
<string name="gap_tail">ギャップの終端</string>
<string name="ignore_text_in_shared_media">外部アプリから共有されたメディアに付属する余計なテキストを追加しない</string>
<string name="input_sharp_itself">\'#\'だけを入力</string>
<string name="notify_posts_from_this_user">このユーザの投稿を通知する</string>
<string name="stop_notify_posts_from_this_user">このユーザの投稿の通知を解除</string>
</resources>

View File

@ -90,6 +90,7 @@
<string name="display_name_follow_request_by">%1$s sent follow request</string>
<string name="display_name_follow_request_accepted_by">%1$s accepted your follow request</string>
<string name="display_name_quoted_by">%1$s quoted</string>
<string name="display_name_posted_by">%1$s posted</string>
<string name="display_name_reaction_by">%1$s reactioned</string>
<string name="display_name_followed_by">%1$s is following you</string>
<string name="display_name_unfollowed_by">%1$s unfollowed you</string>
@ -632,6 +633,8 @@
<string name="notification_type_favourite">fav.</string>
<string name="notification_type_reaction">reaction</string>
<string name="notification_type_vote">vote</string>
<string name="notification_type_post">post</string>
<string name="dont_show_normal_toot">Don\'t show normal toot</string>
<string name="dont_show_non_public_toot">Don\'t show non-public toot</string>
<string name="set_focus_point">set focus point (Mastodon 2.3+)</string>
@ -1053,4 +1056,6 @@
<string name="gap_tail">Tail of gap</string>
<string name="ignore_text_in_shared_media">Don\'t append extra text that come with shared media from external apps</string>
<string name="input_sharp_itself">Input \'#\' itself</string>
<string name="notify_posts_from_this_user">Notify posts from this user</string>
<string name="stop_notify_posts_from_this_user">Stop notify posts from this user</string>
</resources>