Merge remote-tracking branch 'tuskyapp/develop'

# Conflicts:
#	app/build.gradle
#	app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
#	app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt
#	app/src/main/res/values-cy/strings.xml
#	app/src/main/res/values-eu/strings.xml
#	app/src/main/res/values-ja/strings.xml
#	app/src/main/res/values-oc/strings.xml
#	app/src/main/res/values-pt-rBR/strings.xml
#	app/src/main/res/values-zh-rCN/strings.xml
#	app/src/main/res/values-zh-rSG/strings.xml
#	app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt
#	fastlane/metadata/android/en-US/images/phoneScreenshots/00_login.png
This commit is contained in:
kyori19 2023-01-29 04:48:24 +09:00
commit 52a757e572
No known key found for this signature in database
GPG Key ID: F7BDE7DD42BF366A
39 changed files with 1633 additions and 159 deletions

View File

@ -0,0 +1,995 @@
{
"formatVersion": 1,
"database": {
"version": 47,
"identityHash": "308b3faf2255729075a85abab23a1c9e",
"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, `failedToSendNew` INTEGER NOT NULL, `scheduledAt` TEXT, `language` TEXT, `statusId` TEXT)",
"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
},
{
"fieldPath": "failedToSendNew",
"columnName": "failedToSendNew",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "scheduledAt",
"columnName": "scheduledAt",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "language",
"columnName": "language",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "statusId",
"columnName": "statusId",
"affinity": "TEXT",
"notNull": false
}
],
"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, `clientId` TEXT, `clientSecret` TEXT, `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, `notificationsUpdates` INTEGER NOT NULL, `notificationsReports` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `defaultPostLanguage` TEXT 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, `oauthScopes` TEXT NOT NULL, `unifiedPushUrl` TEXT NOT NULL, `pushPubKey` TEXT NOT NULL, `pushPrivKey` TEXT NOT NULL, `pushAuth` TEXT NOT NULL, `pushServerKey` 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": "clientId",
"columnName": "clientId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "clientSecret",
"columnName": "clientSecret",
"affinity": "TEXT",
"notNull": false
},
{
"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": "notificationsUpdates",
"columnName": "notificationsUpdates",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationsReports",
"columnName": "notificationsReports",
"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": "defaultPostLanguage",
"columnName": "defaultPostLanguage",
"affinity": "TEXT",
"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
},
{
"fieldPath": "oauthScopes",
"columnName": "oauthScopes",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unifiedPushUrl",
"columnName": "unifiedPushUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pushPubKey",
"columnName": "pushPubKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pushPrivKey",
"columnName": "pushPrivKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pushAuth",
"columnName": "pushAuth",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pushServerKey",
"columnName": "pushServerKey",
"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, `videoSizeLimit` INTEGER, `imageSizeLimit` INTEGER, `imageMatrixLimit` INTEGER, `maxMediaAttachments` INTEGER, `maxFields` INTEGER, `maxFieldNameLength` INTEGER, `maxFieldValueLength` INTEGER, 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
},
{
"fieldPath": "videoSizeLimit",
"columnName": "videoSizeLimit",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "imageSizeLimit",
"columnName": "imageSizeLimit",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "imageMatrixLimit",
"columnName": "imageMatrixLimit",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "maxMediaAttachments",
"columnName": "maxMediaAttachments",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "maxFields",
"columnName": "maxFields",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "maxFieldNameLength",
"columnName": "maxFieldNameLength",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "maxFieldValueLength",
"columnName": "maxFieldValueLength",
"affinity": "INTEGER",
"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, `editedAt` INTEGER, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `repliesCount` 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, `card` TEXT, `language` TEXT, `quote` TEXT, 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": "editedAt",
"columnName": "editedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"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": "repliesCount",
"columnName": "repliesCount",
"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
},
{
"fieldPath": "card",
"columnName": "card",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "language",
"columnName": "language",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "quote",
"columnName": "quote",
"affinity": "TEXT",
"notNull": false
}
],
"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, `order` INTEGER 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_editedAt` INTEGER, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_repliesCount` 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, `s_language` TEXT, PRIMARY KEY(`id`, `accountId`))",
"fields": [
{
"fieldPath": "accountId",
"columnName": "accountId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "order",
"columnName": "order",
"affinity": "INTEGER",
"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.editedAt",
"columnName": "s_editedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastStatus.emojis",
"columnName": "s_emojis",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.favouritesCount",
"columnName": "s_favouritesCount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.repliesCount",
"columnName": "s_repliesCount",
"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
},
{
"fieldPath": "lastStatus.language",
"columnName": "s_language",
"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, '308b3faf2255729075a85abab23a1c9e')"
]
}
}

View File

@ -39,7 +39,18 @@
</activity>
<activity
android:name=".components.login.LoginActivity"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="${applicationId}"
android:scheme="@string/oauth_scheme" />
</intent-filter>
</activity>
<activity android:name=".components.login.LoginWebViewActivity" />
<activity

View File

