diff --git a/app/build.gradle b/app/build.gradle
index 406b5fa2..68f9c8bb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -20,8 +20,8 @@ android {
applicationId APP_ID
minSdkVersion 21
targetSdkVersion 29
- versionCode 79
- versionName "13.1-CW1"
+ versionCode 80
+ versionName "14.0-CW1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -68,6 +68,9 @@ android {
androidExtensions {
experimental = true
}
+ buildFeatures {
+ viewBinding true
+ }
testOptions {
unitTests {
returnDefaultValues = true
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 78b4be88..a05994a1 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -43,6 +43,10 @@
public *;
}
+-keep enum com.keylesspalace.tusky.db.DraftAttachment$Type {
+ public *;
+}
+
# preserve line numbers for crash reporting
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
diff --git a/app/schemas/com.keylesspalace.tusky.db.AppDatabase/24.json b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/24.json
new file mode 100644
index 00000000..c47a305b
--- /dev/null
+++ b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/24.json
@@ -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')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json
new file mode 100644
index 00000000..01a491b4
--- /dev/null
+++ b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json
@@ -0,0 +1,821 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 25,
+ "identityHash": "e2cb844862443c2c5cc884c11f120d43",
+ "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": "DraftEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `accountId` INTEGER NOT NULL, `inReplyToId` TEXT, `content` TEXT, `contentWarning` TEXT, `sensitive` INTEGER NOT NULL, `visibility` INTEGER NOT NULL, `attachments` TEXT NOT NULL, `poll` TEXT, `failedToSend` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "inReplyToId",
+ "columnName": "inReplyToId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "contentWarning",
+ "columnName": "contentWarning",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sensitive",
+ "columnName": "sensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "poll",
+ "columnName": "poll",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "failedToSend",
+ "columnName": "failedToSend",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "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, 'e2cb844862443c2c5cc884c11f120d43')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 168990cc..1302a031 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -146,6 +146,7 @@
+
{
- onBackPressed()
- return true
- }
- }
- return super.onOptionsItemSelected(item)
- }
-
}
private fun TextView.setClickableTextWithoutUnderlines(@StringRes textId: Int) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
index bc4c336e..14c5737e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
@@ -57,6 +57,7 @@ import com.keylesspalace.tusky.interfaces.ActionButtonActivity
import com.keylesspalace.tusky.interfaces.LinkListener
import com.keylesspalace.tusky.interfaces.ReselectableFragment
import com.keylesspalace.tusky.pager.AccountPagerAdapter
+import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.view.showMuteAccountDialog
import com.keylesspalace.tusky.viewmodel.AccountViewModel
@@ -77,16 +78,18 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
private val viewModel: AccountViewModel by viewModels { viewModelFactory }
- private val accountFieldAdapter = AccountFieldAdapter(this)
+ private lateinit var accountFieldAdapter : AccountFieldAdapter
private var followState: FollowState = FollowState.NOT_FOLLOWING
private var blocking: Boolean = false
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
+ private var animateEmojis: Boolean = false
// fields for scroll animation
private var hideFab: Boolean = false
@@ -116,12 +119,13 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
loadResources()
makeNotificationBarTransparent()
setContentView(R.layout.activity_account)
-
+
// Obtain information to fill out the profile.
viewModel.setAccountInfo(intent.getStringExtra(KEY_ACCOUNT_ID)!!)
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
animateAvatar = sharedPrefs.getBoolean("animateGifAvatars", false)
+ animateEmojis = sharedPrefs.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
hideFab = sharedPrefs.getBoolean("fabHide", false)
setupToolbar()
@@ -159,8 +163,8 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
accountMuteButton.hide()
accountFollowsYouTextView.hide()
-
// setup the RecyclerView for the account fields
+ accountFieldAdapter = AccountFieldAdapter(this, animateEmojis)
accountFieldList.isNestedScrollingEnabled = false
accountFieldList.layoutManager = LinearLayoutManager(this)
accountFieldList.adapter = accountFieldAdapter
@@ -186,6 +190,16 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
accountTabLayout.postDelayed({ poorTabView.isPressed = false }, 300)
}
+ // If wellbeing mode is enabled, follow stats and posts count should be hidden
+ val preferences = PreferenceManager.getDefaultSharedPreferences(this)
+ val wellbeingEnabled = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_PROFILE, false)
+
+ if (wellbeingEnabled) {
+ accountStatuses.hide()
+ accountFollowers.hide()
+ accountFollowing.hide()
+ }
+
}
/**
@@ -200,8 +214,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
val pageTitles = arrayOf(getString(R.string.title_statuses), getString(R.string.title_statuses_with_replies), getString(R.string.title_statuses_pinned), getString(R.string.title_media))
- TabLayoutMediator(accountTabLayout, accountFragmentViewPager) {
- tab, position ->
+ TabLayoutMediator(accountTabLayout, accountFragmentViewPager) { tab, position ->
tab.text = pageTitles[position]
}.attach()
@@ -365,16 +378,15 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
val usernameFormatted = getString(R.string.status_username_format, account.username)
accountUsernameTextView.text = usernameFormatted
- accountDisplayNameTextView.text = account.name.emojify(account.emojis, accountDisplayNameTextView)
+ accountDisplayNameTextView.text = account.name.emojify(account.emojis, accountDisplayNameTextView, animateEmojis)
- val emojifiedNote = account.note.emojify(account.emojis, accountNoteTextView)
+ val emojifiedNote = account.note.emojify(account.emojis, accountNoteTextView, animateEmojis)
LinkHelper.setClickableText(accountNoteTextView, emojifiedNote, null, this)
// accountFieldAdapter.fields = account.fields ?: emptyList()
accountFieldAdapter.emojis = account.emojis ?: emptyList()
accountFieldAdapter.notifyDataSetChanged()
-
accountLockedImageView.visible(account.locked)
accountBadgeTextView.visible(account.bot)
@@ -428,7 +440,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
private fun updateToolbar() {
loadedAccount?.let { account ->
- val emojifiedName = account.name.emojify(account.emojis, accountToolbar)
+ val emojifiedName = account.name.emojify(account.emojis, accountToolbar, animateEmojis)
try {
supportActionBar?.title = EmojiCompat.get().process(emojifiedName)
@@ -536,13 +548,32 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
blockingDomain = relation.blockingDomain
showingReblogs = relation.showingReblogs
- accountFollowsYouTextView.visible(relation.followedBy)
+ // If wellbeing mode is enabled, "follows you" text should not be visible
+ val preferences = PreferenceManager.getDefaultSharedPreferences(this)
+ val wellbeingEnabled = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_PROFILE, false)
+
+ accountFollowsYouTextView.visible(relation.followedBy && !wellbeingEnabled)
+
+ // 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
+ }
+
+ // remove the listener so it doesn't fire on non-user changes
+ accountNoteTextInputLayout.editText?.removeTextChangedListener(noteWatcher)
accountNoteTextInputLayout.visible(relation.note != null)
accountNoteTextInputLayout.editText?.setText(relation.note)
- // add the listener late to avoid it firing on the first change
- accountNoteTextInputLayout.editText?.removeTextChangedListener(noteWatcher)
accountNoteTextInputLayout.editText?.addTextChangedListener(noteWatcher)
updateButtons()
@@ -574,6 +605,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
accountFollowButton.setText(R.string.action_unfollow)
}
}
+ updateSubscribeButton()
}
private fun updateMuteButton() {
@@ -584,6 +616,20 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
}
}
+ private fun updateSubscribeButton() {
+ if(followState != FollowState.FOLLOWING) {
+ accountSubscribeButton.hide()
+ }
+
+ if(subscribing) {
+ accountSubscribeButton.setIconResource(R.drawable.ic_notifications_active_24dp)
+ accountSubscribeButton.contentDescription = getString(R.string.action_unsubscribe_account)
+ } else {
+ accountSubscribeButton.setIconResource(R.drawable.ic_notifications_24dp)
+ accountSubscribeButton.contentDescription = getString(R.string.action_subscribe_account)
+ }
+ }
+
private fun updateButtons() {
invalidateOptionsMenu()
@@ -595,6 +641,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
if (blocking || viewModel.isSelf) {
accountFloatingActionButton.hide()
accountMuteButton.hide()
+ accountSubscribeButton.hide()
} else {
accountFloatingActionButton.show()
if (muting)
@@ -608,6 +655,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
accountFloatingActionButton.hide()
accountFollowButton.hide()
accountMuteButton.hide()
+ accountSubscribeButton.hide()
}
}
@@ -615,14 +663,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
menuInflater.inflate(R.menu.account_toolbar, menu)
if (!viewModel.isSelf) {
- val follow = menu.findItem(R.id.action_follow)
- follow.title = if (followState == FollowState.NOT_FOLLOWING) {
- getString(R.string.action_follow)
- } else {
- getString(R.string.action_unfollow)
- }
-
- follow.isVisible = followState != FollowState.REQUESTED
val block = menu.findItem(R.id.action_block)
block.title = if (blocking) {
@@ -666,8 +706,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
}
} else {
- // It shouldn't be possible to block, follow, mute or report yourself.
- menu.removeItem(R.id.action_follow)
+ // It shouldn't be possible to block, mute or report yourself.
menu.removeItem(R.id.action_block)
menu.removeItem(R.id.action_mute)
menu.removeItem(R.id.action_mute_domain)
@@ -722,10 +761,10 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
if (viewModel.relationshipData.value?.data?.muting != true) {
loadedAccount?.let {
showMuteAccountDialog(
- this,
- it.username
- ) { notifications ->
- viewModel.muteAccount(notifications)
+ this,
+ it.username
+ ) { notifications, duration ->
+ viewModel.muteAccount(notifications, duration)
}
}
} else {
@@ -759,14 +798,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- return true
- }
- R.id.action_mention -> {
- mention()
- return true
- }
R.id.action_open_in_web -> {
// If the account isn't loaded yet, eat the input.
if (loadedAccount != null) {
@@ -774,10 +805,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
}
return true
}
- R.id.action_follow -> {
- viewModel.changeFollowState()
- return true
- }
R.id.action_block -> {
toggleBlock()
return true
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt
index 6cf3367e..d592f053 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt
@@ -18,7 +18,6 @@ package com.keylesspalace.tusky
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.view.MenuItem
import com.keylesspalace.tusky.fragment.AccountListFragment
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
@@ -68,16 +67,6 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
.commit()
}
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- return true
- }
- }
- return super.onOptionsItemSelected(item)
- }
-
override fun androidInjector() = dispatchingAndroidInjector
companion object {
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
index 2933d689..f1c3d54d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
@@ -31,6 +31,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
import com.keylesspalace.tusky.viewmodel.State
@@ -71,7 +72,9 @@ class AccountsInListFragment : DialogFragment(), Injectable {
private val searchAdapter = SearchAdapter()
private val radius by lazy { resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp) }
- private val animateAvatar by lazy { PreferenceManager.getDefaultSharedPreferences(requireContext()).getBoolean("animateGifAvatars", false) }
+ private val pm by lazy { PreferenceManager.getDefaultSharedPreferences(requireContext()) }
+ private val animateAvatar by lazy { pm.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) }
+ private val animateEmojis by lazy { pm.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -209,7 +212,7 @@ class AccountsInListFragment : DialogFragment(), Injectable {
}
fun bind(account: Account) {
- displayNameTextView.text = account.name.emojify(account.emojis, displayNameTextView)
+ displayNameTextView.text = account.name.emojify(account.emojis, displayNameTextView, animateEmojis)
usernameTextView.text = account.username
loadAvatar(account.avatar, avatar, radius, animateAvatar)
}
@@ -252,7 +255,7 @@ class AccountsInListFragment : DialogFragment(), Injectable {
override val containerView = itemView
fun bind(account: Account, inAList: Boolean) {
- displayNameTextView.text = account.name.emojify(account.emojis, displayNameTextView)
+ displayNameTextView.text = account.name.emojify(account.emojis, displayNameTextView, animateEmojis)
usernameTextView.text = account.username
loadAvatar(account.avatar, avatar, radius, animateAvatar)
diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
index 36387268..92994f16 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
@@ -24,6 +24,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
+import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
@@ -127,6 +128,15 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left);
}
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
@Override
public void finish() {
super.finish();
diff --git a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt
index 3d86b6e1..64d952b9 100644
--- a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt
@@ -296,10 +296,6 @@ class EditProfileActivity : BaseActivity(), Injectable {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- return true
- }
R.id.action_save -> {
save()
return true
diff --git a/app/src/main/java/com/keylesspalace/tusky/FiltersActivity.kt b/app/src/main/java/com/keylesspalace/tusky/FiltersActivity.kt
index 5adce8ed..0726b26e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/FiltersActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/FiltersActivity.kt
@@ -1,7 +1,6 @@
package com.keylesspalace.tusky
import android.os.Bundle
-import android.view.MenuItem
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
@@ -205,14 +204,4 @@ class FiltersActivity: BaseActivity() {
}
}
- // Activate back arrow in toolbar
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- return true
- }
- }
- return super.onOptionsItemSelected(item)
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt b/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt
index 915baf96..d6cc7bca 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt
@@ -18,7 +18,6 @@ package com.keylesspalace.tusky
import android.os.Bundle
import androidx.annotation.RawRes
import android.util.Log
-import android.view.MenuItem
import android.widget.TextView
import com.keylesspalace.tusky.util.IOUtils
import kotlinx.android.extensions.CacheImplementation
@@ -48,16 +47,6 @@ class LicenseActivity : BaseActivity() {
}
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- return true
- }
- }
- return super.onOptionsItemSelected(item)
- }
-
private fun loadFileIntoTextView(@RawRes fileId: Int, textView: TextView) {
val sb = StringBuilder()
diff --git a/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
index 3894f652..fa3c92c3 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
@@ -21,7 +21,6 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
-import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.*
@@ -130,19 +129,27 @@ class ListsActivity : BaseActivity(), Injectable, HasAndroidInjector {
else R.string.action_rename_list) { _, _ ->
onPickedDialogName(editText.text, list?.id)
}
- .setNegativeButton(android.R.string.cancel) { d, _ ->
- d.dismiss()
- }
+ .setNegativeButton(android.R.string.cancel, null)
.show()
val positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE)
editText.onTextChanged { s, _, _, _ ->
- positiveButton.isEnabled = !s.isBlank()
+ positiveButton.isEnabled = s.isNotBlank()
}
editText.setText(list?.title)
editText.text?.let { editText.setSelection(it.length) }
}
+ private fun showListDeleteDialog(list: MastoList) {
+ AlertDialog.Builder(this)
+ .setMessage(getString(R.string.dialog_delete_list_warning, list.title))
+ .setPositiveButton(R.string.action_delete){ _, _ ->
+ viewModel.deleteList(list.id)
+ }
+ .setNegativeButton(android.R.string.cancel, null)
+ .show()
+ }
+
private fun update(state: ListsViewModel.State) {
adapter.submitList(state.lists)
@@ -199,7 +206,7 @@ class ListsActivity : BaseActivity(), Injectable, HasAndroidInjector {
when (item.itemId) {
R.id.list_edit -> openListSettings(list)
R.id.list_rename -> renameListDialog(list)
- R.id.list_delete -> viewModel.deleteList(list.id)
+ R.id.list_delete -> showListDeleteDialog(list)
else -> return@setOnMenuItemClickListener false
}
true
@@ -210,14 +217,6 @@ class ListsActivity : BaseActivity(), Injectable, HasAndroidInjector {
override fun androidInjector() = dispatchingAndroidInjector
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) {
- onBackPressed()
- return true
- }
- return false
- }
-
private object ListsDiffer : DiffUtil.ItemCallback() {
override fun areItemsTheSame(oldItem: MastoList, newItem: MastoList): Boolean {
return oldItem.id == newItem.id
diff --git a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
index 2269d328..d2911ec0 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
@@ -20,14 +20,13 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
-import android.os.Build
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.util.Log
-import android.view.MenuItem
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
+import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import com.bumptech.glide.Glide
import com.keylesspalace.tusky.di.Injectable
@@ -362,16 +361,19 @@ class LoginActivity : BaseActivity(), Injectable {
private fun openInCustomTab(uri: Uri, context: Context): Boolean {
val toolbarColor = ThemeUtils.getColor(context, R.attr.colorSurface)
- val customTabsIntentBuilder = CustomTabsIntent.Builder()
+ val navigationbarColor = ThemeUtils.getColor(context, android.R.attr.navigationBarColor)
+ val navigationbarDividerColor = ThemeUtils.getColor(context, R.attr.dividerColor)
+
+ val colorSchemeParams = CustomTabColorSchemeParams.Builder()
.setToolbarColor(toolbarColor)
+ .setNavigationBarColor(navigationbarColor)
+ .setNavigationBarDividerColor(navigationbarDividerColor)
+ .build()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
- customTabsIntentBuilder.setNavigationBarColor(
- ThemeUtils.getColor(context, android.R.attr.navigationBarColor)
- )
- }
+ val customTabsIntent = CustomTabsIntent.Builder()
+ .setDefaultColorSchemeParams(colorSchemeParams)
+ .build()
- val customTabsIntent = customTabsIntentBuilder.build()
try {
customTabsIntent.launchUrl(context, uri)
} catch (e: ActivityNotFoundException) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
index 31a4e80c..3b3af8ae 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
@@ -31,6 +31,7 @@ import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
+import androidx.core.content.edit
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.emoji.text.EmojiCompat
import androidx.emoji.text.EmojiCompat.InitCallback
@@ -52,11 +53,14 @@ import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity.Companion.canHandleMimeType
import com.keylesspalace.tusky.components.conversation.ConversationsRepository
+import com.keylesspalace.tusky.components.drafts.DraftHelper
+import com.keylesspalace.tusky.components.drafts.DraftsActivity
import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.components.preference.PreferencesActivity
import com.keylesspalace.tusky.components.scheduled.ScheduledTootActivity
import com.keylesspalace.tusky.components.search.SearchActivity
import com.keylesspalace.tusky.db.AccountEntity
+import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.fragment.SFragment
import com.keylesspalace.tusky.interfaces.AccountSelectionListener
@@ -98,6 +102,12 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
@Inject
lateinit var conversationRepository: ConversationsRepository
+ @Inject
+ lateinit var appDb: AppDatabase
+
+ @Inject
+ lateinit var draftHelper: DraftHelper
+
private lateinit var header: AccountHeaderView
private var notificationTabPosition = 0
@@ -229,6 +239,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
// Flush old media that was cached for sharing
deleteStaleCachedMedia(applicationContext.getExternalFilesDir("Tusky"))
}
+ draftWarning()
}
override fun onResume() {
@@ -397,7 +408,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
nameRes = R.string.action_access_saved_toot
iconRes = R.drawable.ic_notebook
onClick = {
- val intent = Intent(context, SavedTootActivity::class.java)
+ val intent = DraftsActivity.newIntent(context)
startActivityWithSlideInAnimation(intent)
}
},
@@ -554,6 +565,9 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
val activeTabPosition = if (selectNotificationTab) notificationTabPosition else 0
mainToolbar.title = tabs[activeTabPosition].title(this@MainActivity)
+ mainToolbar.setOnClickListener {
+ (adapter.getFragment(activeTabLayout.selectedTabPosition) as? ReselectableFragment)?.onReselect()
+ }
}
@@ -601,6 +615,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
NotificationHelper.deleteNotificationChannelsForAccount(activeAccount, this)
cacheUpdater.clearForUser(activeAccount.id)
conversationRepository.deleteCacheForAccount(activeAccount.id)
+ draftHelper.deleteAllDraftsAndAttachmentsForAccount(activeAccount.id)
removeShortcut(this, activeAccount)
val newAccount = accountManager.logActiveAccountOut()
if (!NotificationHelper.areNotificationsEnabled(this, accountManager)) {
@@ -679,16 +694,18 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
.into(object : CustomTarget(navIconSize, navIconSize) {
override fun onLoadStarted(placeholder: Drawable?) {
- if(placeholder != null) {
+ if (placeholder != null) {
mainToolbar.navigationIcon = FixedSizeDrawable(placeholder, navIconSize, navIconSize)
}
}
override fun onResourceReady(resource: Drawable, transition: Transition?) {
- mainToolbar.navigationIcon = resource
+ mainToolbar.navigationIcon = FixedSizeDrawable(resource, navIconSize, navIconSize)
}
override fun onLoadCleared(placeholder: Drawable?) {
- mainToolbar.navigationIcon = placeholder
+ if (placeholder != null) {
+ mainToolbar.navigationIcon = FixedSizeDrawable(placeholder, navIconSize, navIconSize)
+ }
}
})
}
@@ -713,8 +730,9 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
}
private fun updateProfiles() {
+ val animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
val profiles: MutableList = accountManager.getAllAccountsOrderedByActive().map { acc ->
- val emojifiedName = EmojiCompat.get().process(acc.displayName.emojify(acc.emojis, header))
+ val emojifiedName = EmojiCompat.get().process(acc.displayName.emojify(acc.emojis, header, animateEmojis))
ProfileDrawerItem().apply {
isSelected = acc.isActive
@@ -738,6 +756,29 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
header.setActiveProfile(accountManager.activeAccount!!.id)
}
+ private fun draftWarning() {
+ val sharedPrefsKey = "show_draft_warning"
+ appDb.tootDao().savedTootCount()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .autoDispose(this, Lifecycle.Event.ON_DESTROY)
+ .subscribe { draftCount ->
+ val showDraftWarning = preferences.getBoolean(sharedPrefsKey, true)
+ if (draftCount > 0 && showDraftWarning) {
+ AlertDialog.Builder(this)
+ .setMessage(R.string.new_drafts_warning)
+ .setNegativeButton("Don't show again") { _, _ ->
+ preferences.edit(commit = true) {
+ putBoolean(sharedPrefsKey, false)
+ }
+ }
+ .setPositiveButton(android.R.string.ok, null)
+ .show()
+ }
+ }
+
+ }
+
override fun getActionButton(): FloatingActionButton? = composeButton
override fun androidInjector() = androidInjector
diff --git a/app/src/main/java/com/keylesspalace/tusky/ModalTimelineActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ModalTimelineActivity.kt
index e4655a5e..c3017b0c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ModalTimelineActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/ModalTimelineActivity.kt
@@ -3,7 +3,6 @@ package com.keylesspalace.tusky
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.view.MenuItem
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.keylesspalace.tusky.fragment.TimelineFragment
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
@@ -56,14 +55,6 @@ class ModalTimelineActivity : BottomSheetActivity(), ActionButtonActivity, HasAn
override fun getActionButton(): FloatingActionButton? = null
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) {
- onBackPressed()
- return true
- }
- return false
- }
-
override fun androidInjector() = dispatchingAndroidInjector
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/SavedTootActivity.java b/app/src/main/java/com/keylesspalace/tusky/SavedTootActivity.java
index 9a163989..63a32b17 100644
--- a/app/src/main/java/com/keylesspalace/tusky/SavedTootActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/SavedTootActivity.java
@@ -18,7 +18,6 @@ package com.keylesspalace.tusky;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.view.MenuItem;
import android.view.View;
import androidx.annotation.Nullable;
@@ -89,7 +88,7 @@ public final class SavedTootActivity extends BaseActivity implements SavedTootAd
setSupportActionBar(toolbar);
ActionBar bar = getSupportActionBar();
if (bar != null) {
- bar.setTitle(getString(R.string.title_saved_toot));
+ bar.setTitle(getString(R.string.title_drafts));
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowHomeEnabled(true);
}
@@ -118,17 +117,6 @@ public final class SavedTootActivity extends BaseActivity implements SavedTootAd
if (asyncTask != null) asyncTask.cancel(true);
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home: {
- onBackPressed();
- return true;
- }
- }
- return super.onOptionsItemSelected(item);
- }
-
private void fetchToots() {
asyncTask = new FetchPojosTask(this, database.tootDao())
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -166,6 +154,7 @@ public final class SavedTootActivity extends BaseActivity implements SavedTootAd
ComposeOptions composeOptions = new ComposeOptions(
/*scheduledTootUid*/null,
item.getUid(),
+ /*drafId*/null,
item.getText(),
jsonUrls,
descriptions,
@@ -177,6 +166,7 @@ public final class SavedTootActivity extends BaseActivity implements SavedTootAd
item.getInReplyToUsername(),
item.getInReplyToText(),
/*mediaAttachments*/null,
+ /*draftAttachments*/null,
/*scheduledAt*/null,
/*sensitive*/null,
/*poll*/null,
diff --git a/app/src/main/java/com/keylesspalace/tusky/StatusListActivity.kt b/app/src/main/java/com/keylesspalace/tusky/StatusListActivity.kt
index 56ea4d2f..9eba5bbe 100644
--- a/app/src/main/java/com/keylesspalace/tusky/StatusListActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/StatusListActivity.kt
@@ -18,7 +18,6 @@ package com.keylesspalace.tusky
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.view.MenuItem
import androidx.fragment.app.commit
import com.keylesspalace.tusky.fragment.TimelineFragment
@@ -66,14 +65,6 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
}
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home){
- onBackPressed()
- return true
- }
- return super.onOptionsItemSelected(item)
- }
-
override fun androidInjector() = dispatchingAndroidInjector
companion object {
diff --git a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt
index 6b1aaef9..2b61f141 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt
@@ -18,7 +18,6 @@ package com.keylesspalace.tusky
import android.graphics.Color
import android.os.Bundle
import android.util.Log
-import android.view.MenuItem
import android.view.View
import android.widget.FrameLayout
import androidx.appcompat.app.AlertDialog
@@ -345,14 +344,6 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
}
}
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) {
- onBackPressed()
- return true
- }
- return false
- }
-
override fun onPause() {
super.onPause()
if (tabsChanged) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java b/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java
index a49dcc88..0ff6ff56 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/ViewTagActivity.java
@@ -18,7 +18,6 @@ package com.keylesspalace.tusky;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.view.MenuItem;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
@@ -72,17 +71,6 @@ public class ViewTagActivity extends BottomSheetActivity implements HasAndroidIn
fragmentTransaction.commit();
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home: {
- onBackPressed();
- return true;
- }
- }
- return super.onOptionsItemSelected(item);
- }
-
@Override
public AndroidInjector