BigTextStyleを使う。通知タップ時にアカウントの通知カラムを開く。
This commit is contained in:
parent
ba361806bd
commit
055b196be6
|
@ -140,7 +140,7 @@ class ActPushMessageList : AppCompatActivity() {
|
||||||
println("to: ${pm.loginAcct}")
|
println("to: ${pm.loginAcct}")
|
||||||
println("type: ${pm.notificationType}")
|
println("type: ${pm.notificationType}")
|
||||||
println("id: ${pm.notificationId}")
|
println("id: ${pm.notificationId}")
|
||||||
println("text: ${pm.rawBody?.size}")
|
println("text: ${pm.textExpand}")
|
||||||
println("dataSize: ${pm.rawBody?.size}")
|
println("dataSize: ${pm.rawBody?.size}")
|
||||||
println("messageJson=${pm.messageJson?.toString(1, sort = true)}")
|
println("messageJson=${pm.messageJson?.toString(1, sort = true)}")
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ class ActPushMessageList : AppCompatActivity() {
|
||||||
"type: ${pm.notificationType}",
|
"type: ${pm.notificationType}",
|
||||||
"id: ${pm.notificationId}",
|
"id: ${pm.notificationId}",
|
||||||
"dataSize: ${pm.rawBody?.size}",
|
"dataSize: ${pm.rawBody?.size}",
|
||||||
pm.text
|
pm.textExpand
|
||||||
).mapNotNull { it.notBlank() }.joinToString("\n")
|
).mapNotNull { it.notBlank() }.joinToString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,8 @@ private fun ActMain.handleNotificationClick(uri: Uri, dataIdString: String) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pushRepo.onTapNotification(account)
|
||||||
|
|
||||||
recycleClickedNotification(this, uri)
|
recycleClickedNotification(this, uri)
|
||||||
|
|
||||||
val columnList = appState.columnList
|
val columnList = appState.columnList
|
||||||
|
|
|
@ -71,8 +71,8 @@ object PullNotification {
|
||||||
|
|
||||||
val params = listOf(
|
val params = listOf(
|
||||||
"db_id" to account.db_id.toString(),
|
"db_id" to account.db_id.toString(),
|
||||||
"type" to trackingType.str,
|
"type" to trackingType.str, // URIをユニークにするため。参照されない
|
||||||
"notificationId" to notificationId
|
"notificationId" to notificationId, // URIをユニークにするため。参照されない
|
||||||
).mapNotNull {
|
).mapNotNull {
|
||||||
when (val second = it.second) {
|
when (val second = it.second) {
|
||||||
null -> null
|
null -> null
|
||||||
|
|
|
@ -161,6 +161,10 @@ class PushMastodon(
|
||||||
pm.text = arrayOf(
|
pm.text = arrayOf(
|
||||||
// あなたのトゥートが tateisu 🤹 さんにお気に入り登録されました
|
// あなたのトゥートが tateisu 🤹 さんにお気に入り登録されました
|
||||||
json.string("title"),
|
json.string("title"),
|
||||||
|
).mapNotNull { it?.trim()?.notBlank() }.joinToString("\n")
|
||||||
|
pm.textExpand = arrayOf(
|
||||||
|
// あなたのトゥートが tateisu 🤹 さんにお気に入り登録されました
|
||||||
|
json.string("title"),
|
||||||
// 対象の投稿の本文?
|
// 対象の投稿の本文?
|
||||||
json.string("body"),
|
json.string("body"),
|
||||||
// 対象の投稿の本文? (古い
|
// 対象の投稿の本文? (古い
|
||||||
|
|
|
@ -2,11 +2,14 @@ package jp.juggler.subwaytooter.push
|
||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import androidx.work.await
|
import androidx.work.await
|
||||||
import jp.juggler.crypt.*
|
import jp.juggler.crypt.*
|
||||||
|
import jp.juggler.subwaytooter.ActCallback
|
||||||
import jp.juggler.subwaytooter.R
|
import jp.juggler.subwaytooter.R
|
||||||
import jp.juggler.subwaytooter.api.entity.Acct
|
import jp.juggler.subwaytooter.api.entity.Acct
|
||||||
import jp.juggler.subwaytooter.api.entity.Host
|
import jp.juggler.subwaytooter.api.entity.Host
|
||||||
|
@ -25,6 +28,7 @@ import jp.juggler.subwaytooter.push.PushWorker.Companion.enqueueRegisterEndpoint
|
||||||
import jp.juggler.subwaytooter.table.*
|
import jp.juggler.subwaytooter.table.*
|
||||||
import jp.juggler.subwaytooter.util.loadIcon
|
import jp.juggler.subwaytooter.util.loadIcon
|
||||||
import jp.juggler.util.coroutine.AppDispatchers
|
import jp.juggler.util.coroutine.AppDispatchers
|
||||||
|
import jp.juggler.util.coroutine.EmptyScope
|
||||||
import jp.juggler.util.data.*
|
import jp.juggler.util.data.*
|
||||||
import jp.juggler.util.data.Base128.decodeBase128
|
import jp.juggler.util.data.Base128.decodeBase128
|
||||||
import jp.juggler.util.log.LogCategory
|
import jp.juggler.util.log.LogCategory
|
||||||
|
@ -32,6 +36,7 @@ import jp.juggler.util.log.withCaption
|
||||||
import jp.juggler.util.os.applicationContextSafe
|
import jp.juggler.util.os.applicationContextSafe
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.unifiedpush.android.connector.UnifiedPush
|
import org.unifiedpush.android.connector.UnifiedPush
|
||||||
|
@ -526,7 +531,7 @@ class PushRepo(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解読できた(例外が出なかった)なら通知を出す
|
// 解読できた(例外が出なかった)なら通知を出す
|
||||||
showPushNotification(pm)
|
showPushNotification(pm,account,notificationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -608,7 +613,11 @@ class PushRepo(
|
||||||
/**
|
/**
|
||||||
* SNSからの通知を表示する
|
* SNSからの通知を表示する
|
||||||
*/
|
*/
|
||||||
private suspend fun showPushNotification(pm: PushMessage) {
|
private suspend fun showPushNotification(
|
||||||
|
pm: PushMessage,
|
||||||
|
account: SavedAccount,
|
||||||
|
notificationId:String,
|
||||||
|
) {
|
||||||
if (ncPushMessage.isDissabled(context)) {
|
if (ncPushMessage.isDissabled(context)) {
|
||||||
log.w("ncPushMessage isDissabled.")
|
log.w("ncPushMessage isDissabled.")
|
||||||
return
|
return
|
||||||
|
@ -628,8 +637,26 @@ class PushRepo(
|
||||||
val iconSmall = pm.loadSmallIcon(context)
|
val iconSmall = pm.loadSmallIcon(context)
|
||||||
val iconBitmapLarge = context.loadIcon(pm.iconLarge, (48f * density + 0.5f).toInt())
|
val iconBitmapLarge = context.loadIcon(pm.iconLarge, (48f * density + 0.5f).toInt())
|
||||||
|
|
||||||
val urlTap = "subwaytooter://pushMessage/${pm.id}"
|
|
||||||
val iTap = context.intentNotificationDelete(urlTap.toUri())
|
val params = listOf(
|
||||||
|
"db_id" to account.db_id.toString(),
|
||||||
|
// URIをユニークにするため。参照されない
|
||||||
|
"type" to "v2push", // "type" to trackingType.str,
|
||||||
|
// URIをユニークにするため。参照されない
|
||||||
|
"notificationId" to notificationId,
|
||||||
|
).mapNotNull {
|
||||||
|
when (val second = it.second) {
|
||||||
|
null -> null
|
||||||
|
else -> "${it.first.encodePercent()}=${second.encodePercent()}"
|
||||||
|
}
|
||||||
|
}.joinToString("&")
|
||||||
|
|
||||||
|
val iTap = Intent(context, ActCallback::class.java).apply {
|
||||||
|
data = "subwaytooter://notification_click/?$params".toUri()
|
||||||
|
// FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY を付与してはいけない
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
}
|
||||||
|
|
||||||
val piTap = PendingIntent.getActivity(
|
val piTap = PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
ncPushMessage.pircTap,
|
ncPushMessage.pircTap,
|
||||||
|
@ -660,6 +687,9 @@ class PushRepo(
|
||||||
setContentIntent(piTap)
|
setContentIntent(piTap)
|
||||||
setDeleteIntent(piDelete)
|
setDeleteIntent(piDelete)
|
||||||
setAutoCancel(true)
|
setAutoCancel(true)
|
||||||
|
pm.textExpand.notEmpty()?.let {
|
||||||
|
setStyle(NotificationCompat.BigTextStyle().bigText(it))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,4 +717,18 @@ class PushRepo(
|
||||||
?: error("missing messageDbId in $uri")
|
?: error("missing messageDbId in $uri")
|
||||||
daoPushMessage.dismiss(messageDbId)
|
daoPushMessage.dismiss(messageDbId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知タップのインテントをメイン画面が受け取った
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun onTapNotification(account: SavedAccount) {
|
||||||
|
EmptyScope.launch(AppDispatchers.IO) {
|
||||||
|
try{
|
||||||
|
daoPushMessage.dismissByAcct(account.acct)
|
||||||
|
}catch(ex:Throwable){
|
||||||
|
log.e(ex,"onTapNotification failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.database.Cursor
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.provider.BaseColumns
|
import android.provider.BaseColumns
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
|
import jp.juggler.subwaytooter.api.entity.Acct
|
||||||
import jp.juggler.util.*
|
import jp.juggler.util.*
|
||||||
import jp.juggler.util.data.*
|
import jp.juggler.util.data.*
|
||||||
import jp.juggler.util.log.LogCategory
|
import jp.juggler.util.log.LogCategory
|
||||||
|
@ -26,8 +27,10 @@ data class PushMessage(
|
||||||
var notificationId: String? = null,
|
var notificationId: String? = null,
|
||||||
// 通知の種別。小アイコン、アクセント色、Misskeyの文言に影響する
|
// 通知の種別。小アイコン、アクセント色、Misskeyの文言に影響する
|
||||||
var notificationType: String? = null,
|
var notificationType: String? = null,
|
||||||
// 通知表示の本文。
|
// 通知表示の本文
|
||||||
var text: String? = null,
|
var text: String? = null,
|
||||||
|
// 展開表示した本文
|
||||||
|
var textExpand: String? = null,
|
||||||
// 小アイコンURL。昔のMastodonはバッジ画像が提供されていた。
|
// 小アイコンURL。昔のMastodonはバッジ画像が提供されていた。
|
||||||
var iconSmall: String? = null,
|
var iconSmall: String? = null,
|
||||||
// 大アイコンURL。通知の原因となったユーザのアイコン画像。
|
// 大アイコンURL。通知の原因となったユーザのアイコン画像。
|
||||||
|
@ -51,6 +54,7 @@ data class PushMessage(
|
||||||
private const val COL_NOTIFICATION_ID = "notification_id"
|
private const val COL_NOTIFICATION_ID = "notification_id"
|
||||||
private const val COL_NOTIFICATION_TYPE = "notification_type"
|
private const val COL_NOTIFICATION_TYPE = "notification_type"
|
||||||
private const val COL_TEXT = "text"
|
private const val COL_TEXT = "text"
|
||||||
|
private const val COL_TEXT_EXPAND = "text_expand"
|
||||||
private const val COL_ICON_SMALL = "icon_small"
|
private const val COL_ICON_SMALL = "icon_small"
|
||||||
private const val COL_ICON_LARGE = "icon_large"
|
private const val COL_ICON_LARGE = "icon_large"
|
||||||
private const val COL_MESSAGE_JSON = "message_json"
|
private const val COL_MESSAGE_JSON = "message_json"
|
||||||
|
@ -61,17 +65,24 @@ data class PushMessage(
|
||||||
deleteBeforeCreate = true
|
deleteBeforeCreate = true
|
||||||
column(0, COL_ID, MetaColumns.TS_INT_PRIMARY_KEY_NOT_NULL)
|
column(0, COL_ID, MetaColumns.TS_INT_PRIMARY_KEY_NOT_NULL)
|
||||||
column(0, COL_LOGIN_ACCT, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_LOGIN_ACCT, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_TIMESTAMP, MetaColumns.TS_ZERO)
|
column(0, COL_TIMESTAMP, MetaColumns.TS_ZERO_NOT_NULL)
|
||||||
column(0, COL_TIME_SAVE, MetaColumns.TS_ZERO)
|
column(0, COL_TIME_SAVE, MetaColumns.TS_ZERO_NOT_NULL)
|
||||||
column(0, COL_TIME_DISMISS, MetaColumns.TS_ZERO)
|
column(0, COL_TIME_DISMISS, MetaColumns.TS_ZERO_NOT_NULL)
|
||||||
column(0, COL_NOTIFICATION_ID, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_NOTIFICATION_ID, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_NOTIFICATION_TYPE, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_NOTIFICATION_TYPE, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_TEXT, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_TEXT, MetaColumns.TS_TEXT_NULL)
|
||||||
|
column(0, COL_TEXT_EXPAND, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_ICON_SMALL, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_ICON_SMALL, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_ICON_LARGE, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_ICON_LARGE, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_MESSAGE_JSON, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_MESSAGE_JSON, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_HEADER_JSON, MetaColumns.TS_TEXT_NULL)
|
column(0, COL_HEADER_JSON, MetaColumns.TS_TEXT_NULL)
|
||||||
column(0, COL_RAW_BODY, MetaColumns.TS_BLOB_NULL)
|
column(0, COL_RAW_BODY, MetaColumns.TS_BLOB_NULL)
|
||||||
|
createExtra={
|
||||||
|
arrayOf(
|
||||||
|
"create index if not exists ${TABLE}_save on $TABLE($COL_TIME_SAVE)",
|
||||||
|
"create index if not exists ${TABLE}_acct_dismiss on $TABLE($COL_LOGIN_ACCT,$COL_TIME_DISMISS)",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDBCreate(db: SQLiteDatabase) {
|
override fun onDBCreate(db: SQLiteDatabase) {
|
||||||
|
@ -103,6 +114,7 @@ data class PushMessage(
|
||||||
val idxNotificationId = cursor.getColumnIndex(COL_NOTIFICATION_ID)
|
val idxNotificationId = cursor.getColumnIndex(COL_NOTIFICATION_ID)
|
||||||
val idxNotificationType = cursor.getColumnIndex(COL_NOTIFICATION_TYPE)
|
val idxNotificationType = cursor.getColumnIndex(COL_NOTIFICATION_TYPE)
|
||||||
val idxText = cursor.getColumnIndex(COL_TEXT)
|
val idxText = cursor.getColumnIndex(COL_TEXT)
|
||||||
|
val idxTextExpand = cursor.getColumnIndex(COL_TEXT_EXPAND)
|
||||||
val idxIconSmall = cursor.getColumnIndex(COL_ICON_SMALL)
|
val idxIconSmall = cursor.getColumnIndex(COL_ICON_SMALL)
|
||||||
val idxIconLarge = cursor.getColumnIndex(COL_ICON_LARGE)
|
val idxIconLarge = cursor.getColumnIndex(COL_ICON_LARGE)
|
||||||
val idxMessageJson = cursor.getColumnIndex(COL_MESSAGE_JSON)
|
val idxMessageJson = cursor.getColumnIndex(COL_MESSAGE_JSON)
|
||||||
|
@ -119,6 +131,7 @@ data class PushMessage(
|
||||||
notificationId = cursor.getStringOrNull(idxNotificationId),
|
notificationId = cursor.getStringOrNull(idxNotificationId),
|
||||||
notificationType = cursor.getStringOrNull(idxNotificationType),
|
notificationType = cursor.getStringOrNull(idxNotificationType),
|
||||||
text = cursor.getStringOrNull(idxText),
|
text = cursor.getStringOrNull(idxText),
|
||||||
|
textExpand = cursor.getStringOrNull(idxTextExpand),
|
||||||
iconSmall = cursor.getStringOrNull(idxIconSmall),
|
iconSmall = cursor.getStringOrNull(idxIconSmall),
|
||||||
iconLarge = cursor.getStringOrNull(idxIconLarge),
|
iconLarge = cursor.getStringOrNull(idxIconLarge),
|
||||||
messageJson = cursor.getStringOrNull(idxMessageJson)?.decodeJsonObject(),
|
messageJson = cursor.getStringOrNull(idxMessageJson)?.decodeJsonObject(),
|
||||||
|
@ -148,6 +161,7 @@ data class PushMessage(
|
||||||
put(COL_NOTIFICATION_ID, notificationId)
|
put(COL_NOTIFICATION_ID, notificationId)
|
||||||
put(COL_NOTIFICATION_TYPE, notificationType)
|
put(COL_NOTIFICATION_TYPE, notificationType)
|
||||||
put(COL_TEXT, text)
|
put(COL_TEXT, text)
|
||||||
|
put(COL_TEXT_EXPAND, textExpand)
|
||||||
put(COL_ICON_SMALL, iconSmall)
|
put(COL_ICON_SMALL, iconSmall)
|
||||||
put(COL_ICON_LARGE, iconLarge)
|
put(COL_ICON_LARGE, iconLarge)
|
||||||
put(COL_MESSAGE_JSON, messageJson?.toString())
|
put(COL_MESSAGE_JSON, messageJson?.toString())
|
||||||
|
@ -192,6 +206,13 @@ data class PushMessage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun dismissByAcct(acct: Acct) {
|
||||||
|
db.execSQL(
|
||||||
|
"update $table set $COL_TIME_DISMISS=? where $COL_LOGIN_ACCT=? and $COL_TIME_DISMISS=0",
|
||||||
|
arrayOf(System.currentTimeMillis().toString(), acct.ascii),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun deleteOld(now: Long) {
|
fun deleteOld(now: Long) {
|
||||||
try {
|
try {
|
||||||
val expire = now - TimeUnit.DAYS.toMillis(30)
|
val expire = now - TimeUnit.DAYS.toMillis(30)
|
||||||
|
@ -202,7 +223,7 @@ data class PushMessage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun listAll(): List<PushMessage> =
|
fun listAll(): List<PushMessage> =
|
||||||
db.queryAll(TABLE, "$COL_TIME_SAVE desc")
|
db.queryAll(TABLE, "$COL_TIME_SAVE desc")
|
||||||
?.use { ColIdx(it).readAll(it) }
|
?.use { ColIdx(it).readAll(it) }
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
|
|
Loading…
Reference in New Issue