@ -89,6 +89,7 @@ import com.keylesspalace.tusky.components.search.SearchActivity
import com.keylesspalace.tusky.components.timeline.TimelineFragment
import com.keylesspalace.tusky.databinding.ActivityMainBinding
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.db.DraftsAlert
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Notification
@ -164,6 +165,9 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
@Inject
lateinit var logoutUsecase: LogoutUsecase
@Inject
lateinit var draftsAlert: DraftsAlert
@Inject
lateinit var developerToolsUseCase: DeveloperToolsUseCase
@ -346,6 +350,9 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
1
)
}
// "Post failed" dialog should display in this activity
draftsAlert.observeInContext(this, true)
}
override fun onPause() {

View File

@ -61,6 +61,7 @@ import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.report.ReportActivity
import com.keylesspalace.tusky.databinding.ActivityAccountBinding
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.db.DraftsAlert
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Relationship
@ -100,6 +101,8 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var draftsAlert: DraftsAlert
private val viewModel: AccountViewModel by viewModels { viewModelFactory }
@ -391,6 +394,9 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
viewModel.noteSaved.observe(this) {
binding.saveNoteInfo.visible(it, View.INVISIBLE)
}
// "Post failed" dialog should display in this activity
draftsAlert.observeInContext(this, true)
}
/**
@ -582,6 +588,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
}
}
updateFollowButton()
updateSubscribeButton()
}
}
}
@ -655,7 +662,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
binding.accountFollowButton.setText(R.string.action_unfollow)
}
}
updateSubscribeButton()
}
private fun updateMuteButton() {
@ -685,6 +691,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
binding.accountFollowButton.show()
updateFollowButton()
updateSubscribeButton()
if (blocking) {
binding.accountFloatingActionButton.hide()
@ -692,10 +699,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
binding.accountSubscribeButton.hide()
} else {
binding.accountFloatingActionButton.show()
if (muting)
binding.accountMuteButton.show()
else
binding.accountMuteButton.hide()
binding.accountMuteButton.visible(muting)
updateMuteButton()
}
}

View File

@ -282,6 +282,7 @@ class ComposeViewModel @Inject constructor(
mediaFocus = mediaFocus,
poll = poll.value,
failedToSend = false,
failedToSendAlert = false,
scheduledAt = scheduledAt.value,
language = postLanguage,
statusId = originalStatusId,

View File

@ -63,6 +63,7 @@ class DraftHelper @Inject constructor(
mediaFocus: List<Attachment.Focus?>,
poll: NewPoll?,
failedToSend: Boolean,
failedToSendAlert: Boolean,
scheduledAt: String?,
language: String?,
statusId: String?,
@ -123,6 +124,7 @@ class DraftHelper @Inject constructor(
attachments = attachments,
poll = poll,
failedToSend = failedToSend,
failedToSendNew = failedToSendAlert,
scheduledAt = scheduledAt,
language = language,
statusId = statusId,

View File

@ -33,6 +33,7 @@ import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.databinding.ActivityDraftsBinding
import com.keylesspalace.tusky.db.DraftEntity
import com.keylesspalace.tusky.db.DraftsAlert
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.util.parseAsMastodonHtml
import com.keylesspalace.tusky.util.visible
@ -46,6 +47,9 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var draftsAlert: DraftsAlert
private val viewModel: DraftsViewModel by viewModels { viewModelFactory }
private lateinit var binding: ActivityDraftsBinding
@ -83,6 +87,9 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
adapter.addLoadStateListener {
binding.draftsErrorMessageView.visible(adapter.itemCount == 0)
}
// If a failed post is saved to drafts while this activity is up, do nothing; the user is already in the drafts view.
draftsAlert.observeInContext(this, false)
}
override fun onOpenDraft(draft: DraftEntity) {

View File

@ -21,6 +21,7 @@ import android.content.SharedPreferences
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.Menu
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
@ -37,6 +38,7 @@ import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.AccessToken
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.getNonNullString
import com.keylesspalace.tusky.util.openLinkInCustomTab
import com.keylesspalace.tusky.util.viewBinding
import kotlinx.coroutines.launch
import okhttp3.HttpUrl
@ -64,24 +66,8 @@ class LoginActivity : BaseActivity(), Injectable {
is LoginResult.Ok -> lifecycleScope.launch {
fetchOauthToken(result.code)
}
is LoginResult.Err -> {
// Authorization failed. Put the error response where the user can read it and they
// can try again.
setLoading(false)
// Use error returned by the server or fall back to the generic message
binding.domainTextInputLayout.error =
result.errorMessage.ifBlank { getString(R.string.error_authorization_denied) }
Log.e(
TAG,
"%s %s".format(
getString(R.string.error_authorization_denied),
result.errorMessage
)
)
}
is LoginResult.Cancel -> {
setLoading(false)
}
is LoginResult.Err -> displayError(result.errorMessage)
is LoginResult.Cancel -> setLoading(false)
}
}
@ -114,7 +100,7 @@ class LoginActivity : BaseActivity(), Injectable {
getString(R.string.preferences_file_key), Context.MODE_PRIVATE
)
binding.loginButton.setOnClickListener { onButtonClick() }
binding.loginButton.setOnClickListener { onLoginClick(true) }
binding.whatsAnInstanceTextView.setOnClickListener {
val dialog = AlertDialog.Builder(this)
@ -125,13 +111,9 @@ class LoginActivity : BaseActivity(), Injectable {
textView?.movementMethod = LinkMovementMethod.getInstance()
}
if (isAdditionalLogin() || isAccountMigration()) {
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
} else {
binding.toolbar.visibility = View.GONE
}
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(isAdditionalLogin() || isAccountMigration())
supportActionBar?.setDisplayShowTitleEnabled(false)
}
override fun requiresLogin(): Boolean {
@ -145,12 +127,23 @@ class LoginActivity : BaseActivity(), Injectable {
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menu?.add(R.string.action_browser_login)?.apply {
setOnMenuItemClickListener {
onLoginClick(false)
true
}
}
return super.onCreateOptionsMenu(menu)
}
/**
* 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
* saved in SharedPreferences and every subsequent run they are simply fetched from there.
*/
private fun onButtonClick() {
private fun onLoginClick(openInWebView: Boolean) {
binding.loginButton.isEnabled = false
binding.domainTextInputLayout.error = null
@ -183,7 +176,7 @@ class LoginActivity : BaseActivity(), Injectable {
.putString(CLIENT_SECRET, credentials.clientSecret)
.apply()
redirectUserToAuthorizeAndLogin(domain, credentials.clientId)
redirectUserToAuthorizeAndLogin(domain, credentials.clientId, openInWebView)
},
{ e ->
binding.loginButton.isEnabled = true
@ -197,10 +190,10 @@ class LoginActivity : BaseActivity(), Injectable {
}
}
private fun redirectUserToAuthorizeAndLogin(domain: String, clientId: String) {
private fun redirectUserToAuthorizeAndLogin(domain: String, clientId: String, openInWebView: Boolean) {
// To authorize this app and log in it's necessary to redirect to the domain given,
// login there, and the server will redirect back to the app with its response.
val url = HttpUrl.Builder()
val uri = HttpUrl.Builder()
.scheme("https")
.host(domain)
.addPathSegments(MastodonApi.ENDPOINT_AUTHORIZE)
@ -209,13 +202,59 @@ class LoginActivity : BaseActivity(), Injectable {
.addQueryParameter("response_type", "code")
.addQueryParameter("scope", OAUTH_SCOPES)
.build()
doWebViewAuth.launch(LoginData(domain, url.toString().toUri(), oauthRedirectUri.toUri()))
.toString()
.toUri()
if (openInWebView) {
doWebViewAuth.launch(LoginData(domain, uri, oauthRedirectUri.toUri()))
} else {
openLinkInCustomTab(uri, this)
}
}
override fun onStart() {
super.onStart()
// first show or user cancelled login
/* Check if we are resuming during authorization by seeing if the intent contains the
* redirect that was given to the server. If so, its response is here! */
val uri = intent.data
if (uri?.toString()?.startsWith(oauthRedirectUri) == true) {
// This should either have returned an authorization code or an error.
val code = uri.getQueryParameter("code")
val error = uri.getQueryParameter("error")
/* restore variables from SharedPreferences */
val domain = preferences.getNonNullString(DOMAIN, "")
val clientId = preferences.getNonNullString(CLIENT_ID, "")
val clientSecret = preferences.getNonNullString(CLIENT_SECRET, "")
if (code != null && domain.isNotEmpty() && clientId.isNotEmpty() && clientSecret.isNotEmpty()) {
lifecycleScope.launch {
fetchOauthToken(code)
}
} else {
displayError(error)
}
} else {
// first show or user cancelled login
setLoading(false)
}
}
private fun displayError(error: String?) {
// Authorization failed. Put the error response where the user can read it and they
// can try again.
setLoading(false)
binding.domainTextInputLayout.error = if (error == null) {
// This case means a junk response was received somehow.
getString(R.string.error_authorization_unknown)
} else {
// Use error returned by the server or fall back to the generic message
Log.e(TAG, "%s %s".format(getString(R.string.error_authorization_denied), error))
error.ifBlank { getString(R.string.error_authorization_denied) }
}
}
private suspend fun fetchOauthToken(code: String) {

View File

@ -36,7 +36,6 @@ import com.keylesspalace.tusky.util.CryptoUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.unifiedpush.android.connector.UnifiedPush
import retrofit2.HttpException
private const val TAG = "PushNotificationHelper"
@ -210,10 +209,8 @@ suspend fun updateUnifiedPushSubscription(context: Context, api: MastodonApi, ac
suspend fun unregisterUnifiedPushEndpoint(api: MastodonApi, accountManager: AccountManager, account: AccountEntity) {
withContext(Dispatchers.IO) {
api.unsubscribePushNotifications("Bearer ${account.accessToken}", account.domain)
.onFailure {
Log.d(TAG, "Error unregistering push endpoint for account " + account.id)
Log.d(TAG, Log.getStackTraceString(it))
Log.d(TAG, (it as HttpException).response().toString())
.onFailure { throwable ->
Log.w(TAG, "Error unregistering push endpoint for account " + account.id, throwable)
}
.onSuccess {
Log.d(TAG, "UnifiedPush unregistration succeeded for account " + account.id)

View File

@ -31,7 +31,7 @@ import java.io.File;
*/
@Database(entities = { DraftEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class,
TimelineAccountEntity.class, ConversationEntity.class
}, version = 46)
}, version = 47)
public abstract class AppDatabase extends RoomDatabase {
public abstract AccountDao accountDao();
@ -640,4 +640,11 @@ public abstract class AppDatabase extends RoomDatabase {
database.execSQL("ALTER TABLE `DraftEntity` ADD COLUMN `statusId` TEXT");
}
};
public static final Migration MIGRATION_46_47 = new Migration(46, 47) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE `DraftEntity` ADD COLUMN `failedToSendNew` INTEGER NOT NULL DEFAULT 0");
}
};
}

View File

@ -15,6 +15,7 @@
package com.keylesspalace.tusky.db
import androidx.lifecycle.LiveData
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Insert
@ -30,6 +31,12 @@ interface DraftDao {
@Query("SELECT * FROM DraftEntity WHERE accountId = :accountId ORDER BY id ASC")
fun draftsPagingSource(accountId: Long): PagingSource<Int, DraftEntity>
@Query("SELECT COUNT(*) FROM DraftEntity WHERE accountId = :accountId AND failedToSendNew = 1")
fun draftsNeedUserAlert(accountId: Long): LiveData<Int>
@Query("UPDATE DraftEntity SET failedToSendNew = 0 WHERE accountId = :accountId AND failedToSendNew = 1")
suspend fun draftsClearNeedUserAlert(accountId: Long)
@Query("SELECT * FROM DraftEntity WHERE accountId = :accountId")
suspend fun loadDrafts(accountId: Long): List<DraftEntity>

View File

@ -40,6 +40,7 @@ data class DraftEntity(
val attachments: List<DraftAttachment>,
val poll: NewPoll?,
val failedToSend: Boolean,
val failedToSendNew: Boolean,
val scheduledAt: String?,
val language: String?,
val statusId: String?,

View File

@ -0,0 +1,99 @@
/* Copyright 2023 Andi McClure
*
* 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.db
import android.content.Context
import android.content.DialogInterface
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.drafts.DraftsActivity
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
/**
* This class manages an alert popup when a post has failed and been saved to drafts.
* It must be separately registered in each lifetime in which it is to appear,
* and it only appears if the post failure belongs to the current user.
*/
private const val TAG = "DraftsAlert"
@Singleton
class DraftsAlert @Inject constructor(db: AppDatabase) {
// For tracking when a media upload fails in the service
private val draftDao: DraftDao = db.draftDao()
@Inject
lateinit var accountManager: AccountManager
public fun <T> observeInContext(context: T, showAlert: Boolean) where T : Context, T : LifecycleOwner {
accountManager.activeAccount?.let { activeAccount ->
val coroutineScope = context.lifecycleScope
// Assume a single MainActivity, AccountActivity or DraftsActivity never sees more then one user id in its lifetime.
val activeAccountId = activeAccount.id
// This LiveData will be automatically disposed when the activity is destroyed.
val draftsNeedUserAlert = draftDao.draftsNeedUserAlert(activeAccountId)
// observe ensures that this gets called at the most appropriate moment wrt the context lifecycle—
// at init, at next onResume, or immediately if the context is resumed already.
if (showAlert) {
draftsNeedUserAlert.observe(context) { count ->
Log.d(TAG, "User id $activeAccountId changed: Notification-worthy draft count $count")
if (count > 0) {
AlertDialog.Builder(context)
.setTitle(R.string.action_post_failed)
.setMessage(
context.getResources().getQuantityString(R.plurals.action_post_failed_detail, count)
)
.setPositiveButton(R.string.action_post_failed_show_drafts) { _: DialogInterface?, _: Int ->
clearDraftsAlert(coroutineScope, activeAccountId) // User looked at drafts
val intent = DraftsActivity.newIntent(context)
context.startActivity(intent)
}
.setNegativeButton(R.string.action_post_failed_do_nothing) { _: DialogInterface?, _: Int ->
clearDraftsAlert(coroutineScope, activeAccountId) // User doesn't care
}
.show()
}
}
} else {
draftsNeedUserAlert.observe(context) { _ ->
Log.d(TAG, "User id $activeAccountId: Clean out notification-worthy drafts")
clearDraftsAlert(coroutineScope, activeAccountId)
}
}
} ?: run {
Log.w(TAG, "Attempted to observe drafts, but there is no active account")
}
}
/**
* Clear drafts alert for specified user
*/
fun clearDraftsAlert(coroutineScope: LifecycleCoroutineScope, id: Long) {
coroutineScope.launch {
draftDao.draftsClearNeedUserAlert(id)
}
}
}

View File

@ -73,7 +73,8 @@ rb.emojis as 'rb_emojis', rb.bot as 'rb_bot'
FROM TimelineStatusEntity s
LEFT JOIN TimelineAccountEntity a ON (s.timelineUserId = a.timelineUserId AND s.authorServerId = a.serverId)
LEFT JOIN TimelineAccountEntity rb ON (s.timelineUserId = rb.timelineUserId AND s.reblogAccountId = rb.serverId)
WHERE s.serverId = :statusId OR s.reblogServerId = :statusId"""
WHERE (s.serverId = :statusId OR s.reblogServerId = :statusId)
AND s.authorServerId IS NOT NULL"""
)
abstract suspend fun getStatus(statusId: String): TimelineStatusWithAccount?

View File

@ -73,7 +73,7 @@ class AppModule {
AppDatabase.MIGRATION_35_36, AppDatabase.MIGRATION_36_37, AppDatabase.MIGRATION_37_38,
AppDatabase.MIGRATION_38_39, AppDatabase.MIGRATION_39_40, AppDatabase.MIGRATION_40_41,
AppDatabase.MIGRATION_41_42, AppDatabase.MIGRATION_42_43, AppDatabase.MIGRATION_43_44,
AppDatabase.MIGRATION_44_45, AppDatabase.MIGRATION_45_46,
AppDatabase.MIGRATION_44_45, AppDatabase.MIGRATION_45_46, AppDatabase.MIGRATION_46_47
)
.build()
}

View File

@ -98,6 +98,9 @@ class ViewVideoFragment : ViewMediaFragment() {
binding.mediaDescription.visible(showingDescription)
binding.mediaDescription.movementMethod = ScrollingMovementMethod()
// Ensure the description is visible over the video
binding.mediaDescription.elevation = binding.videoView.elevation + 1
binding.videoView.transitionName = url
binding.videoView.setVideoPath(url)
mediaController = object : MediaController(mediaActivity) {

View File

@ -266,7 +266,7 @@ class SendStatusService : Service(), Injectable {
mediaUploader.cancelUploadScope(*failedStatus.media.map { it.localId }.toIntArray())
saveStatusToDrafts(failedStatus)
saveStatusToDrafts(failedStatus, failedToSendAlert = true)
val notification = buildDraftNotification(
R.string.send_post_notification_error_title,
@ -289,7 +289,7 @@ class SendStatusService : Service(), Injectable {
val sendJob = sendJobs.remove(statusId)
sendJob?.cancel()
saveStatusToDrafts(statusToCancel)
saveStatusToDrafts(statusToCancel, failedToSendAlert = false)
val notification = buildDraftNotification(
R.string.send_post_notification_cancel_title,
@ -306,7 +306,7 @@ class SendStatusService : Service(), Injectable {
}
}
private suspend fun saveStatusToDrafts(status: StatusToSend) {
private suspend fun saveStatusToDrafts(status: StatusToSend, failedToSendAlert: Boolean) {
draftHelper.saveDraft(
draftId = status.draftId,
accountId = status.accountId,
@ -320,6 +320,7 @@ class SendStatusService : Service(), Injectable {
mediaFocus = status.media.map { it.focus },
poll = status.poll,
failedToSend = true,
failedToSendAlert = failedToSendAlert,
scheduledAt = status.scheduledAt,
language = status.language,
statusId = status.statusId,

View File

@ -252,7 +252,7 @@ private fun openLinkInBrowser(uri: Uri?, context: Context) {
* @param uri the uri to open
* @param context context
*/
private fun openLinkInCustomTab(uri: Uri, context: Context) {
fun openLinkInCustomTab(uri: Uri, context: Context) {
val toolbarColor = MaterialColors.getColor(context, R.attr.colorSurface, Color.BLACK)
val navigationbarColor = MaterialColors.getColor(context, android.R.attr.navigationBarColor, Color.BLACK)
val navigationbarDividerColor = MaterialColors.getColor(context, R.attr.dividerColor, Color.BLACK)

View File

@ -3,11 +3,11 @@
<string name="error_generic">Bu gwall.</string>
<string name="error_empty">Ni all hwn fod yn wag.</string>
<string name="error_invalid_domain">Rhoddwyd parth annilys</string>
<string name="error_failed_app_registration">Methu awdurdodi gyda\'r gweinydd hwnnw.</string>
<string name="error_failed_app_registration">Methu awdurdodi gyda\'r gweinydd hwnnw. Os bydd hyn yn parhau, ceisiwch Mewngofnodi yn Porwr o\'r ddewislen.</string>
<string name="error_no_web_browser_found">Methu dod o hyd i borwr gwe i\'w ddefnyddio.</string>
<string name="error_authorization_unknown">Bu gwall awdurdodi anhysbys.</string>
<string name="error_authorization_denied">Gwrthodwyd awdurdodi.</string>
<string name="error_retrieving_oauth_token">Methu cael tocyn mewngofnodi.</string>
<string name="error_authorization_unknown">Bu gwall awdurdodi anhysbys. Os bydd hyn yn parhau, ceisiwch Mewngofnodi yn Porwr o\'r ddewislen.</string>
<string name="error_authorization_denied">Gwrthodwyd awdurdodi. Os ydych chi\'n siŵr dy fod di wedi gyflenwi\'r manylion cywir, ceisiwch Mewngofnodi yn Porwr o\'r ddewislen.</string>
<string name="error_retrieving_oauth_token">Methu cael tocyn mewngofnodi. Os bydd hyn yn parhau, ceisiwch Mewngofnodi yn Porwr o\'r ddewislen.</string>
<string name="error_compose_character_limit">Mae\'ch neges yn rhy hir!</string>
<string name="error_media_upload_type">Ni allwch lwytho\'r math hwnnw o ffeil.</string>
<string name="error_media_upload_opening">Nid oedd modd agor y ffeil honno.</string>
@ -52,7 +52,7 @@
<string name="action_favourite">Ffefryn</string>
<string name="action_more">Mwy</string>
<string name="action_compose">Creu</string>
<string name="action_login">Mewngofnodi â Mastodon</string>
<string name="action_login">Mewngofnodi â Thusky</string>
<string name="action_logout">Allgofnodi</string>
<string name="action_logout_confirm">Ydych chi\'n siŵr eich bod am allgofnodi o\'r cyfrif %1$s?</string>
<string name="action_follow">Dilyn</string>
@ -487,7 +487,7 @@
<string name="notification_header_report_format">Adroddodd %s %s</string>
<string name="notification_summary_report_format">%s · %d post wedi\'u hatodi</string>
<string name="pref_title_notification_filter_reports">mae yna adroddiad newydd</string>
<string name="report_category_violation">Torri rheolau</string>
<string name="report_category_violation">Toriad rheol</string>
<string name="report_category_spam">Sbam</string>
<string name="failed_to_pin">Wedi methu pinio</string>
<string name="failed_to_unpin">Wedi methu dadbinio</string>
@ -657,4 +657,13 @@
<string name="send_account_link_to">Rhannu URL cyfrif i…</string>
<string name="send_account_username_to">Rhannu enw denyddiwr cyfrif i…</string>
<string name="account_username_copied">Enw defnyddiwr wedi\'i gopïo</string>
<string name="pref_reading_order_oldest_first">Hynaf yn gyntaf</string>
<string name="pref_reading_order_newest_first">Diweddaraf yn gyntaf</string>
<string name="pref_title_reading_order">Trefn darllen</string>
<string name="pref_summary_http_proxy_disabled">Analluogwyd</string>
<string name="pref_summary_http_proxy_missing">&lt;heb ei osod&gt;</string>
<string name="pref_summary_http_proxy_invalid">&lt;annilys&gt;</string>
<string name="action_browser_login">Mewngofnodi â phorwr</string>
<string name="description_login">Yn gweithio yn y rhan mwyaf o achosion. Nid oes unrhyw ddata yn cael ei ollwng i apiau eraill.</string>
<string name="description_browser_login">Gall gefnogi dulliau dilysu ychwanegol, ond mae angen porwr a gefnogir.</string>
</resources>

View File

@ -3,11 +3,11 @@
<string name="error_generic">Errorea gertatu da.</string>
<string name="error_empty">Eremu hau ezin da hutsik egon.</string>
<string name="error_invalid_domain">Domeinu baliogabea sartu da</string>
<string name="error_failed_app_registration">Akatsa saioa hasterakoan.</string>
<string name="error_failed_app_registration">Akatsa instantzia horrekin autentikatzerakoan. Akatsak badarrai, menutik, nabigatzailean saioa hasteko aukerarekin saiatu.</string>
<string name="error_no_web_browser_found">Ez da web nabigatzailerik aurkitu.</string>
<string name="error_authorization_unknown">Identifikatu gabeko baimentza akatsa gertatu da.</string>
<string name="error_authorization_denied">Akatsa baimentzerakoan.</string>
<string name="error_retrieving_oauth_token">Akatsa login identifikatzailea lortzerakoan.</string>
<string name="error_authorization_unknown">Identifikatu gabeko baimen-akatsa gertatu da. Akatsak badarrai, menutik, nabigatzailean saioa hasteko aukerarekin saiatu.</string>
<string name="error_authorization_denied">Baimena ukatu da. Ziur bazaude zuk sartutako egiaztagiriak zuzenak direla, menutik, nabigatzailean saioa hasteko aukerarekin saiatu.</string>
<string name="error_retrieving_oauth_token">Akatsa saio-hasieraren identifikatzailea eskuratzerakoan. Akatsak badarrai, menutik, nabigatzailean saioa hasteko aukerarekin saiatu.</string>
<string name="error_compose_character_limit">Tut luzeegia!</string>
<string name="error_media_upload_type">Ez da fitxategi mota hau onartzen.</string>
<string name="error_media_upload_opening">Ezin izan da fitxategi hau ireki.</string>
@ -32,18 +32,18 @@
<string name="title_edit_profile">Profila editatu</string>
<string name="title_drafts">Zirriborroak</string>
<string name="title_licenses">Lizentziak</string>
<string name="post_boosted_format">%s(e)k bultzatu du</string>
<string name="post_sensitive_media_title">Kontuz edukiarekin</string>
<string name="post_media_hidden_title">Ezkutuko multimedia</string>
<string name="post_boosted_format">%s-(e)k bultzatu du</string>
<string name="post_sensitive_media_title">Eduki hunkigarria</string>
<string name="post_media_hidden_title">Ezkutuko media</string>
<string name="post_sensitive_media_directions">Sakatu ikusteko</string>
<string name="post_content_warning_show_more">Gehiago erakutsi </string>
<string name="post_content_warning_show_more">Gehiago erakutsi</string>
<string name="post_content_warning_show_less">Gutxiago erakutsi</string>
<string name="post_content_show_more">Zabaldu</string>
<string name="post_content_show_less">Bildu</string>
<string name="post_content_show_less">Itxi</string>
<string name="footer_empty">Edukirik ez. Arrastatu behera birkargatzeko!</string>
<string name="notification_reblog_format">%s(e)k zure tuta bultzatu du</string>
<string name="notification_favourite_format">%s(e)k zure tuta gogoko du</string>
<string name="notification_follow_format">%s(e)k jarraitu zaitu</string>
<string name="notification_follow_format">%s-(e)k jarraitu zaitu</string>
<string name="report_username_format">\@%s salatu</string>
<string name="report_comment_hint">Informazio gehigarria?</string>
<string name="action_quick_reply">Erantzun azkarra</string>
@ -97,7 +97,7 @@
<string name="action_emoji_keyboard">Emoji teklatua</string>
<string name="download_image">%1$s jaisten</string>
<string name="action_copy_link">Lotura kopiatu</string>
<string name="send_post_link_to">Tutaren URLa partekatu…</string>
<string name="send_post_link_to">Tutaren URL partekatu…</string>
<string name="send_post_content_to">Tuta partekatu…</string>
<string name="send_media_to">Partekatu media hona…</string>
<string name="confirmation_reported">Bidalia!</string>
@ -127,9 +127,9 @@
<string name="dialog_title_finishing_media_upload">Mediaren igoera bukatzen</string>
<string name="dialog_message_uploading_media">Igotzen…</string>
<string name="dialog_download_image">Jaitsi</string>
<string name="dialog_message_cancel_follow_request">Jarraipen-eskakizunari uko egin\?</string>
<string name="dialog_message_cancel_follow_request">Jarraipenaren eskakizunari uko egin\?</string>
<string name="dialog_unfollow_warning">Kontu hau jarraitzeari utzi\?</string>
<string name="dialog_delete_post_warning">Tuta ezabatu\?</string>
<string name="dialog_delete_post_warning">Tut hau ezabatu\?</string>
<string name="visibility_public">Publikoa: Istorio publikoetan erakutsi</string>
<string name="visibility_unlisted">Ezkutukoa: Ez erakutsi istorio publikoetan</string>
<string name="visibility_private">Pribatua: Jarraitzaileentzat soilik ikusgai</string>
@ -140,7 +140,7 @@
<string name="pref_title_notification_alert_sound">Soinuarekin jakinarazi</string>
<string name="pref_title_notification_alert_vibrate">Bibrazioarekin jakinarazi</string>
<string name="pref_title_notification_alert_light">Led-arekin jakinarazi</string>
<string name="pref_title_notification_filters">Jakinarazi noiz</string>
<string name="pref_title_notification_filters">Honen arabera jakinarazi</string>
<string name="pref_title_notification_filter_mentions">Aipatzen naute</string>
<string name="pref_title_notification_filter_follows">Jarraitzen didate</string>
<string name="pref_title_notification_filter_reblogs">Bultzatzen naute</string>
@ -154,8 +154,8 @@
<string name="app_theme_auto">Automatikoa</string>
<string name="pref_title_browser_settings">Nabigatzailea</string>
<string name="pref_title_custom_tabs">Chromeko fitxak erabili</string>
<string name="pref_title_hide_follow_button">Tut egiteko botoia ezkutatu beherantz joaterakoan</string>
<string name="pref_title_post_filter">Denbora-lerro filtroak</string>
<string name="pref_title_hide_follow_button">Tut berria idazteko botoia ezkutatu beherantz joan einean</string>
<string name="pref_title_post_filter">Denbora-lerroaren iragaztea</string>
<string name="pref_title_post_tabs">Fitxak</string>
<string name="pref_title_show_boosts">Bultzadak erakutsi</string>
<string name="pref_title_show_replies">Erakutsi erantzunak</string>
@ -172,10 +172,10 @@
<string name="post_privacy_public">Publiko</string>
<string name="post_privacy_unlisted">Zerrendagabetuta</string>
<string name="post_privacy_followers_only">Jarraitzaileak soilik</string>
<string name="pref_post_text_size">Status testuaren tamaina</string>
<string name="post_text_size_smallest">Oso txikia</string>
<string name="pref_post_text_size">Tutaren testuaren tamaina</string>
<string name="post_text_size_smallest">Txikiena</string>
<string name="post_text_size_small">Txikia</string>
<string name="post_text_size_medium">Erdikoa</string>
<string name="post_text_size_medium">Ertaina</string>
<string name="post_text_size_large">Handia</string>
<string name="post_text_size_largest">Handiena</string>
<string name="notification_mention_name">Aipamen berriak</string>
@ -186,7 +186,7 @@
<string name="notification_boost_description">Bultzatutako tuten jakinarazpenak</string>
<string name="notification_favourite_name">Gogokoak</string>
<string name="notification_favourite_description">Zure tutak gogoko bezala ezartzerakoan jakinarazpenak</string>
<string name="notification_mention_format">%s(e)k aipatu zaitu</string>
<string name="notification_mention_format">%s-(e)k aipatu zaitu</string>
<string name="notification_summary_large">%1$s, %2$s, %3$s eta beste %4$d</string>
<string name="notification_summary_medium">%1$s, %2$s eta %3$s</string>
<string name="notification_summary_small">%1$s eta %2$s</string>
@ -211,10 +211,10 @@
<string name="about_bug_feature_request_site">Akatsen berri-emateak eta hobekuntza-eskariak:
\n https://github.com/accelforce/Yuito/issues</string>
<string name="about_tusky_account">Yuitoren profila</string>
<string name="post_share_content">Partekatu tutaren edukia</string>
<string name="post_share_link">Partekatu tutaren lotura</string>
<string name="post_share_content">Tutaren edukia partekatu</string>
<string name="post_share_link">Tutaren esteka partekatu</string>
<string name="post_media_images">Irudiak</string>
<string name="post_media_video">Bideoak</string>
<string name="post_media_video">Bideoa</string>
<string name="state_follow_requested">Eskaera bidalita</string>
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
<string name="abbreviated_in_years">%du-an</string>
@ -244,18 +244,18 @@
<string name="lock_account_label_description">Jarraitzaileak eskuz onartu beharko dituzu</string>
<string name="compose_save_draft">Zirriborroa gorde?</string>
<string name="send_post_notification_title">Tuta bidaltzen…</string>
<string name="send_post_notification_error_title">Errorea tuta bidaltzerakoan</string>
<string name="send_post_notification_error_title">Errorea tuta bidaltzean</string>
<string name="send_post_notification_channel_name">Tuta bidaltzen</string>
<string name="send_post_notification_cancel_title">Bidalketa ezeztatua</string>
<string name="send_post_notification_saved_content">Tutaren kopia zirriborroetan sartu da</string>
<string name="send_post_notification_cancel_title">Bidalketa bertan behera utzita</string>
<string name="send_post_notification_saved_content">Tutaren kopia bat zure zirriborroetan gorde da</string>
<string name="action_compose_shortcut">Idatzi</string>
<string name="error_no_custom_emojis">%s instantziak ez ditu emoji pertsonalizatuak eskaintzen</string>
<string name="emoji_style">Emojien estiloa</string>
<string name="system_default">Sistema</string>
<string name="download_fonts">Lehenago jaitsi beharko dituzu</string>
<string name="performing_lookup_title">Bilatzen…</string>
<string name="expand_collapse_all_posts">Tut guztiak ezkutatu/zabaldu</string>
<string name="action_open_post">Ireki</string>
<string name="expand_collapse_all_posts">Tut guztiak zabaldu/itxi</string>
<string name="action_open_post">Tuta ireki</string>
<string name="restart_required">Berrabiaraztea beharrezkoa da</string>
<string name="restart_emoji">Aplikazioa berrabiarazi beharko duzu aldaketa ezartzeko</string>
<string name="later">Beranduago</string>
@ -281,7 +281,7 @@
<string name="error_network">Sareko errore bat sortu da! Zure konexioa ziurta ezazu berriro, mesedez!</string>
<string name="title_direct_messages">Mezu Zuzenak</string>
<string name="title_tab_preferences">Fitxak</string>
<string name="title_posts_pinned">Lotuta</string>
<string name="title_posts_pinned">Finkatua</string>
<string name="title_domain_mutes">Ezkutuko domeinuak</string>
<string name="title_scheduled_posts">Programatutako tutak</string>
<string name="post_username_format">\@%s</string>
@ -310,7 +310,7 @@
<string name="downloading_media">Media jaisten</string>
<string name="confirmation_domain_unmuted">%s ez dago ezkutatua</string>
<string name="dialog_redraft_post_warning">Tut hau ezabatu eta zirriborro berria egin\?</string>
<string name="mute_domain_warning">Ziur al zaude %s ezabatu nahi duzula\? Domeinu horretatik datorren edukia ez duzu denbora-lerro publikoetan edo jakinarazpenetan ikusiko. Domeinu horretan dituzun jarraitzaileak ezabatuko dira.</string>
<string name="mute_domain_warning">Ziur al zaude %s-(r)en eduki guztia ezabatu nahi duzula\? Domeinu horretatik datorren edukia ez duzu denbora-lerro publikoetan edo jakinarazpenetan ikusiko. Domeinu horretan dituzun jarraitzaileak ezabatuko dira.</string>
<string name="mute_domain_warning_dialog_ok">Domeinu osoa ezkutatu</string>
<string name="pref_title_notification_filter_poll">Galdeketak bukatu dira</string>
<string name="pref_title_timeline_filters">Iragazkiak</string>
@ -367,12 +367,12 @@
<item quantity="other">gehienezko %1$d fitxa iritsita</item>
</plurals>
<string name="description_post_media">Media: %s</string>
<string name="description_post_cw">Edukiaren abisua: %s</string>
<string name="description_post_cw">Edukiarekiko abisua: %s</string>
<string name="description_post_media_no_description_placeholder">Deskribapenik ez</string>
<string name="description_post_reblogged">Birblogeatuta</string>
<string name="description_post_favourited">Gogotuta</string>
<string name="description_visibility_public">Publiko</string>
<string name="description_visibility_unlisted">Zerrendagabetuta</string>
<string name="description_post_reblogged">Partekatua</string>
<string name="description_post_favourited">Gogokoa</string>
<string name="description_visibility_public">Publikoa</string>
<string name="description_visibility_unlisted">Zerrendatu gabea</string>
<string name="description_visibility_private">Jarraitzaileak</string>
<string name="description_visibility_direct">Zuzena</string>
<string name="description_poll">Inkestatu aukerekin: %1$s, %2$s, %3$s, %4$s; %5$s</string>
@ -414,7 +414,7 @@
<string name="hint_additional_info">Iruzkin gehigarriak</string>
<string name="report_remote_instance">%s(r)i birbidali</string>
<string name="failed_report">Txostena huts egin du</string>
<string name="failed_fetch_posts">Egoeren eskuratzea huts egin du</string>
<string name="failed_fetch_posts">Akatsa tutak eskuratzean</string>
<string name="report_description_1">Txostena zure zerbitzariaren moderatzaileari bidaliko zaio. Jarraian, kontu honen zergatia salatzen duzun azalpena eman dezakezu:</string>
<string name="report_description_remote_instance">Kontua beste zerbitzari batekoa da. Bidali txostenaren kopia anonimatua hara ere\?</string>
<string name="title_accounts">Kontuak</string>
@ -438,7 +438,7 @@
<string name="action_view_bookmarks">Laster-markak</string>
<string name="action_open_reblogger">Ireki bultzadaren egilea</string>
<string name="pref_title_public_filter_keywords">Denbora lerro publikoak</string>
<string name="description_post_bookmarked">Laster-markatuta</string>
<string name="description_post_bookmarked">Laster-marketara gehitua</string>
<string name="select_list_title">Aukeratu zerrenda</string>
<string name="list">Zerrenda</string>
<string name="no_drafts">Ez duzu zirriborrorik.</string>
@ -448,8 +448,8 @@
<string name="notification_follow_request_description">Jarraitzeko eskaereri buruzko jakinarazpenak</string>
<string name="dialog_mute_warning">\@%s isildu\?</string>
<string name="dialog_block_warning">\@%s blokeatu\?</string>
<string name="action_mute_conversation">Mututu elkarrizketa</string>
<string name="notification_follow_request_format">%s(e)k zu jarraitzeko eskatu dizu</string>
<string name="action_mute_conversation">Elkarrizketa mututu</string>
<string name="notification_follow_request_format">%s-(e)k zu jarraitzeko eskatu zaitu</string>
<string name="hashtags">Traolak</string>
<string name="dialog_mute_hide_notifications">Jakinarazpenak ezkutatu</string>
<string name="action_unmute_desc">Desmututu %s</string>
@ -461,13 +461,13 @@
<item quantity="one">Minutu %d faltan</item>
<item quantity="other">%d minutu faltan</item>
</plurals>
<string name="add_hashtag_title">Gehitu traola</string>
<string name="pref_main_nav_position_option_bottom">Azpia</string>
<string name="pref_main_nav_position_option_top">Goia</string>
<string name="pref_main_nav_position">Nabigatze posizio nagusia</string>
<string name="pref_title_gradient_for_media">Erakutsi gradiente koloretsua ezkutuko mediarentzako</string>
<string name="pref_title_notification_filter_follow_requests">jarraipen-eskaera</string>
<string name="action_unmute_conversation">Desmututu elkarrizketa</string>
<string name="add_hashtag_title">Traola gehitu</string>
<string name="pref_main_nav_position_option_bottom">Beheran</string>
<string name="pref_main_nav_position_option_top">Goian</string>
<string name="pref_main_nav_position">Nabigazio nagusiaren posizioa</string>
<string name="pref_title_gradient_for_media">Gradiente koloretsuak erakutsi ezkutuko mediaren lekuan</string>
<string name="pref_title_notification_filter_follow_requests">jarraitzeko eskaera jasotzean</string>
<string name="action_unmute_conversation">Elkarrizketa desmututu</string>
<string name="action_unmute_domain">Desmututu %s</string>
<string name="review_notifications">Jakinarazpenak berrikusi</string>
<string name="pref_title_confirm_favourites">Erakutsi baieztapen elkarrizketa-koadroa gogokoenetara gehitu aurretik</string>
@ -514,4 +514,13 @@
\nPush-jakinarazpenek ez dute eraginik izango, baina jakinarazpenen hobespenak eskuz berrikus ditzakezu.</string>
<string name="wellbeing_hide_stats_posts">Mezuetan estatistika kuantitatiboak ezkutatu</string>
<string name="action_unbookmark">Laster-marka kendu</string>
<string name="error_image_edit_failed">Ezin izan da irudia editatu.</string>
<string name="error_multimedia_size_limit">Bideo eta audio fitxategiek ezin dute %s MBeko tamaina baino handiagoa izan.</string>
<string name="error_muting_hashtag_format">Akatsa #%s mututzerakoan</string>
<string name="error_unmuting_hashtag_format">Errorea #%s desmututzerakoan</string>
<string name="error_following_hashtags_unsupported">Instantzia honek traolak jarraitzeko funtzioarekin bateragarritasuna ez dauka.</string>
<string name="error_following_hashtag_format">Akatsa #%s jarraitzerakoan</string>
<string name="error_unfollowing_hashtag_format">Akatsa #%s jarraitzerakoan</string>
<string name="error_could_not_load_login_page">Ezin izan da saio-hasierako orria kargatu.</string>
<string name="error_loading_account_details">Akatsa kontuaren xehetasunak kargatzerakoan</string>
</resources>

View File

@ -3,11 +3,11 @@
<string name="error_generic">エラーが発生しました。</string>
<string name="error_empty">本文なしでは投稿できません。</string>
<string name="error_invalid_domain">無効なドメインです</string>
<string name="error_failed_app_registration">そのインスタンスでの認証に失敗しました。</string>
<string name="error_failed_app_registration">そのインスタンスでの認証に失敗しました。失敗が続く場合、メニューからブラウザでのログインを試してください。</string>
<string name="error_no_web_browser_found">ウェブブラウザが見つかりませんでした。</string>
<string name="error_authorization_unknown">不明な承認エラーが発生しました。</string>
<string name="error_authorization_denied">認が拒否されました。</string>
<string name="error_retrieving_oauth_token">ログイントークンの取得に失敗しました。</string>
<string name="error_authorization_unknown">不明な承認エラーが発生しました。失敗が続く場合、メニューからブラウザでのログインを試してください。</string>
<string name="error_authorization_denied">が拒否されました。正しい認証情報を入力したことが確かな場合、メニューからブラウザでのログインを試してください</string>
<string name="error_retrieving_oauth_token">ログイントークンの取得に失敗しました。もし失敗が続く場合、メニューからブラウザでのログインを試してください。</string>
<string name="error_compose_character_limit">投稿文が長すぎます!</string>
<string name="error_media_upload_type">その形式のファイルはアップロードできません。</string>
<string name="error_media_upload_opening">ファイルを開けませんでした。</string>
@ -58,7 +58,7 @@
<string name="action_quote">引用</string>
<string name="action_more">その他</string>
<string name="action_compose">投稿する</string>
<string name="action_login">Mastodonでログイン</string>
<string name="action_login">TUsky でログイン</string>
<string name="action_logout">ログアウト</string>
<string name="action_logout_confirm">アカウント %1$s からログアウトしてもよろしいですか?</string>
<string name="action_follow">フォローする</string>
@ -592,4 +592,37 @@
<string name="send_account_username_to">アカウントのユーザー名を共有…</string>
<string name="account_username_copied">ユーザー名がコピーされました</string>
<string name="pref_title_use_quick_toot">簡易投稿欄を表示</string>
<string name="a11y_label_loading_thread">スレッドの読み込み中</string>
<string name="pref_reading_order_newest_first">新しい順</string>
<string name="pref_title_reading_order">読む順番</string>
<string name="pref_reading_order_oldest_first">古い順</string>
<string name="set_focus_description">サムネイル画像で常に表示される中心点を設定するには、円をタップまたはドラッグして中してくだだい。</string>
<string name="mute_notifications_switch">通知のミュート</string>
<string name="account_date_joined">%1$s に参加</string>
<string name="status_edit_info">%1$s 編集 %2$s</string>
<string name="status_created_info">%1$s の投稿 %2$s</string>
<string name="post_lookup_error_format">投稿 %s の検索エラー</string>
<string name="error_failed_set_focus">中心点の設定に失敗しました</string>
<string name="follow_requests_info">アカウントがロックされていなかったとしても、%1$s のスタッフは以下のアカウントのフォローリクエストを確認した方がいいと判断しました。</string>
<string name="action_set_focus">中心点の設定</string>
<string name="compose_unsaved_changes">保存していない変更があります。</string>
<string name="error_status_source_load">サーバーからステータスの元情報を取得できませんでした。</string>
<string name="pref_summary_http_proxy_disabled">無効</string>
<string name="pref_summary_http_proxy_missing">&lt;設定なし&gt;</string>
<string name="pref_summary_http_proxy_invalid">&lt;無効&gt;</string>
<string name="pref_title_notification_filter_updates">やり取りした投稿が編集された時</string>
<string name="notification_update_description">やり取りした投稿が編集されたときの通知</string>
<string name="pref_title_http_proxy_port_message">ポートは %d から %d の間でなければなりません</string>
<string name="action_post_failed">アップロードに失敗しました</string>
<string name="action_post_failed_detail">アップロードに失敗した投稿は下書きに保存されました。
\n
\nサーバーと接続できなかったか、投稿が拒否されました。</string>
<string name="action_post_failed_show_drafts">下書きを表示</string>
<string name="action_post_failed_do_nothing">閉じる</string>
<string name="action_browser_login">ブラウザでログイン</string>
<string name="description_login">ほとんどの場合に動作します。他のアプリにはデータが漏洩しません。</string>
<string name="description_browser_login">追加の認証方法がサポートされる可能性がありますが、対応ブラウザが必要です。</string>
<string name="action_post_failed_detail_plural">アップロードに失敗した投稿は下書きに保存されました。
\n
\nサーバーと接続できなかったか、投稿が拒否されました。</string>
</resources>

View File

@ -440,4 +440,62 @@
<string name="wellbeing_hide_stats_profile">Slēpt profilu kvantitatīvo statistiku</string>
<string name="wellbeing_hide_stats_posts">Slēpt ierakstu kvantitatīvo statistiku</string>
<string name="drafts_failed_loading_reply">Neizdevās ielādēt atbildes informāciju</string>
<string name="action_delete_and_redraft">Dzēst un sākt no jauna</string>
<string name="action_dismiss">Aizvākt</string>
<string name="dialog_message_cancel_follow_request">Vai atcelt sekošanas pieprasījumu\?</string>
<string name="dialog_redraft_post_warning">Vai dzēst šo ierakstu un sākt no jauna\?</string>
<string name="about_powered_by_tusky">Darbību nodrošina Tusky</string>
<string name="hint_search_people_list">Meklēt personas, kurām seko</string>
<string name="send_post_notification_error_title">Sūtot ziņu, radās kļūda</string>
<string name="account_moved_description">%1$s ir pārcēlies uz:</string>
<string name="failed_to_pin">Piespraušana neizdevās</string>
<string name="failed_to_unpin">Atspraušana neizdevās</string>
<string name="post_share_content">Dalīties ar ieraksta saturu</string>
<string name="set_focus_description">Pieskaries vai velc apli, lai izvēlētos fokusa punktu, kas vienmēr būs redzams sīktēlos.</string>
<string name="expand_collapse_all_posts">Izplest/sakļaut visus ierakstus</string>
<string name="caption_twemoji">Mastodon standarta emocijzīmju komplekts</string>
<string name="caption_notoemoji">Google aktuālais emocijzīmju komplekts</string>
<string name="notification_report_description">Paziņojumi par moderēšanas ziņojumiem</string>
<string name="notification_mention_format">%s pieminēja tevi</string>
<string name="notification_summary_small">%1$s un %2$s</string>
<string name="notification_summary_medium">%1$s, %2$s un %3$s</string>
<string name="post_share_link">Dalīties ar saiti uz ierakstu</string>
<string name="error_failed_set_caption">Neizdevās pievienot parakstu</string>
<string name="error_failed_set_focus">Neizdevās iestatīt fokusa punktu</string>
<string name="pref_title_absolute_time">Izmantot absolūto laiku</string>
<string name="conversation_1_recipients">%1$s</string>
<string name="conversation_2_recipients">%1$s un %2$s</string>
<string name="description_post_cw">Satura brīdinājums: %s</string>
<string name="about_project_site">Projekta vietne:
\n https://tusky.app</string>
<string name="a11y_label_loading_thread">Ielādē pavedienu</string>
<string name="confirmation_hashtag_unfollowed">pārtraukta sekošana #%s</string>
<string name="confirmation_domain_unmuted">%s atcelta slēpšana</string>
<string name="error_create_list">Nevarēja izveidot sarakstu</string>
<string name="pref_title_reading_order">Lasīšanas secība</string>
<string name="filter_add_description">Filtrējamā frāze</string>
<string name="pref_summary_http_proxy_disabled">Atspējots</string>
<string name="pref_summary_http_proxy_missing">&lt;nav iestatīts&gt;</string>
<string name="pref_summary_http_proxy_invalid">&lt;nederīgs&gt;</string>
<string name="filter_expiration_format">%s (%s)</string>
<string name="add_account_description">Pievienot jaunu Mastodon kontu</string>
<string name="pref_title_animate_custom_emojis">Animēt pielāgotās emocijzīmes</string>
<string name="notification_sign_up_name">Jaunu dalībnieku reģistrācija</string>
<string name="pref_show_self_username_disambiguate">Kad pievienoti vairāki konti</string>
<string name="restart_required">Nepieciešama lietotnes restartēšana</string>
<string name="reblog_private">Pastiprināt sākotnējai auditorijai</string>
<string name="description_post_reblogged">Pastiprināts</string>
<string name="replying_to">Atbildot @%s</string>
<string name="lock_account_label_description">Prasa manuāli apstiprināt sekotājus</string>
<string name="title_reblogged_by">Pastiprināja</string>
<plurals name="reblogs">
<item quantity="zero"><b>%s</b> pastiprinājumi</item>
<item quantity="one"><b>%s</b> pastiprinājums</item>
<item quantity="other"><b>%s</b> pastiprinājumi</item>
</plurals>
<plurals name="max_tab_number_reached">
<item quantity="zero">sasniegts maksimālais ciļņu skaits %1$d</item>
<item quantity="one">sasniegts maksimālais ciļņu skaits %1$d</item>
<item quantity="other">sasniegts maksimālais ciļņu skaits %1$d</item>
</plurals>
</resources>

View File

@ -60,7 +60,7 @@
<string name="action_unfavourite">Favoriet verwijderen</string>
<string name="action_more">Meer</string>
<string name="action_compose">Bericht schrijven</string>
<string name="action_login">Aanmelden</string>
<string name="action_login">Aanmelden met Mastodon</string>
<string name="action_logout">Afmelden</string>
<string name="action_logout_confirm">Ben je er zeker van dat je het account %1$s wil afmelden?</string>
<string name="action_follow">Volgen</string>
@ -328,14 +328,10 @@
<string name="description_post_media_no_description_placeholder">Geen omschrijving</string>
<string name="description_post_reblogged">Geboost</string>
<string name="description_post_favourited">Als favoriet gemarkeerd</string>
<string name="description_visibility_public"> Openbaar
</string>
<string name="description_visibility_unlisted"> Minder openbaar
</string>
<string name="description_visibility_private"> Volgers
</string>
<string name="description_visibility_direct"> Direct
</string>
<string name="description_visibility_public">Openbaar</string>
<string name="description_visibility_unlisted">Minder openbaar</string>
<string name="description_visibility_private">Volgers</string>
<string name="description_visibility_direct">Direct</string>
<string name="download_media">Media downloaden</string>
<string name="downloading_media">Media aan het downloaden</string>
<string name="pref_title_timeline_filters">Filters</string>
@ -561,4 +557,39 @@
<string name="error_following_hashtag_format">Fout tijdens het volgen van #%s</string>
<string name="error_unfollowing_hashtag_format">Fout tijdens het ontvolgen van #%s</string>
<string name="delete_scheduled_post_warning">Dit ingeplande bericht verwijderen\?</string>
<string name="pref_title_reading_order">Leesvolgorde</string>
<string name="pref_reading_order_oldest_first">Oudste eerst</string>
<string name="pref_reading_order_newest_first">Nieuwste eerst</string>
<string name="failed_to_add_to_list">Account toevoegen aan de lijst is mislukt</string>
<string name="action_add_or_remove_from_list">Toevoegen of verwijderen van lijst</string>
<string name="failed_to_pin">Kan niet vastmaken</string>
<string name="pref_summary_http_proxy_disabled">Uitgeschakeld</string>
<string name="failed_to_remove_from_list">Account verwijderen van de lijst is mislukt</string>
<string name="compose_unsaved_changes">Er zijn niet opgeslagen wijzigingen.</string>
<string name="mute_notifications_switch">Meldingen negeren</string>
<string name="title_edits">Bewerkingen</string>
<string name="pref_default_post_language">Standaardtaal van berichten</string>
<string name="notification_report_name">Rapporten</string>
<string name="description_post_edited">Bewerkt</string>
<string name="status_edit_info">%1$s bewerkte %2$s</string>
<string name="status_created_info">%1$s maakte %2$s</string>
<string name="instance_rule_info">Door in te loggen ben je het eens met de regels van %s.</string>
<string name="report_category_spam">Spam</string>
<string name="report_category_other">Overig</string>
<string name="hint_media_description_missing">Media moet een beschrijving hebben.</string>
<string name="failed_to_unpin">Kan niet losmaken</string>
<string name="instance_rule_title">%s regels</string>
<string name="language_display_name_format">%s (%s)</string>
<string name="report_category_violation">Regelovertreding</string>
<string name="no_lists">Je hebt geen lijsten.</string>
<string name="status_created_at_now">nu</string>
<string name="post_media_alt">ALT</string>
<string name="action_unfollow_hashtag_format">Ontvolg #%s\?</string>
<string name="error_muting_hashtag_format">Fout bij negeren #%s</string>
<string name="action_continue_edit">Ga door met bewerken</string>
<string name="pref_title_notification_filter_reports">Er is een nieuw rapport</string>
<string name="notification_report_format">Nieuw rapport over %s</string>
<string name="account_username_copied">Gebruikersnaam gekopieerd</string>
<string name="confirmation_hashtag_unfollowed">#%s ontvolgd</string>
<string name="title_followed_hashtags">Gevolgde hashtags</string>
</resources>

View File

@ -601,4 +601,16 @@
<string name="action_discard">Ignorar las modificacions</string>
<string name="action_continue_edit">Téner de modificar</string>
<string name="compose_unsaved_changes">Avètz de modificacions pas salvadas.</string>
<string name="a11y_label_loading_thread">Cargament del fil</string>
<string name="pref_title_reading_order">Òrdre de lectura</string>
<string name="pref_reading_order_oldest_first">Mai ancians en primièr</string>
<string name="pref_reading_order_newest_first">Mai recents primièr</string>
<string name="pref_summary_http_proxy_disabled">Desactivat</string>
<string name="pref_summary_http_proxy_missing">&lt;pas definit&gt;</string>
<string name="pref_summary_http_proxy_invalid">&lt;invalid&gt;</string>
<string name="action_share_account_link">Partejar lo ligam al compte</string>
<string name="action_share_account_username">Partejar lo nom dutilizaire del compte</string>
<string name="send_account_link_to">Partejar lURL del compte amb…</string>
<string name="send_account_username_to">Partejar lo nom dutilizaire del compte amb…</string>
<string name="account_username_copied">Nom dutilizaire copiat</string>
</resources>

View File

@ -3,9 +3,9 @@
<string name="error_generic">Wystąpił błąd.</string>
<string name="error_empty">To nie może pozostać puste.</string>
<string name="error_invalid_domain">Wprowadzono nieprawidłową domenę</string>
<string name="error_failed_app_registration">Nie udało się uwierzytelnić z tą instancją.</string>
<string name="error_failed_app_registration">Nie udało się uwierzytelnić z tą instancją. Jeśli problem będzie się powtarzał, spróbuj zalogować się za pomocą przeglądarki z menu aplikacji.</string>
<string name="error_no_web_browser_found">Nie znaleziono przeglądarki internetowej.</string>
<string name="error_authorization_unknown">Wystąpił nieokreślony błąd podczas próby autoryzacji.</string>
<string name="error_authorization_unknown">Wystąpił nieokreślony błąd podczas próby autoryzacji. Jeśli problem będzie się powtarzał, spróbuj zalogować się za pomocą przeglądarki z menu aplikacji.</string>
<string name="error_authorization_denied">Odmówiono autoryzacji.</string>
<string name="error_retrieving_oauth_token">Nie udało się uzyskać tokenu logowania.</string>
<string name="error_compose_character_limit">Zbyt długi wpis!</string>
@ -54,7 +54,7 @@
<string name="action_logout">Wyloguj się</string>
<string name="action_logout_confirm">Czy na pewno chcesz wylogować się z konta %1$s?</string>
<string name="action_follow">Obserwuj</string>
<string name="action_unfollow">Odobserwuj</string>
<string name="action_unfollow">Przestań śledzić</string>
<string name="action_block">Zablokuj</string>
<string name="action_unblock">Odblokuj</string>
<string name="action_hide_reblogs">Ukryj podbicia</string>
@ -598,4 +598,29 @@
<string name="compose_save_draft_loses_media">Czy chcesz zapisać jako szkic\? (Załączniki zostaną załadowane ponownie po przywróceniu szkicu.)</string>
<string name="error_following_hashtags_unsupported">Ta instancja nie wspiera obserwowania hashtagów.</string>
<string name="title_followed_hashtags">Obserwowane hashtagi</string>
<string name="a11y_label_loading_thread">Ładowanie wątku</string>
<string name="instance_rule_info">Logując się akceptujesz regulamin %s.</string>
<string name="pref_reading_order_oldest_first">Najpierw najstarsze</string>
<string name="pref_reading_order_newest_first">Najpierw najnowsze</string>
<string name="no_lists">Nie masz żadnych list.</string>
<string name="mute_notifications_switch">Wycisz powiadomienia</string>
<string name="status_edit_info">%1$s edytował %2$s</string>
<string name="status_created_info">%1$s stworzył %2$s</string>
<string name="title_edits">Edycje</string>
<string name="compose_unsaved_changes">Masz niezapisane zmiany.</string>
<string name="instance_rule_title">%s regulamin</string>
<string name="action_post_failed">Błąd wysyłania</string>
<string name="action_post_failed_show_drafts">Pokaż szkice</string>
<string name="action_post_failed_do_nothing">Odrzuć</string>
<string name="post_media_alt">ALT</string>
<string name="action_browser_login">Zaloguj się przez przeglądarkę</string>
<string name="action_continue_edit">Kontynuuj edycję</string>
<string name="report_category_spam">Spam</string>
<string name="send_account_link_to">Udostępnij link do konta…</string>
<string name="send_account_username_to">Udostępnij nazwę użytkownika…</string>
<string name="account_username_copied">Skopiowano nazwę użytkownika</string>
<string name="description_post_edited">Edytowano</string>
<string name="report_category_other">Inne</string>
<string name="post_edited">Edytowano %s</string>
<string name="delete_scheduled_post_warning">Usunąć ten zaplanowany wpis\?</string>
</resources>

View File

@ -20,7 +20,7 @@
<string name="title_notifications">Notificações</string>
<string name="title_public_local">Linha local</string>
<string name="title_public_federated">Linha global</string>
<string name="title_direct_messages">Mensagens Diretas</string>
<string name="title_direct_messages">Mensagens diretas</string>
<string name="title_tab_preferences">Editar abas</string>
<string name="title_view_thread">Conversa</string>
<string name="title_posts">Toots</string>
@ -54,7 +54,7 @@
<string name="action_unfavourite">Desfavoritar</string>
<string name="action_more">Mais</string>
<string name="action_compose">Compor</string>
<string name="action_login">Entrar com Mastodon</string>
<string name="action_login">Entrar com Tusky</string>
<string name="action_logout">Sair</string>
<string name="action_logout_confirm">Tem certeza de que deseja sair da conta %1$s\?</string>
<string name="action_follow">Seguir</string>
@ -518,4 +518,22 @@
<string name="duration_180_days">180 dias</string>
<string name="duration_14_days">14 dias</string>
<string name="duration_365_days">365 dias</string>
<string name="pref_summary_http_proxy_disabled">Desabilitado</string>
<string name="pref_summary_http_proxy_missing">&lt;não definido&gt;</string>
<string name="pref_summary_http_proxy_invalid">&lt;inválido&gt;</string>
<string name="pref_show_self_username_always">Sempre</string>
<string name="error_image_edit_failed">A imagem não pôde ser editada.</string>
<string name="error_multimedia_size_limit">Arquivos de vídeo e áudio não podem exceder %s MB de tamanho.</string>
<string name="hint_media_description_missing">A mídia deve ter uma descrição.</string>
<string name="pref_show_self_username_never">Nunca</string>
<string name="post_media_alt">ALT</string>
<string name="error_muting_hashtag_format">Erro ao silenciar #%s</string>
<string name="action_browser_login">Entrar com Navegador</string>
<string name="account_username_copied">Nome de usuário copiado</string>
<string name="title_followed_hashtags">Hashtags seguidas</string>
<string name="action_details">Detalhes</string>
<string name="error_following_hashtag_format">Erro ao seguir #%s</string>
<string name="error_unfollowing_hashtag_format">Erro ao deixar de seguir #%s</string>
<string name="error_could_not_load_login_page">Não foi possível carregar a página de login.</string>
<string name="error_loading_account_details">Falha ao carregar detalhes da conta</string>
</resources>

View File

@ -36,7 +36,7 @@
<string name="action_logout">Вийти</string>
<string name="title_drafts">Чернетки</string>
<string name="title_favourites">Вподобане</string>
<string name="action_login">Увійти з Mastodon</string>
<string name="action_login">Увійти з Tusky</string>
<string name="login_connection">Зʼєднання…</string>
<string name="search_no_results">Немає результатів</string>
<string name="hint_search">Пошук…</string>
@ -139,10 +139,10 @@
<string name="title_view_thread">Тред</string>
<string name="title_tab_preferences">Вкладки</string>
<string name="error_media_upload_sending">Не вдалося відвантажити.</string>
<string name="error_retrieving_oauth_token">Не вдалося отримати токен входу.</string>
<string name="error_authorization_denied">Авторизацію відхилено.</string>
<string name="error_authorization_unknown">Сталася помилка невпізнання авторизації.</string>
<string name="error_failed_app_registration">Помилка автентифікації цього сервера.</string>
<string name="error_retrieving_oauth_token">Не вдалося отримати токен входу. Якщо проблема не зникає, спробуйте увійти через браузер з меню.</string>
<string name="error_authorization_denied">Авторизацію відхилено. Якщо ви впевнені, що вказали правильні облікові дані, спробуйте увійти через браузер з меню.</string>
<string name="error_authorization_unknown">Сталася помилка невпізнання авторизації. Якщо проблема не зникає, спробуйте увійти через браузер з меню.</string>
<string name="error_failed_app_registration">Помилка автентифікації цього сервера. Якщо проблема не зникає, спробуйте увійти через браузер з меню.</string>
<string name="error_invalid_domain">Введено недійсний домен</string>
<string name="action_open_reblogged_by">Показати поширення</string>
<string name="pref_title_show_boosts">Показати поширення</string>
@ -630,4 +630,16 @@
<string name="pref_summary_http_proxy_disabled">Вимкнено</string>
<string name="pref_summary_http_proxy_missing">&lt;не налаштовано&gt;</string>
<string name="pref_summary_http_proxy_invalid">&lt;недійсний&gt;</string>
<string name="action_browser_login">Увійти через браузер</string>
<string name="description_login">Працює в більшості випадків. Дані не витікають в інші застосунки.</string>
<string name="description_browser_login">Може підтримувати додаткові методи автентифікації, але для цього потрібен підтримуваний браузер.</string>
<string name="action_post_failed">Не вдалося вивантажити</string>
<string name="action_post_failed_show_drafts">Показати чернетки</string>
<string name="action_post_failed_do_nothing">Відхилити</string>
<string name="action_post_failed_detail">Не вдалося вивантажити ваш допис і його було збережено в чернетках.
\n
\nАбо з не вдалося зв\'язатися з сервером, або він відхилив допис.</string>
<string name="action_post_failed_detail_plural">Не вдалося вивантажити ваш допис і його було збережено в чернетках.
\n
\nАбо з не вдалося зв\'язатися з сервером, або він відхилив допис.</string>
</resources>

View File

@ -93,7 +93,7 @@
<string name="send_post_link_to">Đăng lại URL tút với…</string>
<string name="send_post_content_to">Đăng lại tút với…</string>
<string name="downloading_media">Đang lưu vào thiết bị</string>
<string name="download_media">Tải về</string>
<string name="download_media">Tải xuống</string>
<string name="action_share_as">Đăng lại với tư cách …</string>
<string name="action_open_as">Mở với tư cách %s</string>
<string name="action_copy_link">Chép URL</string>
@ -455,7 +455,7 @@
<string name="action_unmute_domain">Bỏ ẩn %s</string>
<string name="pref_title_hide_top_toolbar">Ẩn tiêu đề tab</string>
<string name="account_note_saved">Đã lưu!</string>
<string name="account_note_hint">Ghi chú</string>
<string name="account_note_hint">Ghi chú về người này</string>
<string name="no_announcements">Chưa có thông báo.</string>
<string name="title_announcements">Có gì mới\?</string>
<string name="wellbeing_hide_stats_profile">Ẩn số liệu trên trang hồ sơ</string>
@ -571,7 +571,7 @@
<string name="hint_media_description_missing">Hình ảnh phải có mô tả.</string>
<string name="error_status_source_load">Không xác định được trạng thái máy chủ.</string>
<string name="pref_title_http_proxy_port_message">Cổng nên là khoảng giữa %d đến %d</string>
<string name="post_media_alt"></string>
<string name="post_media_alt"></string>
<string name="action_discard">Hủy bỏ thay đổi</string>
<string name="action_continue_edit">Tiếp tục sửa</string>
<string name="compose_unsaved_changes">Thay đổi chưa được lưu.</string>
@ -591,4 +591,16 @@
<string name="pref_summary_http_proxy_disabled">Tắt</string>
<string name="pref_summary_http_proxy_missing">&lt;không đặt&gt;</string>
<string name="pref_summary_http_proxy_invalid">&lt;không hợp lệ&gt;</string>
<string name="description_browser_login">Có thể hỗ trợ các phương thức xác thực bổ sung nhưng yêu cầu trình duyệt được hỗ trợ.</string>
<string name="action_browser_login">Đăng nhập bằng trình duyệt</string>
<string name="description_login">Đăng nhập ổn định. Dữ liệu sẽ không bị lộ.</string>
<string name="action_post_failed">Tải lên thất bại</string>
<string name="action_post_failed_detail">Tút của bạn không tải lên được và đã được lưu nháp.
\n
\nKhông thể liên lạc được với máy chủ hoặc nó đã từ chối tút.</string>
<string name="action_post_failed_detail_plural">Tút của bạn không tải lên được và đã được lưu nháp.
\n
\nKhông thể liên lạc được với máy chủ hoặc nó đã từ chối tút.</string>
<string name="action_post_failed_show_drafts">Xem bản nháp</string>
<string name="action_post_failed_do_nothing">Bỏ qua</string>
</resources>

View File

@ -4,11 +4,11 @@
<string name="error_network">网络请求出错,请检查互联网连接并重试!</string>
<string name="error_empty">内容不能为空。</string>
<string name="error_invalid_domain">该域名无效</string>
<string name="error_failed_app_registration">未能通过该实例的身份验证。</string>
<string name="error_failed_app_registration">未能通过该实例的身份验证。如果这个问题持续,请从菜单处尝试“在浏览器中登录”。</string>
<string name="error_no_web_browser_found">找不到可用的浏览器。</string>
<string name="error_authorization_unknown">发生不明授权错误。</string>
<string name="error_authorization_denied">授权被拒绝。</string>
<string name="error_retrieving_oauth_token">未能获取登录令牌。</string>
<string name="error_authorization_unknown">发生不明授权错误。如果这个问题持续,请从菜单处尝试 “在浏览器中登录”。</string>
<string name="error_authorization_denied">授权被拒绝。如果你确定提供了正确的凭据,请从菜单处尝试“在浏览器中登录”。</string>
<string name="error_retrieving_oauth_token">未能获取登录令牌。如果这个问题持续,请从菜单处尝试 “在浏览器中登录”。</string>
<string name="error_compose_character_limit">嘟文太长了!</string>
<string name="error_media_upload_type">无法上传此类型的文件。</string>
<string name="error_media_upload_opening">此文件无法打开。</string>
@ -60,9 +60,9 @@
<string name="action_unfavourite">取消喜欢</string>
<string name="action_more">更多</string>
<string name="action_compose">发表嘟文</string>
<string name="action_login">登录 Mastodon 帐号</string>
<string name="action_login">用 Tusky 登录</string>
<string name="action_logout">注销</string>
<string name="action_logout_confirm">确定要退出号 %1$s 吗?</string>
<string name="action_logout_confirm">确定要退出号 %1$s 吗?</string>
<string name="action_follow">关注</string>
<string name="action_unfollow">取消关注</string>
<string name="action_block">屏蔽</string>
@ -78,7 +78,7 @@
<string name="action_close">关闭</string>
<string name="action_view_profile">个人资料</string>
<string name="action_view_preferences">设置</string>
<string name="action_view_account_preferences">户设置</string>
<string name="action_view_account_preferences">户设置</string>
<string name="action_view_favourites">喜欢</string>
<string name="action_view_mutes">被隐藏的用户</string>
<string name="action_view_blocks">被屏蔽的用户</string>
@ -141,9 +141,9 @@
<string name="label_header">标题</string>
<string name="link_whats_an_instance">什么是实例?</string>
<string name="login_connection">正在连接…</string>
<string name="dialog_whats_an_instance">请输入你号所在的 Mastodon 站点的域名,比如 mastodon.socialicosahedron.websitesocial.tchncs.de<a href="https://instances.social">等等</a>
<string name="dialog_whats_an_instance">请输入你号所在的 Mastodon 站点的域名,比如 mastodon.socialicosahedron.websitesocial.tchncs.de<a href="https://instances.social">等等</a>
\n
\n还没有 Mastodon 帐号?你也可以输入想注册的 Mastodon 站点的域名,然后在该服务器创建新的帐号并授权 Yuito 登入。
\n还没有 Mastodon 账号?你也可以输入想注册的 Mastodon 站点的域名,然后在该服务器创建新的账号并授权 Tusky 登入。
\n
\n在 Mastodon 里,你的账号信息储存在某一特定实例当中,但 Mastodon 可使跨站互动和站内互动一样简单。
\n
@ -242,7 +242,7 @@
问题反馈:\n
https://github.com/accelforce/Yuito/issues
</string>
<string name="about_tusky_account">Yuito 官方</string>
<string name="about_tusky_account">Yuito 官方</string>
<string name="post_share_content">分享嘟文内容</string>
<string name="post_share_link">分享嘟文链接</string>
<string name="post_media_images">图片</string>
@ -271,8 +271,8 @@
<string name="filter_dialog_remove_button">移除</string>
<string name="filter_dialog_update_button">更新</string>
<string name="filter_add_description">需要过滤的文字</string>
<string name="add_account_name">添加</string>
<string name="add_account_description">添加新的 Mastodon </string>
<string name="add_account_name">添加</string>
<string name="add_account_description">添加新的 Mastodon </string>
<string name="action_lists">列表</string>
<string name="title_lists">列表</string>
<string name="error_create_list">无法新建列表</string>
@ -293,7 +293,7 @@
</plurals>
<string name="action_set_caption">设置图片标题</string>
<string name="action_remove">移除</string>
<string name="lock_account_label">保护你的户(锁嘟)</string>
<string name="lock_account_label">保护你的户(锁嘟)</string>
<string name="lock_account_label_description">你需要手动审核所有关注请求</string>
<string name="compose_save_draft">保存为草稿?</string>
<string name="send_post_notification_title">正在发送嘟文…</string>
@ -425,8 +425,8 @@
<string name="report_remote_instance">转发到 %s</string>
<string name="failed_report">举报失败</string>
<string name="failed_fetch_posts">无法获取嘟文</string>
<string name="report_description_1">该报告将发送给给您的服务器管理员。您可以在下面提供有关回报此户的原因的说明:</string>
<string name="report_description_remote_instance">户来自其他服务器。向那里发送一份匿名的报告副本?</string>
<string name="report_description_1">该报告将发送给给您的服务器管理员。您可以在下面提供有关回报此户的原因的说明:</string>
<string name="report_description_remote_instance">户来自其他服务器。向那里发送一份匿名的报告副本?</string>
<string name="title_accounts">账户</string>
<string name="failed_search">搜索失败</string>
<string name="pref_title_show_notifications_filter">显示通知过滤器</string>
@ -547,7 +547,7 @@
<string name="error_unfollowing_hashtag_format">取关 #%s 出错</string>
<string name="filter_expiration_format">%s (%s)</string>
<string name="duration_no_change">(无更改)</string>
<string name="description_post_language">帖子语言</string>
<string name="description_post_language">嘟文语言</string>
<string name="url_domain_notifier">%s (🔗 %s)</string>
<string name="error_failed_set_focus">设置焦点失败</string>
<string name="action_set_focus">设置焦点</string>
@ -610,4 +610,16 @@
<string name="pref_summary_http_proxy_invalid">&lt;无效&gt;</string>
<string name="pref_reading_order_newest_first">从新到旧</string>
<string name="pref_reading_order_oldest_first">从旧到新</string>
<string name="action_browser_login">用浏览器登录</string>
<string name="description_login">多数情况下有效。没有数据泄露给其他应用。</string>
<string name="description_browser_login">可能支持额外的验证方法但需要受支持的浏览器。</string>
<string name="action_post_failed_detail_plural">你的嘟文上传失败,已被保存到草稿。
\n
\n要么是无法联系服务器要么是服务器拒绝了它。</string>
<string name="action_post_failed_show_drafts">显示草稿</string>
<string name="action_post_failed_do_nothing">取消</string>
<string name="action_post_failed">上传失败了</string>
<string name="action_post_failed_detail">你的嘟文上传失败,已被保存到草稿。
\n
\n要么是无法联系服务器要么是服务器拒绝了它。</string>
</resources>

View File

@ -60,9 +60,9 @@
<string name="action_unfavourite">取消喜欢</string>
<string name="action_more">更多</string>
<string name="action_compose">新嘟文</string>
<string name="action_login">登录 Mastodon </string>
<string name="action_login">登录 Mastodon </string>
<string name="action_logout">退出登录</string>
<string name="action_logout_confirm">确定要退出号 %1$s 吗?</string>
<string name="action_logout_confirm">确定要退出号 %1$s 吗?</string>
<string name="action_follow">关注</string>
<string name="action_unfollow">取消关注</string>
<string name="action_block">屏蔽</string>
@ -141,10 +141,11 @@
<string name="label_header">标题</string>
<string name="link_whats_an_instance">需要帮助?</string>
<string name="login_connection">正在连接…</string>
<string name="dialog_whats_an_instance">请输入你帐号所在的 Mastodon 站点的域名,比如 pawoo.netacg.mnwxw.moe<a href="https://instances.social">等等</a>
\n\n还没有 Mastodon 帐号?你也可以输入想注册的 Mastodon 站点的域名,然后在该服务器创建新的帐号并授权 Yuito 登入。
\n\n在 Mastodon 里,跨站互动和站内互动一样简单。可以前往 <a href="https://joinmastodon.org">https://joinmastodon.org</a> 了解更多信息。
</string>
<string name="dialog_whats_an_instance">请输入你账号所在的 Mastodon 站点的域名,比如 pawoo.netacg.mnwxw.moe<a href="https://instances.social">等等</a>
\n
\n还没有 Mastodon 账号?你也可以输入想注册的 Mastodon 站点的域名,然后在该服务器创建新的账号并授权 Tusky 登入。
\n
\n在 Mastodon 里,跨站互动和站内互动一样简单。可以前往 <a href="https://joinmastodon.org">https://joinmastodon.org</a> 了解更多信息。 </string>
<string name="dialog_title_finishing_media_upload">正在结束上传…</string>
<string name="dialog_message_uploading_media">正在上传…</string>
<string name="dialog_download_image">下载</string>
@ -239,7 +240,7 @@
问题反馈:\n
https://github.com/accelforce/Yuito/issues
</string>
<string name="about_tusky_account">Yuito 官方</string>
<string name="about_tusky_account">Yuito 官方</string>
<string name="post_share_content">分享嘟文内容</string>
<string name="post_share_link">分享嘟文链接</string>
<string name="post_media_images">照片</string>
@ -268,8 +269,8 @@
<string name="filter_dialog_remove_button">移除</string>
<string name="filter_dialog_update_button">更新</string>
<string name="filter_add_description">需要过滤的文字</string>
<string name="add_account_name">添加</string>
<string name="add_account_description">添加新的 Mastodon </string>
<string name="add_account_name">添加</string>
<string name="add_account_description">添加新的 Mastodon </string>
<string name="action_lists">列表</string>
<string name="title_lists">列表</string>
<string name="error_create_list">无法新建列表</string>

View File

@ -0,0 +1,6 @@
<resources>
<plurals name="action_post_failed_detail">
<item quantity="one">@string/action_post_failed_detail</item>
<item quantity="other">@string/action_post_failed_detail_plural</item>
</plurals>
</resources>

View File

@ -4,11 +4,11 @@
<string name="error_network">A network error occurred! Please check your connection and try again!</string>
<string name="error_empty">This cannot be empty.</string>
<string name="error_invalid_domain">Invalid domain entered</string>
<string name="error_failed_app_registration">Failed authenticating with that instance.</string>
<string name="error_failed_app_registration">Failed authenticating with that instance. If this persists, try "Login in Browser" from the menu.</string>
<string name="error_no_web_browser_found">Couldn\'t find a web browser to use.</string>
<string name="error_authorization_unknown">An unidentified authorization error occurred.</string>
<string name="error_authorization_denied">Authorization was denied.</string>
<string name="error_retrieving_oauth_token">Failed getting a login token.</string>
<string name="error_authorization_unknown">An unidentified authorization error occurred. If this persists, try "Login in Browser" from the menu.</string>
<string name="error_authorization_denied">Authorization was denied. If you\'re sure that you supplied the correct credentials, try "Login in Browser" from the menu.</string>
<string name="error_retrieving_oauth_token">Failed getting a login token. If this persists, try "Login in Browser" from the menu.</string>
<string name="error_loading_account_details">Failed loading account details</string>
<string name="error_could_not_load_login_page">Could not load the login page.</string>
<string name="error_compose_character_limit">The post is too long!</string>
@ -101,9 +101,15 @@
<string name="action_unbookmark">Remove bookmark</string>
<string name="action_more">More</string>
<string name="action_compose">Compose</string>
<string name="action_login">Log in with Mastodon</string>
<string name="action_login">Login with Tusky</string>
<string name="action_browser_login">Login with Browser</string>
<string name="action_logout">Log out</string>
<string name="action_logout_confirm">Are you sure you want to log out of the account %1$s?</string>
<string name="action_post_failed">Upload failed</string>
<string name="action_post_failed_detail">Your post failed to upload and has been saved to drafts.\n\nEither the server could not be contacted, or it rejected the post.</string>
<string name="action_post_failed_detail_plural">Your posts failed to upload and have been saved to drafts.\n\nEither the server could not be contacted, or it rejected the posts.</string>
<string name="action_post_failed_show_drafts">Show drafts</string>
<string name="action_post_failed_do_nothing">Dismiss</string>
<string name="action_follow">Follow</string>
<string name="action_unfollow">Unfollow</string>
<string name="action_block">Block</string>
@ -593,6 +599,8 @@
Poll with choices: %1$s, %2$s, %3$s, %4$s; %5$s
</string>
<string name="description_post_language">Post language</string>
<string name="description_login">Works in most cases. No data is leaked to other apps.</string>
<string name="description_browser_login">May support additional authentication methods, but requires a supported browser.</string>
<string name="hint_list_name">List name</string>

View File

@ -130,6 +130,7 @@ class MainActivityTest {
val viewModel = QuickTootViewModel(mockAccountManager, mock())
activity.eventHub = EventHub()
activity.accountManager = mockAccountManager
activity.draftsAlert = mock {}
activity.mastodonApi = mock {
onBlocking { accountVerifyCredentials() } doReturn NetworkResult.success(account)
onBlocking { listAnnouncements(false) } doReturn NetworkResult.success(emptyList())

View File

@ -0,0 +1,7 @@
Tusky 21.0
- Support for post editing
- New setting to control preferred reading direction
- Larger media previews and a new overlay to indicate media with description
- It is now possible to add accounts to lists from their profile
and much more

View File

@ -0,0 +1,8 @@
Tusky 16.0 bertsioa
- Denbora-lerroaren karga-logika guztiz berridatzia izan da, azkarragoa eta mantentzeko errazagoa izateko, baita akats gutxiago eduki dezan ere.
- Orain, Tusky aplikazioak APNG eta animaziodun WebP formatudun emoji pertsonalizatuak anima ditzake.
- Akats-zuzenketa ugari
- Android 11rekin bateragarria
- Itzulpen berriak: Eskoziako gaelera, galiziera eta ukrainera
- Hobetutako itzulpenak

View File

@ -0,0 +1,9 @@
Tusky 20.0
- Aplikaziorako ikono berria Dzuk-en eskutik https://dzuk.zone
- Orain traolak jarrai ditzakezu. Traolan klik egin eta ondoren, tresna-barrako ikonoa.
- Android 13rekin bateragarria
- Bidalketa bat egiterakoan, erabilitako hizkuntza aukera dezakezu
- Profiletako edukien fitxak orain eduki hunkigarria errespetatzen du eta arinago kargatzen da.
- Orain, irudiaren foku-puntua bidali aurretik zehazteko aukera duzu
- Tresna-barran aukera berri bat zure erabiltzaile-izen osoa erakusteko

View File

@ -0,0 +1,7 @@
Tusky 21.0
- Підтримка редагування дописів
- Нове налаштування для керування бажаним напрямком читання
- Більші прев'ю медіа та новий вигляд позначення медіа з описом
- З'явилася можливість додавати облікові записи до списків з їхнього профілю
та багато іншого

View File

@ -0,0 +1,7 @@
Tusky 21.0
- Hỗ trợ sửa tút
- Thêm cài đặt cách đọc
- Xem trước media và lớp phủ mới để biểu thị phương tiện có mô tả
- Cho phép thêm tài khoản vào danh sách hồ sơ
và còn nữa

View File

@ -0,0 +1,7 @@
Tusky 21.0
- 支持编辑嘟文
- 控制偏首选阅读方向的新设置
- 支持预览更大的媒体文件以及表明带描述媒体文件的新遮罩
- 允许从账户的资料页将其添加到列表
还有其他更多内容有待发现