diff --git a/app/build.gradle b/app/build.gradle
index 4766dc8ec..20d306505 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -74,6 +74,9 @@ android {
androidExtensions {
experimental = true
}
+ buildFeatures {
+ viewBinding true
+ }
testOptions {
unitTests {
returnDefaultValues = true
@@ -144,7 +147,7 @@ dependencies {
implementation "androidx.room:room-rxjava2:$roomVersion"
kapt "androidx.room:room-compiler:$roomVersion"
- implementation "com.google.android.material:material:1.2.1"
+ implementation "com.google.android.material:material:1.3.0"
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 78b4be883..a05994a10 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/25.json b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json
new file mode 100644
index 000000000..01a491b4a
--- /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 eeb7c12af..723021ee5 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 949557cc3..4bc79ce94 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
@@ -78,7 +78,7 @@ 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
@@ -89,6 +89,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
private var loadedAccount: Account? = null
private var animateAvatar: Boolean = false
+ private var animateEmojis: Boolean = false
// fields for scroll animation
private var hideFab: Boolean = false
@@ -124,6 +125,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
animateAvatar = sharedPrefs.getBoolean("animateGifAvatars", false)
+ animateEmojis = sharedPrefs.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
hideFab = sharedPrefs.getBoolean("fabHide", false)
setupToolbar()
@@ -162,6 +164,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
accountFollowsYouTextView.hide()
// setup the RecyclerView for the account fields
+ accountFieldAdapter = AccountFieldAdapter(this, animateEmojis)
accountFieldList.isNestedScrollingEnabled = false
accountFieldList.layoutManager = LinearLayoutManager(this)
accountFieldList.adapter = accountFieldAdapter
@@ -375,9 +378,9 @@ 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()
@@ -437,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)
@@ -565,11 +568,12 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
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()
@@ -619,8 +623,10 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
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)
}
}
@@ -650,14 +656,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) {
@@ -701,8 +699,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)
@@ -759,8 +756,8 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
showMuteAccountDialog(
this,
it.username
- ) { notifications ->
- viewModel.muteAccount(notifications)
+ ) { notifications, duration ->
+ viewModel.muteAccount(notifications, duration)
}
}
} else {
@@ -794,14 +791,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) {
@@ -809,10 +798,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 6cf3367eb..d592f0531 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 2933d6893..f1c3d54dd 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 363872684..92994f165 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 3d86b6e12..64d952b99 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 5adce8edb..0726b26e6 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 19f66e85b..b61ae65e3 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
@@ -49,16 +48,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 3894f652d..fa3c92c3d 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 bd216776c..e6070149c 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
@@ -109,14 +108,6 @@ class LoginActivity : BaseActivity(), Injectable {
}
}
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == android.R.id.home) {
- onBackPressed()
- return true
- }
- return super.onOptionsItemSelected(item)
- }
-
/**
* Obtain the oauth client credentials for this app. This is only necessary the first time the
* app is run on a given server instance. So, after the first authentication, they are
@@ -339,16 +330,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 d1f99c56c..577126a1e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
@@ -40,6 +40,7 @@ import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.widget.PopupMenu
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
@@ -61,11 +62,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.di.ViewModelFactory
import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.fragment.NotificationsFragment
@@ -115,6 +119,12 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
@Inject
lateinit var conversationRepository: ConversationsRepository
+ @Inject
+ lateinit var appDb: AppDatabase
+
+ @Inject
+ lateinit var draftHelper: DraftHelper
+
@Inject
lateinit var viewModelFactory: ViewModelFactory
@@ -262,6 +272,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
// Flush old media that was cached for sharing
deleteStaleCachedMedia(applicationContext.getExternalFilesDir("Tusky"))
}
+ draftWarning()
}
override fun onResume() {
@@ -448,7 +459,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)
}
},
@@ -733,6 +744,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()
+ }
keepScreenOn()
return popups
@@ -783,6 +797,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)) {
@@ -861,16 +876,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)
+ }
}
})
}
@@ -895,8 +912,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
@@ -920,6 +938,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 a43e2d080..de397fce2 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 androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import com.google.android.material.floatingactionbutton.FloatingActionButton
@@ -80,14 +79,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 9901cf85a..4ccd330a4 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,
@@ -180,6 +169,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 c092a014a..7a5a49fc7 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.activity.viewModels
import androidx.fragment.app.commit
import androidx.lifecycle.Lifecycle
@@ -85,14 +84,6 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
floating_btn.setOnClickListener(viewQuickToot::onFABClicked)
}
- 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 9fcacec38..aad5b5459 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 b66908b7c..6f0e8ee17 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;
@@ -95,17 +94,6 @@ public class ViewTagActivity extends BottomSheetActivity implements HasAndroidIn
.subscribe(quickTootView::handleEvent);
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home: {
- onBackPressed();
- return true;
- }
- }
- return super.onOptionsItemSelected(item);
- }
-
@Override
public AndroidInjector