Notification bell (#2012)
* Add notification bell button, API endpoints and new relationship field * Add notification type for subscriptions * Add subscriptions to legacy notification filtering * Update schemas * Fix build * Make rewrite static method into method of Notification class, fix getNotificationText * Mastodon wording for subscriptions
This commit is contained in:
parent
a917e0dad8
commit
b91a0aceeb
18 changed files with 970 additions and 33 deletions
747
app/schemas/com.keylesspalace.tusky.db.AppDatabase/24.json
Normal file
747
app/schemas/com.keylesspalace.tusky.db.AppDatabase/24.json
Normal file
|
@ -0,0 +1,747 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 24,
|
||||
"identityHash": "ea8559bbdf434c7b9086384a9a4cc8e6",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "TootEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER, `poll` TEXT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "uid",
|
||||
"columnName": "uid",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "text",
|
||||
"columnName": "text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "urls",
|
||||
"columnName": "urls",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "descriptions",
|
||||
"columnName": "descriptions",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "contentWarning",
|
||||
"columnName": "contentWarning",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToId",
|
||||
"columnName": "inReplyToId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToText",
|
||||
"columnName": "inReplyToText",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToUsername",
|
||||
"columnName": "inReplyToUsername",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "visibility",
|
||||
"columnName": "visibility",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "poll",
|
||||
"columnName": "poll",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"uid"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "AccountEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsSubscriptions` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "domain",
|
||||
"columnName": "domain",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accessToken",
|
||||
"columnName": "accessToken",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isActive",
|
||||
"columnName": "isActive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "accountId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "username",
|
||||
"columnName": "username",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "displayName",
|
||||
"columnName": "displayName",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "profilePictureUrl",
|
||||
"columnName": "profilePictureUrl",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsEnabled",
|
||||
"columnName": "notificationsEnabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsMentioned",
|
||||
"columnName": "notificationsMentioned",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsFollowed",
|
||||
"columnName": "notificationsFollowed",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsFollowRequested",
|
||||
"columnName": "notificationsFollowRequested",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsReblogged",
|
||||
"columnName": "notificationsReblogged",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsFavorited",
|
||||
"columnName": "notificationsFavorited",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsPolls",
|
||||
"columnName": "notificationsPolls",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsSubscriptions",
|
||||
"columnName": "notificationsSubscriptions",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationSound",
|
||||
"columnName": "notificationSound",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationVibration",
|
||||
"columnName": "notificationVibration",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationLight",
|
||||
"columnName": "notificationLight",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "defaultPostPrivacy",
|
||||
"columnName": "defaultPostPrivacy",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "defaultMediaSensitivity",
|
||||
"columnName": "defaultMediaSensitivity",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "alwaysShowSensitiveMedia",
|
||||
"columnName": "alwaysShowSensitiveMedia",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "alwaysOpenSpoiler",
|
||||
"columnName": "alwaysOpenSpoiler",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "mediaPreviewEnabled",
|
||||
"columnName": "mediaPreviewEnabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastNotificationId",
|
||||
"columnName": "lastNotificationId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "activeNotifications",
|
||||
"columnName": "activeNotifications",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojis",
|
||||
"columnName": "emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "tabPreferences",
|
||||
"columnName": "tabPreferences",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsFilter",
|
||||
"columnName": "notificationsFilter",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_AccountEntity_domain_accountId",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"domain",
|
||||
"accountId"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "InstanceEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, `maxPollOptions` INTEGER, `maxPollOptionLength` INTEGER, `version` TEXT, PRIMARY KEY(`instance`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "instance",
|
||||
"columnName": "instance",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojiList",
|
||||
"columnName": "emojiList",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "maximumTootCharacters",
|
||||
"columnName": "maximumTootCharacters",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxPollOptions",
|
||||
"columnName": "maxPollOptions",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxPollOptionLength",
|
||||
"columnName": "maxPollOptionLength",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "version",
|
||||
"columnName": "version",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"instance"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "TimelineStatusEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `bookmarked` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT, `visibility` INTEGER, `attachments` TEXT, `mentions` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, `poll` TEXT, `muted` INTEGER, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "serverId",
|
||||
"columnName": "serverId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "timelineUserId",
|
||||
"columnName": "timelineUserId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "authorServerId",
|
||||
"columnName": "authorServerId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToId",
|
||||
"columnName": "inReplyToId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "inReplyToAccountId",
|
||||
"columnName": "inReplyToAccountId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "createdAt",
|
||||
"columnName": "createdAt",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojis",
|
||||
"columnName": "emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogsCount",
|
||||
"columnName": "reblogsCount",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "favouritesCount",
|
||||
"columnName": "favouritesCount",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogged",
|
||||
"columnName": "reblogged",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "bookmarked",
|
||||
"columnName": "bookmarked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourited",
|
||||
"columnName": "favourited",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "sensitive",
|
||||
"columnName": "sensitive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "spoilerText",
|
||||
"columnName": "spoilerText",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "visibility",
|
||||
"columnName": "visibility",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "attachments",
|
||||
"columnName": "attachments",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mentions",
|
||||
"columnName": "mentions",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "application",
|
||||
"columnName": "application",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogServerId",
|
||||
"columnName": "reblogServerId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogAccountId",
|
||||
"columnName": "reblogAccountId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "poll",
|
||||
"columnName": "poll",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "muted",
|
||||
"columnName": "muted",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"serverId",
|
||||
"timelineUserId"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"authorServerId",
|
||||
"timelineUserId"
|
||||
],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "TimelineAccountEntity",
|
||||
"onDelete": "NO ACTION",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"authorServerId",
|
||||
"timelineUserId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"serverId",
|
||||
"timelineUserId"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "TimelineAccountEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, `bot` INTEGER NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "serverId",
|
||||
"columnName": "serverId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timelineUserId",
|
||||
"columnName": "timelineUserId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "localUsername",
|
||||
"columnName": "localUsername",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "username",
|
||||
"columnName": "username",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "displayName",
|
||||
"columnName": "displayName",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "avatar",
|
||||
"columnName": "avatar",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojis",
|
||||
"columnName": "emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "bot",
|
||||
"columnName": "bot",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"serverId",
|
||||
"timelineUserId"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "ConversationEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `id` TEXT NOT NULL, `accounts` TEXT NOT NULL, `unread` INTEGER NOT NULL, `s_id` TEXT NOT NULL, `s_url` TEXT, `s_inReplyToId` TEXT, `s_inReplyToAccountId` TEXT, `s_account` TEXT NOT NULL, `s_content` TEXT NOT NULL, `s_createdAt` INTEGER NOT NULL, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_favourited` INTEGER NOT NULL, `s_bookmarked` INTEGER NOT NULL, `s_sensitive` INTEGER NOT NULL, `s_spoilerText` TEXT NOT NULL, `s_attachments` TEXT NOT NULL, `s_mentions` TEXT NOT NULL, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsible` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, `s_poll` TEXT, PRIMARY KEY(`id`, `accountId`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "accountId",
|
||||
"columnName": "accountId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accounts",
|
||||
"columnName": "accounts",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "unread",
|
||||
"columnName": "unread",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.id",
|
||||
"columnName": "s_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.url",
|
||||
"columnName": "s_url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.inReplyToId",
|
||||
"columnName": "s_inReplyToId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.inReplyToAccountId",
|
||||
"columnName": "s_inReplyToAccountId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.account",
|
||||
"columnName": "s_account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.content",
|
||||
"columnName": "s_content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.createdAt",
|
||||
"columnName": "s_createdAt",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.emojis",
|
||||
"columnName": "s_emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.favouritesCount",
|
||||
"columnName": "s_favouritesCount",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.favourited",
|
||||
"columnName": "s_favourited",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.bookmarked",
|
||||
"columnName": "s_bookmarked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.sensitive",
|
||||
"columnName": "s_sensitive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.spoilerText",
|
||||
"columnName": "s_spoilerText",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.attachments",
|
||||
"columnName": "s_attachments",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.mentions",
|
||||
"columnName": "s_mentions",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.showingHiddenContent",
|
||||
"columnName": "s_showingHiddenContent",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.expanded",
|
||||
"columnName": "s_expanded",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.collapsible",
|
||||
"columnName": "s_collapsible",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.collapsed",
|
||||
"columnName": "s_collapsed",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastStatus.poll",
|
||||
"columnName": "s_poll",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id",
|
||||
"accountId"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ea8559bbdf434c7b9086384a9a4cc8e6')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -84,6 +84,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
private var muting: Boolean = false
|
||||
private var blockingDomain: Boolean = false
|
||||
private var showingReblogs: Boolean = false
|
||||
private var subscribing: Boolean = false
|
||||
private var loadedAccount: Account? = null
|
||||
|
||||
private var animateAvatar: Boolean = false
|
||||
|
@ -159,7 +160,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
accountMuteButton.hide()
|
||||
accountFollowsYouTextView.hide()
|
||||
|
||||
|
||||
// setup the RecyclerView for the account fields
|
||||
accountFieldList.isNestedScrollingEnabled = false
|
||||
accountFieldList.layoutManager = LinearLayoutManager(this)
|
||||
|
@ -185,7 +185,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
poorTabView.isPressed = true
|
||||
accountTabLayout.postDelayed({ poorTabView.isPressed = false }, 300)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -374,7 +373,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
accountFieldAdapter.emojis = account.emojis ?: emptyList()
|
||||
accountFieldAdapter.notifyDataSetChanged()
|
||||
|
||||
|
||||
accountLockedImageView.visible(account.locked)
|
||||
accountBadgeTextView.visible(account.bot)
|
||||
|
||||
|
@ -538,6 +536,20 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
|
||||
accountFollowsYouTextView.visible(relation.followedBy)
|
||||
|
||||
// because subscribing is Pleroma extension, enable it __only__ when we have non-null subscribing field
|
||||
// it's also now supported in Mastodon 3.3.0rc but called notifying and use different API call
|
||||
if(!viewModel.isSelf && followState == FollowState.FOLLOWING
|
||||
&& (relation.subscribing != null || relation.notifying != null)) {
|
||||
accountSubscribeButton.show()
|
||||
accountSubscribeButton.setOnClickListener {
|
||||
viewModel.changeSubscribingState()
|
||||
}
|
||||
if(relation.notifying != null)
|
||||
subscribing = relation.notifying
|
||||
else if(relation.subscribing != null)
|
||||
subscribing = relation.subscribing
|
||||
}
|
||||
|
||||
accountNoteTextInputLayout.visible(relation.note != null)
|
||||
accountNoteTextInputLayout.editText?.setText(relation.note)
|
||||
|
||||
|
@ -574,6 +586,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
accountFollowButton.setText(R.string.action_unfollow)
|
||||
}
|
||||
}
|
||||
updateSubscribeButton()
|
||||
}
|
||||
|
||||
private fun updateMuteButton() {
|
||||
|
@ -584,6 +597,18 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateSubscribeButton() {
|
||||
if(followState != FollowState.FOLLOWING) {
|
||||
accountSubscribeButton.hide()
|
||||
}
|
||||
|
||||
if(subscribing) {
|
||||
accountSubscribeButton.setIconResource(R.drawable.ic_notifications_active_24dp)
|
||||
} else {
|
||||
accountSubscribeButton.setIconResource(R.drawable.ic_notifications_24dp)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateButtons() {
|
||||
invalidateOptionsMenu()
|
||||
|
||||
|
@ -595,6 +620,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
if (blocking || viewModel.isSelf) {
|
||||
accountFloatingActionButton.hide()
|
||||
accountMuteButton.hide()
|
||||
accountSubscribeButton.hide()
|
||||
} else {
|
||||
accountFloatingActionButton.show()
|
||||
if (muting)
|
||||
|
@ -608,6 +634,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
accountFloatingActionButton.hide()
|
||||
accountFollowButton.hide()
|
||||
accountMuteButton.hide()
|
||||
accountSubscribeButton.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import androidx.annotation.Nullable;
|
|||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
|
@ -198,8 +199,12 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
holder.setUsername(statusViewData.getNickname());
|
||||
holder.setCreatedAt(statusViewData.getCreatedAt());
|
||||
|
||||
holder.setAvatars(concreteNotificaton.getStatusViewData().getAvatar(),
|
||||
concreteNotificaton.getAccount().getAvatar());
|
||||
if(concreteNotificaton.getType() == Notification.Type.STATUS) {
|
||||
holder.setAvatar(statusViewData.getAvatar(), statusViewData.isBot());
|
||||
} else {
|
||||
holder.setAvatars(statusViewData.getAvatar(),
|
||||
concreteNotificaton.getAccount().getAvatar());
|
||||
}
|
||||
}
|
||||
|
||||
holder.setMessage(concreteNotificaton, statusListener);
|
||||
|
@ -267,6 +272,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
case POLL: {
|
||||
return VIEW_TYPE_STATUS;
|
||||
}
|
||||
case STATUS:
|
||||
case FAVOURITE:
|
||||
case REBLOG: {
|
||||
return VIEW_TYPE_STATUS_NOTIFICATION;
|
||||
|
@ -374,6 +380,10 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private SimpleDateFormat shortSdf;
|
||||
private SimpleDateFormat longSdf;
|
||||
|
||||
private int avatarRadius48dp;
|
||||
private int avatarRadius36dp;
|
||||
private int avatarRadius24dp;
|
||||
|
||||
StatusNotificationViewHolder(View itemView, StatusDisplayOptions statusDisplayOptions) {
|
||||
super(itemView);
|
||||
message = itemView.findViewById(R.id.notification_top_text);
|
||||
|
@ -398,6 +408,10 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
statusContent.setOnClickListener(this);
|
||||
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
||||
|
||||
this.avatarRadius48dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||
this.avatarRadius36dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_36dp);
|
||||
this.avatarRadius24dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||
}
|
||||
|
||||
private void showNotificationContent(boolean show) {
|
||||
|
@ -488,6 +502,16 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
format = context.getString(R.string.notification_reblog_format);
|
||||
break;
|
||||
}
|
||||
case STATUS: {
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_home_24dp);
|
||||
if (icon != null) {
|
||||
icon.setColorFilter(ContextCompat.getColor(context,
|
||||
R.color.tusky_blue), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
format = context.getString(R.string.notification_subscription_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
message.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
|
||||
String wholeMessage = String.format(format, displayName);
|
||||
|
@ -526,19 +550,34 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
this.notificationId = notificationId;
|
||||
}
|
||||
|
||||
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
||||
|
||||
int statusAvatarRadius = statusAvatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_36dp);
|
||||
void setAvatar(@Nullable String statusAvatarUrl, boolean isBot) {
|
||||
statusAvatar.setPaddingRelative(0, 0, 0, 0);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(statusAvatarUrl,
|
||||
statusAvatar, statusAvatarRadius, statusDisplayOptions.animateAvatars());
|
||||
statusAvatar, avatarRadius48dp, statusDisplayOptions.animateAvatars());
|
||||
|
||||
int notificationAvatarRadius = statusAvatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||
if (statusDisplayOptions.showBotOverlay() && isBot) {
|
||||
notificationAvatar.setVisibility(View.VISIBLE);
|
||||
notificationAvatar.setBackgroundColor(0x50ffffff);
|
||||
Glide.with(notificationAvatar)
|
||||
.load(R.drawable.ic_bot_24dp)
|
||||
.into(notificationAvatar);
|
||||
|
||||
} else {
|
||||
notificationAvatar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
||||
int padding = Utils.dpToPx(statusAvatar.getContext(), 12);
|
||||
statusAvatar.setPaddingRelative(0, 0, padding, padding);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(statusAvatarUrl,
|
||||
statusAvatar, avatarRadius36dp, statusDisplayOptions.animateAvatars());
|
||||
|
||||
notificationAvatar.setVisibility(View.VISIBLE);
|
||||
ImageLoadingHelper.loadAvatar(notificationAvatarUrl, notificationAvatar,
|
||||
notificationAvatarRadius, statusDisplayOptions.animateAvatars());
|
||||
avatarRadius24dp, statusDisplayOptions.animateAvatars());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -121,7 +121,7 @@ public class NotificationHelper {
|
|||
public static final String CHANNEL_BOOST = "CHANNEL_BOOST";
|
||||
public static final String CHANNEL_FAVOURITE = "CHANNEL_FAVOURITE";
|
||||
public static final String CHANNEL_POLL = "CHANNEL_POLL";
|
||||
|
||||
public static final String CHANNEL_SUBSCRIPTIONS = "CHANNEL_SUBSCRIPTIONS";
|
||||
|
||||
/**
|
||||
* WorkManager Tag
|
||||
|
@ -138,6 +138,7 @@ public class NotificationHelper {
|
|||
*/
|
||||
|
||||
public static void make(final Context context, Notification body, AccountEntity account, boolean isFirstOfBatch) {
|
||||
body = body.rewriteToStatusTypeIfNeeded(account.getAccountId());
|
||||
|
||||
if (!filterNotification(account, body, context)) {
|
||||
return;
|
||||
|
@ -355,6 +356,7 @@ public class NotificationHelper {
|
|||
CHANNEL_BOOST + account.getIdentifier(),
|
||||
CHANNEL_FAVOURITE + account.getIdentifier(),
|
||||
CHANNEL_POLL + account.getIdentifier(),
|
||||
CHANNEL_SUBSCRIPTIONS + account.getIdentifier(),
|
||||
};
|
||||
int[] channelNames = {
|
||||
R.string.notification_mention_name,
|
||||
|
@ -362,7 +364,8 @@ public class NotificationHelper {
|
|||
R.string.notification_follow_request_name,
|
||||
R.string.notification_boost_name,
|
||||
R.string.notification_favourite_name,
|
||||
R.string.notification_poll_name
|
||||
R.string.notification_poll_name,
|
||||
R.string.notification_subscription_name,
|
||||
};
|
||||
int[] channelDescriptions = {
|
||||
R.string.notification_mention_descriptions,
|
||||
|
@ -370,7 +373,8 @@ public class NotificationHelper {
|
|||
R.string.notification_follow_request_description,
|
||||
R.string.notification_boost_description,
|
||||
R.string.notification_favourite_description,
|
||||
R.string.notification_poll_description
|
||||
R.string.notification_poll_description,
|
||||
R.string.notification_subscription_description,
|
||||
};
|
||||
|
||||
List<NotificationChannel> channels = new ArrayList<>(6);
|
||||
|
@ -516,6 +520,8 @@ public class NotificationHelper {
|
|||
switch (notification.getType()) {
|
||||
case MENTION:
|
||||
return account.getNotificationsMentioned();
|
||||
case STATUS:
|
||||
return account.getNotificationsSubscriptions();
|
||||
case FOLLOW:
|
||||
return account.getNotificationsFollowed();
|
||||
case FOLLOW_REQUEST:
|
||||
|
@ -536,6 +542,8 @@ public class NotificationHelper {
|
|||
switch (notification.getType()) {
|
||||
case MENTION:
|
||||
return CHANNEL_MENTION + account.getIdentifier();
|
||||
case STATUS:
|
||||
return CHANNEL_SUBSCRIPTIONS + account.getIdentifier();
|
||||
case FOLLOW:
|
||||
return CHANNEL_FOLLOW + account.getIdentifier();
|
||||
case FOLLOW_REQUEST:
|
||||
|
@ -606,6 +614,9 @@ public class NotificationHelper {
|
|||
case MENTION:
|
||||
return String.format(context.getString(R.string.notification_mention_format),
|
||||
accountName);
|
||||
case STATUS:
|
||||
return String.format(context.getString(R.string.notification_subscription_format),
|
||||
accountName);
|
||||
case FOLLOW:
|
||||
return String.format(context.getString(R.string.notification_follow_format),
|
||||
accountName);
|
||||
|
@ -636,6 +647,7 @@ public class NotificationHelper {
|
|||
case MENTION:
|
||||
case FAVOURITE:
|
||||
case REBLOG:
|
||||
case STATUS:
|
||||
if (!TextUtils.isEmpty(notification.getStatus().getSpoilerText())) {
|
||||
return notification.getStatus().getSpoilerText();
|
||||
} else {
|
||||
|
|
|
@ -111,6 +111,17 @@ class NotificationPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
switchPreference {
|
||||
setTitle(R.string.pref_title_notification_filter_subscriptions)
|
||||
key = PrefKeys.NOTIFICATION_FILTER_SUBSCRIPTIONS
|
||||
isIconSpaceReserved = false
|
||||
isChecked = activeAccount.notificationsSubscriptions
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
updateAccount { it.notificationsSubscriptions = newValue as Boolean }
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preferenceCategory(R.string.pref_title_notification_alerts) { category ->
|
||||
|
|
|
@ -43,6 +43,7 @@ data class AccountEntity(@field:PrimaryKey(autoGenerate = true) var id: Long,
|
|||
var notificationsReblogged: Boolean = true,
|
||||
var notificationsFavorited: Boolean = true,
|
||||
var notificationsPolls: Boolean = true,
|
||||
var notificationsSubscriptions: Boolean = true,
|
||||
var notificationSound: Boolean = true,
|
||||
var notificationVibration: Boolean = true,
|
||||
var notificationLight: Boolean = true,
|
||||
|
|
|
@ -30,7 +30,7 @@ import androidx.annotation.NonNull;
|
|||
|
||||
@Database(entities = {TootEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class,
|
||||
TimelineAccountEntity.class, ConversationEntity.class
|
||||
}, version = 23)
|
||||
}, version = 24)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
public abstract TootDao tootDao();
|
||||
|
@ -340,4 +340,11 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
}
|
||||
};
|
||||
|
||||
public static final Migration MIGRATION_23_24 = new Migration(23, 24) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `notificationsSubscriptions` INTEGER NOT NULL DEFAULT 1");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ class AppModule {
|
|||
AppDatabase.MIGRATION_13_14, AppDatabase.MIGRATION_14_15, AppDatabase.MIGRATION_15_16,
|
||||
AppDatabase.MIGRATION_16_17, AppDatabase.MIGRATION_17_18, AppDatabase.MIGRATION_18_19,
|
||||
AppDatabase.MIGRATION_19_20, AppDatabase.MIGRATION_20_21, AppDatabase.MIGRATION_21_22,
|
||||
AppDatabase.MIGRATION_22_23)
|
||||
AppDatabase.MIGRATION_22_23, AppDatabase.MIGRATION_23_24)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ data class Notification(
|
|||
FAVOURITE("favourite"),
|
||||
FOLLOW("follow"),
|
||||
FOLLOW_REQUEST("follow_request"),
|
||||
POLL("poll");
|
||||
POLL("poll"),
|
||||
STATUS("status");
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -44,7 +45,7 @@ data class Notification(
|
|||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
val asList = listOf(MENTION, REBLOG, FAVOURITE, FOLLOW, FOLLOW_REQUEST, POLL)
|
||||
val asList = listOf(MENTION, REBLOG, FAVOURITE, FOLLOW, FOLLOW_REQUEST, POLL, STATUS)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
@ -72,4 +73,14 @@ data class Notification(
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// for Pleroma compatibility that uses Mention type
|
||||
fun rewriteToStatusTypeIfNeeded(accountId: String) : Notification {
|
||||
if (type == Type.MENTION && status != null) {
|
||||
return if (status.mentions.any {
|
||||
it.id == accountId
|
||||
}) this else copy(type = Type.STATUS)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ data class Relationship (
|
|||
@SerializedName("muting_notifications") val mutingNotifications: Boolean,
|
||||
val requested: Boolean,
|
||||
@SerializedName("showing_reblogs") val showingReblogs: Boolean,
|
||||
val subscribing: Boolean? = null, // Pleroma extension
|
||||
@SerializedName("domain_blocking") val blockingDomain: Boolean,
|
||||
val note: String? // nullable for backward compatibility / feature detection
|
||||
val note: String?, // nullable for backward compatibility / feature detection
|
||||
val notifying: Boolean? // since 3.3.0rc
|
||||
)
|
||||
|
|
|
@ -179,7 +179,9 @@ public class NotificationsFragment extends SFragment implements
|
|||
@Override
|
||||
public NotificationViewData apply(Either<Placeholder, Notification> input) {
|
||||
if (input.isRight()) {
|
||||
Notification notification = input.asRight();
|
||||
Notification notification = input.asRight()
|
||||
.rewriteToStatusTypeIfNeeded(accountManager.getActiveAccount().getAccountId());
|
||||
|
||||
return ViewDataUtils.notificationToViewData(
|
||||
notification,
|
||||
alwaysShowSensitiveMedia,
|
||||
|
@ -770,6 +772,8 @@ public class NotificationsFragment extends SFragment implements
|
|||
return getString(R.string.notification_follow_request_name);
|
||||
case POLL:
|
||||
return getString(R.string.notification_poll_name);
|
||||
case STATUS:
|
||||
return getString(R.string.notification_subscription_name);
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
|
|
@ -307,7 +307,8 @@ interface MastodonApi {
|
|||
@POST("api/v1/accounts/{id}/follow")
|
||||
fun followAccount(
|
||||
@Path("id") accountId: String,
|
||||
@Field("reblogs") showReblogs: Boolean
|
||||
@Field("reblogs") showReblogs: Boolean? = null,
|
||||
@Field("notify") notify: Boolean? = null
|
||||
): Single<Relationship>
|
||||
|
||||
@POST("api/v1/accounts/{id}/unfollow")
|
||||
|
@ -347,6 +348,16 @@ interface MastodonApi {
|
|||
@Path("id") accountId: String
|
||||
): Single<List<IdentityProof>>
|
||||
|
||||
@POST("api/v1/pleroma/accounts/{id}/subscribe")
|
||||
fun subscribeAccount(
|
||||
@Path("id") accountId: String
|
||||
): Single<Relationship>
|
||||
|
||||
@POST("api/v1/pleroma/accounts/{id}/unsubscribe")
|
||||
fun unsubscribeAccount(
|
||||
@Path("id") accountId: String
|
||||
): Single<Relationship>
|
||||
|
||||
@GET("api/v1/blocks")
|
||||
fun blocks(
|
||||
@Query("max_id") maxId: String?
|
||||
|
|
|
@ -53,6 +53,7 @@ object PrefKeys {
|
|||
const val NOTIFICATION_FILTER_REBLOGS = "notificationFilterReblogs"
|
||||
const val NOTIFICATION_FILTER_FOLLOW_REQUESTS = "notificationFilterFollowRequests"
|
||||
const val NOTIFICATIONS_FILTER_FOLLOWS = "notificationFilterFollows"
|
||||
const val NOTIFICATION_FILTER_SUBSCRIPTIONS = "notificationFilterSubscriptions"
|
||||
|
||||
const val TAB_FILTER_HOME_REPLIES = "tabFilterHomeReplies"
|
||||
const val TAB_FILTER_HOME_BOOSTS = "tabFilterHomeBoosts"
|
||||
|
|
|
@ -127,6 +127,16 @@ class AccountViewModel @Inject constructor(
|
|||
changeRelationship(RelationShipAction.UNMUTE)
|
||||
}
|
||||
|
||||
fun changeSubscribingState() {
|
||||
val relationship = relationshipData.value?.data
|
||||
if(relationship?.notifying == true /* Mastodon 3.3.0rc1 */
|
||||
|| relationship?.subscribing == true /* Pleroma */ ) {
|
||||
changeRelationship(RelationShipAction.UNSUBSCRIBE)
|
||||
} else {
|
||||
changeRelationship(RelationShipAction.SUBSCRIBE)
|
||||
}
|
||||
}
|
||||
|
||||
fun blockDomain(instance: String) {
|
||||
mastodonApi.blockDomain(instance).enqueue(object: Callback<Any> {
|
||||
override fun onResponse(call: Call<Any>, response: Response<Any>) {
|
||||
|
@ -180,6 +190,7 @@ class AccountViewModel @Inject constructor(
|
|||
private fun changeRelationship(relationshipAction: RelationShipAction, parameter: Boolean? = null) {
|
||||
val relation = relationshipData.value?.data
|
||||
val account = accountData.value?.data
|
||||
val isMastodon = relationshipData.value?.data?.notifying != null
|
||||
|
||||
if (relation != null && account != null) {
|
||||
// optimistically post new state for faster response
|
||||
|
@ -197,17 +208,37 @@ class AccountViewModel @Inject constructor(
|
|||
RelationShipAction.UNBLOCK -> relation.copy(blocking = false)
|
||||
RelationShipAction.MUTE -> relation.copy(muting = true)
|
||||
RelationShipAction.UNMUTE -> relation.copy(muting = false)
|
||||
RelationShipAction.SUBSCRIBE -> {
|
||||
if(isMastodon)
|
||||
relation.copy(notifying = true)
|
||||
else relation.copy(subscribing = true)
|
||||
}
|
||||
RelationShipAction.UNSUBSCRIBE -> {
|
||||
if(isMastodon)
|
||||
relation.copy(notifying = false)
|
||||
else relation.copy(subscribing = false)
|
||||
}
|
||||
}
|
||||
relationshipData.postValue(Loading(newRelation))
|
||||
}
|
||||
|
||||
when (relationshipAction) {
|
||||
RelationShipAction.FOLLOW -> mastodonApi.followAccount(accountId, parameter ?: true)
|
||||
RelationShipAction.FOLLOW -> mastodonApi.followAccount(accountId, showReblogs = parameter ?: true)
|
||||
RelationShipAction.UNFOLLOW -> mastodonApi.unfollowAccount(accountId)
|
||||
RelationShipAction.BLOCK -> mastodonApi.blockAccount(accountId)
|
||||
RelationShipAction.UNBLOCK -> mastodonApi.unblockAccount(accountId)
|
||||
RelationShipAction.MUTE -> mastodonApi.muteAccount(accountId, parameter ?: true)
|
||||
RelationShipAction.UNMUTE -> mastodonApi.unmuteAccount(accountId)
|
||||
RelationShipAction.SUBSCRIBE -> {
|
||||
if(isMastodon)
|
||||
mastodonApi.followAccount(accountId, notify = true)
|
||||
else mastodonApi.subscribeAccount(accountId)
|
||||
}
|
||||
RelationShipAction.UNSUBSCRIBE -> {
|
||||
if(isMastodon)
|
||||
mastodonApi.followAccount(accountId, notify = false)
|
||||
else mastodonApi.unsubscribeAccount(accountId)
|
||||
}
|
||||
}.subscribe(
|
||||
{ relationship ->
|
||||
relationshipData.postValue(Success(relationship))
|
||||
|
@ -263,7 +294,6 @@ class AccountViewModel @Inject constructor(
|
|||
if (!isSelf)
|
||||
obtainRelationship(isReload)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setAccountInfo(accountId: String) {
|
||||
|
@ -273,7 +303,7 @@ class AccountViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
enum class RelationShipAction {
|
||||
FOLLOW, UNFOLLOW, BLOCK, UNBLOCK, MUTE, UNMUTE
|
||||
FOLLOW, UNFOLLOW, BLOCK, UNBLOCK, MUTE, UNMUTE, SUBSCRIBE, UNSUBSCRIBE
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
13
app/src/main/res/drawable/ic_notifications_active_24dp.xml
Normal file
13
app/src/main/res/drawable/ic_notifications_active_24dp.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:pathData="M0 0h24v24H0V0z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M18 16v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-0.83-0.68-1.5-1.51-1.5S10.5 3.17 10.5 4v0.68C7.63 5.36 6 7.92 6 11v5l-1.3 1.29c-0.63 0.63 -0.19 1.71 0.7 1.71h13.17c0.89 0 1.34-1.08 0.71 -1.71L18 16zm-6.01 6c1.1 0 2-0.9 2-2h-4c0 1.1 0.89 2 2 2zM6.77 4.73c0.42-0.38 0.43 -1.03 0.03 -1.43-0.38-0.38-1-0.39-1.39-0.02C3.7 4.84 2.52 6.96 2.14 9.34c-0.09 0.61 0.38 1.16 1 1.16 0.48 0 0.9-0.35 0.98 -0.83 0.3 -1.94 1.26-3.67 2.65-4.94zM18.6 3.28c-0.4-0.37-1.02-0.36-1.4 0.02 -0.4 0.4 -0.38 1.04 0.03 1.42 1.38 1.27 2.35 3 2.65 4.94 0.07 0.48 0.49 0.83 0.98 0.83 0.61 0 1.09-0.55 0.99 -1.16-0.38-2.37-1.55-4.48-3.25-6.05z" />
|
||||
</vector>
|
|
@ -72,6 +72,26 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Follow Requested" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/accountSubscribeButton"
|
||||
style="@style/TuskyButton.Outlined"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:minWidth="0dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:scaleType="centerInside"
|
||||
app:icon="@drawable/ic_notifications_24dp"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/accountFollowButton"
|
||||
app:layout_constraintEnd_toStartOf="@id/accountFollowButton"
|
||||
app:layout_constraintHorizontal_bias="1"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="@id/accountMuteButton"
|
||||
app:layout_constraintTop_toTopOf="@+id/accountFollowButton" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/accountMuteButton"
|
||||
style="@style/TuskyButton.Outlined"
|
||||
|
@ -86,7 +106,7 @@
|
|||
app:icon="@drawable/ic_unmute_24dp"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/accountFollowButton"
|
||||
app:layout_constraintEnd_toStartOf="@id/accountFollowButton"
|
||||
app:layout_constraintEnd_toStartOf="@id/accountSubscribeButton"
|
||||
app:layout_constraintHorizontal_bias="1"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="@id/guideAvatar"
|
||||
|
|
|
@ -145,8 +145,6 @@
|
|||
android:layout_marginRight="14dp"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:scaleType="centerCrop"
|
||||
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||
tools:src="@drawable/avatar_default" />
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
<string name="notification_favourite_format">%s favorited your toot</string>
|
||||
<string name="notification_follow_format">%s followed you</string>
|
||||
<string name="notification_follow_request_format">%s requested to follow you</string>
|
||||
<string name="notification_subscription_format">%s just posted</string>
|
||||
|
||||
<string name="report_username_format">Report @%s</string>
|
||||
<string name="report_comment_hint">Additional comments?</string>
|
||||
|
@ -223,6 +224,7 @@
|
|||
<string name="pref_title_notification_filter_reblogs">my posts are boosted</string>
|
||||
<string name="pref_title_notification_filter_favourites">my posts are favorited</string>
|
||||
<string name="pref_title_notification_filter_poll">polls have ended</string>
|
||||
<string name="pref_title_notification_filter_subscriptions">somebody I\'m subscribed to published a new toot</string>
|
||||
<string name="pref_title_appearance_settings">Appearance</string>
|
||||
<string name="pref_title_app_theme">App Theme</string>
|
||||
<string name="pref_title_timelines">Timelines</string>
|
||||
|
@ -287,7 +289,8 @@
|
|||
<string name="notification_favourite_description">Notifications when your toots get marked as favorite</string>
|
||||
<string name="notification_poll_name">Polls</string>
|
||||
<string name="notification_poll_description">Notifications about polls that have ended</string>
|
||||
|
||||
<string name="notification_subscription_name">New toots</string>
|
||||
<string name="notification_subscription_description">Notifications when somebody you\'re subscribed to published a new toot</string>
|
||||
|
||||
<string name="notification_mention_format">%s mentioned you</string>
|
||||
<string name="notification_summary_large">%1$s, %2$s, %3$s and %4$d others</string>
|
||||
|
|
Loading…
Reference in a new issue