mirror of https://github.com/tuskyapp/Tusky.git
Browse Source
* move Html parsing to ViewData * refactor reports to use viewdata * cleanup code * refactor conversations * fix getEditableText * rename StatusParsingHelper * fix tests * commit db schema file * add file header * rename helper function to parseAsMastodonHtml * order imports correctly * move mapping off main thread to default dispatcher * fix ktlintpull/2436/head
34 changed files with 1232 additions and 500 deletions
@ -0,0 +1,809 @@
|
||||
{ |
||||
"formatVersion": 1, |
||||
"database": { |
||||
"version": 33, |
||||
"identityHash": "920a0e0c9a600bd236f6bf959b469c18", |
||||
"entities": [ |
||||
{ |
||||
"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, `notificationsSignUps` 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": "notificationsSignUps", |
||||
"columnName": "notificationsSignUps", |
||||
"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" |
||||
], |
||||
"orders": [], |
||||
"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, `minPollDuration` INTEGER, `maxPollDuration` INTEGER, `charactersReservedPerUrl` 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": "minPollDuration", |
||||
"columnName": "minPollDuration", |
||||
"affinity": "INTEGER", |
||||
"notNull": false |
||||
}, |
||||
{ |
||||
"fieldPath": "maxPollDuration", |
||||
"columnName": "maxPollDuration", |
||||
"affinity": "INTEGER", |
||||
"notNull": false |
||||
}, |
||||
{ |
||||
"fieldPath": "charactersReservedPerUrl", |
||||
"columnName": "charactersReservedPerUrl", |
||||
"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 NOT NULL, `visibility` INTEGER NOT NULL, `attachments` TEXT, `mentions` TEXT, `tags` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, `poll` TEXT, `muted` INTEGER, `expanded` INTEGER NOT NULL, `contentCollapsed` INTEGER NOT NULL, `contentShowing` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, 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": true |
||||
}, |
||||
{ |
||||
"fieldPath": "visibility", |
||||
"columnName": "visibility", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
}, |
||||
{ |
||||
"fieldPath": "attachments", |
||||
"columnName": "attachments", |
||||
"affinity": "TEXT", |
||||
"notNull": false |
||||
}, |
||||
{ |
||||
"fieldPath": "mentions", |
||||
"columnName": "mentions", |
||||
"affinity": "TEXT", |
||||
"notNull": false |
||||
}, |
||||
{ |
||||
"fieldPath": "tags", |
||||
"columnName": "tags", |
||||
"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 |
||||
}, |
||||
{ |
||||
"fieldPath": "expanded", |
||||
"columnName": "expanded", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
}, |
||||
{ |
||||
"fieldPath": "contentCollapsed", |
||||
"columnName": "contentCollapsed", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
}, |
||||
{ |
||||
"fieldPath": "contentShowing", |
||||
"columnName": "contentShowing", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
}, |
||||
{ |
||||
"fieldPath": "pinned", |
||||
"columnName": "pinned", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
} |
||||
], |
||||
"primaryKey": { |
||||
"columnNames": [ |
||||
"serverId", |
||||
"timelineUserId" |
||||
], |
||||
"autoGenerate": false |
||||
}, |
||||
"indices": [ |
||||
{ |
||||
"name": "index_TimelineStatusEntity_authorServerId_timelineUserId", |
||||
"unique": false, |
||||
"columnNames": [ |
||||
"authorServerId", |
||||
"timelineUserId" |
||||
], |
||||
"orders": [], |
||||
"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_tags` TEXT, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, `s_muted` 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.tags", |
||||
"columnName": "s_tags", |
||||
"affinity": "TEXT", |
||||
"notNull": false |
||||
}, |
||||
{ |
||||
"fieldPath": "lastStatus.showingHiddenContent", |
||||
"columnName": "s_showingHiddenContent", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
}, |
||||
{ |
||||
"fieldPath": "lastStatus.expanded", |
||||
"columnName": "s_expanded", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
}, |
||||
{ |
||||
"fieldPath": "lastStatus.collapsed", |
||||
"columnName": "s_collapsed", |
||||
"affinity": "INTEGER", |
||||
"notNull": true |
||||
}, |
||||
{ |
||||
"fieldPath": "lastStatus.muted", |
||||
"columnName": "s_muted", |
||||
"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, '920a0e0c9a600bd236f6bf959b469c18')" |
||||
] |
||||
} |
||||
} |
||||
@ -0,0 +1,87 @@
|
||||
/* Copyright 2022 Tusky Contributors |
||||
* |
||||
* This file is a part of Tusky. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the |
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even |
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
||||
* Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not, |
||||
* see <http://www.gnu.org/licenses>. */ |
||||
|
||||
package com.keylesspalace.tusky.components.conversation |
||||
|
||||
import com.keylesspalace.tusky.entity.Poll |
||||
import com.keylesspalace.tusky.viewdata.StatusViewData |
||||
|
||||
data class ConversationViewData( |
||||
val id: String, |
||||
val accounts: List<ConversationAccountEntity>, |
||||
val unread: Boolean, |
||||
val lastStatus: StatusViewData.Concrete |
||||
) { |
||||
fun toEntity( |
||||
accountId: Long, |
||||
favourited: Boolean = lastStatus.status.favourited, |
||||
bookmarked: Boolean = lastStatus.status.bookmarked, |
||||
muted: Boolean = lastStatus.status.muted ?: false, |
||||
poll: Poll? = lastStatus.status.poll, |
||||
expanded: Boolean = lastStatus.isExpanded, |
||||
collapsed: Boolean = lastStatus.isCollapsed, |
||||
showingHiddenContent: Boolean = lastStatus.isShowingContent |
||||
): ConversationEntity { |
||||
return ConversationEntity( |
||||
accountId = accountId, |
||||
id = id, |
||||
accounts = accounts, |
||||
unread = unread, |
||||
lastStatus = lastStatus.toConversationStatusEntity( |
||||
favourited = favourited, |
||||
bookmarked = bookmarked, |
||||
muted = muted, |
||||
poll = poll, |
||||
expanded = expanded, |
||||
collapsed = collapsed, |
||||
showingHiddenContent = showingHiddenContent |
||||
) |
||||
) |
||||
} |
||||
} |
||||
|
||||
fun StatusViewData.Concrete.toConversationStatusEntity( |
||||
favourited: Boolean = status.favourited, |
||||
bookmarked: Boolean = status.bookmarked, |
||||
muted: Boolean = status.muted ?: false, |
||||
poll: Poll? = status.poll, |
||||
expanded: Boolean = isExpanded, |
||||
collapsed: Boolean = isCollapsed, |
||||
showingHiddenContent: Boolean = isShowingContent |
||||
): ConversationStatusEntity { |
||||
return ConversationStatusEntity( |
||||
id = id, |
||||
url = status.url, |
||||
inReplyToId = status.inReplyToId, |
||||
inReplyToAccountId = status.inReplyToAccountId, |
||||
account = status.account.toEntity(), |
||||
content = status.content, |
||||
createdAt = status.createdAt, |
||||
emojis = status.emojis, |
||||
favouritesCount = status.favouritesCount, |
||||
favourited = favourited, |
||||
bookmarked = bookmarked, |
||||
sensitive = status.sensitive, |
||||
spoilerText = status.spoilerText, |
||||
attachments = status.attachments, |
||||
mentions = status.mentions, |
||||
tags = status.tags, |
||||
showingHiddenContent = showingHiddenContent, |
||||
expanded = expanded, |
||||
collapsed = collapsed, |
||||
muted = muted, |
||||
poll = poll |
||||
) |
||||
} |
||||
@ -1,54 +0,0 @@
|
||||
/* Copyright 2020 Tusky Contributors |
||||
* |
||||
* This file is a part of Tusky. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the |
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even |
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
||||
* Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not, |
||||
* see <http://www.gnu.org/licenses>. */ |
||||
|
||||
package com.keylesspalace.tusky.json |
||||
|
||||
import android.text.Spanned |
||||
import android.text.SpannedString |
||||
import androidx.core.text.HtmlCompat |
||||
import androidx.core.text.parseAsHtml |
||||
import androidx.core.text.toHtml |
||||
import com.google.gson.JsonDeserializationContext |
||||
import com.google.gson.JsonDeserializer |
||||
import com.google.gson.JsonElement |
||||
import com.google.gson.JsonParseException |
||||
import com.google.gson.JsonPrimitive |
||||
import com.google.gson.JsonSerializationContext |
||||
import com.google.gson.JsonSerializer |
||||
import com.keylesspalace.tusky.util.trimTrailingWhitespace |
||||
import java.lang.reflect.Type |
||||
|
||||
class SpannedTypeAdapter : JsonDeserializer<Spanned>, JsonSerializer<Spanned?> { |
||||
@Throws(JsonParseException::class) |
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Spanned { |
||||
return json.asString |
||||
/* Mastodon uses 'white-space: pre-wrap;' so spaces are displayed as returned by the Api. |
||||
* We can't use CSS so we replace spaces with non-breaking-spaces to emulate the behavior. |
||||
*/ |
||||
?.replace("<br> ", "<br> ") |
||||
?.replace("<br /> ", "<br /> ") |
||||
?.replace("<br/> ", "<br/> ") |
||||
?.replace(" ", " ") |
||||
?.parseAsHtml() |
||||
/* Html.fromHtml returns trailing whitespace if the html ends in a </p> tag, which |
||||
* most status contents do, so it should be trimmed. */ |
||||
?.trimTrailingWhitespace() |
||||
?: SpannedString("") |
||||
} |
||||
|
||||
override fun serialize(src: Spanned?, typeOfSrc: Type, context: JsonSerializationContext): JsonElement { |
||||
return JsonPrimitive(src!!.toHtml(HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL)) |
||||
} |
||||
} |
||||
@ -0,0 +1,62 @@
|
||||
/* Copyright 2022 Tusky Contributors |
||||
* |
||||
* This file is a part of Tusky. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the |
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even |
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
||||
* Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not, |
||||
* see <http://www.gnu.org/licenses>. */ |
||||
|
||||
package com.keylesspalace.tusky.util |
||||
|
||||
import android.text.SpannableStringBuilder |
||||
import android.text.Spanned |
||||
import androidx.core.text.parseAsHtml |
||||
|
||||
/** |
||||
* parse a String containing html from the Mastodon api to Spanned |
||||
*/ |
||||
fun String.parseAsMastodonHtml(): Spanned { |
||||
return this.replace("<br> ", "<br> ") |
||||
.replace("<br /> ", "<br /> ") |
||||
.replace("<br/> ", "<br/> ") |
||||
.replace(" ", " ") |
||||
.parseAsHtml() |
||||
/* Html.fromHtml returns trailing whitespace if the html ends in a </p> tag, which |
||||
* most status contents do, so it should be trimmed. */ |
||||
.trimTrailingWhitespace() |
||||
} |
||||
|
||||
fun replaceCrashingCharacters(content: Spanned): Spanned { |
||||
return replaceCrashingCharacters(content as CharSequence) as Spanned |
||||
} |
||||
|
||||
fun replaceCrashingCharacters(content: CharSequence): CharSequence? { |
||||
var replacing = false |
||||
var builder: SpannableStringBuilder? = null |
||||
val length = content.length |
||||
for (index in 0 until length) { |
||||
val character = content[index] |
||||
|
||||
// If there are more than one or two, switch to a map |
||||
if (character == SOFT_HYPHEN) { |
||||
if (!replacing) { |
||||
replacing = true |
||||
builder = SpannableStringBuilder(content, 0, index) |
||||
} |
||||
builder!!.append(ASCII_HYPHEN) |
||||
} else if (replacing) { |
||||
builder!!.append(character) |
||||
} |
||||
} |
||||
return if (replacing) builder else content |
||||
} |
||||
|
||||
private const val SOFT_HYPHEN = '\u00ad' |
||||
private const val ASCII_HYPHEN = '-' |
||||
Loading…
Reference in new issue