diff --git a/README.md b/README.md
index 876145e93..4903de10f 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
Yuito is fork of [Tusky](https://github.com/tuskyapp/Tusky).
-Tusky is a beautiful Android client for [Mastodon](https://github.com/tootsuite/mastodon). Mastodon is an ActivityPub federated social network. That means no single entity controls the whole network, rather, like e-mail, volunteers and organisations operate their own independent servers, users from which can all interact with each other seamlessly.
+Tusky is a beautiful Android client for [Mastodon](https://github.com/mastodon/mastodon). Mastodon is an ActivityPub federated social network. That means no single entity controls the whole network, rather, like e-mail, volunteers and organisations operate their own independent servers, users from which can all interact with each other seamlessly.
## Features
@@ -15,14 +15,14 @@ Tusky is a beautiful Android client for [Mastodon](https://github.com/tootsuite/
- Most Mastodon APIs implemented
- Multi-Account support
- Dark, light and black themes with the possibility to auto-switch based on the time of day
-- Drafts - compose toots and save them for later
+- Drafts - compose posts and save them for later
- Choose between different emoji styles
- Optimized for all screen sizes
- Completely open-source - no non-free dependencies like Google services
### Support
-If you have any bug reports, feature requests or questions please open an issue or send us a toot at [@ars42525@odakyu.app](https://odakyu.app/@ars42525)!
+If you have any bug reports, feature requests or questions please open an issue or send us a message at [@ars42525@odakyu.app](https://odakyu.app/@ars42525)!
For translating Tusky into your language, visit https://weblate.tusky.app/
diff --git a/app/build.gradle b/app/build.gradle
index dc2a4facf..742813508 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -15,11 +15,11 @@ def getGitSha = {
}
android {
- compileSdkVersion 30
+ compileSdkVersion 31
defaultConfig {
applicationId 'net.accelf.yuito'
minSdkVersion 21
- targetSdkVersion 30
+ targetSdkVersion 31
versionCode 43
versionName '4.1.3'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -96,12 +96,12 @@ android {
}
ext.coroutinesVersion = "1.6.0"
-ext.lifecycleVersion = "2.3.1"
-ext.roomVersion = '2.3.0'
+ext.lifecycleVersion = "2.4.1"
+ext.roomVersion = '2.4.2'
ext.retrofitVersion = '2.9.0'
ext.okhttpVersion = '4.9.3'
-ext.glideVersion = '4.12.0'
-ext.daggerVersion = '2.40.5'
+ext.glideVersion = '4.13.1'
+ext.daggerVersion = '2.41'
ext.materialdrawerVersion = '8.4.5'
repositories {
@@ -117,33 +117,35 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx3:$coroutinesVersion"
- implementation "androidx.core:core-ktx:1.5.0"
- implementation "androidx.appcompat:appcompat:1.3.0"
- implementation "androidx.fragment:fragment-ktx:1.3.4"
- implementation "androidx.browser:browser:1.3.0"
+ implementation "androidx.core:core-ktx:1.7.0"
+ implementation "androidx.appcompat:appcompat:1.4.1"
+ implementation "androidx.fragment:fragment-ktx:1.4.1"
+ implementation "androidx.browser:browser:1.4.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.exifinterface:exifinterface:1.3.3"
implementation "androidx.cardview:cardview:1.0.0"
- implementation "androidx.preference:preference-ktx:1.1.1"
- implementation "androidx.sharetarget:sharetarget:1.1.0"
+ implementation "androidx.preference:preference-ktx:1.2.0"
+ implementation "androidx.sharetarget:sharetarget:1.2.0-rc01"
implementation "androidx.emoji:emoji:1.1.0"
implementation "androidx.emoji:emoji-appcompat:1.1.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycleVersion"
- implementation "androidx.constraintlayout:constraintlayout:2.1.2"
- implementation "androidx.paging:paging-runtime-ktx:3.0.0"
+ implementation "androidx.constraintlayout:constraintlayout:2.1.3"
+ implementation "androidx.paging:paging-runtime-ktx:3.1.1"
implementation "androidx.viewpager2:viewpager2:1.0.0"
- implementation "androidx.work:work-runtime:2.5.0"
+ implementation "androidx.work:work-runtime:2.7.1"
implementation "androidx.room:room-ktx:$roomVersion"
+ implementation "androidx.room:room-paging:$roomVersion"
implementation "androidx.room:room-rxjava3:$roomVersion"
kapt "androidx.room:room-compiler:$roomVersion"
+ implementation 'androidx.core:core-splashscreen:1.0.0-beta02'
- implementation "com.google.android.material:material:1.4.0"
+ implementation "com.google.android.material:material:1.5.0"
- implementation "com.google.code.gson:gson:2.8.9"
+ implementation "com.google.code.gson:gson:2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
@@ -158,14 +160,14 @@ dependencies {
implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion"
kapt "com.github.bumptech.glide:compiler:$glideVersion"
- implementation "com.github.penfeizhou.android.animation:glide-plugin:2.17.0"
+ implementation "com.github.penfeizhou.android.animation:glide-plugin:2.20.0"
- implementation "io.reactivex.rxjava3:rxjava:3.0.12"
+ implementation "io.reactivex.rxjava3:rxjava:3.1.3"
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
implementation "io.reactivex.rxjava3:rxkotlin:3.0.1"
- implementation "com.uber.autodispose2:autodispose-androidx-lifecycle:2.0.0"
- implementation "com.uber.autodispose2:autodispose:2.0.0"
+ implementation "com.uber.autodispose2:autodispose-androidx-lifecycle:2.1.1"
+ implementation "com.uber.autodispose2:autodispose:2.1.1"
implementation "com.google.dagger:dagger:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
diff --git a/app/schemas/com.keylesspalace.tusky.db.AppDatabase/31.json b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/31.json
new file mode 100644
index 000000000..c705293ce
--- /dev/null
+++ b/app/schemas/com.keylesspalace.tusky.db.AppDatabase/31.json
@@ -0,0 +1,809 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 31,
+ "identityHash": "a75615171612bdfc9e3d4201ebf6071a",
+ "entities": [
+ {
+ "tableName": "DraftEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `accountId` INTEGER NOT NULL, `inReplyToId` TEXT, `content` TEXT, `contentWarning` TEXT, `sensitive` INTEGER NOT NULL, `visibility` INTEGER NOT NULL, `attachments` TEXT NOT NULL, `poll` TEXT, `failedToSend` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "inReplyToId",
+ "columnName": "inReplyToId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "contentWarning",
+ "columnName": "contentWarning",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sensitive",
+ "columnName": "sensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "poll",
+ "columnName": "poll",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "failedToSend",
+ "columnName": "failedToSend",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "AccountEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsSubscriptions` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "domain",
+ "columnName": "domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accessToken",
+ "columnName": "accessToken",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isActive",
+ "columnName": "isActive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "username",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "displayName",
+ "columnName": "displayName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "profilePictureUrl",
+ "columnName": "profilePictureUrl",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsEnabled",
+ "columnName": "notificationsEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsMentioned",
+ "columnName": "notificationsMentioned",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsFollowed",
+ "columnName": "notificationsFollowed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsFollowRequested",
+ "columnName": "notificationsFollowRequested",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsReblogged",
+ "columnName": "notificationsReblogged",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsFavorited",
+ "columnName": "notificationsFavorited",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsPolls",
+ "columnName": "notificationsPolls",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsSubscriptions",
+ "columnName": "notificationsSubscriptions",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationSound",
+ "columnName": "notificationSound",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationVibration",
+ "columnName": "notificationVibration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationLight",
+ "columnName": "notificationLight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "defaultPostPrivacy",
+ "columnName": "defaultPostPrivacy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "defaultMediaSensitivity",
+ "columnName": "defaultMediaSensitivity",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "alwaysShowSensitiveMedia",
+ "columnName": "alwaysShowSensitiveMedia",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "alwaysOpenSpoiler",
+ "columnName": "alwaysOpenSpoiler",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mediaPreviewEnabled",
+ "columnName": "mediaPreviewEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastNotificationId",
+ "columnName": "lastNotificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "activeNotifications",
+ "columnName": "activeNotifications",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojis",
+ "columnName": "emojis",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "tabPreferences",
+ "columnName": "tabPreferences",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationsFilter",
+ "columnName": "notificationsFilter",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": true
+ },
+ "indices": [
+ {
+ "name": "index_AccountEntity_domain_accountId",
+ "unique": true,
+ "columnNames": [
+ "domain",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "InstanceEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, `maxPollOptions` INTEGER, `maxPollOptionLength` INTEGER, `minPollDuration` INTEGER, `maxPollDuration` INTEGER, `charactersReservedPerUrl` INTEGER, `version` TEXT, PRIMARY KEY(`instance`))",
+ "fields": [
+ {
+ "fieldPath": "instance",
+ "columnName": "instance",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojiList",
+ "columnName": "emojiList",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maximumTootCharacters",
+ "columnName": "maximumTootCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxPollOptions",
+ "columnName": "maxPollOptions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxPollOptionLength",
+ "columnName": "maxPollOptionLength",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "minPollDuration",
+ "columnName": "minPollDuration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxPollDuration",
+ "columnName": "maxPollDuration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "charactersReservedPerUrl",
+ "columnName": "charactersReservedPerUrl",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "instance"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TimelineStatusEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `bookmarked` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT NOT NULL, `visibility` INTEGER NOT NULL, `attachments` TEXT, `mentions` TEXT, `tags` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, `poll` TEXT, `muted` INTEGER, `expanded` INTEGER NOT NULL, `contentCollapsed` INTEGER NOT NULL, `contentShowing` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "timelineUserId",
+ "columnName": "timelineUserId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "authorServerId",
+ "columnName": "authorServerId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "inReplyToId",
+ "columnName": "inReplyToId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "inReplyToAccountId",
+ "columnName": "inReplyToAccountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "content",
+ "columnName": "content",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojis",
+ "columnName": "emojis",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "reblogsCount",
+ "columnName": "reblogsCount",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "favouritesCount",
+ "columnName": "favouritesCount",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "reblogged",
+ "columnName": "reblogged",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bookmarked",
+ "columnName": "bookmarked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "favourited",
+ "columnName": "favourited",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sensitive",
+ "columnName": "sensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "spoilerText",
+ "columnName": "spoilerText",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "attachments",
+ "columnName": "attachments",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mentions",
+ "columnName": "mentions",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "tags",
+ "columnName": "tags",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "application",
+ "columnName": "application",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "reblogServerId",
+ "columnName": "reblogServerId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "reblogAccountId",
+ "columnName": "reblogAccountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll",
+ "columnName": "poll",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "muted",
+ "columnName": "muted",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "expanded",
+ "columnName": "expanded",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contentCollapsed",
+ "columnName": "contentCollapsed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "contentShowing",
+ "columnName": "contentShowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pinned",
+ "columnName": "pinned",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "serverId",
+ "timelineUserId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
+ "unique": false,
+ "columnNames": [
+ "authorServerId",
+ "timelineUserId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "TimelineAccountEntity",
+ "onDelete": "NO ACTION",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "authorServerId",
+ "timelineUserId"
+ ],
+ "referencedColumns": [
+ "serverId",
+ "timelineUserId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "TimelineAccountEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, `bot` INTEGER NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "timelineUserId",
+ "columnName": "timelineUserId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "localUsername",
+ "columnName": "localUsername",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "username",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "displayName",
+ "columnName": "displayName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatar",
+ "columnName": "avatar",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojis",
+ "columnName": "emojis",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bot",
+ "columnName": "bot",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "serverId",
+ "timelineUserId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "ConversationEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `id` TEXT NOT NULL, `accounts` TEXT NOT NULL, `unread` INTEGER NOT NULL, `s_id` TEXT NOT NULL, `s_url` TEXT, `s_inReplyToId` TEXT, `s_inReplyToAccountId` TEXT, `s_account` TEXT NOT NULL, `s_content` TEXT NOT NULL, `s_createdAt` INTEGER NOT NULL, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_favourited` INTEGER NOT NULL, `s_bookmarked` INTEGER NOT NULL, `s_sensitive` INTEGER NOT NULL, `s_spoilerText` TEXT NOT NULL, `s_attachments` TEXT NOT NULL, `s_mentions` TEXT NOT NULL, `s_tags` TEXT, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsible` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, `s_muted` INTEGER NOT NULL, `s_poll` TEXT, PRIMARY KEY(`id`, `accountId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accounts",
+ "columnName": "accounts",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "unread",
+ "columnName": "unread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.id",
+ "columnName": "s_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.url",
+ "columnName": "s_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastStatus.inReplyToId",
+ "columnName": "s_inReplyToId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastStatus.inReplyToAccountId",
+ "columnName": "s_inReplyToAccountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastStatus.account",
+ "columnName": "s_account",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.content",
+ "columnName": "s_content",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.createdAt",
+ "columnName": "s_createdAt",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.emojis",
+ "columnName": "s_emojis",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.favouritesCount",
+ "columnName": "s_favouritesCount",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.favourited",
+ "columnName": "s_favourited",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.bookmarked",
+ "columnName": "s_bookmarked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.sensitive",
+ "columnName": "s_sensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.spoilerText",
+ "columnName": "s_spoilerText",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.attachments",
+ "columnName": "s_attachments",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.mentions",
+ "columnName": "s_mentions",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.tags",
+ "columnName": "s_tags",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastStatus.showingHiddenContent",
+ "columnName": "s_showingHiddenContent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.expanded",
+ "columnName": "s_expanded",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.collapsible",
+ "columnName": "s_collapsible",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.collapsed",
+ "columnName": "s_collapsed",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.muted",
+ "columnName": "s_muted",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastStatus.poll",
+ "columnName": "s_poll",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id",
+ "accountId"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a75615171612bdfc9e3d4201ebf6071a')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/green/res/values/flavor-colors.xml b/app/src/green/res/values/flavor-colors.xml
new file mode 100644
index 000000000..e1f58f2ea
--- /dev/null
+++ b/app/src/green/res/values/flavor-colors.xml
@@ -0,0 +1,6 @@
+
+
+
+ #19A341
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 91649fb17..46654b625 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,37 +21,23 @@
android:supportsRtl="true"
android:theme="@style/TuskyTheme"
android:usesCleartextTraffic="false">
+
+ android:name=".components.login.LoginActivity"
+ android:windowSoftInputMode="adjustResize">
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -98,6 +84,9 @@
+
-
@@ -125,7 +113,8 @@
android:theme="@style/Base.Theme.AppCompat" />
+ android:launchMode="singleTop"
+ android:exported="false">
@@ -135,18 +124,18 @@
android:resource="@xml/searchable" />
-
-
+
-
+
-
+
+ tools:node="merge">
+
+
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
index 02fa07382..03a74458d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
@@ -34,7 +34,7 @@ import com.keylesspalace.tusky.databinding.FragmentAccountsInListBinding
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.di.ViewModelFactory
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.BindingHolder
import com.keylesspalace.tusky.util.Either
@@ -49,7 +49,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import java.io.IOException
import javax.inject.Inject
-private typealias AccountInfo = Pair
+private typealias AccountInfo = Pair
class AccountsInListFragment : DialogFragment(), Injectable {
@@ -168,21 +168,21 @@ class AccountsInListFragment : DialogFragment(), Injectable {
viewModel.deleteAccountFromList(listId, accountId)
}
- private fun onAddToList(account: Account) {
+ private fun onAddToList(account: TimelineAccount) {
viewModel.addAccountToList(listId, account)
}
- private object AccountDiffer : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(oldItem: Account, newItem: Account): Boolean {
- return oldItem == newItem
+ private object AccountDiffer : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: TimelineAccount, newItem: TimelineAccount): Boolean {
+ return oldItem.id == newItem.id
}
- override fun areContentsTheSame(oldItem: Account, newItem: Account): Boolean {
- return oldItem.deepEquals(newItem)
+ override fun areContentsTheSame(oldItem: TimelineAccount, newItem: TimelineAccount): Boolean {
+ return oldItem == newItem
}
}
- inner class Adapter : ListAdapter>(AccountDiffer) {
+ inner class Adapter : ListAdapter>(AccountDiffer) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder {
val binding = ItemFollowRequestBinding.inflate(LayoutInflater.from(parent.context), parent, false)
@@ -209,12 +209,11 @@ class AccountsInListFragment : DialogFragment(), Injectable {
private object SearchDiffer : DiffUtil.ItemCallback() {
override fun areItemsTheSame(oldItem: AccountInfo, newItem: AccountInfo): Boolean {
- return oldItem == newItem
+ return oldItem.first.id == newItem.first.id
}
override fun areContentsTheSame(oldItem: AccountInfo, newItem: AccountInfo): Boolean {
- return oldItem.second == newItem.second &&
- oldItem.first.deepEquals(newItem.first)
+ return oldItem == newItem
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
index 8e193c349..d34dd6df8 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
@@ -38,6 +38,7 @@ import androidx.preference.PreferenceManager;
import com.google.android.material.snackbar.Snackbar;
import com.keylesspalace.tusky.adapter.AccountSelectionAdapter;
+import com.keylesspalace.tusky.components.login.LoginActivity;
import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.di.Injectable;
diff --git a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
deleted file mode 100644
index 0d5df274c..000000000
--- a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
+++ /dev/null
@@ -1,358 +0,0 @@
-/* Copyright 2017 Andrew Dawson
- *
- * 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 . */
-
-package com.keylesspalace.tusky
-
-import android.content.ActivityNotFoundException
-import android.content.Context
-import android.content.Intent
-import android.content.SharedPreferences
-import android.net.Uri
-import android.os.Bundle
-import android.text.method.LinkMovementMethod
-import android.util.Log
-import android.view.View
-import android.widget.TextView
-import androidx.appcompat.app.AlertDialog
-import androidx.browser.customtabs.CustomTabColorSchemeParams
-import androidx.browser.customtabs.CustomTabsIntent
-import com.bumptech.glide.Glide
-import com.keylesspalace.tusky.databinding.ActivityLoginBinding
-import com.keylesspalace.tusky.di.Injectable
-import com.keylesspalace.tusky.entity.AccessToken
-import com.keylesspalace.tusky.entity.AppCredentials
-import com.keylesspalace.tusky.network.MastodonApi
-import com.keylesspalace.tusky.util.ThemeUtils
-import com.keylesspalace.tusky.util.getNonNullString
-import com.keylesspalace.tusky.util.viewBinding
-import okhttp3.HttpUrl
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
-import javax.inject.Inject
-
-class LoginActivity : BaseActivity(), Injectable {
-
- @Inject
- lateinit var mastodonApi: MastodonApi
-
- private val binding by viewBinding(ActivityLoginBinding::inflate)
-
- private lateinit var preferences: SharedPreferences
-
- private val oauthRedirectUri: String
- get() {
- val scheme = getString(R.string.oauth_scheme)
- val host = BuildConfig.APPLICATION_ID
- return "$scheme://$host/"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setContentView(binding.root)
-
- if (savedInstanceState == null && BuildConfig.CUSTOM_INSTANCE.isNotBlank() && !isAdditionalLogin()) {
- binding.domainEditText.setText(BuildConfig.CUSTOM_INSTANCE)
- binding.domainEditText.setSelection(BuildConfig.CUSTOM_INSTANCE.length)
- }
-
- if (BuildConfig.CUSTOM_LOGO_URL.isNotBlank()) {
- Glide.with(binding.loginLogo)
- .load(BuildConfig.CUSTOM_LOGO_URL)
- .placeholder(null)
- .into(binding.loginLogo)
- }
-
- preferences = getSharedPreferences(
- getString(R.string.preferences_file_key), Context.MODE_PRIVATE
- )
-
- binding.loginButton.setOnClickListener { onButtonClick() }
-
- binding.whatsAnInstanceTextView.setOnClickListener {
- val dialog = AlertDialog.Builder(this)
- .setMessage(R.string.dialog_whats_an_instance)
- .setPositiveButton(R.string.action_close, null)
- .show()
- val textView = dialog.findViewById(android.R.id.message)
- textView?.movementMethod = LinkMovementMethod.getInstance()
- }
-
- if (isAdditionalLogin()) {
- setSupportActionBar(binding.toolbar)
- supportActionBar?.setDisplayHomeAsUpEnabled(true)
- supportActionBar?.setDisplayShowTitleEnabled(false)
- } else {
- binding.toolbar.visibility = View.GONE
- }
- }
-
- override fun requiresLogin(): Boolean {
- return false
- }
-
- override fun finish() {
- super.finish()
- if (isAdditionalLogin()) {
- overridePendingTransition(R.anim.slide_from_left, R.anim.slide_to_right)
- }
- }
-
- /**
- * 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() {
-
- binding.loginButton.isEnabled = false
-
- val domain = canonicalizeDomain(binding.domainEditText.text.toString())
-
- try {
- HttpUrl.Builder().host(domain).scheme("https").build()
- } catch (e: IllegalArgumentException) {
- setLoading(false)
- binding.domainTextInputLayout.error = getString(R.string.error_invalid_domain)
- return
- }
-
- val callback = object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
- if (!response.isSuccessful) {
- binding.loginButton.isEnabled = true
- binding.domainTextInputLayout.error = getString(R.string.error_failed_app_registration)
- setLoading(false)
- Log.e(TAG, "App authentication failed. " + response.message())
- return
- }
- val credentials = response.body()
- val clientId = credentials!!.clientId
- val clientSecret = credentials.clientSecret
-
- preferences.edit()
- .putString("domain", domain)
- .putString("clientId", clientId)
- .putString("clientSecret", clientSecret)
- .apply()
-
- redirectUserToAuthorizeAndLogin(domain, clientId)
- }
-
- override fun onFailure(call: Call, t: Throwable) {
- binding.loginButton.isEnabled = true
- binding.domainTextInputLayout.error = getString(R.string.error_failed_app_registration)
- setLoading(false)
- Log.e(TAG, Log.getStackTraceString(t))
- }
- }
-
- mastodonApi
- .authenticateApp(
- domain, getString(R.string.app_name), oauthRedirectUri,
- OAUTH_SCOPES, getString(R.string.tusky_website)
- )
- .enqueue(callback)
- setLoading(true)
- }
-
- private fun redirectUserToAuthorizeAndLogin(domain: String, clientId: String) {
- /* 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 endpoint = MastodonApi.ENDPOINT_AUTHORIZE
- val parameters = mapOf(
- "client_id" to clientId,
- "redirect_uri" to oauthRedirectUri,
- "response_type" to "code",
- "scope" to OAUTH_SCOPES
- )
- val url = "https://" + domain + endpoint + "?" + toQueryString(parameters)
- val uri = Uri.parse(url)
- if (!openInCustomTab(uri, this)) {
- val viewIntent = Intent(Intent.ACTION_VIEW, uri)
- if (viewIntent.resolveActivity(packageManager) != null) {
- startActivity(viewIntent)
- } else {
- binding.domainEditText.error = getString(R.string.error_no_web_browser_found)
- setLoading(false)
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- /* 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
- val redirectUri = oauthRedirectUri
-
- if (uri != null && uri.toString().startsWith(redirectUri)) {
- // 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()) {
-
- setLoading(true)
- /* Since authorization has succeeded, the final step to log in is to exchange
- * the authorization code for an access token. */
- val callback = object : Callback {
- override fun onResponse(call: Call, response: Response) {
- if (response.isSuccessful) {
- onLoginSuccess(response.body()!!.accessToken, domain)
- } else {
- setLoading(false)
- binding.domainTextInputLayout.error = getString(R.string.error_retrieving_oauth_token)
- Log.e(TAG, "%s %s".format(getString(R.string.error_retrieving_oauth_token), response.message()))
- }
- }
-
- override fun onFailure(call: Call, t: Throwable) {
- setLoading(false)
- binding.domainTextInputLayout.error = getString(R.string.error_retrieving_oauth_token)
- Log.e(TAG, "%s %s".format(getString(R.string.error_retrieving_oauth_token), t.message))
- }
- }
-
- mastodonApi.fetchOAuthToken(
- domain, clientId, clientSecret, redirectUri, code,
- "authorization_code"
- ).enqueue(callback)
- } else if (error != null) {
- /* Authorization failed. Put the error response where the user can read it and they
- * can try again. */
- setLoading(false)
- binding.domainTextInputLayout.error = getString(R.string.error_authorization_denied)
- Log.e(TAG, "%s %s".format(getString(R.string.error_authorization_denied), error))
- } else {
- // This case means a junk response was received somehow.
- setLoading(false)
- binding.domainTextInputLayout.error = getString(R.string.error_authorization_unknown)
- }
- } else {
- // first show or user cancelled login
- setLoading(false)
- }
- }
-
- private fun setLoading(loadingState: Boolean) {
- if (loadingState) {
- binding.loginLoadingLayout.visibility = View.VISIBLE
- binding.loginInputLayout.visibility = View.GONE
- } else {
- binding.loginLoadingLayout.visibility = View.GONE
- binding.loginInputLayout.visibility = View.VISIBLE
- binding.loginButton.isEnabled = true
- }
- }
-
- private fun isAdditionalLogin(): Boolean {
- return intent.getBooleanExtra(LOGIN_MODE, false)
- }
-
- private fun onLoginSuccess(accessToken: String, domain: String) {
-
- setLoading(true)
-
- accountManager.addAccount(accessToken, domain)
-
- val intent = Intent(this, MainActivity::class.java)
- intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
- startActivity(intent)
- finish()
- overridePendingTransition(R.anim.explode, R.anim.explode)
- }
-
- companion object {
- private const val TAG = "LoginActivity" // logging tag
- private const val OAUTH_SCOPES = "read write follow"
- private const val LOGIN_MODE = "LOGIN_MODE"
- private const val DOMAIN = "domain"
- private const val CLIENT_ID = "clientId"
- private const val CLIENT_SECRET = "clientSecret"
-
- @JvmStatic
- fun getIntent(context: Context, mode: Boolean): Intent {
- val loginIntent = Intent(context, LoginActivity::class.java)
- loginIntent.putExtra(LOGIN_MODE, mode)
- return loginIntent
- }
-
- /** Make sure the user-entered text is just a fully-qualified domain name. */
- private fun canonicalizeDomain(domain: String): String {
- // Strip any schemes out.
- var s = domain.replaceFirst("http://", "")
- s = s.replaceFirst("https://", "")
- // If a username was included (e.g. username@example.com), just take what's after the '@'.
- val at = s.lastIndexOf('@')
- if (at != -1) {
- s = s.substring(at + 1)
- }
- return s.trim { it <= ' ' }
- }
-
- /**
- * Chain together the key-value pairs into a query string, for either appending to a URL or
- * as the content of an HTTP request.
- */
- private fun toQueryString(parameters: Map): String {
- val s = StringBuilder()
- var between = ""
- for ((key, value) in parameters) {
- s.append(between)
- s.append(Uri.encode(key))
- s.append("=")
- s.append(Uri.encode(value))
- between = "&"
- }
- return s.toString()
- }
-
- private fun openInCustomTab(uri: Uri, context: Context): Boolean {
-
- val toolbarColor = ThemeUtils.getColor(context, R.attr.colorSurface)
- val navigationbarColor = ThemeUtils.getColor(context, android.R.attr.navigationBarColor)
- val navigationbarDividerColor = ThemeUtils.getColor(context, R.attr.dividerColor)
-
- val colorSchemeParams = CustomTabColorSchemeParams.Builder()
- .setToolbarColor(toolbarColor)
- .setNavigationBarColor(navigationbarColor)
- .setNavigationBarDividerColor(navigationbarDividerColor)
- .build()
-
- val customTabsIntent = CustomTabsIntent.Builder()
- .setDefaultColorSchemeParams(colorSchemeParams)
- .build()
-
- try {
- customTabsIntent.launchUrl(context, uri)
- } catch (e: ActivityNotFoundException) {
- Log.w(TAG, "Activity was not found for intent $customTabsIntent")
- return false
- }
-
- return true
- }
- }
-}
diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
index 9410458ba..e445102e3 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
@@ -44,6 +44,7 @@ import androidx.appcompat.widget.PopupMenu
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import androidx.core.content.pm.ShortcutManagerCompat
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.emoji.text.EmojiCompat
import androidx.emoji.text.EmojiCompat.InitCallback
import androidx.lifecycle.Lifecycle
@@ -74,9 +75,10 @@ import com.keylesspalace.tusky.components.compose.ComposeActivity.Companion.canH
import com.keylesspalace.tusky.components.conversation.ConversationsRepository
import com.keylesspalace.tusky.components.drafts.DraftHelper
import com.keylesspalace.tusky.components.drafts.DraftsActivity
+import com.keylesspalace.tusky.components.login.LoginActivity
import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.components.preference.PreferencesActivity
-import com.keylesspalace.tusky.components.scheduled.ScheduledTootActivity
+import com.keylesspalace.tusky.components.scheduled.ScheduledStatusActivity
import com.keylesspalace.tusky.components.search.SearchActivity
import com.keylesspalace.tusky.components.timeline.TimelineFragment
import com.keylesspalace.tusky.databinding.ActivityMainBinding
@@ -132,6 +134,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.launch
+import net.accelf.yuito.CustomUncaughtExceptionHandler
import net.accelf.yuito.FooterDrawerItem
import net.accelf.yuito.QuickTootViewModel
import net.accelf.yuito.streaming.StreamingManager
@@ -185,8 +188,14 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
}
override fun onCreate(savedInstanceState: Bundle?) {
+ Thread.setDefaultUncaughtExceptionHandler(CustomUncaughtExceptionHandler(applicationContext))
+
+ installSplashScreen()
super.onCreate(savedInstanceState)
+ // delete old notification channels
+ NotificationHelper.deleteLegacyNotificationChannels(this, accountManager)
+
val activeAccount = accountManager.activeAccount
?: return // will be redirected to LoginActivity by BaseActivity
@@ -515,10 +524,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
}
},
primaryDrawerItem {
- nameRes = R.string.action_access_scheduled_toot
+ nameRes = R.string.action_access_scheduled_posts
iconRes = R.drawable.ic_access_time
onClick = {
- startActivityWithSlideInAnimation(ScheduledTootActivity.newIntent(context))
+ startActivityWithSlideInAnimation(ScheduledStatusActivity.newIntent(context))
}
},
primaryDrawerItem {
diff --git a/app/src/main/java/com/keylesspalace/tusky/SplashActivity.kt b/app/src/main/java/com/keylesspalace/tusky/SplashActivity.kt
deleted file mode 100644
index 31ae757bc..000000000
--- a/app/src/main/java/com/keylesspalace/tusky/SplashActivity.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright 2018 Conny Duck
- *
- * 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 . */
-
-package com.keylesspalace.tusky
-
-import android.content.Intent
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import com.keylesspalace.tusky.components.notifications.NotificationHelper
-import com.keylesspalace.tusky.db.AccountManager
-import com.keylesspalace.tusky.di.Injectable
-import net.accelf.yuito.CustomUncaughtExceptionHandler
-import javax.inject.Inject
-
-class SplashActivity : AppCompatActivity(), Injectable {
-
- @Inject
- lateinit var accountManager: AccountManager
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- val customUncaughtExceptionHandler = CustomUncaughtExceptionHandler(applicationContext)
- Thread.setDefaultUncaughtExceptionHandler(customUncaughtExceptionHandler)
-
- /** delete old notification channels */
- NotificationHelper.deleteLegacyNotificationChannels(this, accountManager)
-
- /** Determine whether the user is currently logged in, and if so go ahead and load the
- * timeline. Otherwise, start the activity_login screen. */
-
- val intent = if (accountManager.activeAccount != null) {
- Intent(this, MainActivity::class.java)
- } else {
- LoginActivity.getIntent(this, false)
- }
- startActivity(intent)
- finish()
- }
-}
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
index 2598b5e22..64d29577b 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
@@ -36,6 +36,7 @@ import android.view.MenuItem
import android.view.View
import android.webkit.MimeTypeMap
import android.widget.Toast
+import androidx.core.app.ShareCompat
import androidx.core.content.FileProvider
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
@@ -205,10 +206,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val request = DownloadManager.Request(Uri.parse(url))
- request.setDestinationInExternalPublicDir(
- Environment.DIRECTORY_PICTURES,
- getString(R.string.app_name) + "/" + filename
- )
+ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename)
downloadManager.enqueue(request)
}
@@ -255,11 +253,11 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
}
private fun shareFile(file: File, mimeType: String?) {
- val sendIntent = Intent()
- sendIntent.action = Intent.ACTION_SEND
- sendIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(applicationContext, "$APPLICATION_ID.fileprovider", file))
- sendIntent.type = mimeType
- startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_media_to)))
+ ShareCompat.IntentBuilder(this)
+ .setType(mimeType)
+ .addStream(FileProvider.getUriForFile(applicationContext, "$APPLICATION_ID.fileprovider", file))
+ .setChooserTitle(R.string.send_media_to)
+ .startChooser()
}
private var isCreating: Boolean = false
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountAdapter.kt
index 320f8126f..366dae7f9 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountAdapter.kt
@@ -18,7 +18,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.removeDuplicates
@@ -28,7 +28,7 @@ abstract class AccountAdapter internal constructo
protected val animateAvatar: Boolean,
protected val animateEmojis: Boolean
) : RecyclerView.Adapter() {
- var accountList = mutableListOf()
+ var accountList = mutableListOf()
private var bottomLoading: Boolean = false
override fun getItemCount(): Int {
@@ -73,12 +73,12 @@ abstract class AccountAdapter internal constructo
}
}
- fun update(newAccounts: List) {
+ fun update(newAccounts: List) {
accountList = removeDuplicates(newAccounts)
notifyDataSetChanged()
}
- fun addItems(newAccounts: List) {
+ fun addItems(newAccounts: List) {
val end = accountList.size
val last = accountList[end - 1]
if (newAccounts.none { it.id == last.id }) {
@@ -100,7 +100,7 @@ abstract class AccountAdapter internal constructo
}
}
- fun removeItem(position: Int): Account? {
+ fun removeItem(position: Int): TimelineAccount? {
if (position < 0 || position >= accountList.size) {
return null
}
@@ -109,7 +109,7 @@ abstract class AccountAdapter internal constructo
return account
}
- fun addItem(account: Account, position: Int) {
+ fun addItem(account: TimelineAccount, position: Int) {
if (position < 0 || position > accountList.size) {
return
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java
index 559426e38..f48243899 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java
@@ -9,7 +9,7 @@ import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import com.keylesspalace.tusky.R;
-import com.keylesspalace.tusky.entity.Account;
+import com.keylesspalace.tusky.entity.TimelineAccount;
import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.interfaces.LinkListener;
import com.keylesspalace.tusky.util.CustomEmojiHelper;
@@ -33,9 +33,9 @@ public class AccountViewHolder extends RecyclerView.ViewHolder {
showBotOverlay = sharedPrefs.getBoolean("showBotOverlay", true);
}
- public void setupWithAccount(Account account, boolean animateAvatar, boolean animateEmojis) {
+ public void setupWithAccount(TimelineAccount account, boolean animateAvatar, boolean animateEmojis) {
accountId = account.getId();
- String format = username.getContext().getString(R.string.status_username_format);
+ String format = username.getContext().getString(R.string.post_username_format);
String formattedUsername = String.format(format, account.getUsername());
username.setText(formattedUsername);
CharSequence emojifiedName = CustomEmojiHelper.emojify(account.getName(), account.getEmojis(), displayName, animateEmojis);
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.kt
index 33a236056..859807e97 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.kt
@@ -22,7 +22,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.emojify
import com.keylesspalace.tusky.util.loadAvatar
@@ -55,11 +55,11 @@ class BlocksAdapter(
private val unblock: ImageButton = itemView.findViewById(R.id.blocked_user_unblock)
private var id: String? = null
- fun setupWithAccount(account: Account, animateAvatar: Boolean, animateEmojis: Boolean) {
+ fun setupWithAccount(account: TimelineAccount, animateAvatar: Boolean, animateEmojis: Boolean) {
id = account.id
val emojifiedName = account.name.emojify(account.emojis, displayName, animateEmojis)
displayName.text = emojifiedName
- val format = username.context.getString(R.string.status_username_format)
+ val format = username.context.getString(R.string.post_username_format)
val formattedUsername = String.format(format, account.username)
username.text = formattedUsername
val avatarRadius = avatar.context.resources
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestViewHolder.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestViewHolder.kt
index 2be8b7621..38b301b3a 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestViewHolder.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestViewHolder.kt
@@ -22,7 +22,7 @@ import android.text.style.StyleSpan
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.emojify
import com.keylesspalace.tusky.util.loadAvatar
@@ -34,7 +34,7 @@ class FollowRequestViewHolder(
private val showHeader: Boolean
) : RecyclerView.ViewHolder(binding.root) {
- fun setupWithAccount(account: Account, animateAvatar: Boolean, animateEmojis: Boolean) {
+ fun setupWithAccount(account: TimelineAccount, animateAvatar: Boolean, animateEmojis: Boolean) {
val wrappedName = account.name.unicodeWrap()
val emojifiedName: CharSequence = wrappedName.emojify(account.emojis, itemView, animateEmojis)
binding.displayNameTextView.text = emojifiedName
@@ -45,7 +45,7 @@ class FollowRequestViewHolder(
}.emojify(account.emojis, itemView, animateEmojis)
}
binding.notificationTextView.visible(showHeader)
- val format = itemView.context.getString(R.string.status_username_format)
+ val format = itemView.context.getString(R.string.post_username_format)
val formattedUsername = String.format(format, account.username)
binding.usernameTextView.text = formattedUsername
val avatarRadius = binding.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.kt
index 9fca33e8f..41bb286f5 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.kt
@@ -9,7 +9,7 @@ import android.widget.TextView
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.emojify
import com.keylesspalace.tusky.util.loadAvatar
@@ -69,7 +69,7 @@ class MutesAdapter(
private var notifications = false
fun setupWithAccount(
- account: Account,
+ account: TimelineAccount,
mutingNotifications: Boolean?,
animateAvatar: Boolean,
animateEmojis: Boolean
@@ -77,7 +77,7 @@ class MutesAdapter(
id = account.id
val emojifiedName = account.name.emojify(account.emojis, displayName, animateEmojis)
displayName.text = emojifiedName
- val format = username.context.getString(R.string.status_username_format)
+ val format = username.context.getString(R.string.post_username_format)
val formattedUsername = String.format(format, account.username)
username.text = formattedUsername
val avatarRadius = avatar.context.resources
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
index bfda8942c..68f921013 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java
@@ -41,10 +41,10 @@ import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding;
-import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Emoji;
import com.keylesspalace.tusky.entity.Notification;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.entity.TimelineAccount;
import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.interfaces.LinkListener;
import com.keylesspalace.tusky.interfaces.StatusActionListener;
@@ -339,7 +339,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
this.statusDisplayOptions = statusDisplayOptions;
}
- void setMessage(Account account) {
+ void setMessage(TimelineAccount account) {
Context context = message.getContext();
String format = context.getString(R.string.notification_follow_format);
@@ -350,7 +350,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
);
message.setText(emojifiedMessage);
- String username = context.getString(R.string.status_username_format, account.getUsername());
+ String username = context.getString(R.string.post_username_format, account.getUsername());
usernameView.setText(username);
CharSequence emojifiedDisplayName = CustomEmojiHelper.emojify(
@@ -447,7 +447,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
private void setUsername(String name) {
Context context = username.getContext();
- String format = context.getString(R.string.status_username_format);
+ String format = context.getString(R.string.post_username_format);
String usernameText = String.format(format, name);
username.setText(usernameText);
}
@@ -545,9 +545,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
contentWarningDescriptionTextView.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE);
contentWarningButton.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE);
if (statusViewData.isExpanded()) {
- contentWarningButton.setText(R.string.status_content_warning_show_less);
+ contentWarningButton.setText(R.string.post_content_warning_show_less);
} else {
- contentWarningButton.setText(R.string.status_content_warning_show_more);
+ contentWarningButton.setText(R.string.post_content_warning_show_more);
}
contentWarningButton.setOnClickListener(view -> {
@@ -649,10 +649,10 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
contentCollapseButton.setVisibility(View.VISIBLE);
if (statusViewData.isCollapsed()) {
- contentCollapseButton.setText(R.string.status_content_warning_show_more);
+ contentCollapseButton.setText(R.string.post_content_warning_show_more);
statusContent.setFilters(COLLAPSE_INPUT_FILTER);
} else {
- contentCollapseButton.setText(R.string.status_content_warning_show_less);
+ contentCollapseButton.setText(R.string.post_content_warning_show_less);
statusContent.setFilters(NO_INPUT_FILTER);
}
} else {
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
index 8775230d8..2b37289f1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
@@ -200,7 +200,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
protected void setUsername(String name) {
Context context = username.getContext();
- String usernameText = context.getString(R.string.status_username_format, name);
+ String usernameText = context.getString(R.string.post_username_format, name);
username.setText(usernameText);
}
@@ -245,9 +245,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
private void setContentWarningButtonText(boolean expanded) {
if (expanded) {
- contentWarningButton.setText(R.string.status_content_warning_show_less);
+ contentWarningButton.setText(R.string.post_content_warning_show_less);
} else {
- contentWarningButton.setText(R.string.status_content_warning_show_more);
+ contentWarningButton.setText(R.string.post_content_warning_show_more);
}
}
@@ -588,9 +588,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
}
if (sensitive) {
- sensitiveMediaWarning.setText(R.string.status_sensitive_media_title);
+ sensitiveMediaWarning.setText(R.string.post_sensitive_media_title);
} else {
- sensitiveMediaWarning.setText(R.string.status_media_hidden_title);
+ sensitiveMediaWarning.setText(R.string.post_media_hidden_title);
}
sensitiveMediaWarning.setVisibility(showingContent ? View.GONE : View.VISIBLE);
@@ -635,7 +635,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
private void updateMediaLabel(int index, boolean sensitive, boolean showingContent) {
Context context = itemView.getContext();
CharSequence label = (sensitive && !showingContent) ?
- context.getString(R.string.status_sensitive_media_title) :
+ context.getString(R.string.post_sensitive_media_title) :
mediaDescriptions[index];
mediaLabels[index].setText(label);
}
@@ -687,7 +687,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
duration = formatDuration(attachment.getMeta().getDuration()) + " ";
}
if (TextUtils.isEmpty(attachment.getDescription())) {
- return duration + context.getString(R.string.description_status_media_no_description_placeholder);
+ return duration + context.getString(R.string.description_post_media_no_description_placeholder);
} else {
return duration + attachment.getDescription();
}
@@ -935,9 +935,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
getCreatedAtDescription(actionable.getCreatedAt(), statusDisplayOptions),
getReblogDescription(context, status),
status.getUsername(),
- actionable.getReblogged() ? context.getString(R.string.description_status_reblogged) : "",
- actionable.getFavourited() ? context.getString(R.string.description_status_favourited) : "",
- actionable.getBookmarked() ? context.getString(R.string.description_status_bookmarked) : "",
+ actionable.getReblogged() ? context.getString(R.string.description_post_reblogged) : "",
+ actionable.getFavourited() ? context.getString(R.string.description_post_favourited) : "",
+ actionable.getBookmarked() ? context.getString(R.string.description_post_bookmarked) : "",
getMediaDescription(context, status),
getVisibilityDescription(context, actionable.getVisibility()),
getFavsText(context, actionable.getFavouritesCount()),
@@ -952,7 +952,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
Status reblog = status.getRebloggingStatus();
if (reblog != null) {
return context
- .getString(R.string.status_boosted_format, reblog.getAccount().getUsername());
+ .getString(R.string.post_boosted_format, reblog.getAccount().getUsername());
} else {
return "";
}
@@ -969,20 +969,20 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
(builder, a) -> {
if (a.getDescription() == null) {
String placeholder =
- context.getString(R.string.description_status_media_no_description_placeholder);
+ context.getString(R.string.description_post_media_no_description_placeholder);
return builder.append(placeholder);
} else {
builder.append("; ");
return builder.append(a.getDescription());
}
});
- return context.getString(R.string.description_status_media, mediaDescriptions);
+ return context.getString(R.string.description_post_media, mediaDescriptions);
}
private static CharSequence getContentWarningDescription(Context context,
@NonNull StatusViewData.Concrete status) {
if (!TextUtils.isEmpty(status.getSpoilerText())) {
- return context.getString(R.string.description_status_cw, status.getSpoilerText());
+ return context.getString(R.string.description_post_cw, status.getSpoilerText());
} else {
return "";
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java
index 165691455..b054aea9c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java
@@ -86,7 +86,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
final StatusDisplayOptions statusDisplayOptions) {
Context context = statusInfo.getContext();
CharSequence wrappedName = StringUtils.unicodeWrap(name);
- CharSequence boostedText = context.getString(R.string.status_boosted_format, wrappedName);
+ CharSequence boostedText = context.getString(R.string.post_boosted_format, wrappedName);
CharSequence emojifiedText = CustomEmojiHelper.emojify(
boostedText, accountEmoji, statusInfo, statusDisplayOptions.animateEmojis()
);
@@ -118,10 +118,10 @@ public class StatusViewHolder extends StatusBaseViewHolder {
contentCollapseButton.setVisibility(View.VISIBLE);
if (status.isCollapsed()) {
- contentCollapseButton.setText(R.string.status_content_warning_show_more);
+ contentCollapseButton.setText(R.string.post_content_warning_show_more);
content.setFilters(COLLAPSE_INPUT_FILTER);
} else {
- contentCollapseButton.setText(R.string.status_content_warning_show_less);
+ contentCollapseButton.setText(R.string.post_content_warning_show_less);
content.setFilters(NO_INPUT_FILTER);
}
} else {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
index cd9f33410..12b2fa35b 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
@@ -239,7 +239,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
binding.accountFragmentViewPager.adapter = adapter
binding.accountFragmentViewPager.offscreenPageLimit = 2
- val pageTitles = arrayOf(getString(R.string.title_statuses), getString(R.string.title_statuses_with_replies), getString(R.string.title_statuses_pinned), getString(R.string.title_media))
+ val pageTitles = arrayOf(getString(R.string.title_posts), getString(R.string.title_posts_with_replies), getString(R.string.title_posts_pinned), getString(R.string.title_media))
TabLayoutMediator(binding.accountTabLayout, binding.accountFragmentViewPager) { tab, position ->
tab.text = pageTitles[position]
@@ -411,7 +411,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
private fun onAccountChanged(account: Account?) {
loadedAccount = account ?: return
- val usernameFormatted = getString(R.string.status_username_format, account.username)
+ val usernameFormatted = getString(R.string.post_username_format, account.username)
binding.accountUsernameTextView.text = usernameFormatted
binding.accountDisplayNameTextView.text = account.name.emojify(account.emojis, binding.accountDisplayNameTextView, animateEmojis)
@@ -482,7 +482,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
} catch (e: IllegalStateException) {
supportActionBar?.title = emojifiedName
}
- supportActionBar?.subtitle = String.format(getString(R.string.status_username_format), account.username)
+ supportActionBar?.subtitle = String.format(getString(R.string.post_username_format), account.username)
}
}
@@ -499,7 +499,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
}
binding.accountMovedDisplayName.text = movedAccount.name
- binding.accountMovedUsername.text = getString(R.string.status_username_format, movedAccount.username)
+ binding.accountMovedUsername.text = getString(R.string.post_username_format, movedAccount.username)
val avatarRadius = resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt
index 41aabdde3..18ce34e9e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt
@@ -16,7 +16,9 @@
package com.keylesspalace.tusky.components.compose
import android.Manifest
+import android.app.NotificationManager
import android.app.ProgressDialog
+import android.content.ClipData
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
@@ -46,8 +48,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
-import androidx.core.view.inputmethod.InputConnectionCompat
-import androidx.core.view.inputmethod.InputContentInfoCompat
+import androidx.core.view.ContentInfoCompat
+import androidx.core.view.OnReceiveContentListener
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
@@ -109,7 +111,7 @@ class ComposeActivity :
ComposeAutoCompleteAdapter.AutocompletionProvider,
OnEmojiSelectedListener,
Injectable,
- InputConnectionCompat.OnCommitContentListener,
+ OnReceiveContentListener,
ComposeScheduleView.OnTimeSetListener {
@Inject
@@ -155,6 +157,18 @@ class ComposeActivity :
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ val notificationId = intent.getIntExtra(NOTIFICATION_ID_EXTRA, -1)
+ if (notificationId != -1) {
+ // ComposeActivity was opened from a notification, delete the notification
+ val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.cancel(notificationId)
+ }
+
+ val accountId = intent.getLongExtra(ACCOUNT_ID_EXTRA, -1)
+ if (accountId != -1L) {
+ accountManager.setActiveAccount(accountId)
+ }
+
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT)
if (theme == "black") {
@@ -194,9 +208,9 @@ class ComposeActivity :
viewModel.setup(composeOptions)
setupReplyViews(composeOptions?.replyingStatusAuthor, composeOptions?.replyingStatusContent)
setupQuoteView(composeOptions?.quoteStatusAuthor, composeOptions?.quoteStatusContent)
- val tootText = composeOptions?.tootText
- if (!tootText.isNullOrEmpty()) {
- binding.composeEditField.setText(tootText)
+ val statusContent = composeOptions?.content
+ if (!statusContent.isNullOrEmpty()) {
+ binding.composeEditField.setText(statusContent)
}
viewModel.loadInstanceDataFromNetwork(loadInstanceData(preferences, composeOptions?.tootRightNow == true))
@@ -249,26 +263,25 @@ class ComposeActivity :
}
}
}
- } else if (type == "text/plain" && intent.action == Intent.ACTION_SEND) {
+ }
- val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT)
- val text = intent.getStringExtra(Intent.EXTRA_TEXT).orEmpty()
- val shareBody = if (!subject.isNullOrBlank() && subject !in text) {
- subject + '\n' + text
- } else {
- text
- }
+ val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT)
+ val text = intent.getStringExtra(Intent.EXTRA_TEXT).orEmpty()
+ val shareBody = if (!subject.isNullOrBlank() && subject !in text) {
+ subject + '\n' + text
+ } else {
+ text
+ }
- if (shareBody.isNotBlank()) {
- val start = binding.composeEditField.selectionStart.coerceAtLeast(0)
- val end = binding.composeEditField.selectionEnd.coerceAtLeast(0)
- val left = min(start, end)
- val right = max(start, end)
- binding.composeEditField.text.replace(left, right, shareBody, 0, shareBody.length)
- // move edittext cursor to first when shareBody parsed
- binding.composeEditField.text.insert(0, "\n")
- binding.composeEditField.setSelection(0)
- }
+ if (shareBody.isNotBlank()) {
+ val start = binding.composeEditField.selectionStart.coerceAtLeast(0)
+ val end = binding.composeEditField.selectionEnd.coerceAtLeast(0)
+ val left = min(start, end)
+ val right = max(start, end)
+ binding.composeEditField.text.replace(left, right, shareBody, 0, shareBody.length)
+ // move edittext cursor to first when shareBody parsed
+ binding.composeEditField.text.insert(0, "\n")
+ binding.composeEditField.setSelection(0)
}
}
}
@@ -336,7 +349,7 @@ class ComposeActivity :
}
private fun setupComposeField(preferences: SharedPreferences, startingText: String?) {
- binding.composeEditField.setOnCommitContentListener(this)
+ binding.composeEditField.setOnReceiveContentListener(this)
binding.composeEditField.setOnKeyListener { _, keyCode, event -> this.onKeyDown(keyCode, event) }
@@ -776,7 +789,9 @@ class ComposeActivity :
val urlSpans = binding.composeEditField.urls
if (urlSpans != null) {
for (span in urlSpans) {
- offset += max(0, span.url.length - charactersReservedPerUrl)
+ // it's expected that this will be negative
+ // when the url length is less than the reserved character count
+ offset += (span.url.length - charactersReservedPerUrl)
}
}
var length = binding.composeEditField.length() - offset
@@ -819,26 +834,18 @@ class ComposeActivity :
}
}
- /** This is for the fancy keyboards which can insert images and stuff. */
- override fun onCommitContent(inputContentInfo: InputContentInfoCompat, flags: Int, opts: Bundle?): Boolean {
- // Verify the returned content's type is of the correct MIME type
- val supported = inputContentInfo.description.hasMimeType("image/*")
-
- if (supported) {
- val lacksPermission = (flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0
- if (lacksPermission) {
- try {
- inputContentInfo.requestPermission()
- } catch (e: Exception) {
- Log.e(TAG, "InputContentInfoCompat#requestPermission() failed." + e.message)
- return false
+ /** This is for the fancy keyboards which can insert images and stuff, and drag&drop etc */
+ override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat? {
+ if (contentInfo.clip.description.hasMimeType("image/*")) {
+ val split = contentInfo.partition { item: ClipData.Item -> item.uri != null }
+ split.first?.let { content ->
+ for (i in 0 until content.clip.itemCount) {
+ pickMedia(content.clip.getItemAt(i).uri)
}
}
- pickMedia(inputContentInfo.contentUri, inputContentInfo)
- return true
+ return split.second
}
-
- return false
+ return contentInfo
}
private fun sendStatus() {
@@ -865,12 +872,11 @@ class ComposeActivity :
}
viewModel.sendStatus(contentText, spoilerText).observe(
- this,
- {
- finishingUploadDialog?.dismiss()
- deleteDraftAndFinish()
- }
- )
+ this
+ ) {
+ finishingUploadDialog?.dismiss()
+ deleteDraftAndFinish()
+ }
} else {
binding.composeEditField.error = getString(R.string.error_compose_character_limit)
enableButtons(true)
@@ -940,12 +946,9 @@ class ComposeActivity :
viewModel.removeMediaFromQueue(item)
}
- private fun pickMedia(uri: Uri, contentInfoCompat: InputContentInfoCompat? = null) {
+ private fun pickMedia(uri: Uri) {
withLifecycleContext {
viewModel.pickMedia(uri).observe { exceptionOrItem ->
-
- contentInfoCompat?.releasePermission()
-
exceptionOrItem.asLeftOrNull()?.let {
val errorId = when (it) {
is VideoSizeException -> {
@@ -1098,29 +1101,29 @@ class ComposeActivity :
@Parcelize
data class ComposeOptions(
- // Let's keep fields var until all consumers are Kotlin
- var scheduledTootId: String? = null,
- var draftId: Int? = null,
- var tootText: String? = null,
- var mediaUrls: List? = null,
- var mediaDescriptions: List? = null,
- var mentionedUsernames: Set? = null,
- var inReplyToId: String? = null,
- var quoteId: String? = null,
- var quoteStatusAuthor: String? = null,
- var quoteStatusContent: String? = null,
- var replyVisibility: Status.Visibility? = null,
- var visibility: Status.Visibility? = null,
- var contentWarning: String? = null,
- var replyingStatusAuthor: String? = null,
- var replyingStatusContent: String? = null,
- var mediaAttachments: List? = null,
- var draftAttachments: List? = null,
- var scheduledAt: String? = null,
- var sensitive: Boolean? = null,
- var poll: NewPoll? = null,
- var modifiedInitialState: Boolean? = null,
- var tootRightNow: Boolean? = null
+ // Let's keep fields var until all consumers are Kotlin
+ var scheduledTootId: String? = null,
+ var draftId: Int? = null,
+ var content: String? = null,
+ var mediaUrls: List? = null,
+ var mediaDescriptions: List? = null,
+ var mentionedUsernames: Set? = null,
+ var inReplyToId: String? = null,
+ var quoteId: String? = null,
+ var quoteStatusAuthor: String? = null,
+ var quoteStatusContent: String? = null,
+ var replyVisibility: Status.Visibility? = null,
+ var visibility: Status.Visibility? = null,
+ var contentWarning: String? = null,
+ var replyingStatusAuthor: String? = null,
+ var replyingStatusContent: String? = null,
+ var mediaAttachments: List? = null,
+ var draftAttachments: List? = null,
+ var scheduledAt: String? = null,
+ var sensitive: Boolean? = null,
+ var poll: NewPoll? = null,
+ var modifiedInitialState: Boolean? = null,
+ var tootRightNow: Boolean? = null,
) : Parcelable
companion object {
@@ -1128,6 +1131,8 @@ class ComposeActivity :
private const val PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1
internal const val COMPOSE_OPTIONS_EXTRA = "COMPOSE_OPTIONS"
+ private const val NOTIFICATION_ID_EXTRA = "NOTIFICATION_ID"
+ private const val ACCOUNT_ID_EXTRA = "ACCOUNT_ID"
private const val PHOTO_UPLOAD_URI_KEY = "PHOTO_UPLOAD_URI"
@JvmField
@@ -1136,10 +1141,28 @@ class ComposeActivity :
const val PREF_DEFAULT_TAG = "default_tag"
const val PREF_USE_DEFAULT_TAG = "use_default_tag"
+ /**
+ * @param options ComposeOptions to configure the ComposeActivity
+ * @param notificationId the id of the notification that starts the Activity
+ * @param accountId the id of the account to compose with, null for the current account
+ * @return an Intent to start the ComposeActivity
+ */
@JvmStatic
- fun startIntent(context: Context, options: ComposeOptions): Intent {
+ @JvmOverloads
+ fun startIntent(
+ context: Context,
+ options: ComposeOptions,
+ notificationId: Int? = null,
+ accountId: Long? = null
+ ): Intent {
return Intent(context, ComposeActivity::class.java).apply {
putExtra(COMPOSE_OPTIONS_EXTRA, options)
+ if (notificationId != null) {
+ putExtra(NOTIFICATION_ID_EXTRA, notificationId)
+ }
+ if (accountId != null) {
+ putExtra(ACCOUNT_ID_EXTRA, accountId)
+ }
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeAutoCompleteAdapter.java b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeAutoCompleteAdapter.java
index b2fa94c34..8a4f0ce1f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeAutoCompleteAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeAutoCompleteAdapter.java
@@ -16,7 +16,6 @@
package com.keylesspalace.tusky.components.compose;
import android.content.Context;
-import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -28,9 +27,9 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.keylesspalace.tusky.R;
-import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Emoji;
import com.keylesspalace.tusky.entity.HashTag;
+import com.keylesspalace.tusky.entity.TimelineAccount;
import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper;
@@ -144,9 +143,9 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
AccountResult accountResult = ((AccountResult) getItem(position));
if (accountResult != null) {
- Account account = accountResult.account;
+ TimelineAccount account = accountResult.account;
String formattedUsername = context.getString(
- R.string.status_username_format,
+ R.string.post_username_format,
account.getUsername()
);
accountViewHolder.username.setText(formattedUsername);
@@ -268,9 +267,9 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
}
public final static class AccountResult extends AutocompleteResult {
- private final Account account;
+ private final TimelineAccount account;
- public AccountResult(Account account) {
+ public AccountResult(TimelineAccount account) {
this.account = account;
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt
index 8bdd1f109..0764a03df 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt
@@ -34,7 +34,7 @@ import com.keylesspalace.tusky.entity.NewPoll
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.service.ServiceClient
-import com.keylesspalace.tusky.service.TootToSend
+import com.keylesspalace.tusky.service.StatusToSend
import com.keylesspalace.tusky.util.Either
import com.keylesspalace.tusky.util.RxAwareViewModel
import com.keylesspalace.tusky.util.VersionUtils
@@ -315,25 +315,25 @@ class ComposeViewModel @Inject constructor(
mediaDescriptions.add(item.description ?: "")
}
- val tootToSend = TootToSend(
- text = content,
- warningText = spoilerText,
- visibility = statusVisibility.value!!.serverString(),
- sensitive = mediaUris.isNotEmpty() && (markMediaAsSensitive.value!! || showContentWarning.value!!),
- mediaIds = mediaIds,
- mediaUris = mediaUris.map { it.toString() },
- mediaDescriptions = mediaDescriptions,
- scheduledAt = scheduledAt.value,
- inReplyToId = inReplyToId,
- poll = poll.value,
- replyingStatusContent = null,
- replyingStatusAuthorUsername = null,
- quoteId = quoteId,
- accountId = accountManager.activeAccount!!.id,
- draftId = draftId,
- idempotencyKey = randomAlphanumericString(16),
- retries = 0
- )
+ val tootToSend = StatusToSend(
+ text = content,
+ warningText = spoilerText,
+ visibility = statusVisibility.value!!.serverString(),
+ sensitive = mediaUris.isNotEmpty() && (markMediaAsSensitive.value!! || showContentWarning.value!!),
+ mediaIds = mediaIds,
+ mediaUris = mediaUris.map { it.toString() },
+ mediaDescriptions = mediaDescriptions,
+ scheduledAt = scheduledAt.value,
+ inReplyToId = inReplyToId,
+ poll = poll.value,
+ replyingStatusContent = null,
+ replyingStatusAuthorUsername = null,
+ quoteId = quoteId,
+ accountId = accountManager.activeAccount!!.id,
+ draftId = draftId,
+ idempotencyKey = randomAlphanumericString(16),
+ retries = 0
+ )
serviceClient.sendToot(tootToSend)
}
@@ -468,7 +468,7 @@ class ComposeViewModel @Inject constructor(
draftId = composeOptions?.draftId ?: 0
scheduledTootId = composeOptions?.scheduledTootId
- startingText = composeOptions?.tootText
+ startingText = composeOptions?.content
val tootVisibility = composeOptions?.visibility ?: Status.Visibility.UNKNOWN
if (tootVisibility.num != Status.Visibility.UNKNOWN.num) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt
index c4cde77bd..631e15dd9 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt
@@ -15,6 +15,7 @@
package com.keylesspalace.tusky.components.compose
+import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.os.Environment
@@ -37,6 +38,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import java.io.File
+import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.Date
@@ -83,36 +85,70 @@ class MediaUploader @Inject constructor(
fun prepareMedia(inUri: Uri): Single {
return Single.fromCallable {
- var mediaSize = getMediaSize(contentResolver, inUri)
+ var mediaSize = MEDIA_SIZE_UNKNOWN
var uri = inUri
- val mimeType = contentResolver.getType(uri)
-
- val suffix = "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType ?: "tmp")
+ var mimeType: String? = null
try {
- contentResolver.openInputStream(inUri).use { input ->
- if (input == null) {
- Log.w(TAG, "Media input is null")
- uri = inUri
- return@use
+ when (inUri.scheme) {
+ ContentResolver.SCHEME_CONTENT -> {
+
+ mimeType = contentResolver.getType(uri)
+
+ val suffix = "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType ?: "tmp")
+
+ contentResolver.openInputStream(inUri).use { input ->
+ if (input == null) {
+ Log.w(TAG, "Media input is null")
+ uri = inUri
+ return@use
+ }
+ val file = File.createTempFile("randomTemp1", suffix, context.cacheDir)
+ FileOutputStream(file.absoluteFile).use { out ->
+ input.copyTo(out)
+ uri = FileProvider.getUriForFile(
+ context,
+ BuildConfig.APPLICATION_ID + ".fileprovider",
+ file
+ )
+ mediaSize = getMediaSize(contentResolver, uri)
+ }
+ }
}
- val file = File.createTempFile("randomTemp1", suffix, context.cacheDir)
- FileOutputStream(file.absoluteFile).use { out ->
- input.copyTo(out)
- uri = FileProvider.getUriForFile(
- context,
- BuildConfig.APPLICATION_ID + ".fileprovider",
- file
- )
- mediaSize = getMediaSize(contentResolver, uri)
+ ContentResolver.SCHEME_FILE -> {
+ val path = uri.path
+ if (path == null) {
+ Log.w(TAG, "empty uri path $uri")
+ throw CouldNotOpenFileException()
+ }
+ val inputFile = File(path)
+ val suffix = inputFile.name.substringAfterLast('.', "tmp")
+ mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(suffix)
+ val file = File.createTempFile("randomTemp1", ".$suffix", context.cacheDir)
+ val input = FileInputStream(inputFile)
+
+ FileOutputStream(file.absoluteFile).use { out ->
+ input.copyTo(out)
+ uri = FileProvider.getUriForFile(
+ context,
+ BuildConfig.APPLICATION_ID + ".fileprovider",
+ file
+ )
+ mediaSize = getMediaSize(contentResolver, uri)
+ }
+ }
+ else -> {
+ Log.w(TAG, "Unknown uri scheme $uri")
+ throw CouldNotOpenFileException()
}
}
} catch (e: IOException) {
Log.w(TAG, e)
- uri = inUri
+ throw CouldNotOpenFileException()
}
if (mediaSize == MEDIA_SIZE_UNKNOWN) {
- throw CouldNotOpenFileException()
+ Log.w(TAG, "Could not determine file size of upload")
+ throw MediaTypeException()
}
if (mimeType != null) {
@@ -138,6 +174,7 @@ class MediaUploader @Inject constructor(
}
}
} else {
+ Log.w(TAG, "Could not determine mime type of upload")
throw MediaTypeException()
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/view/EditTextTyped.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/view/EditTextTyped.kt
index a8403c954..dca696d84 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/compose/view/EditTextTyped.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/view/EditTextTyped.kt
@@ -22,6 +22,8 @@ import android.util.AttributeSet
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView
+import androidx.core.view.OnReceiveContentListener
+import androidx.core.view.ViewCompat
import androidx.core.view.inputmethod.EditorInfoCompat
import androidx.core.view.inputmethod.InputConnectionCompat
import androidx.emoji.widget.EmojiEditTextHelper
@@ -32,41 +34,33 @@ class EditTextTyped @JvmOverloads constructor(
) :
AppCompatMultiAutoCompleteTextView(context, attributeSet) {
- private var onCommitContentListener: InputConnectionCompat.OnCommitContentListener? = null
private val emojiEditTextHelper: EmojiEditTextHelper = EmojiEditTextHelper(this)
init {
// fix a bug with autocomplete and some keyboards
val newInputType = inputType and (inputType xor InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE)
inputType = newInputType
- super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener))
+ super.setKeyListener(emojiEditTextHelper.getKeyListener(keyListener))
}
- override fun setKeyListener(input: KeyListener) {
- super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input))
+ override fun setKeyListener(input: KeyListener?) {
+ if (input != null) {
+ super.setKeyListener(emojiEditTextHelper.getKeyListener(input))
+ } else {
+ super.setKeyListener(input)
+ }
}
- fun setOnCommitContentListener(listener: InputConnectionCompat.OnCommitContentListener) {
- onCommitContentListener = listener
+ fun setOnReceiveContentListener(listener: OnReceiveContentListener) {
+ ViewCompat.setOnReceiveContentListener(this, arrayOf("image/*"), listener)
}
override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection {
val connection = super.onCreateInputConnection(editorInfo)
- return if (onCommitContentListener != null) {
- EditorInfoCompat.setContentMimeTypes(editorInfo, arrayOf("image/*"))
- getEmojiEditTextHelper().onCreateInputConnection(
- InputConnectionCompat.createWrapper(
- connection, editorInfo,
- onCommitContentListener!!
- ),
- editorInfo
- )!!
- } else {
- connection
- }
- }
-
- private fun getEmojiEditTextHelper(): EmojiEditTextHelper {
- return emojiEditTextHelper
+ EditorInfoCompat.setContentMimeTypes(editorInfo, arrayOf("image/*"))
+ return emojiEditTextHelper.onCreateInputConnection(
+ InputConnectionCompat.createWrapper(this, connection, editorInfo),
+ editorInfo
+ )!!
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt
index f77ddd3a7..a847fe749 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt
@@ -16,18 +16,17 @@
package com.keylesspalace.tusky.components.conversation
import android.text.Spanned
-import android.text.SpannedString
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.TypeConverters
import com.keylesspalace.tusky.db.Converters
-import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.entity.Conversation
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.HashTag
import com.keylesspalace.tusky.entity.Poll
import com.keylesspalace.tusky.entity.Status
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.util.shouldTrimStatus
import java.util.Date
@@ -48,17 +47,15 @@ data class ConversationAccountEntity(
val avatar: String,
val emojis: List
) {
- fun toAccount(): Account {
- return Account(
+ fun toAccount(): TimelineAccount {
+ return TimelineAccount(
id = id,
username = username,
displayName = displayName,
+ url = "",
avatar = avatar,
emojis = emojis,
- url = "",
localUsername = "",
- note = SpannedString(""),
- header = ""
)
}
}
@@ -100,7 +97,7 @@ data class ConversationStatusEntity(
if (inReplyToId != other.inReplyToId) return false
if (inReplyToAccountId != other.inReplyToAccountId) return false
if (account != other.account) return false
- if (content.toString() != other.content.toString()) return false // TODO find a better method to compare two spanned strings
+ if (content.toString() != other.content.toString()) return false
if (createdAt != other.createdAt) return false
if (emojis != other.emojis) return false
if (favouritesCount != other.favouritesCount) return false
@@ -126,7 +123,7 @@ data class ConversationStatusEntity(
result = 31 * result + (inReplyToId?.hashCode() ?: 0)
result = 31 * result + (inReplyToAccountId?.hashCode() ?: 0)
result = 31 * result + account.hashCode()
- result = 31 * result + content.hashCode()
+ result = 31 * result + content.toString().hashCode()
result = 31 * result + createdAt.hashCode()
result = 31 * result + emojis.hashCode()
result = 31 * result + favouritesCount
@@ -177,7 +174,7 @@ data class ConversationStatusEntity(
}
}
-fun Account.toEntity() =
+fun TimelineAccount.toEntity() =
ConversationAccountEntity(
id = id,
username = username,
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java
index 18f09031b..6f95619c7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java
@@ -154,10 +154,10 @@ public class ConversationViewHolder extends StatusBaseViewHolder {
contentCollapseButton.setVisibility(View.VISIBLE);
if (collapsed) {
- contentCollapseButton.setText(R.string.status_content_warning_show_more);
+ contentCollapseButton.setText(R.string.post_content_warning_show_more);
content.setFilters(COLLAPSE_INPUT_FILTER);
} else {
- contentCollapseButton.setText(R.string.status_content_warning_show_less);
+ contentCollapseButton.setText(R.string.post_content_warning_show_less);
content.setFilters(NO_INPUT_FILTER);
}
} else {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt
index ce0048011..e580f554f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt
@@ -90,14 +90,14 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
if (draft.inReplyToId != null) {
bottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED
- viewModel.getToot(draft.inReplyToId)
+ viewModel.getStatus(draft.inReplyToId)
.observeOn(AndroidSchedulers.mainThread())
.autoDispose(from(this))
.subscribe(
{ status ->
val composeOptions = ComposeActivity.ComposeOptions(
draftId = draft.id,
- tootText = draft.content,
+ content = draft.content,
contentWarning = draft.contentWarning,
inReplyToId = draft.inReplyToId,
replyingStatusContent = status.content.toString(),
@@ -121,7 +121,7 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
if (throwable is HttpException && throwable.code() == 404) {
// the original status to which a reply was drafted has been deleted
// let's open the ComposeActivity without reply information
- Toast.makeText(this, getString(R.string.drafts_toot_reply_removed), Toast.LENGTH_LONG).show()
+ Toast.makeText(this, getString(R.string.drafts_post_reply_removed), Toast.LENGTH_LONG).show()
openDraftWithoutReply(draft)
} else {
Snackbar.make(binding.root, getString(R.string.drafts_failed_loading_reply), Snackbar.LENGTH_SHORT)
@@ -137,7 +137,7 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
private fun openDraftWithoutReply(draft: DraftEntity) {
val composeOptions = ComposeActivity.ComposeOptions(
draftId = draft.id,
- tootText = draft.content,
+ content = draft.content,
contentWarning = draft.contentWarning,
draftAttachments = draft.attachments,
poll = draft.poll,
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsViewModel.kt
index 78853d1e5..0c370222f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsViewModel.kt
@@ -60,8 +60,8 @@ class DraftsViewModel @Inject constructor(
}
}
- fun getToot(tootId: String): Single {
- return api.status(tootId)
+ fun getStatus(statusId: String): Single {
+ return api.status(statusId)
}
override fun onCleared() {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt
new file mode 100644
index 000000000..a95e1cf8b
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt
@@ -0,0 +1,288 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * 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 . */
+
+package com.keylesspalace.tusky.components.login
+
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.os.Bundle
+import android.text.method.LinkMovementMethod
+import android.util.Log
+import android.view.View
+import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
+import androidx.core.net.toUri
+import androidx.lifecycle.lifecycleScope
+import com.bumptech.glide.Glide
+import com.keylesspalace.tusky.BaseActivity
+import com.keylesspalace.tusky.BuildConfig
+import com.keylesspalace.tusky.MainActivity
+import com.keylesspalace.tusky.R
+import com.keylesspalace.tusky.databinding.ActivityLoginBinding
+import com.keylesspalace.tusky.di.Injectable
+import com.keylesspalace.tusky.entity.AppCredentials
+import com.keylesspalace.tusky.network.MastodonApi
+import com.keylesspalace.tusky.util.getNonNullString
+import com.keylesspalace.tusky.util.viewBinding
+import kotlinx.coroutines.launch
+import okhttp3.HttpUrl
+import javax.inject.Inject
+
+/** Main login page, the first thing that users see. Has prompt for instance and login button. */
+class LoginActivity : BaseActivity(), Injectable {
+
+ @Inject
+ lateinit var mastodonApi: MastodonApi
+
+ private val binding by viewBinding(ActivityLoginBinding::inflate)
+
+ private lateinit var preferences: SharedPreferences
+
+ private val oauthRedirectUri: String
+ get() {
+ val scheme = getString(R.string.oauth_scheme)
+ val host = BuildConfig.APPLICATION_ID
+ return "$scheme://$host/"
+ }
+
+ private val doWebViewAuth = registerForActivityResult(OauthLogin()) { result ->
+ when (result) {
+ 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)
+ binding.domainTextInputLayout.error = 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)
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(binding.root)
+
+ if (savedInstanceState == null &&
+ BuildConfig.CUSTOM_INSTANCE.isNotBlank() &&
+ !isAdditionalLogin()
+ ) {
+ binding.domainEditText.setText(BuildConfig.CUSTOM_INSTANCE)
+ binding.domainEditText.setSelection(BuildConfig.CUSTOM_INSTANCE.length)
+ }
+
+ if (BuildConfig.CUSTOM_LOGO_URL.isNotBlank()) {
+ Glide.with(binding.loginLogo)
+ .load(BuildConfig.CUSTOM_LOGO_URL)
+ .placeholder(null)
+ .into(binding.loginLogo)
+ }
+
+ preferences = getSharedPreferences(
+ getString(R.string.preferences_file_key), Context.MODE_PRIVATE
+ )
+
+ binding.loginButton.setOnClickListener { onButtonClick() }
+
+ binding.whatsAnInstanceTextView.setOnClickListener {
+ val dialog = AlertDialog.Builder(this)
+ .setMessage(R.string.dialog_whats_an_instance)
+ .setPositiveButton(R.string.action_close, null)
+ .show()
+ val textView = dialog.findViewById(android.R.id.message)
+ textView?.movementMethod = LinkMovementMethod.getInstance()
+ }
+
+ if (isAdditionalLogin()) {
+ setSupportActionBar(binding.toolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ supportActionBar?.setDisplayShowTitleEnabled(false)
+ } else {
+ binding.toolbar.visibility = View.GONE
+ }
+ }
+
+ override fun requiresLogin(): Boolean {
+ return false
+ }
+
+ override fun finish() {
+ super.finish()
+ if (isAdditionalLogin()) {
+ overridePendingTransition(R.anim.slide_from_left, R.anim.slide_to_right)
+ }
+ }
+
+ /**
+ * 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() {
+ binding.loginButton.isEnabled = false
+ binding.domainTextInputLayout.error = null
+
+ val domain = canonicalizeDomain(binding.domainEditText.text.toString())
+
+ try {
+ HttpUrl.Builder().host(domain).scheme("https").build()
+ } catch (e: IllegalArgumentException) {
+ setLoading(false)
+ binding.domainTextInputLayout.error = getString(R.string.error_invalid_domain)
+ return
+ }
+
+ setLoading(true)
+
+ lifecycleScope.launch {
+ val credentials: AppCredentials = try {
+ mastodonApi.authenticateApp(
+ domain, getString(R.string.app_name), oauthRedirectUri,
+ OAUTH_SCOPES, getString(R.string.tusky_website)
+ )
+ } catch (e: Exception) {
+ binding.loginButton.isEnabled = true
+ binding.domainTextInputLayout.error =
+ getString(R.string.error_failed_app_registration)
+ setLoading(false)
+ Log.e(TAG, Log.getStackTraceString(e))
+ return@launch
+ }
+
+ // Before we open browser page we save the data.
+ // Even if we don't open other apps user may go to password manager or somewhere else
+ // and we will need to pick up the process where we left off.
+ // Alternatively we could pass it all as part of the intent and receive it back
+ // but it is a bit of a workaround.
+ preferences.edit()
+ .putString(DOMAIN, domain)
+ .putString(CLIENT_ID, credentials.clientId)
+ .putString(CLIENT_SECRET, credentials.clientSecret)
+ .apply()
+
+ redirectUserToAuthorizeAndLogin(domain, credentials.clientId)
+ }
+ }
+
+ private fun redirectUserToAuthorizeAndLogin(domain: String, clientId: String) {
+ // 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()
+ .scheme("https")
+ .host(domain)
+ .addPathSegments(MastodonApi.ENDPOINT_AUTHORIZE)
+ .addQueryParameter("client_id", clientId)
+ .addQueryParameter("redirect_uri", oauthRedirectUri)
+ .addQueryParameter("response_type", "code")
+ .addQueryParameter("scope", OAUTH_SCOPES)
+ .build()
+ doWebViewAuth.launch(LoginData(url.toString().toUri(), oauthRedirectUri.toUri()))
+ }
+
+ override fun onStart() {
+ super.onStart()
+ // first show or user cancelled login
+ setLoading(false)
+ }
+
+ private suspend fun fetchOauthToken(code: String) {
+ /* restore variables from SharedPreferences */
+ val domain = preferences.getNonNullString(DOMAIN, "")
+ val clientId = preferences.getNonNullString(CLIENT_ID, "")
+ val clientSecret = preferences.getNonNullString(CLIENT_SECRET, "")
+
+ setLoading(true)
+
+ val accessToken = try {
+ mastodonApi.fetchOAuthToken(
+ domain, clientId, clientSecret, oauthRedirectUri, code,
+ "authorization_code"
+ )
+ } catch (e: Exception) {
+ setLoading(false)
+ binding.domainTextInputLayout.error =
+ getString(R.string.error_retrieving_oauth_token)
+ Log.e(
+ TAG,
+ "%s %s".format(getString(R.string.error_retrieving_oauth_token), e.message),
+ )
+ return
+ }
+
+ accountManager.addAccount(accessToken.accessToken, domain)
+
+ val intent = Intent(this, MainActivity::class.java)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ startActivity(intent)
+ finish()
+ overridePendingTransition(R.anim.explode, R.anim.explode)
+ }
+
+ private fun setLoading(loadingState: Boolean) {
+ if (loadingState) {
+ binding.loginLoadingLayout.visibility = View.VISIBLE
+ binding.loginInputLayout.visibility = View.GONE
+ } else {
+ binding.loginLoadingLayout.visibility = View.GONE
+ binding.loginInputLayout.visibility = View.VISIBLE
+ binding.loginButton.isEnabled = true
+ }
+ }
+
+ private fun isAdditionalLogin(): Boolean {
+ return intent.getBooleanExtra(LOGIN_MODE, false)
+ }
+
+ companion object {
+ private const val TAG = "LoginActivity" // logging tag
+ private const val OAUTH_SCOPES = "read write follow"
+ private const val LOGIN_MODE = "LOGIN_MODE"
+ private const val DOMAIN = "domain"
+ private const val CLIENT_ID = "clientId"
+ private const val CLIENT_SECRET = "clientSecret"
+
+ @JvmStatic
+ fun getIntent(context: Context, mode: Boolean): Intent {
+ val loginIntent = Intent(context, LoginActivity::class.java)
+ loginIntent.putExtra(LOGIN_MODE, mode)
+ return loginIntent
+ }
+
+ /** Make sure the user-entered text is just a fully-qualified domain name. */
+ private fun canonicalizeDomain(domain: String): String {
+ // Strip any schemes out.
+ var s = domain.replaceFirst("http://", "")
+ s = s.replaceFirst("https://", "")
+ // If a username was included (e.g. username@example.com), just take what's after the '@'.
+ val at = s.lastIndexOf('@')
+ if (at != -1) {
+ s = s.substring(at + 1)
+ }
+ return s.trim { it <= ' ' }
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt
new file mode 100644
index 000000000..01f6c3b0e
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt
@@ -0,0 +1,162 @@
+package com.keylesspalace.tusky.components.login
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcelable
+import android.util.Log
+import android.webkit.CookieManager
+import android.webkit.WebResourceError
+import android.webkit.WebResourceRequest
+import android.webkit.WebStorage
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import androidx.activity.result.contract.ActivityResultContract
+import com.keylesspalace.tusky.BaseActivity
+import com.keylesspalace.tusky.BuildConfig
+import com.keylesspalace.tusky.databinding.LoginWebviewBinding
+import com.keylesspalace.tusky.di.Injectable
+import com.keylesspalace.tusky.util.viewBinding
+import kotlinx.parcelize.Parcelize
+
+/** Contract for starting [LoginWebViewActivity]. */
+class OauthLogin : ActivityResultContract() {
+ override fun createIntent(context: Context, input: LoginData): Intent {
+ val intent = Intent(context, LoginWebViewActivity::class.java)
+ intent.putExtra(DATA_EXTRA, input)
+ return intent
+ }
+
+ override fun parseResult(resultCode: Int, intent: Intent?): LoginResult {
+ // Can happen automatically on up or back press
+ return if (resultCode == Activity.RESULT_CANCELED) {
+ LoginResult.Cancel
+ } else {
+ intent!!.getParcelableExtra(RESULT_EXTRA)!!
+ }
+ }
+
+ companion object {
+ private const val RESULT_EXTRA = "result"
+ private const val DATA_EXTRA = "data"
+
+ fun parseData(intent: Intent): LoginData {
+ return intent.getParcelableExtra(DATA_EXTRA)!!
+ }
+
+ fun makeResultIntent(result: LoginResult): Intent {
+ val intent = Intent()
+ intent.putExtra(RESULT_EXTRA, result)
+ return intent
+ }
+ }
+}
+
+@Parcelize
+data class LoginData(
+ val url: Uri,
+ val oauthRedirectUrl: Uri,
+) : Parcelable
+
+sealed class LoginResult : Parcelable {
+ @Parcelize
+ data class Ok(val code: String) : LoginResult()
+
+ @Parcelize
+ data class Err(val errorMessage: String) : LoginResult()
+
+ @Parcelize
+ object Cancel : LoginResult()
+}
+
+/** Activity to do Oauth process using WebView. */
+class LoginWebViewActivity : BaseActivity(), Injectable {
+ private val binding by viewBinding(LoginWebviewBinding::inflate)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val data = OauthLogin.parseData(intent)
+
+ setContentView(binding.root)
+
+ setSupportActionBar(binding.loginToolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ supportActionBar?.setDisplayShowTitleEnabled(false)
+
+ val webView = binding.loginWebView
+ webView.settings.allowContentAccess = false
+ webView.settings.allowFileAccess = false
+ webView.settings.databaseEnabled = false
+ webView.settings.displayZoomControls = false
+ webView.settings.javaScriptCanOpenWindowsAutomatically = false
+ // Javascript needs to be enabled because otherwise 2FA does not work in some instances
+ @SuppressLint("SetJavaScriptEnabled")
+ webView.settings.javaScriptEnabled = true
+ webView.settings.userAgentString += " Tusky/${BuildConfig.VERSION_NAME}"
+
+ val oauthUrl = data.oauthRedirectUrl
+
+ webView.webViewClient = object : WebViewClient() {
+ override fun onReceivedError(
+ view: WebView?,
+ request: WebResourceRequest?,
+ error: WebResourceError
+ ) {
+ Log.d("LoginWeb", "Failed to load ${data.url}: $error")
+ finish()
+ }
+
+ override fun shouldOverrideUrlLoading(
+ view: WebView,
+ request: WebResourceRequest
+ ): Boolean {
+ val url = request.url
+ return if (url.scheme == oauthUrl.scheme && url.host == oauthUrl.host) {
+ val error = url.getQueryParameter("error")
+ if (error != null) {
+ sendResult(LoginResult.Err(error))
+ } else {
+ val code = url.getQueryParameter("code").orEmpty()
+ sendResult(LoginResult.Ok(code))
+ }
+ true
+ } else {
+ false
+ }
+ }
+ }
+ webView.setBackgroundColor(Color.TRANSPARENT)
+
+ if (savedInstanceState == null) {
+ webView.loadUrl(data.url.toString())
+ } else {
+ webView.restoreState(savedInstanceState)
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ binding.loginWebView.saveState(outState)
+ }
+
+ override fun onDestroy() {
+ if (isFinishing) {
+ // We don't want to keep user session in WebView, we just want our own accessToken
+ WebStorage.getInstance().deleteAllData()
+ CookieManager.getInstance().removeAllCookies(null)
+ }
+ super.onDestroy()
+ }
+
+ override fun requiresLogin() = false
+
+ private fun sendResult(result: LoginResult) {
+ setResult(Activity.RESULT_OK, OauthLogin.makeResultIntent(result))
+ finish()
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java
index c0bf149f4..6b9afce1d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java
+++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java
@@ -24,7 +24,6 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Color;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;
@@ -46,9 +45,9 @@ import androidx.work.WorkRequest;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.FutureTarget;
-import com.keylesspalace.tusky.BuildConfig;
import com.keylesspalace.tusky.MainActivity;
import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.components.compose.ComposeActivity;
import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.entity.Notification;
@@ -67,6 +66,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@@ -88,8 +88,6 @@ public class NotificationHelper {
public static final String REPLY_ACTION = "REPLY_ACTION";
- public static final String COMPOSE_ACTION = "COMPOSE_ACTION";
-
public static final String KEY_REPLY = "KEY_REPLY";
public static final String KEY_SENDER_ACCOUNT_ID = "KEY_SENDER_ACCOUNT_ID";
@@ -108,10 +106,6 @@ public class NotificationHelper {
public static final String KEY_MENTIONS = "KEY_MENTIONS";
- public static final String KEY_CITED_TEXT = "KEY_CITED_TEXT";
-
- public static final String KEY_CITED_AUTHOR_LOCAL = "KEY_CITED_AUTHOR_LOCAL";
-
/**
* notification channels used on Android O+
**/
@@ -206,21 +200,24 @@ public class NotificationHelper {
.setLabel(context.getString(R.string.label_quick_reply))
.build();
- PendingIntent quickReplyPendingIntent = getStatusReplyIntent(REPLY_ACTION, context, body, account);
+ PendingIntent quickReplyPendingIntent = getStatusReplyIntent(context, body, account);
NotificationCompat.Action quickReplyAction =
new NotificationCompat.Action.Builder(R.drawable.ic_reply_24dp,
- context.getString(R.string.action_quick_reply), quickReplyPendingIntent)
+ context.getString(R.string.action_quick_reply),
+ quickReplyPendingIntent)
.addRemoteInput(replyRemoteInput)
.build();
builder.addAction(quickReplyAction);
- PendingIntent composePendingIntent = getStatusReplyIntent(COMPOSE_ACTION, context, body, account);
+ PendingIntent composeIntent = getStatusComposeIntent(context, body, account);
NotificationCompat.Action composeAction =
new NotificationCompat.Action.Builder(R.drawable.ic_reply_24dp,
- context.getString(R.string.action_compose_shortcut), composePendingIntent)
+ context.getString(R.string.action_compose_shortcut),
+ composeIntent)
+ .setShowsUserInterface(true)
.build();
builder.addAction(composeAction);
@@ -237,7 +234,6 @@ public class NotificationHelper {
}
// Summary
- // =======
final NotificationCompat.Builder summaryBuilder = newNotification(context, body, account, true);
if (currentNotifications.length() != 1) {
@@ -275,7 +271,7 @@ public class NotificationHelper {
summaryStackBuilder.addNextIntent(summaryResultIntent);
PendingIntent summaryResultPendingIntent = summaryStackBuilder.getPendingIntent((int) (notificationId + account.getId() * 10000),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentFlags(false));
// we have to switch account here
Intent eventResultIntent = new Intent(context, MainActivity.class);
@@ -285,18 +281,18 @@ public class NotificationHelper {
eventStackBuilder.addNextIntent(eventResultIntent);
PendingIntent eventResultPendingIntent = eventStackBuilder.getPendingIntent((int) account.getId(),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentFlags(false));
Intent deleteIntent = new Intent(context, NotificationClearBroadcastReceiver.class);
deleteIntent.putExtra(ACCOUNT_ID, account.getId());
PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, summary ? (int) account.getId() : notificationId, deleteIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentFlags(false));
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getChannelId(account, body))
.setSmallIcon(R.drawable.ic_notify)
.setContentIntent(summary ? summaryResultPendingIntent : eventResultPendingIntent)
.setDeleteIntent(deletePendingIntent)
- .setColor(BuildConfig.FLAVOR == "green" ? Color.parseColor("#19A341") : ContextCompat.getColor(context, R.color.tusky_blue))
+ .setColor(ContextCompat.getColor(context, R.color.notification_color))
.setGroup(account.getAccountId())
.setAutoCancel(true)
.setShortcutId(Long.toString(account.getId()))
@@ -307,11 +303,9 @@ public class NotificationHelper {
return builder;
}
- private static PendingIntent getStatusReplyIntent(String action, Context context, Notification body, AccountEntity account) {
+ private static PendingIntent getStatusReplyIntent(Context context, Notification body, AccountEntity account) {
Status status = body.getStatus();
- String citedLocalAuthor = status.getAccount().getLocalUsername();
- String citedText = status.getContent().toString();
String inReplyToId = status.getId();
Status actionableStatus = status.getActionableStatus();
Status.Visibility replyVisibility = actionableStatus.getVisibility();
@@ -326,9 +320,7 @@ public class NotificationHelper {
mentionedUsernames = new ArrayList<>(new LinkedHashSet<>(mentionedUsernames));
Intent replyIntent = new Intent(context, SendStatusBroadcastReceiver.class)
- .setAction(action)
- .putExtra(KEY_CITED_AUTHOR_LOCAL, citedLocalAuthor)
- .putExtra(KEY_CITED_TEXT, citedText)
+ .setAction(REPLY_ACTION)
.putExtra(KEY_SENDER_ACCOUNT_ID, account.getId())
.putExtra(KEY_SENDER_ACCOUNT_IDENTIFIER, account.getIdentifier())
.putExtra(KEY_SENDER_ACCOUNT_FULL_NAME, account.getFullName())
@@ -341,7 +333,50 @@ public class NotificationHelper {
return PendingIntent.getBroadcast(context.getApplicationContext(),
notificationId,
replyIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentFlags(true));
+ }
+
+ private static PendingIntent getStatusComposeIntent(Context context, Notification body, AccountEntity account) {
+ Status status = body.getStatus();
+
+ String citedLocalAuthor = status.getAccount().getLocalUsername();
+ String citedText = status.getContent().toString();
+ String inReplyToId = status.getId();
+ Status actionableStatus = status.getActionableStatus();
+ Status.Visibility replyVisibility = actionableStatus.getVisibility();
+ String contentWarning = actionableStatus.getSpoilerText();
+ List mentions = actionableStatus.getMentions();
+ Set mentionedUsernames = new LinkedHashSet<>();
+ mentionedUsernames.add(actionableStatus.getAccount().getUsername());
+ for (Status.Mention mention : mentions) {
+ String mentionedUsername = mention.getUsername();
+ if (!mentionedUsername.equals(account.getUsername())) {
+ mentionedUsernames.add(mention.getUsername());
+ }
+ }
+
+ ComposeActivity.ComposeOptions composeOptions = new ComposeActivity.ComposeOptions();
+ composeOptions.setInReplyToId(inReplyToId);
+ composeOptions.setReplyVisibility(replyVisibility);
+ composeOptions.setContentWarning(contentWarning);
+ composeOptions.setReplyingStatusAuthor(citedLocalAuthor);
+ composeOptions.setReplyingStatusContent(citedText);
+ composeOptions.setMentionedUsernames(mentionedUsernames);
+ composeOptions.setModifiedInitialState(true);
+
+ Intent composeIntent = ComposeActivity.startIntent(
+ context,
+ composeOptions,
+ notificationId,
+ account.getId()
+ );
+
+ composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ return PendingIntent.getActivity(context.getApplicationContext(),
+ notificationId,
+ composeIntent,
+ pendingIntentFlags(false));
}
public static void createNotificationChannelsForAccount(@NonNull AccountEntity account, @NonNull Context context) {
@@ -409,9 +444,7 @@ public class NotificationHelper {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- //noinspection ConstantConditions
notificationManager.deleteNotificationChannelGroup(account.getIdentifier());
-
}
}
@@ -421,7 +454,6 @@ public class NotificationHelper {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// used until Tusky 1.4
- //noinspection ConstantConditions
notificationManager.deleteNotificationChannel(CHANNEL_MENTION);
notificationManager.deleteNotificationChannel(CHANNEL_FAVOURITE);
notificationManager.deleteNotificationChannel(CHANNEL_BOOST);
@@ -440,7 +472,6 @@ public class NotificationHelper {
// on Android >= O, notifications are enabled, if at least one channel is enabled
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- //noinspection ConstantConditions
if (notificationManager.areNotificationsEnabled()) {
for (NotificationChannel channel : notificationManager.getNotificationChannels()) {
if (channel.getImportance() > NotificationManager.IMPORTANCE_NONE) {
@@ -491,7 +522,6 @@ public class NotificationHelper {
accountManager.saveAccount(account);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- //noinspection ConstantConditions
notificationManager.cancel((int) account.getId());
return true;
})
@@ -511,7 +541,6 @@ public class NotificationHelper {
// unknown notificationtype
return false;
}
- //noinspection ConstantConditions
NotificationChannel channel = notificationManager.getNotificationChannel(channelId);
return channel.getImportance() > NotificationManager.IMPORTANCE_NONE;
}
@@ -674,4 +703,11 @@ public class NotificationHelper {
return null;
}
+ public static int pendingIntentFlags(boolean mutable) {
+ if (mutable) {
+ return PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_MUTABLE : 0);
+ } else {
+ return PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0);
+ }
+ }
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/EmojiPreference.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/EmojiPreference.kt
index e793f17f1..2c565a710 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/EmojiPreference.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/EmojiPreference.kt
@@ -13,8 +13,9 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceManager
+import com.keylesspalace.tusky.MainActivity
import com.keylesspalace.tusky.R
-import com.keylesspalace.tusky.SplashActivity
+import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.databinding.DialogEmojicompatBinding
import com.keylesspalace.tusky.databinding.ItemEmojiPrefBinding
import com.keylesspalace.tusky.util.EmojiCompatFont
@@ -215,12 +216,12 @@ class EmojiPreference(
.setPositiveButton(R.string.restart) { _, _ ->
// Restart the app
// From https://stackoverflow.com/a/17166729/5070653
- val launchIntent = Intent(context, SplashActivity::class.java)
+ val launchIntent = Intent(context, MainActivity::class.java)
val mPendingIntent = PendingIntent.getActivity(
context,
0x1f973, // This is the codepoint of the party face emoji :D
launchIntent,
- PendingIntent.FLAG_CANCEL_CURRENT
+ NotificationHelper.pendingIntentFlags(false)
)
val mgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
mgr.set(
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt
index 0f8b9436a..f458678e7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt
@@ -78,7 +78,7 @@ class PreferencesActivity :
NotificationPreferencesFragment.newInstance()
}
TAB_FILTER_PREFERENCES -> {
- setTitle(R.string.pref_title_status_tabs)
+ setTitle(R.string.pref_title_post_tabs)
TabFilterPreferencesFragment.newInstance()
}
PROXY_PREFERENCES -> {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt
index 53b8c7904..961d6d565 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt
@@ -25,7 +25,14 @@ import com.keylesspalace.tusky.components.compose.ComposeActivity.ComposeOptions
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.Notification
-import com.keylesspalace.tusky.settings.*
+import com.keylesspalace.tusky.settings.AppTheme
+import com.keylesspalace.tusky.settings.PrefKeys
+import com.keylesspalace.tusky.settings.emojiPreference
+import com.keylesspalace.tusky.settings.listPreference
+import com.keylesspalace.tusky.settings.makePreferenceScreen
+import com.keylesspalace.tusky.settings.preference
+import com.keylesspalace.tusky.settings.preferenceCategory
+import com.keylesspalace.tusky.settings.switchPreference
import com.keylesspalace.tusky.util.ThemeUtils
import com.keylesspalace.tusky.util.deserialize
import com.keylesspalace.tusky.util.getNonNullString
@@ -85,11 +92,11 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
listPreference {
setDefaultValue("medium")
- setEntries(R.array.status_text_size_names)
- setEntryValues(R.array.status_text_size_values)
+ setEntries(R.array.post_text_size_names)
+ setEntryValues(R.array.post_text_size_values)
key = PrefKeys.STATUS_TEXT_SIZE
setSummaryProvider { entry }
- setTitle(R.string.pref_status_text_size)
+ setTitle(R.string.pref_post_text_size)
icon = makeIcon(GoogleMaterial.Icon.gmd_format_size)
}
@@ -137,6 +144,13 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
isSingleLineTitle = false
}
+ switchPreference {
+ setDefaultValue(false)
+ key = PrefKeys.ANIMATE_CUSTOM_EMOJIS
+ setTitle(R.string.pref_title_animate_custom_emojis)
+ isSingleLineTitle = false
+ }
+
switchPreference {
setDefaultValue(true)
key = PrefKeys.USE_BLURHASH
@@ -179,13 +193,6 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
isSingleLineTitle = false
}
- switchPreference {
- setDefaultValue(false)
- key = PrefKeys.ANIMATE_CUSTOM_EMOJIS
- setTitle(R.string.pref_title_animate_custom_emojis)
- isSingleLineTitle = false
- }
-
switchPreference {
setDefaultValue(true)
key = PrefKeys.USE_QUICK_TOOT
@@ -232,7 +239,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
preferenceCategory(R.string.pref_title_timeline_filters) {
preference {
- setTitle(R.string.pref_title_status_tabs)
+ setTitle(R.string.pref_title_post_tabs)
setOnPreferenceClickListener {
activity?.let { activity ->
val intent = PreferencesActivity.newIntent(activity, PreferencesActivity.TAB_FILTER_PREFERENCES)
@@ -305,7 +312,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
}
}
- preferenceManager.sharedPreferences.let { prefs ->
+ preferenceManager.sharedPreferences?.let { prefs ->
prefs.getString(PrefKeys.STACK_TRACE, null)?.let { stackTrace ->
preferenceCategory(R.string.pref_title_stacktrace) {
preference {
@@ -313,7 +320,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
setOnPreferenceClickListener {
activity?.let { activity ->
val intent = ComposeActivity.startIntent(activity, ComposeOptions(
- tootText = "@ars42525@odakyu.app $stackTrace".substring(0, 400),
+ content = "@ars42525@odakyu.app $stackTrace".substring(0, 400),
contentWarning = "Yuito StackTrace"
))
activity.startActivity(intent)
@@ -350,23 +357,24 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
}
private fun updateHttpProxySummary() {
- val sharedPreferences = preferenceManager.sharedPreferences
- val httpProxyEnabled = sharedPreferences.getBoolean(PrefKeys.HTTP_PROXY_ENABLED, false)
- val httpServer = sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_SERVER, "")
+ preferenceManager.sharedPreferences?.let { sharedPreferences ->
+ val httpProxyEnabled = sharedPreferences.getBoolean(PrefKeys.HTTP_PROXY_ENABLED, false)
+ val httpServer = sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_SERVER, "")
- try {
- val httpPort = sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_PORT, "-1")
- .toInt()
+ try {
+ val httpPort = sharedPreferences.getNonNullString(PrefKeys.HTTP_PROXY_PORT, "-1")
+ .toInt()
- if (httpProxyEnabled && httpServer.isNotBlank() && httpPort > 0 && httpPort < 65535) {
- httpProxyPref?.summary = "$httpServer:$httpPort"
- return
+ if (httpProxyEnabled && httpServer.isNotBlank() && httpPort > 0 && httpPort < 65535) {
+ httpProxyPref?.summary = "$httpServer:$httpPort"
+ return
+ }
+ } catch (e: NumberFormatException) {
+ // user has entered wrong port, fall back to empty summary
}
- } catch (e: NumberFormatException) {
- // user has entered wrong port, fall back to empty summary
- }
- httpProxyPref?.summary = ""
+ httpProxyPref?.summary = ""
+ }
}
companion object {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt
index fa9de024d..df601efe9 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt
@@ -123,9 +123,9 @@ class StatusViewHolder(
private fun setContentWarningButtonText(contentShown: Boolean) {
if (contentShown) {
- binding.statusContentWarningButton.setText(R.string.status_content_warning_show_less)
+ binding.statusContentWarningButton.setText(R.string.post_content_warning_show_less)
} else {
- binding.statusContentWarningButton.setText(R.string.status_content_warning_show_more)
+ binding.statusContentWarningButton.setText(R.string.post_content_warning_show_more)
}
}
@@ -178,10 +178,10 @@ class StatusViewHolder(
binding.buttonToggleContent.show()
if (collapsed) {
- binding.buttonToggleContent.setText(R.string.status_content_show_more)
+ binding.buttonToggleContent.setText(R.string.post_content_show_more)
binding.statusContent.filters = COLLAPSE_INPUT_FILTER
} else {
- binding.buttonToggleContent.setText(R.string.status_content_show_less)
+ binding.buttonToggleContent.setText(R.string.post_content_show_less)
binding.statusContent.filters = NO_INPUT_FILTER
}
} else {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
index 0f70fc1f2..1614735ce 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
@@ -154,7 +154,7 @@ class ReportStatusesFragment : Fragment(R.layout.fragment_report_statuses), Inje
private fun showError() {
if (snackbarErrorRetry?.isShown != true) {
- snackbarErrorRetry = Snackbar.make(binding.swipeRefreshLayout, R.string.failed_fetch_statuses, Snackbar.LENGTH_INDEFINITE)
+ snackbarErrorRetry = Snackbar.make(binding.swipeRefreshLayout, R.string.failed_fetch_posts, Snackbar.LENGTH_INDEFINITE)
snackbarErrorRetry?.setAction(R.string.action_retry) {
adapter.retry()
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt
similarity index 89%
rename from app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt
rename to app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt
index dfcbd95f7..2ed261c7e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt
@@ -29,7 +29,7 @@ import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.StatusScheduledEvent
import com.keylesspalace.tusky.components.compose.ComposeActivity
-import com.keylesspalace.tusky.databinding.ActivityScheduledTootBinding
+import com.keylesspalace.tusky.databinding.ActivityScheduledStatusBinding
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.entity.ScheduledStatus
@@ -40,7 +40,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
-class ScheduledTootActivity : BaseActivity(), ScheduledTootActionListener, Injectable {
+class ScheduledStatusActivity : BaseActivity(), ScheduledStatusActionListener, Injectable {
@Inject
lateinit var viewModelFactory: ViewModelFactory
@@ -48,19 +48,19 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootActionListener, Injec
@Inject
lateinit var eventHub: EventHub
- private val viewModel: ScheduledTootViewModel by viewModels { viewModelFactory }
+ private val viewModel: ScheduledStatusViewModel by viewModels { viewModelFactory }
- private val adapter = ScheduledTootAdapter(this)
+ private val adapter = ScheduledStatusAdapter(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val binding = ActivityScheduledTootBinding.inflate(layoutInflater)
+ val binding = ActivityScheduledStatusBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.includedToolbar.toolbar)
supportActionBar?.run {
- title = getString(R.string.title_scheduled_toot)
+ title = getString(R.string.title_scheduled_posts)
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
}
@@ -94,7 +94,7 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootActionListener, Injec
if (loadState.refresh is LoadState.NotLoading) {
binding.progressBar.hide()
if (adapter.itemCount == 0) {
- binding.errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.no_scheduled_status)
+ binding.errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.no_scheduled_posts)
binding.errorMessageView.show()
} else {
binding.errorMessageView.hide()
@@ -121,7 +121,7 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootActionListener, Injec
this,
ComposeActivity.ComposeOptions(
scheduledTootId = item.id,
- tootText = item.params.text,
+ content = item.params.text,
contentWarning = item.params.spoilerText,
mediaAttachments = item.mediaAttachments,
inReplyToId = item.params.inReplyToId,
@@ -138,6 +138,6 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootActionListener, Injec
}
companion object {
- fun newIntent(context: Context) = Intent(context, ScheduledTootActivity::class.java)
+ fun newIntent(context: Context) = Intent(context, ScheduledStatusActivity::class.java)
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusAdapter.kt
similarity index 84%
rename from app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt
rename to app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusAdapter.kt
index 75b83e5d2..ec8110de0 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusAdapter.kt
@@ -20,18 +20,18 @@ import android.view.View
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
-import com.keylesspalace.tusky.databinding.ItemScheduledTootBinding
+import com.keylesspalace.tusky.databinding.ItemScheduledStatusBinding
import com.keylesspalace.tusky.entity.ScheduledStatus
import com.keylesspalace.tusky.util.BindingHolder
-interface ScheduledTootActionListener {
+interface ScheduledStatusActionListener {
fun edit(item: ScheduledStatus)
fun delete(item: ScheduledStatus)
}
-class ScheduledTootAdapter(
- val listener: ScheduledTootActionListener
-) : PagingDataAdapter>(
+class ScheduledStatusAdapter(
+ val listener: ScheduledStatusActionListener
+) : PagingDataAdapter>(
object : DiffUtil.ItemCallback() {
override fun areItemsTheSame(oldItem: ScheduledStatus, newItem: ScheduledStatus): Boolean {
return oldItem.id == newItem.id
@@ -43,12 +43,12 @@ class ScheduledTootAdapter(
}
) {
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder {
- val binding = ItemScheduledTootBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder {
+ val binding = ItemScheduledStatusBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BindingHolder(binding)
}
- override fun onBindViewHolder(holder: BindingHolder, position: Int) {
+ override fun onBindViewHolder(holder: BindingHolder, position: Int) {
getItem(position)?.let { item ->
holder.binding.edit.isEnabled = true
holder.binding.delete.isEnabled = true
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootPagingSource.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusPagingSource.kt
similarity index 76%
rename from app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootPagingSource.kt
rename to app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusPagingSource.kt
index c4994cef6..c9af661e4 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootPagingSource.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusPagingSource.kt
@@ -22,16 +22,16 @@ import com.keylesspalace.tusky.entity.ScheduledStatus
import com.keylesspalace.tusky.network.MastodonApi
import kotlinx.coroutines.rx3.await
-class ScheduledTootPagingSourceFactory(
+class ScheduledStatusPagingSourceFactory(
private val mastodonApi: MastodonApi
-) : () -> ScheduledTootPagingSource {
+) : () -> ScheduledStatusPagingSource {
private val scheduledTootsCache = mutableListOf()
- private var pagingSource: ScheduledTootPagingSource? = null
+ private var pagingSource: ScheduledStatusPagingSource? = null
- override fun invoke(): ScheduledTootPagingSource {
- return ScheduledTootPagingSource(mastodonApi, scheduledTootsCache).also {
+ override fun invoke(): ScheduledStatusPagingSource {
+ return ScheduledStatusPagingSource(mastodonApi, scheduledTootsCache).also {
pagingSource = it
}
}
@@ -42,9 +42,9 @@ class ScheduledTootPagingSourceFactory(
}
}
-class ScheduledTootPagingSource(
+class ScheduledStatusPagingSource(
private val mastodonApi: MastodonApi,
- private val scheduledTootsCache: MutableList
+ private val scheduledStatusesCache: MutableList
) : PagingSource() {
override fun getRefreshKey(state: PagingState): String? {
@@ -52,11 +52,11 @@ class ScheduledTootPagingSource(
}
override suspend fun load(params: LoadParams): LoadResult {
- return if (params is LoadParams.Refresh && scheduledTootsCache.isNotEmpty()) {
+ return if (params is LoadParams.Refresh && scheduledStatusesCache.isNotEmpty()) {
LoadResult.Page(
- data = scheduledTootsCache,
+ data = scheduledStatusesCache,
prevKey = null,
- nextKey = scheduledTootsCache.lastOrNull()?.id
+ nextKey = scheduledStatusesCache.lastOrNull()?.id
)
} else {
try {
@@ -71,7 +71,7 @@ class ScheduledTootPagingSource(
nextKey = result.lastOrNull()?.id
)
} catch (e: Exception) {
- Log.w("ScheduledTootPgngSrc", "Error loading scheduled statuses", e)
+ Log.w("ScheduledStatuses", "Error loading scheduled statuses", e)
LoadResult.Error(e)
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusViewModel.kt
similarity index 93%
rename from app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt
rename to app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusViewModel.kt
index 14f012ba6..cd3e5ac0c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusViewModel.kt
@@ -28,12 +28,12 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.await
import javax.inject.Inject
-class ScheduledTootViewModel @Inject constructor(
+class ScheduledStatusViewModel @Inject constructor(
val mastodonApi: MastodonApi,
val eventHub: EventHub
) : ViewModel() {
- private val pagingSourceFactory = ScheduledTootPagingSourceFactory(mastodonApi)
+ private val pagingSourceFactory = ScheduledStatusPagingSourceFactory(mastodonApi)
val data = Pager(
config = PagingConfig(pageSize = 20, initialLoadSize = 20),
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt
index a8f8b5bbd..7b3a325bc 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt
@@ -87,7 +87,7 @@ class SearchActivity : BottomSheetActivity(), HasAndroidInjector {
private fun getPageTitle(position: Int): CharSequence {
return when (position) {
- 0 -> getString(R.string.title_statuses)
+ 0 -> getString(R.string.title_posts)
1 -> getString(R.string.title_accounts)
2 -> getString(R.string.title_hashtags_dialog)
3 -> getString(R.string.title_notestock)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt
index 71d582680..c4a3e8261 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt
@@ -21,11 +21,11 @@ import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.adapter.AccountViewHolder
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.interfaces.LinkListener
class SearchAccountsAdapter(private val linkListener: LinkListener, private val animateAvatars: Boolean, private val animateEmojis: Boolean) :
- PagingDataAdapter(ACCOUNT_COMPARATOR) {
+ PagingDataAdapter(ACCOUNT_COMPARATOR) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountViewHolder {
val view = LayoutInflater.from(parent.context)
@@ -44,11 +44,11 @@ class SearchAccountsAdapter(private val linkListener: LinkListener, private val
companion object {
- val ACCOUNT_COMPARATOR = object : DiffUtil.ItemCallback() {
- override fun areContentsTheSame(oldItem: Account, newItem: Account): Boolean =
- oldItem.deepEquals(newItem)
+ val ACCOUNT_COMPARATOR = object : DiffUtil.ItemCallback() {
+ override fun areContentsTheSame(oldItem: TimelineAccount, newItem: TimelineAccount): Boolean =
+ oldItem == newItem
- override fun areItemsTheSame(oldItem: Account, newItem: Account): Boolean =
+ override fun areItemsTheSame(oldItem: TimelineAccount, newItem: TimelineAccount): Boolean =
oldItem.id == newItem.id
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt
index d5e2a7aba..f59f84ff6 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt
@@ -19,12 +19,12 @@ import androidx.paging.PagingData
import androidx.paging.PagingDataAdapter
import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.components.search.adapter.SearchAccountsAdapter
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.settings.PrefKeys
import kotlinx.coroutines.flow.Flow
-class SearchAccountsFragment : SearchFragment() {
- override fun createAdapter(): PagingDataAdapter {
+class SearchAccountsFragment : SearchFragment() {
+ override fun createAdapter(): PagingDataAdapter {
val preferences = PreferenceManager.getDefaultSharedPreferences(binding.searchRecyclerView.context)
return SearchAccountsAdapter(
@@ -34,7 +34,7 @@ class SearchAccountsFragment : SearchFragment() {
)
}
- override val data: Flow>
+ override val data: Flow>
get() = viewModel.accountsFlow
companion object {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchNotestockFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchNotestockFragment.kt
index c8a7f1006..5c2ba0066 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchNotestockFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchNotestockFragment.kt
@@ -300,7 +300,7 @@ class SearchNotestockFragment : SearchFragment(), Statu
popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
- R.id.status_share_content -> {
+ R.id.post_share_content -> {
val statusToShare: Status = status.actionableStatus
val sendIntent = Intent()
@@ -314,12 +314,12 @@ class SearchNotestockFragment : SearchFragment(), Statu
startActivity(
Intent.createChooser(
sendIntent,
- resources.getText(R.string.send_status_content_to)
+ resources.getText(R.string.send_post_content_to)
)
)
return@setOnMenuItemClickListener true
}
- R.id.status_share_link -> {
+ R.id.post_share_link -> {
val sendIntent = Intent()
sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra(Intent.EXTRA_TEXT, statusUrl)
@@ -327,7 +327,7 @@ class SearchNotestockFragment : SearchFragment(), Statu
startActivity(
Intent.createChooser(
sendIntent,
- resources.getText(R.string.send_status_link_to)
+ resources.getText(R.string.send_post_link_to)
)
)
return@setOnMenuItemClickListener true
@@ -456,7 +456,7 @@ class SearchNotestockFragment : SearchFragment(), Statu
private fun showConfirmDeleteDialog(id: String, position: Int) {
context?.let {
AlertDialog.Builder(it)
- .setMessage(R.string.dialog_delete_toot_warning)
+ .setMessage(R.string.dialog_delete_post_warning)
.setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.deleteStatus(id)
removeItem(position)
@@ -469,7 +469,7 @@ class SearchNotestockFragment : SearchFragment(), Statu
private fun showConfirmEditDialog(id: String, position: Int, status: Status) {
activity?.let {
AlertDialog.Builder(it)
- .setMessage(R.string.dialog_redraft_toot_warning)
+ .setMessage(R.string.dialog_redraft_post_warning)
.setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.deleteStatus(id)
.observeOn(AndroidSchedulers.mainThread())
@@ -486,7 +486,7 @@ class SearchNotestockFragment : SearchFragment(), Statu
val intent = ComposeActivity.startIntent(
requireContext(),
ComposeOptions(
- tootText = redraftStatus.text ?: "",
+ content = redraftStatus.text ?: "",
inReplyToId = redraftStatus.inReplyToId,
visibility = redraftStatus.visibility,
contentWarning = redraftStatus.spoilerText,
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt
index 99838c5c6..de0fec73f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt
@@ -310,7 +310,7 @@ class SearchStatusesFragment : SearchFragment(), Status
popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
- R.id.status_share_content -> {
+ R.id.post_share_content -> {
val statusToShare: Status = status.actionableStatus
val sendIntent = Intent()
@@ -321,15 +321,15 @@ class SearchStatusesFragment : SearchFragment(), Status
statusToShare.content.toString()
sendIntent.putExtra(Intent.EXTRA_TEXT, stringToShare)
sendIntent.type = "text/plain"
- startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_status_content_to)))
+ startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_post_content_to)))
return@setOnMenuItemClickListener true
}
- R.id.status_share_link -> {
+ R.id.post_share_link -> {
val sendIntent = Intent()
sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra(Intent.EXTRA_TEXT, statusUrl)
sendIntent.type = "text/plain"
- startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_status_link_to)))
+ startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_post_link_to)))
return@setOnMenuItemClickListener true
}
R.id.status_copy_link -> {
@@ -454,7 +454,7 @@ class SearchStatusesFragment : SearchFragment(), Status
private fun showConfirmDeleteDialog(id: String, position: Int) {
context?.let {
AlertDialog.Builder(it)
- .setMessage(R.string.dialog_delete_toot_warning)
+ .setMessage(R.string.dialog_delete_post_warning)
.setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.deleteStatus(id)
removeItem(position)
@@ -467,7 +467,7 @@ class SearchStatusesFragment : SearchFragment(), Status
private fun showConfirmEditDialog(id: String, position: Int, status: Status) {
activity?.let {
AlertDialog.Builder(it)
- .setMessage(R.string.dialog_redraft_toot_warning)
+ .setMessage(R.string.dialog_redraft_post_warning)
.setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.deleteStatus(id)
.observeOn(AndroidSchedulers.mainThread())
@@ -485,7 +485,7 @@ class SearchStatusesFragment : SearchFragment(), Status
val intent = ComposeActivity.startIntent(
requireContext(),
ComposeOptions(
- tootText = redraftStatus.text ?: "",
+ content = redraftStatus.text ?: "",
inReplyToId = redraftStatus.inReplyToId,
visibility = redraftStatus.visibility,
contentWarning = redraftStatus.spoilerText,
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
index dd05a835c..6b0c2f05f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
@@ -90,9 +90,9 @@ class TimelineFragment :
private val viewModel: TimelineViewModel by lazy {
if (kind == TimelineViewModel.Kind.HOME) {
- ViewModelProvider(this, viewModelFactory).get(CachedTimelineViewModel::class.java)
+ ViewModelProvider(this, viewModelFactory)[CachedTimelineViewModel::class.java]
} else {
- ViewModelProvider(this, viewModelFactory).get(NetworkTimelineViewModel::class.java)
+ ViewModelProvider(this, viewModelFactory)[NetworkTimelineViewModel::class.java]
}
}
@@ -140,7 +140,7 @@ class TimelineFragment :
isSwipeToRefreshEnabled = arguments.getBoolean(ARG_ENABLE_SWIPE_TO_REFRESH, true)
- val preferences = PreferenceManager.getDefaultSharedPreferences(activity)
+ val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val statusDisplayOptions = StatusDisplayOptions(
animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false),
mediaPreviewEnabled = accountManager.activeAccount!!.mediaPreviewEnabled,
@@ -187,7 +187,7 @@ class TimelineFragment :
if (adapter.itemCount == 0) {
when (loadState.refresh) {
is LoadState.NotLoading -> {
- if (loadState.append is LoadState.NotLoading) {
+ if (loadState.append is LoadState.NotLoading && loadState.source.refresh is LoadState.NotLoading) {
binding.statusView.show()
binding.statusView.setup(R.drawable.elephant_friend_empty, R.string.message_empty, null)
}
@@ -238,7 +238,7 @@ class TimelineFragment :
}
if (actionButtonPresent()) {
- val preferences = PreferenceManager.getDefaultSharedPreferences(context)
+ val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
hideFab = preferences.getBoolean("fabHide", false)
scrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(view: RecyclerView, dx: Int, dy: Int) {
@@ -435,7 +435,7 @@ class TimelineFragment :
}
private fun onPreferenceChanged(key: String) {
- val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
when (key) {
PrefKeys.FAB_HIDE -> {
hideFab = sharedPreferences.getBoolean(PrefKeys.FAB_HIDE, false)
@@ -502,7 +502,7 @@ class TimelineFragment :
* Auto dispose observable on pause
*/
private fun startUpdateTimestamp() {
- val preferences = PreferenceManager.getDefaultSharedPreferences(activity)
+ val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val useAbsoluteTime = preferences.getBoolean(PrefKeys.ABSOLUTE_TIME_VIEW, false)
if (!useAbsoluteTime) {
Observable.interval(1, TimeUnit.MINUTES)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelinePagingAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelinePagingAdapter.kt
index 063e9f394..0ea0b958a 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelinePagingAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelinePagingAdapter.kt
@@ -114,7 +114,7 @@ class TimelinePagingAdapter(
oldItem: StatusViewData,
newItem: StatusViewData
): Boolean {
- return oldItem.viewDataId == newItem.viewDataId
+ return oldItem.id == newItem.id
}
override fun areContentsTheSame(
@@ -128,7 +128,7 @@ class TimelinePagingAdapter(
oldItem: StatusViewData,
newItem: StatusViewData
): Any? {
- return if (oldItem === newItem) {
+ return if (oldItem == newItem) {
// If items are equal - update timestamp only
listOf(StatusBaseViewHolder.Key.KEY_CREATED)
} else // If items are different - update the whole view holder
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineTypeMappers.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineTypeMappers.kt
index 7bb8201a8..b62081760 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineTypeMappers.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineTypeMappers.kt
@@ -23,12 +23,12 @@ import com.google.gson.reflect.TypeToken
import com.keylesspalace.tusky.db.TimelineAccountEntity
import com.keylesspalace.tusky.db.TimelineStatusEntity
import com.keylesspalace.tusky.db.TimelineStatusWithAccount
-import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.HashTag
import com.keylesspalace.tusky.entity.Poll
import com.keylesspalace.tusky.entity.Status
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.util.shouldTrimStatus
import com.keylesspalace.tusky.util.trimTrailingWhitespace
import com.keylesspalace.tusky.viewdata.StatusViewData
@@ -44,7 +44,7 @@ private val emojisListType = object : TypeToken>() {}.type
private val mentionListType = object : TypeToken>() {}.type
private val tagListType = object : TypeToken>() {}.type
-fun Account.toEntity(accountId: Long, gson: Gson): TimelineAccountEntity {
+fun TimelineAccount.toEntity(accountId: Long, gson: Gson): TimelineAccountEntity {
return TimelineAccountEntity(
serverId = id,
timelineUserId = accountId,
@@ -58,25 +58,16 @@ fun Account.toEntity(accountId: Long, gson: Gson): TimelineAccountEntity {
)
}
-fun TimelineAccountEntity.toAccount(gson: Gson): Account {
- return Account(
+fun TimelineAccountEntity.toAccount(gson: Gson): TimelineAccount {
+ return TimelineAccount(
id = serverId,
localUsername = localUsername,
username = username,
displayName = displayName,
- note = SpannedString(""),
url = url,
avatar = avatar,
- header = "",
- locked = false,
- followingCount = 0,
- followersCount = 0,
- statusesCount = 0,
- source = null,
bot = bot,
- emojis = gson.fromJson(emojis, emojisListType),
- fields = null,
- moved = null
+ emojis = gson.fromJson(emojis, emojisListType)
)
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/util/TimelineUtils.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/util/TimelineUtils.kt
new file mode 100644
index 000000000..c8d95fd81
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/util/TimelineUtils.kt
@@ -0,0 +1,17 @@
+package com.keylesspalace.tusky.components.timeline.util
+
+import retrofit2.HttpException
+import java.io.IOException
+
+fun Throwable.isExpected() = this is IOException || this is HttpException
+
+inline fun ifExpected(
+ t: Throwable,
+ cb: () -> T
+): T {
+ if (t.isExpected()) {
+ return cb()
+ } else {
+ throw t
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineRemoteMediator.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineRemoteMediator.kt
index e9d81e59c..c4aa2c72d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineRemoteMediator.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineRemoteMediator.kt
@@ -23,13 +23,13 @@ import androidx.room.withTransaction
import com.google.gson.Gson
import com.keylesspalace.tusky.components.timeline.Placeholder
import com.keylesspalace.tusky.components.timeline.toEntity
+import com.keylesspalace.tusky.components.timeline.util.ifExpected
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.db.TimelineStatusEntity
import com.keylesspalace.tusky.db.TimelineStatusWithAccount
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
-import com.keylesspalace.tusky.util.dec
import kotlinx.coroutines.rx3.await
import retrofit2.HttpException
@@ -101,15 +101,22 @@ class CachedTimelineRemoteMediator(
db.withTransaction {
val overlappedStatuses = replaceStatusRange(statuses, state)
- if (loadType == LoadType.REFRESH && overlappedStatuses == 0 && statuses.isNotEmpty() && !dbEmpty) {
+ /* In case we loaded a whole page and there was no overlap with existing statuses,
+ we insert a placeholder because there might be even more unknown statuses */
+ if (loadType == LoadType.REFRESH && overlappedStatuses == 0 && statuses.size == state.config.pageSize && !dbEmpty) {
+ /* This overrides the last of the newly loaded statuses with a placeholder
+ to guarantee the placeholder has an id that exists on the server as not all
+ servers handle client generated ids as expected */
timelineDao.insertStatus(
- Placeholder(statuses.last().id.dec(), loading = false).toEntity(activeAccount.id)
+ Placeholder(statuses.last().id, loading = false).toEntity(activeAccount.id)
)
}
}
return MediatorResult.Success(endOfPaginationReached = statuses.isEmpty())
} catch (e: Exception) {
- return MediatorResult.Error(e)
+ return ifExpected(e) {
+ MediatorResult.Error(e)
+ }
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt
index 1b1cb6d68..f293ef0f2 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt
@@ -34,6 +34,7 @@ import com.keylesspalace.tusky.appstore.ReblogEvent
import com.keylesspalace.tusky.components.timeline.Placeholder
import com.keylesspalace.tusky.components.timeline.toEntity
import com.keylesspalace.tusky.components.timeline.toViewData
+import com.keylesspalace.tusky.components.timeline.util.ifExpected
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.entity.Poll
@@ -41,8 +42,6 @@ import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.FilterModel
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.network.TimelineCases
-import com.keylesspalace.tusky.util.dec
-import com.keylesspalace.tusky.util.inc
import com.keylesspalace.tusky.viewdata.StatusViewData
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.map
@@ -151,9 +150,11 @@ class CachedTimelineViewModel @Inject constructor(
timelineDao.insertStatus(Placeholder(placeholderId, loading = true).toEntity(activeAccount.id))
- val nextPlaceholderId = timelineDao.getNextPlaceholderIdAfter(activeAccount.id, placeholderId)
-
- val response = api.homeTimeline(maxId = placeholderId.inc(), sinceId = nextPlaceholderId, limit = LOAD_AT_ONCE).await()
+ val response = db.withTransaction {
+ val idAbovePlaceholder = timelineDao.getIdAbove(activeAccount.id, placeholderId)
+ val nextPlaceholderId = timelineDao.getNextPlaceholderIdAfter(activeAccount.id, placeholderId)
+ api.homeTimeline(maxId = idAbovePlaceholder, sinceId = nextPlaceholderId, limit = LOAD_AT_ONCE)
+ }.await()
val statuses = response.body()
if (!response.isSuccessful || statuses == null) {
@@ -187,14 +188,21 @@ class CachedTimelineViewModel @Inject constructor(
)
}
- if (overlappedStatuses == 0 && statuses.isNotEmpty()) {
+ /* In case we loaded a whole page and there was no overlap with existing statuses,
+ we insert a placeholder because there might be even more unknown statuses */
+ if (overlappedStatuses == 0 && statuses.size == LOAD_AT_ONCE) {
+ /* This overrides the last of the newly loaded statuses with a placeholder
+ to guarantee the placeholder has an id that exists on the server as not all
+ servers handle client generated ids as expected */
timelineDao.insertStatus(
- Placeholder(statuses.last().id.dec(), loading = false).toEntity(activeAccount.id)
+ Placeholder(statuses.last().id, loading = false).toEntity(activeAccount.id)
)
}
}
} catch (e: Exception) {
- loadMoreFailed(placeholderId, e)
+ ifExpected(e) {
+ loadMoreFailed(placeholderId, e)
+ }
}
}
}
@@ -228,9 +236,9 @@ class CachedTimelineViewModel @Inject constructor(
db.withTransaction {
if (isFirstOfStreaming) {
- val placeholderId = status.id.dec()
- timelineDao.insertStatus(Placeholder(placeholderId, loading = false).toEntity(activeAccount.id))
+ timelineDao.insertStatus(Placeholder(status.id, loading = false).toEntity(activeAccount.id))
isFirstOfStreaming = false
+ return@withTransaction
}
timelineDao.insertAccount(status.account.toEntity(activeAccount.id, gson))
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineRemoteMediator.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineRemoteMediator.kt
index 114faa922..82cfd41d4 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineRemoteMediator.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineRemoteMediator.kt
@@ -19,9 +19,9 @@ import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
+import com.keylesspalace.tusky.components.timeline.util.ifExpected
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.util.HttpHeaderLink
-import com.keylesspalace.tusky.util.dec
import com.keylesspalace.tusky.util.toViewData
import com.keylesspalace.tusky.viewdata.StatusViewData
import retrofit2.HttpException
@@ -92,7 +92,7 @@ class NetworkTimelineRemoteMediator(
viewModel.statusData.addAll(0, data)
if (insertPlaceholder) {
- viewModel.statusData.add(statuses.size, StatusViewData.Placeholder(statuses.last().id.dec(), false))
+ viewModel.statusData[statuses.size - 1] = StatusViewData.Placeholder(statuses.last().id, false)
}
} else {
val linkHeader = statusResponse.headers()["Link"]
@@ -107,7 +107,9 @@ class NetworkTimelineRemoteMediator(
viewModel.currentSource?.invalidate()
return MediatorResult.Success(endOfPaginationReached = statuses.isEmpty())
} catch (e: Exception) {
- return MediatorResult.Error(e)
+ return ifExpected(e) {
+ MediatorResult.Error(e)
+ }
}
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineViewModel.kt
index ea6b1e781..64236bfa0 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineViewModel.kt
@@ -28,15 +28,16 @@ import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.FavoriteEvent
import com.keylesspalace.tusky.appstore.PinEvent
import com.keylesspalace.tusky.appstore.ReblogEvent
+import com.keylesspalace.tusky.components.timeline.util.ifExpected
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.entity.Poll
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.FilterModel
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.network.TimelineCases
-import com.keylesspalace.tusky.util.dec
import com.keylesspalace.tusky.util.getDomain
-import com.keylesspalace.tusky.util.inc
+import com.keylesspalace.tusky.util.isLessThan
+import com.keylesspalace.tusky.util.isLessThanOrEqual
import com.keylesspalace.tusky.util.toViewData
import com.keylesspalace.tusky.viewdata.StatusViewData
import kotlinx.coroutines.flow.map
@@ -45,6 +46,7 @@ import kotlinx.coroutines.rx3.await
import net.accelf.yuito.streaming.StreamingManager
import retrofit2.HttpException
import retrofit2.Response
+import java.io.IOException
import javax.inject.Inject
/**
@@ -140,8 +142,10 @@ class NetworkTimelineViewModel @Inject constructor(
statusData.indexOfFirst { it is StatusViewData.Placeholder && it.id == placeholderId }
statusData[placeholderIndex] = StatusViewData.Placeholder(placeholderId, isLoading = true)
+ val idAbovePlaceholder = statusData.getOrNull(placeholderIndex - 1)?.id
+
val statusResponse = fetchStatusesForKind(
- fromId = placeholderId.inc(),
+ fromId = idAbovePlaceholder,
uptoId = null,
limit = 20
)
@@ -155,7 +159,7 @@ class NetworkTimelineViewModel @Inject constructor(
statusData.removeAt(placeholderIndex)
val activeAccount = accountManager.activeAccount!!
- val data = statuses.map { status ->
+ val data: MutableList = statuses.map { status ->
status.toViewData(
isShowingContent = activeAccount.alwaysShowSensitiveMedia || !status.actionableStatus.sensitive,
isExpanded = activeAccount.alwaysOpenSpoiler,
@@ -164,30 +168,31 @@ class NetworkTimelineViewModel @Inject constructor(
}.toMutableList()
if (statuses.isNotEmpty()) {
- val firstId = statuses.first().id.hashCode().toLong()
- val lastId = statuses.last().id.hashCode().toLong()
- val overlappedFrom = statusData.indexOfFirst { it.viewDataId <= firstId }
- val overlappedTo = statusData.indexOfFirst { it.viewDataId < lastId }
+ val firstId = statuses.first().id
+ val lastId = statuses.last().id
+ val overlappedFrom = statusData.indexOfFirst { it.asStatusOrNull()?.id?.isLessThanOrEqual(firstId) ?: false }
+ val overlappedTo = statusData.indexOfFirst { it.asStatusOrNull()?.id?.isLessThan(lastId) ?: false }
if (overlappedFrom < overlappedTo) {
- repeat(overlappedTo - overlappedFrom) {
- statusData[overlappedFrom].asStatusOrNull()?.let { oldStatus ->
- val dataIndex = statuses.indexOfFirst { it.id == oldStatus.id }
- if (dataIndex == -1) {
- return@let
- }
- data[dataIndex] = data[dataIndex]
+ data.mapIndexed { i, status -> i to statusData.firstOrNull { it.asStatusOrNull()?.id == status.id }?.asStatusOrNull() }
+ .filter { (_, oldStatus) -> oldStatus != null }
+ .forEach { (i, oldStatus) ->
+ data[i] = data[i].asStatusOrNull()!!
.copy(
- isShowingContent = oldStatus.isShowingContent,
+ isShowingContent = oldStatus!!.isShowingContent,
isExpanded = oldStatus.isExpanded,
isCollapsed = oldStatus.isCollapsed,
)
}
- statusData.removeAt(overlappedFrom)
+ statusData.removeAll { status ->
+ when (status) {
+ is StatusViewData.Placeholder -> lastId.isLessThan(status.id) && status.id.isLessThanOrEqual(firstId)
+ is StatusViewData.Concrete -> lastId.isLessThan(status.id) && status.id.isLessThanOrEqual(firstId)
+ }
}
} else {
- statusData.add(overlappedFrom, StatusViewData.Placeholder(statuses.last().id.dec(), isLoading = false))
+ data[data.size - 1] = StatusViewData.Placeholder(statuses.last().id, isLoading = false)
}
}
@@ -195,7 +200,9 @@ class NetworkTimelineViewModel @Inject constructor(
currentSource?.invalidate()
} catch (e: Exception) {
- loadMoreFailed(placeholderId, e)
+ ifExpected(e) {
+ loadMoreFailed(placeholderId, e)
+ }
}
}
}
@@ -239,27 +246,27 @@ class NetworkTimelineViewModel @Inject constructor(
val activeAccount = accountManager.activeAccount!!
if (isFirstOfStreaming) {
- val placeholderId = status.id.dec()
- statusData.add(0, StatusViewData.Placeholder(placeholderId, isLoading = false))
+ statusData.add(0, StatusViewData.Placeholder(status.id, isLoading = false))
isFirstOfStreaming = false
+ } else {
+ statusData.add(0, status.toViewData(
+ isShowingContent = activeAccount.alwaysShowSensitiveMedia,
+ isExpanded = activeAccount.alwaysOpenSpoiler,
+ isCollapsed = true,
+ ))
}
- statusData.add(0, status.toViewData(
- isShowingContent = activeAccount.alwaysShowSensitiveMedia,
- isExpanded = activeAccount.alwaysOpenSpoiler,
- isCollapsed = true,
- ))
-
currentSource?.invalidate()
}
}
override fun fullReload() {
- nextKey = statusData.firstOrNull { it is StatusViewData.Concrete }?.asStatusOrNull()?.id?.inc()
+ nextKey = statusData.firstOrNull { it is StatusViewData.Concrete }?.asStatusOrNull()?.id
statusData.clear()
currentSource?.invalidate()
}
+ @Throws(IOException::class, HttpException::class)
suspend fun fetchStatusesForKind(
fromId: String?,
uptoId: String?,
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/TimelineViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/TimelineViewModel.kt
index 451e6fd5d..fddfc6e37 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/TimelineViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/TimelineViewModel.kt
@@ -20,7 +20,21 @@ import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
-import com.keylesspalace.tusky.appstore.*
+import com.keylesspalace.tusky.appstore.BlockEvent
+import com.keylesspalace.tusky.appstore.BookmarkEvent
+import com.keylesspalace.tusky.appstore.DomainMuteEvent
+import com.keylesspalace.tusky.appstore.Event
+import com.keylesspalace.tusky.appstore.EventHub
+import com.keylesspalace.tusky.appstore.FavoriteEvent
+import com.keylesspalace.tusky.appstore.MuteConversationEvent
+import com.keylesspalace.tusky.appstore.MuteEvent
+import com.keylesspalace.tusky.appstore.PinEvent
+import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
+import com.keylesspalace.tusky.appstore.ReblogEvent
+import com.keylesspalace.tusky.appstore.StatusDeletedEvent
+import com.keylesspalace.tusky.appstore.StreamUpdateEvent
+import com.keylesspalace.tusky.appstore.UnfollowEvent
+import com.keylesspalace.tusky.components.timeline.util.ifExpected
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.entity.Filter
import com.keylesspalace.tusky.entity.Poll
@@ -38,8 +52,6 @@ import kotlinx.coroutines.rx3.await
import net.accelf.yuito.streaming.StreamType
import net.accelf.yuito.streaming.StreamingManager
import net.accelf.yuito.streaming.Subscription
-import retrofit2.HttpException
-import java.io.IOException
abstract class TimelineViewModel(
private val timelineCases: TimelineCases,
@@ -344,19 +356,6 @@ abstract class TimelineViewModel(
}
}
- private fun isExpectedRequestException(t: Exception) = t is IOException || t is HttpException
-
- private inline fun ifExpected(
- t: Exception,
- cb: () -> Unit,
- ) {
- if (isExpectedRequestException(t)) {
- cb()
- } else {
- throw t
- }
- }
-
companion object {
private const val TAG = "TimelineVM"
internal const val LOAD_AT_ONCE = 30
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java b/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
index 0ab627d54..159a6f529 100644
--- a/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
+++ b/app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
@@ -29,10 +29,9 @@ import java.io.File;
/**
* DB version & declare DAO
*/
-
@Database(entities = { DraftEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class,
TimelineAccountEntity.class, ConversationEntity.class
- }, version = 30)
+ }, version = 31)
public abstract class AppDatabase extends RoomDatabase {
public abstract AccountDao accountDao();
@@ -474,4 +473,14 @@ public abstract class AppDatabase extends RoomDatabase {
database.execSQL("ALTER TABLE `InstanceEntity` ADD COLUMN `maxPollDuration` INTEGER");
}
};
+
+ public static final Migration MIGRATION_30_31 = new Migration(30, 31) {
+ @Override
+ public void migrate(@NonNull SupportSQLiteDatabase database) {
+
+ // no actual scheme change, but placeholder ids are now used differently so the cache needs to be cleared to avoid bugs
+ database.execSQL("DELETE FROM `TimelineAccountEntity`");
+ database.execSQL("DELETE FROM `TimelineStatusEntity`");
+ }
+ };
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/db/TimelineDao.kt b/app/src/main/java/com/keylesspalace/tusky/db/TimelineDao.kt
index 7915ff998..dd59f2a3e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/db/TimelineDao.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/db/TimelineDao.kt
@@ -186,6 +186,15 @@ AND timelineUserId = :accountId
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND authorServerId IS NULL ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1")
abstract suspend fun getTopPlaceholderId(accountId: Long): String?
+ /**
+ * Returns the id directly above [serverId], or null if [serverId] is the id of the top status
+ */
+ @Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND (LENGTH(:serverId) < LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId < serverId)) ORDER BY LENGTH(serverId) ASC, serverId ASC LIMIT 1")
+ abstract suspend fun getIdAbove(accountId: Long, serverId: String): String?
+
+ /**
+ * Returns the id of the next placeholder after [serverId]
+ */
@Query("SELECT serverId FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND authorServerId IS NULL AND (LENGTH(:serverId) > LENGTH(serverId) OR (LENGTH(:serverId) = LENGTH(serverId) AND :serverId > serverId)) ORDER BY LENGTH(serverId) DESC, serverId DESC LIMIT 1")
abstract suspend fun getNextPlaceholderIdAfter(accountId: Long, serverId: String): String?
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt
index 3e04374f8..b3ac85daf 100644
--- a/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt
@@ -22,9 +22,7 @@ import com.keylesspalace.tusky.EditProfileActivity
import com.keylesspalace.tusky.FiltersActivity
import com.keylesspalace.tusky.LicenseActivity
import com.keylesspalace.tusky.ListsActivity
-import com.keylesspalace.tusky.LoginActivity
import com.keylesspalace.tusky.MainActivity
-import com.keylesspalace.tusky.SplashActivity
import com.keylesspalace.tusky.StatusListActivity
import com.keylesspalace.tusky.TabPreferenceActivity
import com.keylesspalace.tusky.ViewMediaActivity
@@ -34,9 +32,11 @@ import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.drafts.DraftsActivity
import com.keylesspalace.tusky.components.instancemute.InstanceListActivity
+import com.keylesspalace.tusky.components.login.LoginActivity
+import com.keylesspalace.tusky.components.login.LoginWebViewActivity
import com.keylesspalace.tusky.components.preference.PreferencesActivity
import com.keylesspalace.tusky.components.report.ReportActivity
-import com.keylesspalace.tusky.components.scheduled.ScheduledTootActivity
+import com.keylesspalace.tusky.components.scheduled.ScheduledStatusActivity
import com.keylesspalace.tusky.components.search.SearchActivity
import dagger.Module
import dagger.android.ContributesAndroidInjector
@@ -86,7 +86,7 @@ abstract class ActivitiesModule {
abstract fun contributesLoginActivity(): LoginActivity
@ContributesAndroidInjector
- abstract fun contributesSplashActivity(): SplashActivity
+ abstract fun contributesLoginWebViewActivity(): LoginWebViewActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesPreferencesActivity(): PreferencesActivity
@@ -110,7 +110,7 @@ abstract class ActivitiesModule {
abstract fun contributesInstanceListActivity(): InstanceListActivity
@ContributesAndroidInjector
- abstract fun contributesScheduledTootActivity(): ScheduledTootActivity
+ abstract fun contributesScheduledStatusActivity(): ScheduledStatusActivity
@ContributesAndroidInjector
abstract fun contributesAnnouncementsActivity(): AnnouncementsActivity
diff --git a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt
index f1375cc05..4695f63b8 100644
--- a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt
@@ -68,7 +68,7 @@ class AppModule {
AppDatabase.MIGRATION_22_23, AppDatabase.MIGRATION_23_24, AppDatabase.MIGRATION_24_25,
AppDatabase.Migration25_26(appContext.getExternalFilesDir("Tusky")),
AppDatabase.MIGRATION_26_27, AppDatabase.MIGRATION_27_28, AppDatabase.MIGRATION_28_29,
- AppDatabase.MIGRATION_29_30
+ AppDatabase.MIGRATION_29_30, AppDatabase.MIGRATION_30_31
)
.build()
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt
index 156020f61..1d7510a2c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/di/ServicesModule.kt
@@ -15,12 +15,12 @@
package com.keylesspalace.tusky.di
-import com.keylesspalace.tusky.service.SendTootService
+import com.keylesspalace.tusky.service.SendStatusService
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class ServicesModule {
@ContributesAndroidInjector
- abstract fun contributesSendTootService(): SendTootService
+ abstract fun contributesSendStatusService(): SendStatusService
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt b/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt
index c82099809..2c3a6604a 100644
--- a/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt
@@ -10,7 +10,7 @@ import com.keylesspalace.tusky.components.compose.ComposeViewModel
import com.keylesspalace.tusky.components.conversation.ConversationsViewModel
import com.keylesspalace.tusky.components.drafts.DraftsViewModel
import com.keylesspalace.tusky.components.report.ReportViewModel
-import com.keylesspalace.tusky.components.scheduled.ScheduledTootViewModel
+import com.keylesspalace.tusky.components.scheduled.ScheduledStatusViewModel
import com.keylesspalace.tusky.components.search.SearchViewModel
import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel
import com.keylesspalace.tusky.components.timeline.viewmodel.NetworkTimelineViewModel
@@ -86,8 +86,8 @@ abstract class ViewModelModule {
@Binds
@IntoMap
- @ViewModelKey(ScheduledTootViewModel::class)
- internal abstract fun scheduledTootViewModel(viewModel: ScheduledTootViewModel): ViewModel
+ @ViewModelKey(ScheduledStatusViewModel::class)
+ internal abstract fun scheduledStatusViewModel(viewModel: ScheduledStatusViewModel): ViewModel
@Binds
@IntoMap
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt
index b8692fa45..ab20a4e64 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt
@@ -17,7 +17,7 @@ package com.keylesspalace.tusky.entity
import android.text.Spanned
import com.google.gson.annotations.SerializedName
-import java.util.*
+import java.util.Date
data class Account(
val id: String,
@@ -53,37 +53,57 @@ data class Account(
val intentionallyUseDisplayName: String
get() = displayName.orEmpty()
- override fun hashCode(): Int {
- return id.hashCode()
- }
-
- override fun equals(other: Any?): Boolean {
- if (other !is Account) {
- return false
- }
- return other.id == this.id
- }
-
- fun deepEquals(other: Account): Boolean {
- return id == other.id &&
- localUsername == other.localUsername &&
- displayName == other.displayName &&
- note == other.note &&
- url == other.url &&
- avatar == other.avatar &&
- header == other.header &&
- locked == other.locked &&
- followersCount == other.followersCount &&
- followingCount == other.followingCount &&
- statusesCount == other.statusesCount &&
- source == other.source &&
- bot == other.bot &&
- emojis == other.emojis &&
- fields == other.fields &&
- moved == other.moved
- }
-
fun isRemote(): Boolean = this.username != this.localUsername
+
+ /**
+ * overriding equals & hashcode because Spanned does not always compare correctly otherwise
+ */
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+ other as Account
+
+ if (id != other.id) return false
+ if (localUsername != other.localUsername) return false
+ if (username != other.username) return false
+ if (displayName != other.displayName) return false
+ if (note.toString() != other.note.toString()) return false
+ if (url != other.url) return false
+ if (avatar != other.avatar) return false
+ if (header != other.header) return false
+ if (locked != other.locked) return false
+ if (followersCount != other.followersCount) return false
+ if (followingCount != other.followingCount) return false
+ if (statusesCount != other.statusesCount) return false
+ if (source != other.source) return false
+ if (bot != other.bot) return false
+ if (emojis != other.emojis) return false
+ if (fields != other.fields) return false
+ if (moved != other.moved) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = id.hashCode()
+ result = 31 * result + localUsername.hashCode()
+ result = 31 * result + username.hashCode()
+ result = 31 * result + (displayName?.hashCode() ?: 0)
+ result = 31 * result + note.toString().hashCode()
+ result = 31 * result + url.hashCode()
+ result = 31 * result + avatar.hashCode()
+ result = 31 * result + header.hashCode()
+ result = 31 * result + locked.hashCode()
+ result = 31 * result + followersCount
+ result = 31 * result + followingCount
+ result = 31 * result + statusesCount
+ result = 31 * result + (source?.hashCode() ?: 0)
+ result = 31 * result + bot.hashCode()
+ result = 31 * result + (emojis?.hashCode() ?: 0)
+ result = 31 * result + (fields?.hashCode() ?: 0)
+ result = 31 * result + (moved?.hashCode() ?: 0)
+ return result
+ }
}
data class AccountSource(
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Conversation.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Conversation.kt
index cb09981db..e5a547f11 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/Conversation.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/Conversation.kt
@@ -19,7 +19,7 @@ import com.google.gson.annotations.SerializedName
data class Conversation(
val id: String,
- val accounts: List,
+ val accounts: List,
@SerializedName("last_status") val lastStatus: Status?, // should never be null, but apparently its possible https://github.com/tuskyapp/Tusky/issues/1038
val unread: Boolean
)
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt
index 6198867d9..ae2d74a90 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/Notification.kt
@@ -24,7 +24,7 @@ import com.google.gson.annotations.JsonAdapter
data class Notification(
val type: Type,
val id: String,
- val account: Account,
+ val account: TimelineAccount,
val status: Status?
) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/SearchResult.kt b/app/src/main/java/com/keylesspalace/tusky/entity/SearchResult.kt
index 18e3d71b0..5bc78cf72 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/SearchResult.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/SearchResult.kt
@@ -16,7 +16,7 @@
package com.keylesspalace.tusky.entity
data class SearchResult(
- val accounts: List,
+ val accounts: List,
val statuses: List,
val hashtags: List
)
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt
index 877bbe51c..d69e5d807 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt
@@ -25,7 +25,7 @@ import java.util.Date
data class Status(
val id: String,
val url: String?, // not present if it's reblog
- val account: Account,
+ val account: TimelineAccount,
@SerializedName("in_reply_to_id") var inReplyToId: String?,
@SerializedName("in_reply_to_account_id") val inReplyToAccountId: String?,
val reblog: Status?,
@@ -158,6 +158,71 @@ data class Status(
return builder.toString()
}
+ /**
+ * overriding equals & hashcode because Spanned does not always compare correctly otherwise
+ */
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+ other as Status
+
+ if (id != other.id) return false
+ if (url != other.url) return false
+ if (account != other.account) return false
+ if (inReplyToId != other.inReplyToId) return false
+ if (inReplyToAccountId != other.inReplyToAccountId) return false
+ if (reblog != other.reblog) return false
+ if (content.toString() != other.content.toString()) return false
+ if (createdAt != other.createdAt) return false
+ if (emojis != other.emojis) return false
+ if (reblogsCount != other.reblogsCount) return false
+ if (favouritesCount != other.favouritesCount) return false
+ if (reblogged != other.reblogged) return false
+ if (favourited != other.favourited) return false
+ if (bookmarked != other.bookmarked) return false
+ if (sensitive != other.sensitive) return false
+ if (spoilerText != other.spoilerText) return false
+ if (visibility != other.visibility) return false
+ if (attachments != other.attachments) return false
+ if (mentions != other.mentions) return false
+ if (tags != other.tags) return false
+ if (application != other.application) return false
+ if (pinned != other.pinned) return false
+ if (muted != other.muted) return false
+ if (poll != other.poll) return false
+ if (card != other.card) return false
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = id.hashCode()
+ result = 31 * result + (url?.hashCode() ?: 0)
+ result = 31 * result + account.hashCode()
+ result = 31 * result + (inReplyToId?.hashCode() ?: 0)
+ result = 31 * result + (inReplyToAccountId?.hashCode() ?: 0)
+ result = 31 * result + (reblog?.hashCode() ?: 0)
+ result = 31 * result + content.toString().hashCode()
+ result = 31 * result + createdAt.hashCode()
+ result = 31 * result + emojis.hashCode()
+ result = 31 * result + reblogsCount
+ result = 31 * result + favouritesCount
+ result = 31 * result + reblogged.hashCode()
+ result = 31 * result + favourited.hashCode()
+ result = 31 * result + bookmarked.hashCode()
+ result = 31 * result + sensitive.hashCode()
+ result = 31 * result + spoilerText.hashCode()
+ result = 31 * result + visibility.hashCode()
+ result = 31 * result + attachments.hashCode()
+ result = 31 * result + mentions.hashCode()
+ result = 31 * result + (tags?.hashCode() ?: 0)
+ result = 31 * result + (application?.hashCode() ?: 0)
+ result = 31 * result + (pinned?.hashCode() ?: 0)
+ result = 31 * result + (muted?.hashCode() ?: 0)
+ result = 31 * result + (poll?.hashCode() ?: 0)
+ result = 31 * result + (card?.hashCode() ?: 0)
+ return result
+ }
+
data class Mention(
val id: String,
val url: String,
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/TimelineAccount.kt b/app/src/main/java/com/keylesspalace/tusky/entity/TimelineAccount.kt
new file mode 100644
index 000000000..6eb89ea5d
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/TimelineAccount.kt
@@ -0,0 +1,40 @@
+/* Copyright 2017 Andrew Dawson
+ *
+ * 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 . */
+
+package com.keylesspalace.tusky.entity
+
+import com.google.gson.annotations.SerializedName
+
+/**
+ * Same as [Account], but only with the attributes required in timelines.
+ * Prefer this class over [Account] because it uses way less memory & deserializes faster from json.
+ */
+data class TimelineAccount(
+ val id: String,
+ @SerializedName("username") val localUsername: String,
+ @SerializedName("acct") val username: String,
+ @SerializedName("display_name") val displayName: String?, // should never be null per Api definition, but some servers break the contract
+ val url: String,
+ val avatar: String,
+ val bot: Boolean = false,
+ val emojis: List? = emptyList(), // nullable for backward compatibility
+ @SerializedName("name") val notestockUsername: String? = null,
+) {
+
+ val name: String
+ get() = if (displayName.isNullOrEmpty()) {
+ localUsername
+ } else displayName
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt
index fad5c58a4..465b9f216 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt
@@ -42,8 +42,8 @@ import com.keylesspalace.tusky.components.account.AccountActivity
import com.keylesspalace.tusky.databinding.FragmentAccountListBinding
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.di.Injectable
-import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Relationship
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.settings.PrefKeys
@@ -255,7 +255,7 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
followRequestsAdapter.removeItem(position)
}
- private fun getFetchCallByListType(fromId: String?): Single>> {
+ private fun getFetchCallByListType(fromId: String?): Single>> {
return when (type) {
Type.FOLLOWS -> {
val accountId = requireId(type, id)
@@ -313,7 +313,7 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
)
}
- private fun onFetchAccountsSuccess(accounts: List, linkHeader: String?) {
+ private fun onFetchAccountsSuccess(accounts: List, linkHeader: String?) {
adapter.setBottomLoading(false)
val links = HttpHeaderLink.parse(linkHeader)
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
index bb9092531..1c9b21bdb 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
@@ -243,7 +243,7 @@ public abstract class SFragment extends Fragment implements Injectable {
popup.setOnMenuItemClickListener(item -> {
switch (item.getItemId()) {
- case R.id.status_share_content: {
+ case R.id.post_share_content: {
Status statusToShare = status;
if (statusToShare.getReblog() != null)
statusToShare = statusToShare.getReblog();
@@ -257,15 +257,15 @@ public abstract class SFragment extends Fragment implements Injectable {
sendIntent.putExtra(Intent.EXTRA_TEXT, stringToShare);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, statusUrl);
sendIntent.setType("text/plain");
- startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_status_content_to)));
+ startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_post_content_to)));
return true;
}
- case R.id.status_share_link: {
+ case R.id.post_share_link: {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, statusUrl);
sendIntent.setType("text/plain");
- startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_status_link_to)));
+ startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_post_link_to)));
return true;
}
case R.id.status_copy_link: {
@@ -407,7 +407,7 @@ public abstract class SFragment extends Fragment implements Injectable {
protected void showConfirmDeleteDialog(final String id, final int position) {
new AlertDialog.Builder(getActivity())
- .setMessage(R.string.dialog_delete_toot_warning)
+ .setMessage(R.string.dialog_delete_post_warning)
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
timelineCases.delete(id)
.observeOn(AndroidSchedulers.mainThread())
@@ -430,7 +430,7 @@ public abstract class SFragment extends Fragment implements Injectable {
return;
}
new AlertDialog.Builder(getActivity())
- .setMessage(R.string.dialog_redraft_toot_warning)
+ .setMessage(R.string.dialog_redraft_post_warning)
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
timelineCases.delete(id)
.observeOn(AndroidSchedulers.mainThread())
@@ -442,7 +442,7 @@ public abstract class SFragment extends Fragment implements Injectable {
deletedStatus = status.toDeletedStatus();
}
ComposeOptions composeOptions = new ComposeOptions();
- composeOptions.setTootText(deletedStatus.getText());
+ composeOptions.setContent(deletedStatus.getText());
composeOptions.setInReplyToId(deletedStatus.getInReplyToId());
composeOptions.setVisibility(deletedStatus.getVisibility());
composeOptions.setContentWarning(deletedStatus.getSpoilerText());
diff --git a/app/src/main/java/com/keylesspalace/tusky/json/SpannedTypeAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/json/SpannedTypeAdapter.kt
index dadc9137a..94a05065b 100644
--- a/app/src/main/java/com/keylesspalace/tusky/json/SpannedTypeAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/json/SpannedTypeAdapter.kt
@@ -16,8 +16,10 @@
package com.keylesspalace.tusky.json
import android.text.Spanned
+import android.text.SpannedString
import androidx.core.text.HtmlCompat
import androidx.core.text.parseAsHtml
+import androidx.core.text.toHtml
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
@@ -32,16 +34,29 @@ import java.lang.reflect.Type
class SpannedTypeAdapter : JsonDeserializer, JsonSerializer {
@Throws(JsonParseException::class)
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Spanned {
- /* Html.fromHtml returns trailing whitespace if the html ends in a
tag, which
- * all status contents do, so it should be trimmed. */
- return Jsoup.parse(json.asString ?: "")
- .apply {
- select(".quote-inline").forEach { it.remove() }
- }
- .html().parseAsHtml().trimTrailingWhitespace()
+ return json.asString
+ /* Mastodon uses 'white-space: pre-wrap;' so spaces are displayed as returned by the Api.
+ * We can't use CSS so we replace spaces with non-breaking-spaces to emulate the behavior.
+ */
+ ?.replace("
", "
")
+ ?.replace("
", "
")
+ ?.replace("
", "
")
+ ?.replace(" ", " ")
+ ?.let { html ->
+ Jsoup.parse(html)
+ .apply {
+ select(".quote-inline").forEach { it.remove() }
+ }
+ .html()
+ }
+ ?.parseAsHtml()
+ /* Html.fromHtml returns trailing whitespace if the html ends in a tag, which
+ * most status contents do, so it should be trimmed. */
+ ?.trimTrailingWhitespace()
+ ?: SpannedString("")
}
override fun serialize(src: Spanned?, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
- return JsonPrimitive(HtmlCompat.toHtml(src!!, HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL))
+ return JsonPrimitive(src!!.toHtml(HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL))
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt
index 8804124cd..3ee8d4cec 100644
--- a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt
@@ -37,6 +37,7 @@ import com.keylesspalace.tusky.entity.ScheduledStatus
import com.keylesspalace.tusky.entity.SearchResult
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.entity.StatusContext
+import com.keylesspalace.tusky.entity.TimelineAccount
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single
import okhttp3.MultipartBody
@@ -178,13 +179,13 @@ interface MastodonApi {
fun statusRebloggedBy(
@Path("id") statusId: String,
@Query("max_id") maxId: String?
- ): Single>>
+ ): Single>>
@GET("api/v1/statuses/{id}/favourited_by")
fun statusFavouritedBy(
@Path("id") statusId: String,
@Query("max_id") maxId: String?
- ): Single>>
+ ): Single>>
@DELETE("api/v1/statuses/{id}")
fun deleteStatus(
@@ -286,7 +287,7 @@ interface MastodonApi {
@Query("resolve") resolve: Boolean? = null,
@Query("limit") limit: Int? = null,
@Query("following") following: Boolean? = null
- ): Single>
+ ): Single>
@GET("api/v1/accounts/{id}")
fun account(
@@ -317,13 +318,13 @@ interface MastodonApi {
fun accountFollowers(
@Path("id") accountId: String,
@Query("max_id") maxId: String?
- ): Single>>
+ ): Single>>
@GET("api/v1/accounts/{id}/following")
fun accountFollowing(
@Path("id") accountId: String,
@Query("max_id") maxId: String?
- ): Single>>
+ ): Single>>
@FormUrlEncoded
@POST("api/v1/accounts/{id}/follow")
@@ -384,12 +385,12 @@ interface MastodonApi {
@GET("api/v1/blocks")
fun blocks(
@Query("max_id") maxId: String?
- ): Single>>
+ ): Single>>
@GET("api/v1/mutes")
fun mutes(
@Query("max_id") maxId: String?
- ): Single>>
+ ): Single>>
@GET("api/v1/domain_blocks")
fun domainBlocks(
@@ -426,7 +427,7 @@ interface MastodonApi {
@GET("api/v1/follow_requests")
fun followRequests(
@Query("max_id") maxId: String?
- ): Single>>
+ ): Single>>
@POST("api/v1/follow_requests/{id}/authorize")
fun authorizeFollowRequest(
@@ -440,24 +441,24 @@ interface MastodonApi {
@FormUrlEncoded
@POST("api/v1/apps")
- fun authenticateApp(
+ suspend fun authenticateApp(
@Header(DOMAIN_HEADER) domain: String,
@Field("client_name") clientName: String,
@Field("redirect_uris") redirectUris: String,
@Field("scopes") scopes: String,
@Field("website") website: String
- ): Call
+ ): AppCredentials
@FormUrlEncoded
@POST("oauth/token")
- fun fetchOAuthToken(
+ suspend fun fetchOAuthToken(
@Header(DOMAIN_HEADER) domain: String,
@Field("client_id") clientId: String,
@Field("client_secret") clientSecret: String,
@Field("redirect_uri") redirectUri: String,
@Field("code") code: String,
@Field("grant_type") grantType: String
- ): Call
+ ): AccessToken
@FormUrlEncoded
@POST("api/v1/lists")
@@ -481,7 +482,7 @@ interface MastodonApi {
fun getAccountsInList(
@Path("listId") listId: String,
@Query("limit") limit: Int
- ): Single>
+ ): Single>
@FormUrlEncoded
// @DELETE doesn't support fields
diff --git a/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt b/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt
index 999b5290a..680117b91 100644
--- a/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt
@@ -18,19 +18,19 @@ package com.keylesspalace.tusky.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import android.graphics.Color
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.RemoteInput
import androidx.core.content.ContextCompat
+import com.keylesspalace.tusky.BuildConfig
import com.keylesspalace.tusky.R
-import com.keylesspalace.tusky.components.compose.ComposeActivity
-import com.keylesspalace.tusky.components.compose.ComposeActivity.ComposeOptions
import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.entity.Status
-import com.keylesspalace.tusky.service.SendTootService
-import com.keylesspalace.tusky.service.TootToSend
+import com.keylesspalace.tusky.service.SendStatusService
+import com.keylesspalace.tusky.service.StatusToSend
import com.keylesspalace.tusky.util.randomAlphanumericString
import dagger.android.AndroidInjection
import javax.inject.Inject
@@ -45,22 +45,19 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
AndroidInjection.inject(this, context)
- val notificationId = intent.getIntExtra(NotificationHelper.KEY_NOTIFICATION_ID, -1)
- val senderId = intent.getLongExtra(NotificationHelper.KEY_SENDER_ACCOUNT_ID, -1)
- val senderIdentifier = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_IDENTIFIER)
- val senderFullName = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_FULL_NAME)
- val citedStatusId = intent.getStringExtra(NotificationHelper.KEY_CITED_STATUS_ID)
- val visibility = intent.getSerializableExtra(NotificationHelper.KEY_VISIBILITY) as Status.Visibility
- val spoiler = intent.getStringExtra(NotificationHelper.KEY_SPOILER) ?: ""
- val mentions = intent.getStringArrayExtra(NotificationHelper.KEY_MENTIONS) ?: emptyArray()
- val citedText = intent.getStringExtra(NotificationHelper.KEY_CITED_TEXT)
- val localAuthorId = intent.getStringExtra(NotificationHelper.KEY_CITED_AUTHOR_LOCAL)
-
- val account = accountManager.getAccountById(senderId)
-
- val notificationManager = NotificationManagerCompat.from(context)
-
if (intent.action == NotificationHelper.REPLY_ACTION) {
+ val notificationId = intent.getIntExtra(NotificationHelper.KEY_NOTIFICATION_ID, -1)
+ val senderId = intent.getLongExtra(NotificationHelper.KEY_SENDER_ACCOUNT_ID, -1)
+ val senderIdentifier = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_IDENTIFIER)
+ val senderFullName = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_FULL_NAME)
+ val citedStatusId = intent.getStringExtra(NotificationHelper.KEY_CITED_STATUS_ID)
+ val visibility = intent.getSerializableExtra(NotificationHelper.KEY_VISIBILITY) as Status.Visibility
+ val spoiler = intent.getStringExtra(NotificationHelper.KEY_SPOILER) ?: ""
+ val mentions = intent.getStringArrayExtra(NotificationHelper.KEY_MENTIONS) ?: emptyArray()
+
+ val account = accountManager.getAccountById(senderId)
+
+ val notificationManager = NotificationManagerCompat.from(context)
val message = getReplyMessage(intent)
@@ -85,9 +82,9 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
} else {
val text = mentions.joinToString(" ", postfix = " ") { "@$it" } + message.toString()
- val sendIntent = SendTootService.sendTootIntent(
+ val sendIntent = SendStatusService.sendStatusIntent(
context,
- TootToSend(
+ StatusToSend(
text = text,
warningText = spoiler,
visibility = visibility.serverString(),
@@ -110,14 +107,20 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
context.startService(sendIntent)
+ val color = if (BuildConfig.FLAVOR == "green") {
+ Color.parseColor("#19A341")
+ } else {
+ ContextCompat.getColor(context, R.color.tusky_blue)
+ }
+
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier)
.setSmallIcon(R.drawable.ic_notify)
- .setColor(ContextCompat.getColor(context, (R.color.tusky_blue)))
+ .setColor(color)
.setGroup(senderFullName)
.setDefaults(0) // So it doesn't ring twice, notify only in Target callback
- builder.setContentTitle(context.getString(R.string.status_sent))
- builder.setContentText(context.getString(R.string.status_sent_long))
+ builder.setContentTitle(context.getString(R.string.post_sent))
+ builder.setContentText(context.getString(R.string.post_sent_long))
builder.setSubText(senderFullName)
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
@@ -126,29 +129,6 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
notificationManager.notify(notificationId, builder.build())
}
- } else if (intent.action == NotificationHelper.COMPOSE_ACTION) {
-
- context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
-
- notificationManager.cancel(notificationId)
-
- accountManager.setActiveAccount(senderId)
-
- val composeIntent = ComposeActivity.startIntent(
- context,
- ComposeOptions(
- inReplyToId = citedStatusId,
- replyVisibility = visibility,
- contentWarning = spoiler,
- mentionedUsernames = mentions.toSet(),
- replyingStatusAuthor = localAuthorId,
- replyingStatusContent = citedText
- )
- )
-
- composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-
- context.startActivity(composeIntent)
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/service/SendTootService.kt b/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt
similarity index 50%
rename from app/src/main/java/com/keylesspalace/tusky/service/SendTootService.kt
rename to app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt
index 473eaa363..8ce8ea38f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/service/SendTootService.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt
@@ -19,8 +19,8 @@ import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.StatusComposedEvent
import com.keylesspalace.tusky.appstore.StatusScheduledEvent
import com.keylesspalace.tusky.components.drafts.DraftHelper
+import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.db.AccountManager
-import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.NewPoll
import com.keylesspalace.tusky.entity.NewStatus
@@ -30,18 +30,17 @@ import dagger.android.AndroidInjection
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
-import java.util.Timer
-import java.util.TimerTask
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
import javax.inject.Inject
-class SendTootService : Service(), Injectable {
+class SendStatusService : Service(), Injectable {
@Inject
lateinit var mastodonApi: MastodonApi
@@ -50,18 +49,14 @@ class SendTootService : Service(), Injectable {
@Inject
lateinit var eventHub: EventHub
@Inject
- lateinit var database: AppDatabase
- @Inject
lateinit var draftHelper: DraftHelper
private val supervisorJob = SupervisorJob()
private val serviceScope = CoroutineScope(Dispatchers.Main + supervisorJob)
- private val tootsToSend = ConcurrentHashMap()
+ private val statusesToSend = ConcurrentHashMap()
private val sendCalls = ConcurrentHashMap>()
- private val timer = Timer()
-
private val notificationManager by lazy { getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
override fun onCreate() {
@@ -75,38 +70,38 @@ class SendTootService : Service(), Injectable {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- if (intent.hasExtra(KEY_TOOT)) {
- val tootToSend = intent.getParcelableExtra(KEY_TOOT)
- ?: throw IllegalStateException("SendTootService started without $KEY_TOOT extra")
+ if (intent.hasExtra(KEY_STATUS)) {
+ val statusToSend = intent.getParcelableExtra(KEY_STATUS)
+ ?: throw IllegalStateException("SendStatusService started without $KEY_STATUS extra")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val channel = NotificationChannel(CHANNEL_ID, getString(R.string.send_toot_notification_channel_name), NotificationManager.IMPORTANCE_LOW)
+ val channel = NotificationChannel(CHANNEL_ID, getString(R.string.send_post_notification_channel_name), NotificationManager.IMPORTANCE_LOW)
notificationManager.createNotificationChannel(channel)
}
- var notificationText = tootToSend.warningText
+ var notificationText = statusToSend.warningText
if (notificationText.isBlank()) {
- notificationText = tootToSend.text
+ notificationText = statusToSend.text
}
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notify)
- .setContentTitle(getString(R.string.send_toot_notification_title))
+ .setContentTitle(getString(R.string.send_post_notification_title))
.setContentText(notificationText)
.setProgress(1, 0, true)
.setOngoing(true)
- .setColor(ContextCompat.getColor(this, R.color.tusky_blue))
+ .setColor(ContextCompat.getColor(this, R.color.notification_color))
.addAction(0, getString(android.R.string.cancel), cancelSendingIntent(sendingNotificationId))
- if (tootsToSend.size == 0 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if (statusesToSend.size == 0 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
startForeground(sendingNotificationId, builder.build())
} else {
notificationManager.notify(sendingNotificationId, builder.build())
}
- tootsToSend[sendingNotificationId] = tootToSend
- sendToot(sendingNotificationId--)
+ statusesToSend[sendingNotificationId] = statusToSend
+ sendStatus(sendingNotificationId--)
} else {
if (intent.hasExtra(KEY_CANCEL)) {
@@ -117,96 +112,96 @@ class SendTootService : Service(), Injectable {
return START_NOT_STICKY
}
- private fun sendToot(tootId: Int) {
+ private fun sendStatus(statusId: Int) {
- // when tootToSend == null, sending has been canceled
- val tootToSend = tootsToSend[tootId] ?: return
+ // when statusToSend == null, sending has been canceled
+ val statusToSend = statusesToSend[statusId] ?: return
// when account == null, user has logged out, cancel sending
- val account = accountManager.getAccountById(tootToSend.accountId)
+ val account = accountManager.getAccountById(statusToSend.accountId)
if (account == null) {
- tootsToSend.remove(tootId)
- notificationManager.cancel(tootId)
+ statusesToSend.remove(statusId)
+ notificationManager.cancel(statusId)
stopSelfWhenDone()
return
}
- tootToSend.retries++
+ statusToSend.retries++
val newStatus = NewStatus(
- tootToSend.text,
- tootToSend.warningText,
- tootToSend.inReplyToId,
- tootToSend.visibility,
- tootToSend.sensitive,
- tootToSend.mediaIds,
- tootToSend.scheduledAt,
- tootToSend.poll,
- tootToSend.quoteId,
+ statusToSend.text,
+ statusToSend.warningText,
+ statusToSend.inReplyToId,
+ statusToSend.visibility,
+ statusToSend.sensitive,
+ statusToSend.mediaIds,
+ statusToSend.scheduledAt,
+ statusToSend.poll,
+ statusToSend.quoteId,
)
val sendCall = mastodonApi.createStatus(
"Bearer " + account.accessToken,
account.domain,
- tootToSend.idempotencyKey,
+ statusToSend.idempotencyKey,
newStatus
)
- sendCalls[tootId] = sendCall
+ sendCalls[statusId] = sendCall
val callback = object : Callback {
override fun onResponse(call: Call, response: Response) {
+ serviceScope.launch {
- val scheduled = !tootToSend.scheduledAt.isNullOrEmpty()
- tootsToSend.remove(tootId)
+ val scheduled = !statusToSend.scheduledAt.isNullOrEmpty()
+ statusesToSend.remove(statusId)
- if (response.isSuccessful) {
- // If the status was loaded from a draft, delete the draft and associated media files.
- if (tootToSend.draftId != 0) {
- serviceScope.launch {
- draftHelper.deleteDraftAndAttachments(tootToSend.draftId)
+ if (response.isSuccessful) {
+ // If the status was loaded from a draft, delete the draft and associated media files.
+ if (statusToSend.draftId != 0) {
+ draftHelper.deleteDraftAndAttachments(statusToSend.draftId)
}
- }
- if (scheduled) {
- response.body()?.let(::StatusScheduledEvent)?.let(eventHub::dispatch)
+ if (scheduled) {
+ response.body()?.let(::StatusScheduledEvent)?.let(eventHub::dispatch)
+ } else {
+ response.body()?.let(::StatusComposedEvent)?.let(eventHub::dispatch)
+ }
+
+ notificationManager.cancel(statusId)
} else {
- response.body()?.let(::StatusComposedEvent)?.let(eventHub::dispatch)
+ // the server refused to accept the status, save status & show error message
+ saveStatusToDrafts(statusToSend)
+
+ val builder = NotificationCompat.Builder(this@SendStatusService, CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_notify)
+ .setContentTitle(getString(R.string.send_post_notification_error_title))
+ .setContentText(getString(R.string.send_post_notification_saved_content))
+ .setColor(
+ ContextCompat.getColor(
+ this@SendStatusService,
+ R.color.notification_color
+ )
+ )
+
+ notificationManager.cancel(statusId)
+ notificationManager.notify(errorNotificationId--, builder.build())
}
-
- notificationManager.cancel(tootId)
- } else {
- // the server refused to accept the toot, save toot & show error message
- saveTootToDrafts(tootToSend)
-
- val builder = NotificationCompat.Builder(this@SendTootService, CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_notify)
- .setContentTitle(getString(R.string.send_toot_notification_error_title))
- .setContentText(getString(R.string.send_toot_notification_saved_content))
- .setColor(ContextCompat.getColor(this@SendTootService, R.color.tusky_blue))
-
- notificationManager.cancel(tootId)
- notificationManager.notify(errorNotificationId--, builder.build())
+ stopSelfWhenDone()
}
-
- stopSelfWhenDone()
}
override fun onFailure(call: Call, t: Throwable) {
- var backoff = TimeUnit.SECONDS.toMillis(tootToSend.retries.toLong())
- if (backoff > MAX_RETRY_INTERVAL) {
- backoff = MAX_RETRY_INTERVAL
- }
+ serviceScope.launch {
+ var backoff = TimeUnit.SECONDS.toMillis(statusToSend.retries.toLong())
+ if (backoff > MAX_RETRY_INTERVAL) {
+ backoff = MAX_RETRY_INTERVAL
+ }
- timer.schedule(
- object : TimerTask() {
- override fun run() {
- sendToot(tootId)
- }
- },
- backoff
- )
+ delay(backoff)
+ sendStatus(statusId)
+ }
}
}
@@ -215,65 +210,52 @@ class SendTootService : Service(), Injectable {
private fun stopSelfWhenDone() {
- if (tootsToSend.isEmpty()) {
- ServiceCompat.stopForeground(this@SendTootService, ServiceCompat.STOP_FOREGROUND_REMOVE)
+ if (statusesToSend.isEmpty()) {
+ ServiceCompat.stopForeground(this@SendStatusService, ServiceCompat.STOP_FOREGROUND_REMOVE)
stopSelf()
}
}
- private fun cancelSending(tootId: Int) {
- val tootToCancel = tootsToSend.remove(tootId)
- if (tootToCancel != null) {
- val sendCall = sendCalls.remove(tootId)
+ private fun cancelSending(statusId: Int) = serviceScope.launch {
+ val statusToCancel = statusesToSend.remove(statusId)
+ if (statusToCancel != null) {
+ val sendCall = sendCalls.remove(statusId)
sendCall?.cancel()
- saveTootToDrafts(tootToCancel)
+ saveStatusToDrafts(statusToCancel)
- val builder = NotificationCompat.Builder(this@SendTootService, CHANNEL_ID)
+ val builder = NotificationCompat.Builder(this@SendStatusService, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notify)
- .setContentTitle(getString(R.string.send_toot_notification_cancel_title))
- .setContentText(getString(R.string.send_toot_notification_saved_content))
- .setColor(ContextCompat.getColor(this@SendTootService, R.color.tusky_blue))
+ .setContentTitle(getString(R.string.send_post_notification_cancel_title))
+ .setContentText(getString(R.string.send_post_notification_saved_content))
+ .setColor(ContextCompat.getColor(this@SendStatusService, R.color.notification_color))
- notificationManager.notify(tootId, builder.build())
+ notificationManager.notify(statusId, builder.build())
- timer.schedule(
- object : TimerTask() {
- override fun run() {
- notificationManager.cancel(tootId)
- stopSelfWhenDone()
- }
- },
- 5000
- )
+ delay(5000)
}
}
- private fun saveTootToDrafts(toot: TootToSend) {
- serviceScope.launch {
- draftHelper.saveDraft(
- draftId = toot.draftId,
- accountId = toot.accountId,
- inReplyToId = toot.inReplyToId,
- content = toot.text,
- contentWarning = toot.warningText,
- sensitive = toot.sensitive,
- visibility = Status.Visibility.byString(toot.visibility),
- mediaUris = toot.mediaUris,
- mediaDescriptions = toot.mediaDescriptions,
- poll = toot.poll,
- failedToSend = true
- )
- }
+ private suspend fun saveStatusToDrafts(status: StatusToSend) {
+ draftHelper.saveDraft(
+ draftId = status.draftId,
+ accountId = status.accountId,
+ inReplyToId = status.inReplyToId,
+ content = status.text,
+ contentWarning = status.warningText,
+ sensitive = status.sensitive,
+ visibility = Status.Visibility.byString(status.visibility),
+ mediaUris = status.mediaUris,
+ mediaDescriptions = status.mediaDescriptions,
+ poll = status.poll,
+ failedToSend = true
+ )
}
- private fun cancelSendingIntent(tootId: Int): PendingIntent {
-
- val intent = Intent(this, SendTootService::class.java)
-
- intent.putExtra(KEY_CANCEL, tootId)
-
- return PendingIntent.getService(this, tootId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+ private fun cancelSendingIntent(statusId: Int): PendingIntent {
+ val intent = Intent(this, SendStatusService::class.java)
+ intent.putExtra(KEY_CANCEL, statusId)
+ return PendingIntent.getService(this, statusId, intent, NotificationHelper.pendingIntentFlags(false))
}
override fun onDestroy() {
@@ -283,7 +265,7 @@ class SendTootService : Service(), Injectable {
companion object {
- private const val KEY_TOOT = "toot"
+ private const val KEY_STATUS = "status"
private const val KEY_CANCEL = "cancel_id"
private const val CHANNEL_ID = "send_toots"
@@ -293,21 +275,21 @@ class SendTootService : Service(), Injectable {
private var errorNotificationId = Int.MIN_VALUE // use even more negative ids to not clash with other notis
@JvmStatic
- fun sendTootIntent(
+ fun sendStatusIntent(
context: Context,
- tootToSend: TootToSend
+ statusToSend: StatusToSend
): Intent {
- val intent = Intent(context, SendTootService::class.java)
- intent.putExtra(KEY_TOOT, tootToSend)
+ val intent = Intent(context, SendStatusService::class.java)
+ intent.putExtra(KEY_STATUS, statusToSend)
- if (tootToSend.mediaUris.isNotEmpty()) {
+ if (statusToSend.mediaUris.isNotEmpty()) {
// forward uri permissions
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val uriClip = ClipData(
- ClipDescription("Toot Media", arrayOf("image/*", "video/*")),
- ClipData.Item(tootToSend.mediaUris[0])
+ ClipDescription("Status Media", arrayOf("image/*", "video/*")),
+ ClipData.Item(statusToSend.mediaUris[0])
)
- tootToSend.mediaUris
+ statusToSend.mediaUris
.drop(1)
.forEach { mediaUri ->
uriClip.addItem(ClipData.Item(mediaUri))
@@ -322,7 +304,7 @@ class SendTootService : Service(), Injectable {
}
@Parcelize
-data class TootToSend(
+data class StatusToSend(
val text: String,
val warningText: String,
val visibility: String,
diff --git a/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt b/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt
index 9ac5adac7..d9d08ff70 100644
--- a/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/service/ServiceClient.kt
@@ -20,8 +20,8 @@ import androidx.core.content.ContextCompat
import javax.inject.Inject
class ServiceClient @Inject constructor(private val context: Context) {
- fun sendToot(tootToSend: TootToSend) {
- val intent = SendTootService.sendTootIntent(context, tootToSend)
+ fun sendToot(tootToSend: StatusToSend) {
+ val intent = SendStatusService.sendStatusIntent(context, tootToSend)
ContextCompat.startForegroundService(context, intent)
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/EmojiCompatFont.kt b/app/src/main/java/com/keylesspalace/tusky/util/EmojiCompatFont.kt
index f513feeef..385be6c12 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/EmojiCompatFont.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/EmojiCompatFont.kt
@@ -280,7 +280,7 @@ class EmojiCompatFont(
R.string.caption_blobmoji,
R.drawable.ic_blobmoji,
"https://tusky.app/hosted/emoji/BlobmojiCompat.ttf",
- "12.0.0"
+ "14.0.1"
)
val TWEMOJI = EmojiCompatFont(
"Twemoji",
@@ -288,7 +288,7 @@ class EmojiCompatFont(
R.string.caption_twemoji,
R.drawable.ic_twemoji,
"https://tusky.app/hosted/emoji/TwemojiCompat.ttf",
- "12.0.0"
+ "14.0.0"
)
val NOTOEMOJI = EmojiCompatFont(
"NotoEmoji",
@@ -296,7 +296,7 @@ class EmojiCompatFont(
R.string.caption_notoemoji,
R.drawable.ic_notoemoji,
"https://tusky.app/hosted/emoji/NotoEmojiCompat.ttf",
- "11.0.0"
+ "14.0.0"
)
/**
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt
index fa3f3f21c..76c9cc3b7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt
@@ -149,7 +149,7 @@ fun setClickableMentions(view: TextView, mentions: List?, listener: Lin
for (mention in mentions) {
val customSpan = getCustomSpanForMentionUrl(mention.url, mention.id, listener)
- end += 1 + mention.username.length // length of @ + username
+ end += 1 + mention.localUsername.length // length of @ + username
flags = getSpanFlags(customSpan)
if (firstMention) {
firstMention = false
@@ -160,7 +160,7 @@ fun setClickableMentions(view: TextView, mentions: List?, listener: Lin
}
append("@")
- append(mention.username)
+ append(mention.localUsername)
setSpan(customSpan, start, end, flags)
append("\u200B") // same reasoning as in setClickableText
end += 1 // shift position to take the previous character into account
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt b/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt
index cd5be1c54..501f90565 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt
@@ -270,12 +270,12 @@ class ListStatusAccessibilityDelegate(
private val collapseCwAction = AccessibilityActionCompat(
R.id.action_collapse_cw,
- context.getString(R.string.status_content_warning_show_less)
+ context.getString(R.string.post_content_warning_show_less)
)
private val expandCwAction = AccessibilityActionCompat(
R.id.action_expand_cw,
- context.getString(R.string.status_content_warning_show_more)
+ context.getString(R.string.post_content_warning_show_more)
)
private val replyAction = AccessibilityActionCompat(
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt
index f2e48f4a2..60ac73f47 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt
@@ -176,9 +176,9 @@ class StatusViewHelper(private val itemView: View) {
sensitiveMediaShow.visibility = View.GONE
} else {
sensitiveMediaWarning.text = if (sensitive) {
- context.getString(R.string.status_sensitive_media_title)
+ context.getString(R.string.post_sensitive_media_title)
} else {
- context.getString(R.string.status_media_hidden_title)
+ context.getString(R.string.post_media_hidden_title)
}
sensitiveMediaWarning.visibility = if (showingContent) View.GONE else View.VISIBLE
@@ -225,7 +225,7 @@ class StatusViewHelper(private val itemView: View) {
val context = mediaLabel.context
var labelText = getLabelTypeText(context, attachments[0].type)
if (sensitive) {
- val sensitiveText = context.getString(R.string.status_sensitive_media_title)
+ val sensitiveText = context.getString(R.string.post_sensitive_media_title)
labelText += String.format(" (%s)", sensitiveText)
}
mediaLabel.text = labelText
@@ -239,10 +239,10 @@ class StatusViewHelper(private val itemView: View) {
private fun getLabelTypeText(context: Context, type: Attachment.Type): String {
return when (type) {
- Attachment.Type.IMAGE -> context.getString(R.string.status_media_images)
- Attachment.Type.GIFV, Attachment.Type.VIDEO -> context.getString(R.string.status_media_video)
- Attachment.Type.AUDIO -> context.getString(R.string.status_media_audio)
- else -> context.getString(R.string.status_media_attachments)
+ Attachment.Type.IMAGE -> context.getString(R.string.post_media_images)
+ Attachment.Type.GIFV, Attachment.Type.VIDEO -> context.getString(R.string.post_media_video)
+ Attachment.Type.AUDIO -> context.getString(R.string.post_media_audio)
+ else -> context.getString(R.string.post_media_attachments)
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt
index f28e09c57..7a4a3659d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt
@@ -16,51 +16,6 @@ fun randomAlphanumericString(count: Int): String {
return String(chars)
}
-// We sort statuses by ID. Something we need to invent some ID for placeholder.
-
-/**
- * "Increment" string so that during sorting it's bigger than [this]. Inverse operation to [dec].
- */
-fun String.inc(): String {
- val builder = this.toCharArray()
- var i = builder.lastIndex
-
- while (i >= 0) {
- if (builder[i] < 'z') {
- builder[i] = builder[i].inc()
- return String(builder)
- } else {
- builder[i] = '0'
- }
- i--
- }
- return String(
- CharArray(builder.size + 1) { index ->
- if (index == 0) '0' else builder[index - 1]
- }
- )
-}
-
-/**
- * "Decrement" string so that during sorting it's smaller than [this]. Inverse operation to [inc].
- */
-fun String.dec(): String {
- if (this.isEmpty()) return this
-
- val builder = this.toCharArray()
- var i = builder.lastIndex
- while (i >= 0) {
- if (builder[i] > '0') {
- builder[i] = builder[i].dec()
- return String(builder)
- } else {
- builder[i] = 'z'
- }
- i--
- }
- return String(builder.copyOfRange(1, builder.size))
-}
-
/**
* A < B (strictly) by length and then by content.
* Examples:
@@ -78,6 +33,19 @@ fun String.isLessThan(other: String): Boolean {
}
}
+/**
+ * A <= B (strictly) by length and then by content.
+ * Examples:
+ * "abc" <= "bcd"
+ * "ab" <= "abc"
+ * "cb" <= "abc"
+ * "ab" <= "ab"
+ * not: "abc" > "cb"
+ */
+fun String.isLessThanOrEqual(other: String): Boolean {
+ return this == other || isLessThan(other)
+}
+
fun Spanned.trimTrailingWhitespace(): Spanned {
var i = length
do {
diff --git a/app/src/main/java/com/keylesspalace/tusky/viewdata/NotificationViewData.java b/app/src/main/java/com/keylesspalace/tusky/viewdata/NotificationViewData.java
index 409b858d2..75f90ca40 100644
--- a/app/src/main/java/com/keylesspalace/tusky/viewdata/NotificationViewData.java
+++ b/app/src/main/java/com/keylesspalace/tusky/viewdata/NotificationViewData.java
@@ -19,6 +19,7 @@ import androidx.annotation.Nullable;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Notification;
+import com.keylesspalace.tusky.entity.TimelineAccount;
import java.util.Objects;
@@ -44,11 +45,11 @@ public abstract class NotificationViewData {
public static final class Concrete extends NotificationViewData {
private final Notification.Type type;
private final String id;
- private final Account account;
+ private final TimelineAccount account;
@Nullable
private final StatusViewData.Concrete statusViewData;
- public Concrete(Notification.Type type, String id, Account account,
+ public Concrete(Notification.Type type, String id, TimelineAccount account,
@Nullable StatusViewData.Concrete statusViewData) {
this.type = type;
this.id = id;
@@ -64,7 +65,7 @@ public abstract class NotificationViewData {
return id;
}
- public Account getAccount() {
+ public TimelineAccount getAccount() {
return account;
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.kt b/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.kt
index 92675eb61..d8f271578 100644
--- a/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.kt
@@ -22,12 +22,11 @@ import com.keylesspalace.tusky.entity.Status
/**
* Created by charlag on 11/07/2017.
*
- *
* Class to represent data required to display either a notification or a placeholder.
* It is either a [StatusViewData.Concrete] or a [StatusViewData.Placeholder].
*/
-sealed class StatusViewData private constructor() {
- abstract val viewDataId: Long
+sealed class StatusViewData {
+ abstract val id: String
data class Concrete(
val status: Status,
@@ -49,8 +48,8 @@ sealed class StatusViewData private constructor() {
/** Whether the status meets the requirement to be collapse */
val isCollapsed: Boolean,
) : StatusViewData() {
- override val viewDataId: Long
- get() = status.id.hashCode().toLong()
+ override val id: String
+ get() = status.id
val content: Spanned
val spoilerText: String
@@ -116,9 +115,6 @@ sealed class StatusViewData private constructor() {
}
}
- val id: String
- get() = status.id
-
/** Helper for Java */
fun copyWithStatus(status: Status): Concrete {
return copy(status = status)
@@ -140,10 +136,10 @@ sealed class StatusViewData private constructor() {
}
}
- data class Placeholder(val id: String, val isLoading: Boolean) : StatusViewData() {
- override val viewDataId: Long
- get() = id.hashCode().toLong()
- }
+ data class Placeholder(
+ override val id: String,
+ val isLoading: Boolean
+ ) : StatusViewData()
fun asStatusOrNull() = this as? Concrete
diff --git a/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountsInListViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountsInListViewModel.kt
index b02c2ac09..fd9893762 100644
--- a/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountsInListViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/viewmodel/AccountsInListViewModel.kt
@@ -17,7 +17,7 @@
package com.keylesspalace.tusky.viewmodel
import android.util.Log
-import com.keylesspalace.tusky.entity.Account
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.Either
import com.keylesspalace.tusky.util.Either.Left
@@ -28,7 +28,7 @@ import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.subjects.BehaviorSubject
import javax.inject.Inject
-data class State(val accounts: Either>, val searchResult: List?)
+data class State(val accounts: Either>, val searchResult: List?)
class AccountsInListViewModel @Inject constructor(private val api: MastodonApi) : RxAwareViewModel() {
@@ -49,7 +49,7 @@ class AccountsInListViewModel @Inject constructor(private val api: MastodonApi)
}
}
- fun addAccountToList(listId: String, account: Account) {
+ fun addAccountToList(listId: String, account: TimelineAccount) {
api.addCountToList(listId, listOf(account.id))
.subscribe(
{
diff --git a/app/src/main/java/net/accelf/yuito/QuickTootViewModel.kt b/app/src/main/java/net/accelf/yuito/QuickTootViewModel.kt
index d9c2262ac..8a57df343 100644
--- a/app/src/main/java/net/accelf/yuito/QuickTootViewModel.kt
+++ b/app/src/main/java/net/accelf/yuito/QuickTootViewModel.kt
@@ -63,7 +63,7 @@ class QuickTootViewModel @Inject constructor(
fun composeOptions(tootRightNow: Boolean): ComposeActivity.ComposeOptions {
return ComposeActivity.ComposeOptions(
- tootText = content.value,
+ content = content.value,
mentionedUsernames = inReplyTo.value
?.let {
linkedSetOf(it.account.username, *(it.mentions.map { mention -> mention.username }.toTypedArray()))
diff --git a/app/src/main/java/net/accelf/yuito/QuoteInlineHelper.java b/app/src/main/java/net/accelf/yuito/QuoteInlineHelper.java
index cf1f21406..8b5f076fc 100644
--- a/app/src/main/java/net/accelf/yuito/QuoteInlineHelper.java
+++ b/app/src/main/java/net/accelf/yuito/QuoteInlineHelper.java
@@ -10,10 +10,10 @@ import androidx.annotation.Px;
import com.google.android.material.button.MaterialButton;
import com.keylesspalace.tusky.R;
-import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Emoji;
import com.keylesspalace.tusky.entity.HashTag;
import com.keylesspalace.tusky.entity.Status;
+import com.keylesspalace.tusky.entity.TimelineAccount;
import com.keylesspalace.tusky.interfaces.LinkListener;
import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper;
@@ -23,21 +23,21 @@ import com.keylesspalace.tusky.util.StatusDisplayOptions;
import java.util.List;
public class QuoteInlineHelper {
- private Status quoteStatus;
+ private final Status quoteStatus;
- private View quoteContainer;
- private ImageView quoteAvatar;
- private TextView quoteDisplayName;
- private TextView quoteUsername;
- private TextView quoteContentWarningDescription;
- private MaterialButton quoteContentWarningButton;
- private TextView quoteContent;
- private TextView quoteMedia;
+ private final View quoteContainer;
+ private final ImageView quoteAvatar;
+ private final TextView quoteDisplayName;
+ private final TextView quoteUsername;
+ private final TextView quoteContentWarningDescription;
+ private final MaterialButton quoteContentWarningButton;
+ private final TextView quoteContent;
+ private final TextView quoteMedia;
- private LinkListener listener;
+ private final LinkListener listener;
@Px
- private int avatarRadius24dp;
- private StatusDisplayOptions statusDisplayOptions;
+ private final int avatarRadius24dp;
+ private final StatusDisplayOptions statusDisplayOptions;
public QuoteInlineHelper(Status status, View container, LinkListener listener,
@Px int avatarRadius24dp, StatusDisplayOptions statusDisplayOptions) {
@@ -62,7 +62,7 @@ public class QuoteInlineHelper {
private void setUsername(String name) {
Context context = quoteUsername.getContext();
- String format = context.getString(R.string.status_username_format);
+ String format = context.getString(R.string.post_username_format);
String usernameText = String.format(format, name);
quoteUsername.setText(usernameText);
}
@@ -97,10 +97,10 @@ public class QuoteInlineHelper {
private void setContentVisibility(boolean show) {
if (show) {
quoteContent.setVisibility(View.VISIBLE);
- quoteContentWarningButton.setText(R.string.status_content_warning_show_less);
+ quoteContentWarningButton.setText(R.string.post_content_warning_show_less);
} else {
quoteContent.setVisibility(View.GONE);
- quoteContentWarningButton.setText(R.string.status_content_warning_show_more);
+ quoteContentWarningButton.setText(R.string.post_content_warning_show_more);
}
}
@@ -120,7 +120,7 @@ public class QuoteInlineHelper {
}
public void setupQuoteContainer() {
- Account account = quoteStatus.getAccount();
+ TimelineAccount account = quoteStatus.getAccount();
setDisplayName(account.getName(), account.getEmojis());
setUsername(account.getUsername());
setContent(
diff --git a/app/src/main/res/drawable-v26/launcher_shadow_gradient.xml b/app/src/main/res/color-v24/launcher_shadow_gradient.xml
similarity index 100%
rename from app/src/main/res/drawable-v26/launcher_shadow_gradient.xml
rename to app/src/main/res/color-v24/launcher_shadow_gradient.xml
diff --git a/app/src/main/res/drawable-hdpi/splash.png b/app/src/main/res/drawable-hdpi/splash.png
deleted file mode 100644
index 6e710c750..000000000
Binary files a/app/src/main/res/drawable-hdpi/splash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/splash.png b/app/src/main/res/drawable-mdpi/splash.png
deleted file mode 100644
index cb3a1806e..000000000
Binary files a/app/src/main/res/drawable-mdpi/splash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/splash.png b/app/src/main/res/drawable-xhdpi/splash.png
deleted file mode 100644
index 883f6fdf0..000000000
Binary files a/app/src/main/res/drawable-xhdpi/splash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/splash.png b/app/src/main/res/drawable-xxhdpi/splash.png
deleted file mode 100644
index ef249bf45..000000000
Binary files a/app/src/main/res/drawable-xxhdpi/splash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/splash.png b/app/src/main/res/drawable-xxxhdpi/splash.png
deleted file mode 100644
index 631bd78ff..000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/splash.png and /dev/null differ
diff --git a/app/src/main/res/drawable/background_splash.xml b/app/src/main/res/drawable/background_splash.xml
deleted file mode 100644
index 4504beef7..000000000
--- a/app/src/main/res/drawable/background_splash.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- -
-
-
- -
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml
index c93203015..570644127 100644
--- a/app/src/main/res/layout/activity_account.xml
+++ b/app/src/main/res/layout/activity_account.xml
@@ -331,7 +331,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="6dp"
- android:text="@string/title_statuses"
+ android:text="@string/title_posts"
android:textColor="@color/account_tab_font_color"
android:textSize="?attr/status_text_medium" />
diff --git a/app/src/main/res/layout/activity_compose.xml b/app/src/main/res/layout/activity_compose.xml
index 94335a755..7642aa6d6 100644
--- a/app/src/main/res/layout/activity_compose.xml
+++ b/app/src/main/res/layout/activity_compose.xml
@@ -371,10 +371,10 @@
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="4dp"
- android:contentDescription="@string/action_schedule_toot"
+ android:contentDescription="@string/action_schedule_post"
android:padding="4dp"
app:srcCompat="@drawable/ic_access_time"
- app:tooltipText="@string/action_schedule_toot" />
+ app:tooltipText="@string/action_schedule_post" />
+ tools:context="com.keylesspalace.tusky.components.login.LoginActivity">
+ tools:context=".components.scheduled.ScheduledStatusActivity">
+ tools:text="Some post content. May be very long." />
+ tools:text="@string/post_content_warning_show_more" />
@@ -130,7 +130,7 @@
android:paddingRight="16dp"
android:paddingBottom="4dp"
android:textAllCaps="true"
- tools:text="@string/status_content_show_less"
+ tools:text="@string/post_content_show_less"
style="@style/TuskyButton.Outlined"
android:textSize="?attr/status_text_medium"
android:visibility="gone" />
diff --git a/app/src/main/res/layout/login_webview.xml b/app/src/main/res/layout/login_webview.xml
new file mode 100644
index 000000000..22d7f3bd9
--- /dev/null
+++ b/app/src/main/res/layout/login_webview.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/status_more.xml b/app/src/main/res/menu/status_more.xml
index c73b7e9f0..4a13b45dd 100644
--- a/app/src/main/res/menu/status_more.xml
+++ b/app/src/main/res/menu/status_more.xml
@@ -5,11 +5,11 @@
android:title="@string/action_share">
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/view_thread_toolbar.xml b/app/src/main/res/menu/view_thread_toolbar.xml
index 456f2094a..65577d208 100644
--- a/app/src/main/res/menu/view_thread_toolbar.xml
+++ b/app/src/main/res/menu/view_thread_toolbar.xml
@@ -9,7 +9,7 @@
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 8a7f4fa58..6e4f7c49f 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -18,17 +18,17 @@
التصريح لازم للإحتفاظ بالوسائط.
لا يمكنك إرفاق كلا من الصور والفيديوهات في نفس المنشور في آن واحد.
اخفقت عملية الرفع.
- خطأ عند إرسال التبويق.
+ خطأ عند إرسال المنشور.
الرئيسي
الاشعارات
المحلي
الفدرالي
الرسائل المباشرة
الألسنة
- تبويق
- المنشورات
- التبويقات والردود
- المدبّسة
+ خيط
+ المنشورات
+ التبويقات والردود
+ المدبّسة
المتابَعون
المتابِعون
المفضلة
@@ -38,19 +38,19 @@
عدل ملفك التعريفي
المسودات
الرّخص
- \@%s
- شارَكَه %s
- محتوى حساس
- وسائط مخفية
- اضغط للعرض
- اعرض المزيد
- اعرض أقل
- توسيع
- تصغير
+ \@%s
+ شارَكَه %s
+ محتوى حساس
+ وسائط مخفية
+ اضغط للعرض
+ اعرض المزيد
+ اعرض أقل
+ توسيع
+ تصغير
لا شيء هنا.
لا يوجد شيء هنا. إسحب إلى أسفل للإنعاش!
- شارَك %s تبويقك
- أعجِب %s بتبويقك
+ شارَك %s منشورك
+ أعجِب %s بمنشورك
%s يتبعك
أبلغ عن @%s
تعليقات إضافية؟
@@ -102,7 +102,7 @@
رفض
البحث
المسودات
- كيفية عرض التبويق
+ كيفية عرض المنشور
تحذير عن المحتوى
لوحة مفاتيح الإيموجي
إضافة لسان
@@ -118,14 +118,14 @@
إنسخ الرابط
إفتحه كـ %s
شاركه كـ…
- شارك رابط التبويق مع…
- شارك التبويق على…
+ شارك رابط التبويق مع…
+ شارك التبويق على…
شارك الوسيط مع…
تم إرساله!
تم فك الحجب عن الحساب
لم يعد الحساب مكتومًا
- تم إرساله!
- تم إرسال الرد بنجاح.
+ تم إرساله!
+ تم إرسال الرد بنجاح.
أي مثيل خادم؟
ما الجديد؟
تحذير عن المحتوى
@@ -150,7 +150,7 @@
تنزيل
هل تريد رفض طلب المتابعة؟
هل تود إلغاء متابعة هذا الحساب؟
- هل تريد حذف هذا التبويق؟
+ هل تريد حذف هذا التبويق؟
للعامة: ينشر على الخيوط العمومية
غير مدرج: لا يُعرَض على الخيوط العمومية
لمتابعيك فقط: يُنشر إلى متابعيك فقط
@@ -179,8 +179,8 @@
إخفاء زر المتابعة أثناء تمرير الصفحة
إخفاء زر التحرير عند التمرير
اللغة
- تصفية الخيوط
- الألسنة
+ تصفية الخيوط
+ الألسنة
عرض الترقيات
عرض الردود
إظهار معاينات الوسائط
@@ -196,20 +196,20 @@
للعامة
غير مدرج
للمُتابِعين فقط
- حجم الخط
- صغير جدا
- صغير
- متوسط
- عريض
- عريض جدا
+ حجم الخط
+ صغير جدا
+ صغير
+ متوسط
+ عريض
+ عريض جدا
إشارات جديدة
الإخطارات عندما يشار إليك
متابِعون جدد
إخطارات عند تلقي متابعين جدد
الترقيات
- إخطارات عندما يقوم أحدهم بترقية تبويقاتي
+ إخطارات عندما يقوم أحدهم بمشاركة منشوراتي
المفضلة
- الإشعار عندما يقوم أحدهم بإضافة تبويقاتك إلى مفضلاته
+ الإشعار عندما يقوم أحدهم بإضافة منشوراتك إلى مفضلاته
%s أشار إليك
%1$s, %2$s, %3$s و %4$d آخرون
%1$s, %2$s, و %3$s
@@ -237,10 +237,10 @@
تقارير الأخطاء و طلبات التحسينات على :\n
https://github.com/accelforce/Yuito/issues
الملف الشخصي لتوسكي
- شارك محتوى التبويق
- شارك الرابط إلى التبويق
- صور
- فيديو
+ شارك محتوى التبويق
+ شارك الرابط إلى التبويق
+ صور
+ فيديو
طلب متابعة
في %dy
@@ -291,11 +291,11 @@
تجميد الحساب
يتطلب منك قبول طلبات المتابَعة يدويا
هل تود الإحتفاظ بالمسودة ؟
- جارٍ إرسال التبويق…
- خطأ أثناء عملية إرسال التبويق
- إرسال التبويقات
- أُلغيَ الإرسال
- تم الاحتفاظ بنسخة مِن التبويق في مسوداتك
+ جارٍ إرسال التبويق…
+ خطأ أثناء عملية إرسال التبويق
+ إرسال التبويقات
+ أُلغيَ الإرسال
+ تم الاحتفاظ بنسخة مِن التبويق في مسوداتك
حرر
لا يحتوي مثيل خادومكم %s على أية حزمة إيموجي مخصصة
تم نسخه إلى الحافظة
@@ -303,8 +303,8 @@
الإفتراضي في النظام
يجب عليك أولا تنزيل حزمة الإيموجي هذه
البحث جارٍ …
- توسيع/طي كافة المنشورات
- افتح التبويق
+ توسيع/طي كافة المنشورات
+ افتح التبويق
مطلوب إعادة تشغيل التطبيق
إعادة تشغيل توسكي مطلوبة قصد تفعيل التعديلات
لاحقًا
@@ -342,10 +342,10 @@
- لقد بلغت الحد الأقصى مِن الألسنة %1$d
- لقد بلغت الحد الأقصى مِن الألسنة %1$d
- الوسائط: %s
- تحذير عن المحتوى: %s
- مِن دون وصف
- أعاد تدوينه
+ الوسائط: %s
+ تحذير عن المحتوى: %s
+ مِن دون وصف
+ أعاد تدوينه
للعامة
غير مُدرَج
المتابِعون
@@ -356,13 +356,13 @@
افتح الوسيط #%d
نزّل الوسائط
جارٍ تنزيل الوسائط
- هل تريد حذف وإعادة صياغة هذا التبويق؟
- تم تفضيله
+ هل تريد حذف وإعادة صياغة هذا التبويق؟
+ تم تفضيله
وسم بدون #
مسح
عامل تصفية
طَبِّق
- تحرير تبويق
+ تحرير منشور
كتابة
هل تريد حقا مسح كافة إشعاراتك؟
ينتهي في %s
@@ -445,7 +445,7 @@
تعليقات إضافية
أعد تحويله إلى %s
فشل الابلاغ
- فشلت عملية جلب المنشورات
+ فشلت عملية جلب المنشورات
اعرض مصفاة الإشعارات
الكلمة كاملة
استطلاع رأي بالخيارات: %1$s, %2$s, %3$s, %4$s; %5$s
@@ -455,7 +455,7 @@
الحسابات
فشل البحث
إضافة استطلاع رأي
- افتح دائما التبويقات التي تحتوي على محتوى حساس
+ افتح دائما المنشورات التي تحتوي على محتوى حساس
استطلاع رأي
5 دقائق
30 دقيقة
@@ -470,21 +470,21 @@
تعديل
عندما تكون الكلمة أو العبارة أبجدية رقمية فقط ، فلن يتم تطبيقها إلا إذا كانت مطابقة للكلمة بأكملها
%1$s • %2$s
- التبويقات المبَرمَجة
+ التبويقات المبَرمَجة
تعديل
- التبويقات المبَرمَجة
- برمجة تبويق
+ التبويقات المبَرمَجة
+ برمجة تبويق
صفّر
خطأ أثناء البحث عن منشور %s
الفواصل المرجعية
أضفه إلى الفواصل المرجعية
الفواصل المرجعية
مدعوم بِـ Tusky
- أضيف إلى الفواصل المرجعية
+ أضيف إلى الفواصل المرجعية
اختر قائمة
القائمة
ليس لديك أية مسودات.
- ليس لديك أية منشورات مُبرمَجة للنشر.
+ ليس لديك أية منشورات مُبرمَجة للنشر.
يجب أن يكون حجم الملفات الصوتية أقل مِن 40 ميغابايت.
تُقدّر أدنى فترة لبرمجة النشر في ماستدون بـ 5 دقائق.
تمكين حركات السحب للانتقال بين الألسنة
@@ -520,23 +520,23 @@
إخفاء عنوان شريط الأدوات العلوي
الاعلانات
أتريد حقا حذف القائمة %s؟
- فشلت عملية إرسال التبويق!
+ فشلت عملية إرسال التبويق!
حُذفَت المسودة
اشترك
إلغاء الإشتراك
نشر %s للتوّ
احذف المحادثة
هل تريد حذف هذه المحادثة؟
- تبويقات جديدة
- مرفقات
+ منشورات جديدة
+ مرفقات
المدة
لا توجد إعلانات.
ملاحظتك الخاصة عن هذا الحساب
تم حفظها!
راجع الإشعارات
- صوت
- لقد حُذِف التبويق الذي حررت من أجله مسودة الرد
- شخص ما أنا مشترك في حسابه قد نشر تبويقا جديدا
+ صوت
+ لقد حُذِف التبويق الذي حررت من أجله مسودة الرد
+ شخص ما أنا مشترك في حسابه قد نشر منشورا جديدا
حرّك الإيموجيات المخصصة
إخفاء الإحصائيات الكمية عن المنشورات
إخفاء الإحصائيات الكمية عن الملفات التعريفية
@@ -551,4 +551,5 @@
90 يومًا
180 يومًا
365 يومًا
+ تحرير منشور
\ No newline at end of file
diff --git a/app/src/main/res/values-ber/strings.xml b/app/src/main/res/values-ber/strings.xml
index b6d317b5a..c754aef8a 100644
--- a/app/src/main/res/values-ber/strings.xml
+++ b/app/src/main/res/values-ber/strings.xml
@@ -30,14 +30,14 @@
ⴽⴽⴻⵙ
ⵉⵔⴻⵡⵡⴰⵢⴻⵏ
ⵉⵎⵙⴻⵇⴷⴰⵛⴻⵏ ⵜⵙⵡⴰⵃⵍⴻⵎ
- ⵉⵛⵛⴰⵔⴻⵏ
+ ⵉⵛⵛⴰⵔⴻⵏ
ⴰⵏⵜⴰ ⵝⵓⵎⵎⴰⵏⵜ\?
ⵔⵏⵓ ⵢⵉⵡⴻⵏ ⵏ ⵓⵎⵉⴹⴰⵏ ⴰⵎⴰⵢⵏⵓⵝ ⵏ ⵎⴰⵚⵟⵓⴷⵓⵏ
ⵔⵏⵓ ⴰⵎⵉⴹⴰⵏ
ⴸⴰⵛⵓ ⵉⴳⴻⵍⵍⴰⵏ ⴸ ⴰⵎⴰⵢⵏⵓⵝ\?
- ⵙⵖⵉⵡⴻⵙ ⵝⵉⵊⴻⵡⵡⵉⵇⵝⴰ
- ⵝⵉⵊⴻⵡⵡⵉⵇⵉⵏ ⵢⴻⵜⵜⵖⴰⵙⵖⴰⵡⵙⴻⵏ
- ⵝⵉⵊⴻⵡⵡⵉⵇⵉⵏ ⵢⴻⵜⵜⵖⴰⵙⵖⴰⵡⵙⴻⵏ
+ ⵙⵖⵉⵡⴻⵙ ⵝⵉⵊⴻⵡⵡⵉⵇⵝⴰ
+ ⵝⵉⵊⴻⵡⵡⵉⵇⵉⵏ ⵢⴻⵜⵜⵖⴰⵙⵖⴰⵡⵙⴻⵏ
+ ⵝⵉⵊⴻⵡⵡⵉⵇⵉⵏ ⵢⴻⵜⵜⵖⴰⵙⵖⴰⵡⵙⴻⵏ
ⵝⵉⵛⵔⴰⴹ
ⵝⵉⵛⵔⴰⴹ
\ No newline at end of file
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index a3db937bc..a6ca7a656 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -1,7 +1,7 @@
Публикация
- Публикацията, на която сте изготвили отговор, е премахната
+ Публикацията, на която сте изготвили отговор, е премахната
1 час
30 минути
5 минути
@@ -14,7 +14,7 @@
Акаунти
Акаунтът е от друг сървър. Да изпратите ли и там анонимно копие на доклада\?
Докладът ще бъде изпратен на модератора на вашия сървър. Можете да предоставите обяснение защо докладвате този акаунт по-долу:
- Извличането на състояния бе неуспешно
+ Извличането на състояния бе неуспешно
Докладването бе неуспешно
Препращане към %s
Допълнителни коментари
@@ -70,12 +70,12 @@
Директно
Последователи
Публично
- Отметнато
- Поставено в любими
- Реблог
- Без описание
- Предупреждение за съдържание: %s
- Мултимедия: %s
+ Отметнато
+ Поставено в любими
+ Реблог
+ Без описание
+ Предупреждение за съдържание: %s
+ Мултимедия: %s
- достигнати са максималните %1$d раздела
@@ -118,19 +118,19 @@
По-късно
Ще трябва да рестартирате Tusky, за да приложите тези промени
Изисква се рестартиране на приложението
- Отваряне на публикация
- Разгъване/свиване на всички състояния
+ Отваряне на публикация
+ Разгъване/свиване на всички състояния
Извършва се търсене…
По подразбиране от системата
Стил на емоджи
Копирано в клипборда
Инстанцията ви %s няма персонализирани емоджита
Композиране
- Копие от публикацията е запазено във вашите чернови
- Изпращането е отменено
- Изпращане на публикации
- Грешка при изпращане на публикация
- Изпращане на публикация…
+ Копие от публикацията е запазено във вашите чернови
+ Изпращането е отменено
+ Изпращане на публикации
+ Грешка при изпращане на публикация
+ Изпращане на публикация…
Запазване на чернова\?
Изисква ръчно одобряване на последователи
Заключване на акаунт
@@ -183,12 +183,12 @@
след %dг
след %dд
Заявено последване
- Прикачени файлове
- Аудио
- Видео
- Изображения
- Споделяне на връзка към публикация
- Споделяне на съдържание на публикация
+ Прикачени файлове
+ Аудио
+ Видео
+ Изображения
+ Споделяне на връзка към публикация
+ Споделяне на съдържание на публикация
Профилът на Tusky
Доклади за грешки и заявки за функции:
\n https://github.com/tuskyapp/Tusky/issues
@@ -213,10 +213,10 @@
Известия, когато публикациите ви бъдат означени като любими
Любими
Известия, когато публикациите ви се споделят
- Най-малък
+ Най-малък
Скрито
- Раздели
- Филтриране на емисия
+ Раздели
+ Филтриране на емисия
Анимиране на персонализирани емоджита
Показване на цветни градиенти за скрита мултимедия
Анимиране на GIF аватари
@@ -256,26 +256,26 @@
Блокиране на @%s\?
Скриване на целия домейн
Сигурни ли сте, че искате да блокирате всички от %s\? Няма да виждате съдържание от този домейн в нито една публична емисия или във вашите известия. Последователите ви от този домейн ще бъдат премахнати.
- Изтриване и преработване на тази публикация\?
- Изтриване на тази публикация\?
+ Изтриване и преработване на тази публикация\?
+ Изтриване на тази публикация\?
Отследване на този акаунт\?
Отмяна на заявката за последване\?
Изтегляне
Качване…
Завършване на мултимедийно качване
- "Тук може да се въведе адресът или домейнът на която и да е инстанция, като mastodon.social, icosahedron.website, social.tchncs.de и <a href=\"https://instances.social\">други!</a>
+ Тук може да се въведе адресът или домейнът на която и да е инстанция, като mastodon.social, icosahedron.website, social.tchncs.de и <a href=\"https://instances.social\">други!</a>
\n
\nАко все още нямате акаунт, можете да въведете името на инстанцията, към който искате да се присъедините, и да създадете акаунт там.
\n
\nИнстанцията е единично място, където се хоства акаунтът ви, но можете лесно да комуникирате и да следвате хора в други инстанции, сякаш сте на същия сайт.
\n
-\nПовече информация можете да намерите на <a href=\"https://joinmastodon.org\">joinmastodon.org</a>. "more!
- \n\nIf you don\'t yet have an account, you can enter the name of the instance you\'d like to
- join and create an account there.\n\nAn instance is a single place where your account is
- hosted, but you can easily communicate with and follow folks on other instances as though
- you were on the same site.
- \n\nMore info can be found at joinmastodon.org.
-
+\nПовече информация можете да намерите на <a href=\"https://joinmastodon.org\">joinmastodon.org</a>. more!
+\n
+\nIf you don\'t yet have an account, you can enter the name of the instance you\'d like to join and create an account there.
+\n
+\nAn instance is a single place where your account is hosted, but you can easily communicate with and follow folks on other instances as though you were on the same site.
+\n
+\nMore info can be found at joinmastodon.org.
Свързване…
Какво е инстанция\?
Заглавна част
@@ -288,15 +288,15 @@
Предупреждение за съдържание
Какво се случва\?
Коя инстанция\?
- Отговорът е изпратен успешно.
- Изпратено!
+ Отговорът е изпратен успешно.
+ Изпратено!
%s е разкрит
Потребителят е раззаглушен
Потребителят е деблокиран
Изпратено!
Споделяне на мултимедия в…
- Споделяне на публикация в…
- Споделяне на URL адреса на публикацията в…
+ Споделяне на публикация в…
+ Споделяне на URL адреса на публикацията в…
Теглене на мултимедия
Изтегляне на мултимедия
Споделяне като …
@@ -315,11 +315,11 @@
Връзки
Добавяне на раздел
Нулиране
- Планиране на публикация
+ Планиране на публикация
Емоджи клавиатура
Предупреждение за съдържание
Видимост на публикация
- Планирани публикации
+ Планирани публикации
Чернови
Търсене
Отхвърляне
@@ -390,18 +390,18 @@
%s сподели вашата публикация
Нищо тук. Дръпнете надолу, за да опресните!
Нищо тук.
- Свиване
- Разгъване
- Покажи по-малко
- Покажи повече
- Щракнете за преглед
- Мултимедията е скрита
- Деликатно съдържание
- %s сподели
- \@%s
+ Свиване
+ Разгъване
+ Покажи по-малко
+ Покажи повече
+ Щракнете за преглед
+ Мултимедията е скрита
+ Деликатно съдържание
+ %s сподели
+ \@%s
Лицензи
Оповестявания
- Планирани публикации
+ Планирани публикации
Чернови
Редакция на профила ви
Заявки за последване
@@ -412,9 +412,9 @@
Любими
Последователи
Последвани
- Закачени
- С отговори
- Публикации
+ Закачени
+ С отговори
+ Публикации
Раздели
Директни съобщения
Локално
@@ -442,7 +442,7 @@
Възникна грешка.
Черновата е изтрита
Неуспешно зареждане на информация за отговор
- Тази публикация не успя да се изпрати!
+ Тази публикация не успя да се изпрати!
Наистина ли искате да изтриете списъка %s\?
- Не можете да качите повече от %1$d мултимедийни прикачени файлове.
@@ -466,7 +466,7 @@
Показване на визуализации на връзки в емисии
Mastodon има минимален интервал за планиране от 5 минути.
Няма оповестявания.
- Нямате планирани състояния.
+ Нямате планирани състояния.
Нямате чернови.
Грешка при търсенето на публикация %s
Редакция
@@ -484,12 +484,12 @@
Нови последователи
Известия за нови споменавания
Нови споменавания
- Най-голям
- Голям
- Среден
- Малък
+ Най-голям
+ Голям
+ Среден
+ Малък
Скрито: Не се показва в публични емисии
- Размер на текста на състоянието
+ Размер на текста на състоянието
Само за последователи
Скрито
Публично
diff --git a/app/src/main/res/values-bn-rBD/strings.xml b/app/src/main/res/values-bn-rBD/strings.xml
index 609063aa9..082f6dead 100644
--- a/app/src/main/res/values-bn-rBD/strings.xml
+++ b/app/src/main/res/values-bn-rBD/strings.xml
@@ -7,11 +7,11 @@
অনুগামিবৃন্দ
অতালিকাভুক্ত
সর্বজনীন
- পছন্দ
- আবার ব্লগ
- বর্ণনা নাই
- সতর্কবার্তা: %s
- মিডিয়া: %s
+ পছন্দ
+ আবার ব্লগ
+ বর্ণনা নাই
+ সতর্কবার্তা: %s
+ মিডিয়া: %s
- সর্বোচ্চ %1$dটি ট্যাব পৌঁছেছে
- সর্বোচ্চ %1$dটি ট্যাব পৌঁছেছে
@@ -42,8 +42,8 @@
পরবর্তীতে
এই পরিবর্তনগুলি প্রয়োগ করার জন্য আপনাকে টাস্কি পুনরায় চালু করতে হবে
অ্যাপ্লিকেশন পুনরায় আরম্ভ করা প্রয়োজন
- টুট খুলুন
- সমস্ত স্টেটাস প্রসারিত/সংকুচিত করুন
+ টুট খুলুন
+ সমস্ত স্টেটাস প্রসারিত/সংকুচিত করুন
অনুসন্ধান করা হচ্ছে …
আপনাকে প্রথমে এই ইমোজি সেটগুলি ডাউনলোড করতে হবে
সিস্টেমের ডিফল্ট
@@ -51,11 +51,11 @@
ক্লিপবোর্ডে অনুলিপি করা হয়েছে
আপনার ইনস্ট্যান্স %s এর কোনো কাস্টম ইমোজিস নেই
রচনা
- টুট এর একটি কপি আপনার ড্রাফটে সংরক্ষণ করা হয়েছে
- পাঠানো বাতিল
- টুট পাঠানো হচ্ছে
- টুট পাঠাতে গিয়ে একটি ত্রুটি ঘটেছে
- টুট পাঠানো হচ্ছে …
+ টুট এর একটি কপি আপনার ড্রাফটে সংরক্ষণ করা হয়েছে
+ পাঠানো বাতিল
+ টুট পাঠানো হচ্ছে
+ টুট পাঠাতে গিয়ে একটি ত্রুটি ঘটেছে
+ টুট পাঠানো হচ্ছে …
ড্রাফট সংরক্ষণ\?
অনুসারী অনুমোদন করার জন্য আপনাকে প্রয়োজন
অ্যাকাউন্ট লক করুন
@@ -99,10 +99,10 @@
\'%dd এ\'
\'%dy এ\'
অনুরোধ অনুসরণ করুন
- ভিডিও
- চিত্রগুলি
- টুট এর সাথে লিংক ভাগ করুন
- টুট এর কন্টেন্ট ভাগ করুন
+ ভিডিও
+ চিত্রগুলি
+ টুট এর সাথে লিংক ভাগ করুন
+ টুট এর কন্টেন্ট ভাগ করুন
টাস্কির প্রোফাইল
বাগ রিপোর্ট এবং বৈশিষ্ট্য অনুরোধ:
\nhttps://github.com/tuskyapp/Tusky/issues
@@ -122,12 +122,12 @@
নতুন অনুসরণকারী
নতুন উল্লেখ সম্পর্কে বিজ্ঞপ্তি
নতুন উল্লেখসমূহ
- বৃহত্তম
- বড়
- মাঝারি
- ছোট
- কনিষ্ঠ
- স্থিতি টেক্সট আকার
+ বৃহত্তম
+ বড়
+ মাঝারি
+ ছোট
+ কনিষ্ঠ
+ স্থিতি টেক্সট আকার
শুধুমাত্র অনুগামিবৃন্দ
অতালিকাভুক্ত
সর্বজনীন
@@ -143,8 +143,8 @@
মিডিয়া পূর্বরূপ ডাউনলোড করুন
উত্তর প্রদর্শন করুন
সমর্থন দেখান
- ট্যাবগুলি
- টাইমলাইন ফিল্টারিং
+ ট্যাবগুলি
+ টাইমলাইন ফিল্টারিং
GIF অবতার অ্যানিমেশন করুন
বট জন্য সূচক প্রদর্শন করুন
ভাষা
@@ -176,26 +176,30 @@
শুধুমাত্র অনুসরণকারীদের: শুধুমাত্র অনুসরণকারীদের পোস্ট করুন
তালিকাভুক্ত নয়: সর্বজনীন সময়সূচীগুলিতে দেখাবেন না
সর্বজনীন: পাবলিক টাইমলাইনে পোস্ট কর
- এই টুট টি মুছে ফেলবেন এবং পুনরায় ড্রাফট করবেন\?
- এই টুট টি মুছে ফেলবেন\?
+ এই টুট টি মুছে ফেলবেন এবং পুনরায় ড্রাফট করবেন\?
+ এই টুট টি মুছে ফেলবেন\?
এই অ্যাকাউন্টটি অনুসরণ করবেন না\?
অনুসরণ অনুরোধ প্রত্যাহার\?
ডাউনলোড
আপলোড হচ্ছে …
মিডিয়া আপলোড সমাপ্ত করা হচ্ছে
- "কোনও উদাহরণের ঠিকানা বা ডোমেন এখানে প্রবেশ করা যেতে পারে যেমন mastodon.social, icosahedron.website, social.tchncs.de, এবং <a href=\"https://instances.social\"> আরও! </a>
+ কোনও উদাহরণের ঠিকানা বা ডোমেন এখানে প্রবেশ করা যেতে পারে যেমন mastodon.social, icosahedron.website, social.tchncs.de, এবং <a href=\"https://instances.social\"> আরও! </a>
\n
\nআপনার যদি এখনো অ্যাকাউন্ট না থাকে তবে আপনি যে ইনস্ট্যান্সটিতে যোগ দিতে চান সেটির নামটি প্রবেশ করতে এবং সেখানে একটি অ্যাকাউন্ট তৈরি করতে পারেন।
+\n
\n
+\n
\nএকটি ইনস্ট্যান্স একটি একক স্থান যেখানে আপনার অ্যাকাউন্ট হোস্ট করা হয়, তবে আপনি সহজেই যোগাযোগ করতে পারেন এবং অন্যান্য ক্ষেত্রে যেমন আপনি একই সাইটে ছিলেন তা অনুসরণ করতে পারেন।
+\n
\n
-\nআরো তথ্য <a href=\"https://joinmastodon.org\"> joinmastodon.org </a> এ পাওয়া যেতে পারে। "more!
- \n\nIf you don\'t yet have an account, you can enter the name of the instance you\'d like to
- join and create an account there.\n\nAn instance is a single place where your account is
- hosted, but you can easily communicate with and follow folks on other instances as though
- you were on the same site.
- \n\nMore info can be found at joinmastodon.org.
-
+\n
+\nআরো তথ্য <a href=\"https://joinmastodon.org\"> joinmastodon.org </a> এ পাওয়া যেতে পারে। more!
+\n
+\nIf you don\'t yet have an account, you can enter the name of the instance you\'d like to join and create an account there.
+\n
+\nAn instance is a single place where your account is hosted, but you can easily communicate with and follow folks on other instances as though you were on the same site.
+\n
+\nMore info can be found at joinmastodon.org.
সংযুক্ত হচ্ছে …
ইনস্ট্যান্স কি\?
হেডার
@@ -208,14 +212,14 @@
সতর্কবার্তা
কি হচ্ছে\?
কোন ইনস্ট্যান্স\?
- উত্তর সফলভাবে পাঠানো হয়েছে।
- পাঠানো হয়েছে!
+ উত্তর সফলভাবে পাঠানো হয়েছে।
+ পাঠানো হয়েছে!
ব্যবহারকারী সশব্দ
ব্যবহারকারী অবরোধ মুক্ত
পাঠানো হয়েছে!
মিডিয়া শেয়ার করুন …
- টুট ভাগ করুন …
- টুট URL ভাগ করুন …
+ টুট ভাগ করুন …
+ টুট URL ভাগ করুন …
মিডিয়া ডাউনলোড করা হচ্ছে
মিডিয়া ডাউনলোড করুন
হিসাবে ভাগ করুন …
@@ -289,13 +293,13 @@
রিপোর্ট @%s
এখানে কিছু নেই. রিফ্রেশ করতে নিচে টানুন!
এখানে কিছুই নেই।
- বন্ধ
- বিস্তৃত
- প্রদর্শন কম
- আরও দেখাও
- দেখার জন্য ক্লিক করুন
- মিডিয়া লুকানো
- সংবেদনশীল কন্টেন্ট
+ বন্ধ
+ বিস্তৃত
+ প্রদর্শন কম
+ আরও দেখাও
+ দেখার জন্য ক্লিক করুন
+ মিডিয়া লুকানো
+ সংবেদনশীল কন্টেন্ট
লাইসেন্সগুলি
খসড়া
আপনার প্রোফাইল সম্পাদনা করুন
@@ -306,8 +310,8 @@
%dমা
%dঘ
%dব
- %s বুস্টকৃত
- \@%s
+ %s বুস্টকৃত
+ \@%s
বিজ্ঞপ্তি লুকাও
\'%s থেকে বিজ্ঞপ্তি বন্ধ করো\'
\'%s থেকে বিজ্ঞপ্তি বন্ধ করো\'
@@ -332,20 +336,20 @@
মাস্টোডনের সর্বনিম্ন ৫ মিনিটের সময়সূচীর বিরতি আছে।
অডিও ফাইলগুলি অবশ্যই ৪০MB এর চেয়ে কম হওয়া উচিত।
তোমার কোনো খসড়া নেই।
- তোমার কোনো সময়সূচীত স্ট্যাটাস নেই।
+ তোমার কোনো সময়সূচীত স্ট্যাটাস নেই।
তালিকা
তালিকা নির্বাচন করো
- বুকমার্ককৃত
+ বুকমার্ককৃত
বুকমার্কগুলি
বুকমার্ক
বুকমার্কগুলি
টাস্কি দ্বারা চালিত
\'%s পোস্ট অনুসন্ধানে ত্রুটি\'
রিসেট
- নির্ধারিত টুট
- নির্ধারিত টুটগুলি
+ নির্ধারিত টুট
+ নির্ধারিত টুটগুলি
সম্পাদন
- নির্ধারিত টুটগুলি
+ নির্ধারিত টুটগুলি
সম্পাদন
পছন্দ %d
একাধিক পছন্দ
@@ -373,7 +377,7 @@
গোপন ডোমেইনগুলি
এই একাউন্ট তা একটি অন্য সার্ভারের। রিপোর্ট এর সঙ্গে একটি বেনামি কপি ওখানে পাঠাতে চান\?
রিপোর্ট আপনার সার্ভার মডারেটরে পাঠানো হবে। আপনি নীচের এই অ্যাকাউন্টটি কেন প্রতিবেদন করছেন তা ব্যাখ্যা করতে পারেন:
- স্টেটাসগুলি আনতে ব্যর্থ
+ স্টেটাসগুলি আনতে ব্যর্থ
রিপোর্ট করতে ব্যর্থ হয়েছে
\'%s এ ফরওয়ার্ড করুন\'
অতিরিক্ত মন্তব্যগুলি
@@ -386,8 +390,7 @@
ভোট
বন্ধ
\'%s এ শেষ হবে\'
-
- %1$s • %2$s
+ %1$s • %2$s
ছবি %s এর জন্য ক্রিয়া
আপনি কি আপনার সমস্ত বিজ্ঞপ্তি স্থায়ীভাবে মুছে ফেলতে চান\?
রচনা
@@ -400,9 +403,9 @@
প্রিয়গুলো
অনুগামিবৃন্দ
অনুসরণ
- পিন করা
- উত্তরের সাথে
- পোস্টগুলি
+ পিন করা
+ উত্তরের সাথে
+ পোস্টগুলি
টুট
ট্যাবগুলি
সরাসরি বার্তা
@@ -447,12 +450,12 @@
সদস্যতা আছে এমন একজন টুট দিয়েছে
কোনো ঘোষণা নেই।
যদিও তোমার অ্যাকাউন্ট রুদ্ধকৃত না, %1$s রা ভেবেছে এই অ্যাকাউন্টগুলোর অনুসরণ অনুরোধ তোমার পরীক্ষা করা উচিত।
- যে টুটের উত্তর খসড়া করেছিলে তা মুছে ফেলা হয়েছে
+ যে টুটের উত্তর খসড়া করেছিলে তা মুছে ফেলা হয়েছে
- %1$d টার বেশি সংযুক্তি পাঠানো যাবে না।
- %1$d টার বেশি সংযুক্তি পাঠানো যাবে না।
- টুট পাঠাতে ব্যর্থ!
+ টুট পাঠাতে ব্যর্থ!
উত্তরের তথ্য আনতে ব্যর্থ
সংরক্ষিত!
অবতারে পরিসংখ্যান লুকাও
@@ -505,8 +508,8 @@
- %s বুস্ট
%1$s স্থানান্তরিত হয়েছে এখানে:
- সংযুক্তি
- শব্দ
+ সংযুক্তি
+ শব্দ
- %dটি নতুন ক্রিয়া
- %dটি নতুন ক্রিয়া
diff --git a/app/src/main/res/values-bn-rIN/strings.xml b/app/src/main/res/values-bn-rIN/strings.xml
index 7c96ad083..de3d8d818 100644
--- a/app/src/main/res/values-bn-rIN/strings.xml
+++ b/app/src/main/res/values-bn-rIN/strings.xml
@@ -26,9 +26,9 @@
সরাসরি বার্তা
ট্যাবগুলি
টুট
- পোস্টগুলি
- উত্তরের সাথে
- পিন করা
+ পোস্টগুলি
+ উত্তরের সাথে
+ পিন করা
অনুসরণ
অনুগামিবৃন্দ
প্রিয়গুলো
@@ -38,15 +38,15 @@
আপনার প্রোফাইল সম্পাদনা করুন
খসড়াগুলো
লাইসেন্সগুলি
- \@%s
- %s সমর্থন দিয়েছে
- সংবেদনশীল কন্টেন্ট
- মিডিয়া লুকানো
- দেখার জন্য ক্লিক করুন
- আরও দেখাও
- প্রদর্শন কম
- বিস্তৃত
- বন্ধ
+ \@%s
+ %s সমর্থন দিয়েছে
+ সংবেদনশীল কন্টেন্ট
+ মিডিয়া লুকানো
+ দেখার জন্য ক্লিক করুন
+ আরও দেখাও
+ প্রদর্শন কম
+ বিস্তৃত
+ বন্ধ
এখানে কিছুই নেই।
এখানে কিছু নেই. রিফ্রেশ করতে নিচে টানুন!
%s সমর্থন দিয়েছে
@@ -123,14 +123,14 @@
হিসাবে ভাগ করুন …
মিডিয়া ডাউনলোড করুন
মিডিয়া ডাউনলোড করা হচ্ছে
- টুট URL ভাগ করুন …
- টুট ভাগ করুন …
+ টুট URL ভাগ করুন …
+ টুট ভাগ করুন …
মিডিয়া শেয়ার করুন …
পাঠানো হয়েছে!
ব্যবহারকারী অবরোধ মুক্ত
ব্যবহারকারী সশব্দ
- পাঠানো হয়েছে!
- উত্তর সফলভাবে পাঠানো হয়েছে।
+ পাঠানো হয়েছে!
+ উত্তর সফলভাবে পাঠানো হয়েছে।
কোন ইনস্ট্যান্স\?
কি হচ্ছে\?
সতর্কবার্তা
@@ -155,8 +155,8 @@
ডাউনলোড
অনুসরণ অনুরোধ প্রত্যাহার\?
এই অ্যাকাউন্টটি অনুসরণ করবেন না\?
- এই টুট টি মুছে ফেলবেন\?
- এই টুট টি মুছে ফেলবেন এবং পুনরায় ড্রাফট করবেন\?
+ এই টুট টি মুছে ফেলবেন\?
+ এই টুট টি মুছে ফেলবেন এবং পুনরায় ড্রাফট করবেন\?
সর্বজনীন: পাবলিক টাইমলাইনে পোস্ট কর
তালিকাভুক্ত নয়: সর্বজনীন সময়সূচীগুলিতে দেখাবেন না
শুধুমাত্র অনুসরণকারীদের: শুধুমাত্র অনুসরণকারীদের পোস্ট করুন
@@ -188,8 +188,8 @@
ভাষা
বট জন্য সূচক প্রদর্শন করুন
GIF অবতার অ্যানিমেশন করুন
- টাইমলাইন ফিল্টারিং
- ট্যাবগুলি
+ টাইমলাইন ফিল্টারিং
+ ট্যাবগুলি
সমর্থন দেখান
উত্তর প্রদর্শন করুন
মিডিয়া পূর্বরূপ ডাউনলোড করুন
@@ -205,12 +205,12 @@
সর্বজনীন
অতালিকাভুক্ত
শুধুমাত্র অনুগামিবৃন্দ
- স্থিতি টেক্সট আকার
- কনিষ্ঠ
- ছোট
- মাঝারি
- বড়
- বৃহত্তম
+ স্থিতি টেক্সট আকার
+ কনিষ্ঠ
+ ছোট
+ মাঝারি
+ বড়
+ বৃহত্তম
নতুন উল্লেখসমূহ
নতুন উল্লেখ সম্পর্কে বিজ্ঞপ্তি
নতুন অনুসরণকারী
@@ -243,10 +243,10 @@
বাগ রিপোর্ট এবং বৈশিষ্ট্য অনুরোধ:
\nhttps://github.com/accelforce/Yuito/issues
টাস্কির প্রোফাইল
- টুট এর কন্টেন্ট ভাগ করুন
- টুট এর সাথে লিংক ভাগ করুন
- চিত্রগুলি
- ভিডিও
+ টুট এর কন্টেন্ট ভাগ করুন
+ টুট এর সাথে লিংক ভাগ করুন
+ চিত্রগুলি
+ ভিডিও
অনুরোধ অনুসরণ করুন
%dy এ
@@ -297,11 +297,11 @@
অ্যাকাউন্ট লক করুন
অনুসারী অনুমোদন করার জন্য আপনাকে প্রয়োজন
ড্রাফট সংরক্ষণ\?
- টুট পাঠানো হচ্ছে …
- টুট পাঠাতে গিয়ে একটি ত্রুটি ঘটেছে
- টুট পাঠানো হচ্ছে
- পাঠানো বাতিল
- টুট এর একটি কপি আপনার ড্রাফটে সংরক্ষণ করা হয়েছে
+ টুট পাঠানো হচ্ছে …
+ টুট পাঠাতে গিয়ে একটি ত্রুটি ঘটেছে
+ টুট পাঠানো হচ্ছে
+ পাঠানো বাতিল
+ টুট এর একটি কপি আপনার ড্রাফটে সংরক্ষণ করা হয়েছে
রচনা
আপনার ইনস্ট্যান্স %s এর কোনো কাস্টম ইমোজিস নেই
ক্লিপবোর্ডে অনুলিপি করা হয়েছে
@@ -309,8 +309,8 @@
সিস্টেমের ডিফল্ট
আপনাকে প্রথমে এই ইমোজি সেটগুলি ডাউনলোড করতে হবে
অনুসন্ধান করা হচ্ছে …
- সমস্ত স্টেটাস প্রসারিত/সংকুচিত করুন
- টুট খুলুন
+ সমস্ত স্টেটাস প্রসারিত/সংকুচিত করুন
+ টুট খুলুন
অ্যাপ্লিকেশন পুনরায় আরম্ভ করা প্রয়োজন
এই পরিবর্তনগুলি প্রয়োগ করার জন্য আপনাকে টাস্কি পুনরায় চালু করতে হবে
পরবর্তীতে
@@ -352,11 +352,11 @@
- সর্বাধিক %1$d টি ট্যাব পৌঁছেছে
- মিডিয়া: %s
- সতর্কবার্তা: %s
- বর্ণনা নাই
- আবার ব্লগ
- পছন্দ
+ মিডিয়া: %s
+ সতর্কবার্তা: %s
+ বর্ণনা নাই
+ আবার ব্লগ
+ পছন্দ
সর্বজনীন
অতালিকাভুক্ত
অনুগামিবৃন্দ
@@ -384,7 +384,7 @@
অতিরিক্ত মন্তব্যগুলি
%s এ ফরওয়ার্ড করুন
রিপোর্ট করতে ব্যর্থ হয়েছে
- স্টেটাসগুলি আনতে ব্যর্থ
+ স্টেটাসগুলি আনতে ব্যর্থ
রিপোর্ট আপনার সার্ভার মডারেটরে পাঠানো হবে। আপনি নীচের এই অ্যাকাউন্টটি কেন প্রতিবেদন করছেন তা ব্যাখ্যা করতে পারেন:
এই একাউন্ট তা একটি অন্য সার্ভারের। রিপোর্ট এর সঙ্গে একটি বেনামি কপি ওখানে পাঠাতে চান\?
গোপন ডোমেইনগুলি
@@ -412,10 +412,10 @@
একাধিক পছন্দ
পছন্দ %d
সম্পাদন
- নির্ধারিত টুটগুলি
+ নির্ধারিত টুটগুলি
সম্পাদন
- নির্ধারিত টুটগুলি
- নির্ধারিত টুট
+ নির্ধারিত টুটগুলি
+ নির্ধারিত টুট
রিসেট
টাস্কি দ্বারা চালিত
%s পোস্ট অনুসন্ধানে ত্রুটি
@@ -465,14 +465,14 @@
তালিকা নির্বাচন করো
হ্যাশট্যাগ
হ্যাশট্যাগ যোগ করো
- বুকমার্ককৃত
+ বুকমার্ককৃত
অনুসরণ রিকোয়েস্টের বিজ্ঞপ্তি
সবচেয়ে শেষ
সর্বপ্রথম
মূল ন্যাভিগেশন জায়গা
ট্যাবের মাঝে সোয়াইপ সংকেত চালু করো
টাইমলাইনে লিঙ্ক প্রিভিউ দেখাও
- তোমার কোনো সময়সূচীত স্ট্যাটাস নেই।
+ তোমার কোনো সময়সূচীত স্ট্যাটাস নেই।
তোমার কোনো খসড়া নেই।
মাস্টোডনের সর্বনিম্ন ৫ মিনিটের সময়সূচীর বিরতি আছে।
শীর্ষস্থানীয় সরঞ্জামদণ্ডের শিরোনামটি লুকান
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 06b52799d..9b652fa1c 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -21,7 +21,7 @@
Local
Federació
Toot
- Posts
+ Posts
Seguits
Seguidors
Preferits
@@ -30,12 +30,12 @@
Peticions de seguiment
Edita el perfil
Esborranys
- \@%s
- %s tootejat
- Contingut sensible
- Fes clic per a visualitzar-lo
- Mostra\'n més
- Mostra\'n menys
+ \@%s
+ %s tootejat
+ Contingut sensible
+ Fes clic per a visualitzar-lo
+ Mostra\'n més
+ Mostra\'n menys
No hi res aquí. Llisca avall per a actualitzar!
%s ha impulsat el teu toot
%s ha marcat com a preferit el teu toot
@@ -83,8 +83,8 @@
Esborranys
S\'està baixant %1$s
Copia l\'enllaç
- Comparteix l\'URL del toot a…
- Comparteix el toot a…
+ Comparteix l\'URL del toot a…
+ Comparteix el toot a…
Enviat!
Usuari desblocat
Usuari sense silenciar
@@ -130,8 +130,8 @@
Navegador
Pestanyes personalitzades del Chrome
Amaga el botó de redacció en desplaçament
- Filtre de la cronologia
- Pestanyes
+ Filtre de la cronologia
+ Pestanyes
Mostra els retoots
Mostra les respostes
Mostra les previsualitzacions
@@ -140,7 +140,7 @@
Pública
Sense llistar
Només seguidors
- Mida de text de l\'estat
+ Mida de text de l\'estat
Mencions noves
Notificacions sobre mencions noves
Seguidors nous
@@ -172,10 +172,10 @@
https://github.com/accelforce/Yuito/issues
Perfil del Yuito
- Comparteix el contingut del toot
- Comparteix l\'enllaç al toot
- Imatges
- Vídeo
+ Comparteix el contingut del toot
+ Comparteix l\'enllaç al toot
+ Imatges
+ Vídeo
en %d anys
en %dd
@@ -196,7 +196,7 @@
S\'ha produït un error en enviar el tut.
Pestanyes
Llicències
- Amplia
+ Amplia
Resposta ràpida
Elimineu els preferits
Preferències del compte
@@ -206,8 +206,8 @@
Elimina l\'impuls
S\'ha produït un error de connexió! Comproveu la connexió i torneu-ho a provar!
Els fitxers de vídeo han de ser de mida menor de 40 MB.
- Multimèdia amagada
- Amaga
+ Multimèdia amagada
+ Amaga
Estàs segur de tancar la sessió de %1$s\?
Amaga els retoots
Mostra els impulsos
@@ -226,18 +226,18 @@
Comparteix com a…
Baixa el fitxer
Compartir la imatge a …
- Enviat!
+ Enviat!
S\'ha enviat la petició de seguiment
- Amb respostes
+ Amb respostes
Teclat d\'emojis
Obrir el media #%d
Obrir com %s
S\'està Descarregant media
- Resposta enviada correctament.
+ Resposta enviada correctament.
Resposta …
Revocar la petició de seguiment\?
- Vols eliminar aquest toot\?
- Esborrar i reescriure aquest toot\?
+ Vols eliminar aquest toot\?
+ Esborrar i reescriure aquest toot\?
Finalització de les enquetes
Tema
Cronologia
@@ -255,11 +255,11 @@
Port del proxy HTTP
Marcar sempre els medias com a sensibles
Error al sincronitzar els paràmetres
- Petit
- Petit
- Mig
- Gran
- Més grand
+ Petit
+ Petit
+ Mig
+ Gran
+ Més grand
Enquestes
Converses
Afegir un filtre
@@ -297,11 +297,11 @@
Protegir el compte
S\'haurà d\'admetre els seguidors manualment
Guardar l\'esborrany\?
- Enviant toot…
- Error enviant el toot
- Enviant toots
- Envio anul·lat
- Una copia del toot s\'ha guardat a esborranys
+ Enviant toot…
+ Error enviant el toot
+ Enviant toots
+ Envio anul·lat
+ Una copia del toot s\'ha guardat a esborranys
Escriure
La teva instància %s no te emojis personalitzats
Copia al porta papers
@@ -309,8 +309,8 @@
Sistema per defecte
Hauràs de descarregar el joc d\'emojis
Cercant…
- Expandir/ocultar tots els estats
- Obrir toot
+ Expandir/ocultar tots els estats
+ Obrir toot
Cal reiniciar l\'aplicació
Has de reiniciar l\'aplicació per tal d\'aplicar aquests canvis
Més tard
@@ -349,9 +349,9 @@
- màxim de %1$d pestanyes aconseguides
- Mèdia : %s
- Sense descripció
- Favorits
+ Mèdia : %s
+ Sense descripció
+ Favorits
Públic
Sense llistar
Seguidors
@@ -374,11 +374,11 @@
tancat
L\'enquesta on has votat està tancada
La enquesta que heu creat ha finalitzat
- Advertència: %s
- Toot fixat
+ Advertència: %s
+ Toot fixat
Toot no fixat
Fixar
- Respost
+ Respost
Accions per a la imatge %s
Activar l\'animació dels GIF
Dominis ocults
@@ -396,7 +396,7 @@
Comentaris addicionals
Reenviar a %s
Report erroni
- Error obtenint els estats
+ Error obtenint els estats
L\'informe s\'enviarà al moderador del teu servidor. Pots afegir una explicació del motiu d\'aquest informe del compte a sota:
Comptes
Mostrar el filtre de les notificacions
@@ -419,19 +419,19 @@
Múltiples tries
Tria %d
Preferits
- Toots programats
+ Toots programats
Preferit
Edita
Preferits
- Toots programats
- Programar el toot
+ Toots programats
+ Programar el toot
Reiniciar
Desenvolupat per Tusky
- S\'ha afegit a les adreces d\'interès
+ S\'ha afegit a les adreces d\'interès
Seleccionar la llista
Llista
S\'ha produït un error en cercar la publicació %s
- No tens cap estat planificat.
+ No tens cap estat planificat.
Els fitxers d\'àudio han de ser de mida menor de 40MB.
No teniu cap esborrany.
L\'interval mínim de planificació a Mastodon és de 5 minuts.
@@ -485,18 +485,18 @@
- falta %d dia
- falten %d dies
- Adjuncions
- Àudio
+ Adjuncions
+ Àudio
Notificacions quan algú a qui esteu subscrit publica un tut nou
Tuts nous
emojis personalitzats animats
algú a qui estic subscrit acaba de publicar un tut nou
%s acaba de fer una publicació
Avisos
- S\'ha esborrat el tut del qual en vau fer un esborrany de resposta
+ S\'ha esborrat el tut del qual en vau fer un esborrany de resposta
S\'ha eliminat l\'esborrany
No s\'ha pogut carregar la informació de la resposta
- No s\'ha pogut enviar aquest tut!
+ No s\'ha pogut enviar aquest tut!
Segur que voleu esborrar la llista %s\?
- No podeu pujar més de %1$d adjunts multimèdia.
@@ -504,4 +504,4 @@
Amaga les estadístiques quantitatives dels perfils
Amaga les estadístiques quantitatives de les publicacions
Limita les notificacions de la cronologia
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-ckb/strings.xml b/app/src/main/res/values-ckb/strings.xml
index c5702f28c..8dd867582 100644
--- a/app/src/main/res/values-ckb/strings.xml
+++ b/app/src/main/res/values-ckb/strings.xml
@@ -2,15 +2,15 @@
چی خەریکه ڕوودەدات؟
کام نموونە؟
- وەڵام دانەوە کە بە سەرکەوتوویی نێردرا.
- ناردن!
+ وەڵام دانەوە کە بە سەرکەوتوویی نێردرا.
+ ناردن!
%s نەشاراوە
بەکارهێنەر نەگۆڕاو
بەکارهێنەر بەربەست نەکراوە
ناردن!
هاوبەشکردنی میدیا بۆ…
- هاوبەشی کردن بە توت بۆ…
- هاوبەشکردنی توتی URL بۆ…
+ هاوبەشی کردن بە توت بۆ…
+ هاوبەشکردنی توتی URL بۆ…
داگرتنی میدیا
داگرتنی میدیا
هاوبەش کردن وەک …
@@ -29,11 +29,11 @@
بەستەرەکان
زیادکردنی سەرخشت
ڕیسێت کردن
- خشتەی توت
+ خشتەی توت
تەختەکلیلی ئیمۆجی
ئاگاداری ناوەڕۆک
بینینی توت
- توتی خشتەکراو
+ توتی خشتەکراو
ڕەشنووسەکان
گەڕان
ڕەتکردنەوە
@@ -103,18 +103,18 @@
%s توتەکەتی بەرزکردەوە
هیچ شتێک لێرە نیە ڕاکە خوارەوە بۆ نوێکردنەوە!
هیچ شتێک لێرە نیە.
- نوشتانەوە
- فراوانکردن
- کەمتر نیشان بدە
- زیاتر پیشان بدە
- کرتە بکە بۆ بینین
- میدیا شاراوە
- ناوەڕۆکی هەستیار
- %s بەرزکرا
- \@%s
+ نوشتانەوە
+ فراوانکردن
+ کەمتر نیشان بدە
+ زیاتر پیشان بدە
+ کرتە بکە بۆ بینین
+ میدیا شاراوە
+ ناوەڕۆکی هەستیار
+ %s بەرزکرا
+ \@%s
مۆڵەتەکان
ڕاگه یه نراوەکان
- توتی خشتەکراو
+ توتی خشتەکراو
دەستکاری پرۆفایلەکەت بکە
بەدواداچونی داواکاریەکان بکە
دۆمەینە شاراوەکان
@@ -124,9 +124,9 @@
دڵخوازەکان
شوێنکەوتوان
بەدوادا
- چەسپا
- لەگەڵ وەڵامەکان
- بابەتەکان
+ چەسپا
+ لەگەڵ وەڵامەکان
+ بابەتەکان
توت
سەرخشتەکان
نامە ڕاستەوخۆکان
@@ -163,8 +163,8 @@
داگرتنی پێشبینینی میدیا
وەڵامدانەوەکان پیشان بدە
پیشاندانی بەهێزکردنەکان
- سەرخشتەکان
- فلتەرکردنی تایملاین
+ سەرخشتەکان
+ فلتەرکردنی تایملاین
نمرەی لاری ڕەنگاوڕەنگ نیشان بدە بۆ میدیای شاراوە
وێنۆجکەی ئەنیمەی GIF
نیشاندەر نیشاندەر بۆ بۆتەکان نیشان بدە
@@ -204,8 +204,8 @@
بلۆککردنی @%s؟
شاردنەوەی هەموو دۆمەینەکە
ئایا دڵنیایت لەوەی دەتەوێت هەموو %s بلۆک بکەیت؟ تۆ ناوەڕۆکێک نابینیت لە دۆمەینەکە لە هیچ هێڵی کاتی گشتی یان لە ئاگانامەکانت. شوێنکەوتوانی تۆ لەو دۆمەینەوە لادەبرێن.
- ئەم دووانە بسڕەوە و دووبارە ڕەشنووس یان دەکەیتەوە؟
- ئەم توتە بسڕەوە؟
+ ئەم دووانە بسڕەوە و دووبارە ڕەشنووس یان دەکەیتەوە؟
+ ئەم توتە بسڕەوە؟
شوێن نەکەوتنی ئەم هەژمارە؟
داواکاری بەدوادا چوەکان هەڵوەشانەوە؟
داگرتن
@@ -256,7 +256,7 @@
نیشاندانی پێشاندانی بەستەر لە هێڵی کات
ماستۆدۆن کەمترین ماوەی خشتەی هەیە لە ٥ خولەک.
هیچ ڕاگه یه نراوێک له بەرده رنه کەون.
- هیچ بارێکی خشتەکراوت نیە.
+ هیچ بارێکی خشتەکراوت نیە.
هیچ ڕەشنووسێکت نییە.
هەڵە لە گەڕان بەدوای بابەت %s
دەستکاریکردن
@@ -271,7 +271,7 @@
ئەژمێرەکان
هەژمارەلە ڕاژەیەکی دیکەیە ترە. کۆپیەکی بێ سەروبەر بنێرە بۆ ڕاپۆرتەکە لەوێ؟
ڕاپۆرتەکە دەنێردرێت بۆ بەڕێوەبەری ڕاژەکەت. دەتوانیت ڕوونکردنەوەیەک پێشکەش بکەیت کە بۆچی ئەم ئەژمێرە لە خوارەوە ڕاپۆرت دەکەیت:
- سەرکەوتوو نەبوو لە هێنانی بارەکان
+ سەرکەوتوو نەبوو لە هێنانی بارەکان
ڕاپۆرتکردن سەرکەوتوو نەبوو
ناردنەوە بۆ %s
سەرنجەکانی زیاتر
@@ -323,12 +323,12 @@
شوێنکەوتوانی
لە لیست نەکراو
گشتی
- نیشانکراوە
- پەسەندکراو
- دووبارە بڵاگ کرا
- هیچ وەسفێک
- ئاگاداری ناوەڕۆک: %s
- میدیا: %s
+ نیشانکراوە
+ پەسەندکراو
+ دووبارە بڵاگ کرا
+ هیچ وەسفێک
+ ئاگاداری ناوەڕۆک: %s
+ میدیا: %s
- بەرزترین رێژەی خشتەبەندەکانی %1$d گەیشت
@@ -369,8 +369,8 @@
دواتر
تۆ پێویستە توسکی دەستپێبکەیتەوە بۆ ئەوەی ئەم گۆڕانکاریانە جێبەجێ بکەیت
دەسپێکردنەوەی کاربەرنامە پێویستە
- کردنەوە توت
- فراوانکردن/نوشتانەوەی هەموو بارەکان
+ کردنەوە توت
+ فراوانکردن/نوشتانەوەی هەموو بارەکان
ئەنجامدانی گەڕان…
تۆ پێویستە سەرەتا ئەم سێتە ئیمۆجییانە دابگریت
سیستەمی بنەڕەت
@@ -378,11 +378,11 @@
ڕوونووسکراوە بۆ کلیپ بۆرد
نموونەکەت %s هیچ ئیمۆجییەکی ئاسایی نییە
دروستکردن
- کۆپیەکی دەستنووسەکە خەزن کراوە بۆ ڕەشنووسەکانت
- ناردنی هەڵوەشاوە
- ناردنی توتس
- هەڵە لە ناردنی توت
- (توت) دەنێرم…
+ کۆپیەکی دەستنووسەکە خەزن کراوە بۆ ڕەشنووسەکانت
+ ناردنی هەڵوەشاوە
+ ناردنی توتس
+ هەڵە لە ناردنی توت
+ (توت) دەنێرم…
ڕەشنووس پاشەکەوت بکەیت؟
داوات لێدەکات کە بە دەستی شوێنکەوتوانی پەسەند بکە
داخستنی ئەژمێر
@@ -434,10 +434,10 @@
لە %dd
لە %dy
بەدواداچوونەوەی داواکراو
- ڤیدیۆ
- وێنەکان
- هاوبەشکردنی لینک بۆ توت
- هاوبەشکردنی ناوەڕۆکی دووت
+ ڤیدیۆ
+ وێنەکان
+ هاوبەشکردنی لینک بۆ توت
+ هاوبەشکردنی ناوەڕۆکی دووت
پرۆفایلی تاسکی
ڕاپۆرتەکانی هەڵەکان و داواکاریەکانی تایبەتمەندی:
\nhttps://github.com/tuskyapp/Tusky/issues
@@ -469,12 +469,12 @@
شوێنکەوتوانی نوێ
ئاگانامەکان دەربارەی ئاماژە نوێیەکان
ئاماژە نوێیەکان
- گەورەترین
- گەورە
- مامناوەندی
- بچووک
- بچووکترین
- قەبارەی دەقی بار
+ گەورەترین
+ گەورە
+ مامناوەندی
+ بچووک
+ بچووکترین
+ قەبارەی دەقی بار
شوێنکەوتوانی تەنها
لە لیست نەکراو
گشتی
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index d51b5cd8c..34d376e65 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -26,9 +26,9 @@
Přímé zprávy
Panely
Toot
- Tooty
- S odpověďmi
- Připnuté
+ Tooty
+ S odpověďmi
+ Připnuté
Sledovaní
Sledující
Oblíbené
@@ -38,15 +38,15 @@
Upravit váš profil
Koncepty
Licence
- \@%s
- %s boostnul/a
- Citlivý obsah
- Média skryta
- Klikněte pro zobrazení
- Zobrazit více
- Zobrazit méně
- Rozbalit
- Zabalit
+ \@%s
+ %s boostnul/a
+ Citlivý obsah
+ Média skryta
+ Klikněte pro zobrazení
+ Zobrazit více
+ Zobrazit méně
+ Rozbalit
+ Zabalit
Tady nic není.
Tady nic není. Obnovte přetažnením dolů!
%s boostnul/a váš toot
@@ -122,14 +122,14 @@
Sdílet jako…
Stáhnout média
Stahuji média
- Sdílet URL tootu na…
- Sdílet toot na…
+ Sdílet URL tootu na…
+ Sdílet toot na…
Sdílet média na…
Odesláno!
Uživatel odblokován
Uživatel odkryt
- Odesláno!
- Odpověď byla úspěšně odeslána.
+ Odesláno!
+ Odpověď byla úspěšně odeslána.
Který server?
Co se právě děje?
Varování o obsahu
@@ -156,7 +156,7 @@
Stáhnout
Zrušit požadavek o sledování?
Přestat sledovat tento účet?
- Smazat tento toot?
+ Smazat tento toot?
Veřejný: Poslat na veřejné časové osy
Neuvedený: Neposlat na veřejné časové osy
Pouze pro sledující: Poslat pouze sledujícím
@@ -185,8 +185,8 @@
Používat Vlastní karty Chrome
Skrýt tlačítko pro psaní při rolování
Jazyk
- Filtrování časových os
- Panely
+ Filtrování časových os
+ Panely
Zobrazi boosty
Zobrazit odpovědi
Stahovat náhledy médií
@@ -202,12 +202,12 @@
Veřejné
Neuvedené
Pouze pro sledující
- Velikost textu příspěvků
- Nejmenší
- Malý
- Střední
- Velký
- Největší
+ Velikost textu příspěvků
+ Nejmenší
+ Malý
+ Střední
+ Velký
+ Největší
Nové zmínky
Oznámení o nových zmínkách
Noví sledující
@@ -242,10 +242,10 @@
https://github.com/accelforce/Yuito/issues
Profil aplikace Yuito
- Sdílet obsah tootu
- Sdílet odkaz k tootu
- Obrázky
- Video
+ Sdílet obsah tootu
+ Sdílet odkaz k tootu
+ Obrázky
+ Video
Vyžádáno sledování
za %d let
@@ -295,11 +295,11 @@
Uzamknout účet
Vyžaduje, abyste ručně schvaloval/a sledující
Uložit koncept?
- Odesílám toot…
- Chyba při odesílání tootu
- Odesílám tooty
- Odesílání bylo zrušeno
- Kopie vašeho tootu byla uložena do vašich konceptů
+ Odesílám toot…
+ Chyba při odesílání tootu
+ Odesílám tooty
+ Odesílání bylo zrušeno
+ Kopie vašeho tootu byla uložena do vašich konceptů
Napsat
Vaše instance %s nemá žádná vlastní emoji
Zkopírováno do schránky
@@ -307,8 +307,8 @@
Výchozí nastavení systému
Musíte si nejprve stáhnout tyto sady emoji
Provádím prohledávání…
- Rozbalit/zabalit všechny příspěvky
- Otevřít toot
+ Rozbalit/zabalit všechny příspěvky
+ Otevřít toot
Je vyžadován restart aplikace
Pro použití těchto změn musíte restartovat aplikaci Yuito
Později
@@ -351,15 +351,15 @@
- bylo dosaženo maxima %1$d panelů
- Média %s
+ Média %s
- Varování o obsahu: %s
+ Varování o obsahu: %s
- Žádný popis
+ Žádný popis
- Boostnutý
+ Boostnutý
- Oblíbený
+ Oblíbený
Veřejný
Neuvedený
@@ -376,7 +376,7 @@
Zobrazovat indikátor pro roboty
Jste si jistý/á, že chcete trvale vymazat všechna vaše oznámení\?
Smazat a přepsat
- Smazat a přepsat tento toot\?
+ Smazat a přepsat tento toot\?
%1$s • %2$s
- %s hlas
@@ -423,7 +423,7 @@
Dodatečné komentáře
Přeposlat na %s
Nahlášení selhalo
- Stahování tootů neuspělo
+ Stahování tootů neuspělo
Nahlášení bude zasláno moderátorovi vašeho serveru. Níže můžete uvést, proč tento účet nahlašujete:
Tento účet je z jiného serveru. Chcete na něj také poslat anonymizovanou kopii\?
Zobrazit filtr oznámení
@@ -439,11 +439,11 @@
Lze zvolit více možností
Možnost %d
Upravit
- Plánované tooty
+ Plánované tooty
Upravit
Přidat anketu
- Plánované tooty
- Naplánovat toot
+ Plánované tooty
+ Naplánovat toot
Obnovit
Vždy rozbalovat tooty označené varováními o obsahu
Celé slovo
@@ -464,12 +464,12 @@
Audio soubory musí být menší než 40MB.
Ukazovat náhledy k odkazům
Mastodon neumožňuje pracovat s intervalem menším než 5 minut.
- Zatím zde nemáte žádné naplánované statusy.
+ Zatím zde nemáte žádné naplánované statusy.
Zatím zde nejsou žádné koncepty.
Možnost přetahování prstem pro přechod mezi kartami
Seznam
Přidat hashtag
- Uloženo do Záložek
+ Uloženo do Záložek
Vybrat seznam
Umístění hlavní navigační lišty
Hashtagy
@@ -485,4 +485,4 @@
Zobrazit dialogové okno s potvrzením při boostování
%s právě vydal
Oznámení
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml
index b016d709d..4e4ecb3c9 100644
--- a/app/src/main/res/values-cy/strings.xml
+++ b/app/src/main/res/values-cy/strings.xml
@@ -23,8 +23,8 @@
Lleol
Ffedereiddwyd
Tŵtio
- Negeseuon
- Gydag ymatebion
+ Negeseuon
+ Gydag ymatebion
Dilyniadau
Dilynwyr
Ffefrynnau
@@ -34,14 +34,14 @@
Golygu\'ch Proffil
Drafftiau
Trwyddedau
- %s wedi\'u hybu
- Cynnwys sensitif
- Cyfryngau cudd
- Cliciwch i weld
- Dangos Mwy
- Dangos Llai
- Chwyddo
- Lleihau
+ %s wedi\'u hybu
+ Cynnwys sensitif
+ Cyfryngau cudd
+ Cliciwch i weld
+ Dangos Mwy
+ Dangos Llai
+ Chwyddo
+ Lleihau
Dim byd yma. Tynnwch lawr i adnewyddu!
%s wedi hybu\'ch tŵt
%s wedi nodi\'ch tŵt yn ffefryn
@@ -98,14 +98,14 @@
Bysellfwrdd emoji
Lawrlwytho %1$s
Copïo\'r ddolen
- Rhannu URL Tŵt i…
- Rhannu Tŵt i…
+ Rhannu URL Tŵt i…
+ Rhannu Tŵt i…
Rhannu cyfryngau i…
Anfonwyd!
Dad-flociwyd y defnyddiwr
Dad-fudwyd y defnyddiwr
- Anfonwyd!
- Anfonwyd yr ateb.
+ Anfonwyd!
+ Anfonwyd yr ateb.
Pa achos?
Beth sy\'n digwydd?
Rhybudd cynnwys
@@ -132,7 +132,7 @@
Lawrlwytho
Tynnu\'r cais i ddilyn yn ôl?
Dad-ddilyn y cyfrif hwn?
- Dileu\'r tŵt hwn?
+ Dileu\'r tŵt hwn?
Cyhoeddus: Postio i ffrydiau cyhoeddus
Heb restru: Peidio â dangos ar ffrydiau cyhoeddus
Dilynwyr yn Unig: Postio i ddilynwyr yn unig
@@ -157,8 +157,8 @@
Porwr
Defnyddio Tabiau Personol Chrome
Cuddio\'r botwm creu wrth sgrolio
- Hidlo ffrwd
- Tabiau
+ Hidlo ffrwd
+ Tabiau
Dangos hybiadau
Dangos atebion
Dangos rhagolwg o gyfryngau
@@ -172,12 +172,12 @@
Cyhoeddus
Heb ei restru
Dilynwyr yn unig
- Maint testun statws
- Lleiaf
- Bach
- Canolig
- Mawr
- Mwyaf
+ Maint testun statws
+ Lleiaf
+ Bach
+ Canolig
+ Mawr
+ Mwyaf
Yn sôn amdanoch o\'r newydd
Hysbysiadau sôn amdanoch o\'r newydd
Dilynwyr Newydd
@@ -211,10 +211,10 @@
https://github.com/accelforce/Yuito/issues
Proffil Yuito
- Rhannu cynnwys tŵt
- Rhannu dolen i\'r tŵt
- Delweddau
- Fideo
+ Rhannu cynnwys tŵt
+ Rhannu dolen i\'r tŵt
+ Delweddau
+ Fideo
Gofyn i ddilyn
%dy
@@ -244,11 +244,11 @@
Cloi cyfrif
Angen cymeradwyo dilynwyr eich hun
Cadw drafft?
- Yn anfon Tŵt…
- Gwall wrth anfon Tŵt
- Yn anfon Tŵtiau
- Canslo anfon
- Cadwyd copi o\'r tŵt i\'ch drafftiau
+ Yn anfon Tŵt…
+ Gwall wrth anfon Tŵt
+ Yn anfon Tŵtiau
+ Canslo anfon
+ Cadwyd copi o\'r tŵt i\'ch drafftiau
Creu
Nid oes gan eich achos %s emoji bersonol
Copïwyd i\'r clipfwrdd
@@ -256,8 +256,8 @@
Rhagosodiad system
Bydd angen i chi lawrlwytho\'r setiau emoji hyn yn gyntaf
Wrthi\'n chwilio…
- Chwyddo/lleihau pob statws
- Agor tŵt
+ Chwyddo/lleihau pob statws
+ Agor tŵt
Angen ailddechrau\'r app
Bydd angen ailddechrau Yuito i roi\'r newidiadau ar waith
Nes ymlaen
@@ -275,11 +275,11 @@
ychwanegu data
Cynnwys
Defnyddio amser absoliwt
- \@%s
+ \@%s
Digwyddodd gwall rhwydwaith! Gwiriwch eich cysylltiad a cheisiwch eto!
Negeseuon Uniongyrchol
Tabiau
- Wedi\'i binio
+ Wedi\'i binio
Parthau cudd
Dim byd yma.
Dileu hwb
@@ -302,4 +302,4 @@
%1$s a %2$s
Dileu
Cyhoeddus
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index a96801c16..357b86c71 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -26,9 +26,9 @@
Direktnachrichten
Tabs
Beitrag
- Beiträge
- mit Antworten
- Angeheftet
+ Beiträge
+ mit Antworten
+ Angeheftet
Folgt
Folgende
Favoriten
@@ -38,15 +38,15 @@
Dein Profil bearbeiten
Entwürfe
Lizenzen
- \@%s
- %s teilte
- Heikle Inhalte
- Medien versteckt
- Zum Anzeigen tippen
- Zeige mehr
- Zeige weniger
- Mehr
- Weniger
+ \@%s
+ %s teilte
+ Heikle Inhalte
+ Medien versteckt
+ Zum Anzeigen tippen
+ Zeige mehr
+ Zeige weniger
+ Mehr
+ Weniger
Hier ist nichts.
Noch keine Beiträge hier! Ziehe nach unten um zu aktualisieren!
%s teilte deinen Beitrag
@@ -119,14 +119,14 @@
Link kopieren
Öffne als %s
Teilen als …
- Beitragslink teilen…
- Beitragsinhalt teilen…
+ Beitragslink teilen…
+ Beitragsinhalt teilen…
Mediendatei teilen…
Gesendet!
entblockt
Stummschaltung aufgehoben
- Gesendet!
- Antwort erfolgreich gesendet.
+ Gesendet!
+ Antwort erfolgreich gesendet.
Welche Instanz?
Was gibt\'s Neues?
Inhaltswarnung
@@ -153,7 +153,7 @@
Herunterladen
Folgeanfrage zurückziehen?
Willst du diesem Profil wirklich nicht mehr folgen?
- Diesen Beitrag löschen?
+ Diesen Beitrag löschen?
Öffentlich: Für alle sichtbar
Ungelistet: Nicht in der öffentlichen Timeline sichtbar
Nur Folgende: Nur für Folgende sichtbar
@@ -182,8 +182,8 @@
Links in der App (Browser Custom Tabs) öffnen
Verstecke Button bei Bildlauf
Sprache
- Timeline-Filter
- Tabs
+ Timeline-Filter
+ Tabs
Geteilte Beiträge anzeigen
Zeige Antworten
Medienvorschauen herunterladen
@@ -199,20 +199,20 @@
Öffentlich
Nicht gelistet
Nur Folgende
- Schriftgröße
- Kleiner
- Klein
- Normal
- Groß
- Größer
+ Schriftgröße
+ Kleiner
+ Klein
+ Normal
+ Groß
+ Größer
Neue Erwähnungen
Benachrichtigungen über neue Erwähnungen
Neue Folgende
Benachrichtigunen über neue Folgende
Geteilte Beiträge
- Benachrichtigungen wenn deine Beiträge geteilt werden
+ Benachrichtigungen, wenn deine Beiträge geteilt werden
Favorisierte Beiträge
- Benachrichtigungen wenn deine Beiträge favorisiert werden
+ Benachrichtigungen, wenn deine Beiträge favorisiert werden
%s hat dich erwähnt
%1$s, %2$s, %3$s und %4$d andere
%1$s, %2$s, und %3$s
@@ -236,10 +236,10 @@
https://github.com/accelforce/Yuito/issues
Yuitos Profil
- Inhalt teilen
- Link teilen
- Bilder
- Video
+ Inhalt teilen
+ Link teilen
+ Bilder
+ Video
Folgeanfrage gesendet
Folgt dir
@@ -272,11 +272,11 @@
Gesperrtes Profil
Wer dir folgen möchte, muss um deine Erlaubnis bitten
Entwurf speichern?
- Beitrag senden…
- Fehler beim Senden
- Beiträge senden
- Senden abgebrochen
- Eine Kopie des Beitrags wurde in deine Entwürfe gespeichert
+ Beitrag senden…
+ Fehler beim Senden
+ Beiträge senden
+ Senden abgebrochen
+ Eine Kopie des Beitrags wurde in deine Entwürfe gespeichert
Beitrag erstellen
Deine Instanz %s hat keine Emojis definiert
In die Zwischenablage kopiert
@@ -284,8 +284,8 @@
System-Standard
Du musst diese Emoji-Sets zunächst herunterladen
Nachschlagen…
- Alle Beiträge aus-/einklappen
- Beitrag öffnen
+ Alle Beiträge aus-/einklappen
+ Beitrag öffnen
App-Neustart erforderlich
Du musst Yuito neustarten um die Änderungen anzuwenden
Später
@@ -319,8 +319,8 @@
- Maximum von %1$d Tab erreicht
- Maximum von %1$d Tabs erreicht
- Keine Beschreibung
- Favorisiert
+ Keine Beschreibung
+ Favorisiert
Öffentlich
Folgende
Direkt
@@ -341,12 +341,12 @@
- <b>%1$s</b> Favoriten
Geteilt von
- Medien: %s
- Inhaltswarnung: %s
- Geteilt
+ Medien: %s
+ Inhaltswarnung: %s
+ Geteilt
Ungelistet
Löschen und neu erstellen
- Bist du dir sicher, dass du diesen Beitrag löschen und neu erstellen möchtest\?
+ Bist du dir sicher, dass du diesen Beitrag löschen und neu erstellen möchtest\?
Umfragen beendet sind
Umfragen
Benachrichtigungen über beendete Umfragen
@@ -416,28 +416,28 @@
Beiträge mit Inhaltswarnungen immer ausklappen
Umfrage mit den Möglichkeiten: %1$s, %2$s, %3$s, %4$s; %5$s
Aktionen für Bild %s
- Fehler beim Holen der Beiträge
+ Fehler beim Holen der Beiträge
Konten
Fehler beim Suchen
Auswahlmöglichkeit hinzufügen
Mehrere Möglichkeiten
Möglichkeit %d
- Geplante Beiträge
+ Geplante Beiträge
Editieren
- Geplante Beiträge
- Plane Beitrag
+ Geplante Beiträge
+ Plane Beitrag
Zurücksetzen
Audiodateien müssen kleiner als 40 MB sein.
Lesezeichen
Lesezeichen
Lesezeichen
Angetrieben durch Tusky
- Als Lesezeichen gespeichert
+ Als Lesezeichen gespeichert
Liste auswählen
Liste
Fehler beim Nachschlagen von Post %s
Du hast keine Entwürfe.
- Du hast keine geplanten Beiträge.
+ Du hast keine geplanten Beiträge.
Das Datum des geplanten Toots muss mindestens 5 Minuten in der Zukunft liegen.
Benachrichtigungen über neue Folgeanfragen
Neue Folgeanfragen
@@ -478,9 +478,9 @@
Titel der Hauptnavigation verstecken
Im Moment gibt es keine Ankündigungen.
Ankündigungen
- Der Beitrag auf den du antworten willst wurde gelöscht
+ Der Beitrag auf den du antworten willst wurde gelöscht
Entwurf gelöscht
- Dieser Beitrag konnte nicht gesendet werden!
+ Dieser Beitrag konnte nicht gesendet werden!
Willst du die Liste %s wirklich löschen\?
- Du kannst nicht mehr als %1$d Anhang hochladen.
@@ -489,12 +489,12 @@
Wohlbefinden
Dauer
Für immer
- Anhänge
- Audio
+ Anhänge
+ Audio
Benachrichtigungen, wenn jemand, den ich abonniert habe, etwas Neues veröffentlicht
Neue Beiträge
GIF-Emojis animieren
- Jemand, den ich abonniert habe, etwas Neues veröffentlicht
+ Jemand, den ich abonniert habe, hat etwas Neues veröffentlicht
%s hat gerade etwas gepostet
%d Min.
Benachrichtigungen überprüfen
@@ -521,4 +521,11 @@
Bestätigungsdialog vor dem Favorisieren eines Beitrags
Diese Unterhaltung wirklich löschen\?
Unterhaltung löschen
+ 30 Tage
+ 60 Tage
+ 90 Tage
+ 365 Tage
+ 14 Tage
+ 180 Tage
+ Beitrag erstellen
diff --git a/app/src/main/res/values-en-rGB/strings.xml b/app/src/main/res/values-en-rGB/strings.xml
index 06bc38e1d..de167b858 100644
--- a/app/src/main/res/values-en-rGB/strings.xml
+++ b/app/src/main/res/values-en-rGB/strings.xml
@@ -1,23 +1,59 @@
The account is from another server. Send an anonymised copy of the report there as well\?
- Favourited
+ Favourited
Favourited by
- <b>%1$s</b> Favourite
- <b>%1$s</b> Favourites
- Notifications when your toots get marked as favourite
+ Notifications when your posts get marked as favourite
Favourites
my posts are favourited
Show favourites
Favourites
Remove favourite
Favourite
- %s favourited your toot
+ %s favourited your post
Favourites
Authorisation was denied.
An unidentified authorisation error occurred.
Log out
Show colourful gradients for hidden media
+ Edit your profile
+ Permission to read media is required.
+ Images and videos cannot both be attached to the same post.
+ A network error occurred! Please check your connection and try again!
+ Failed authenticating with that instance.
+ Couldn\'t find a web browser to use.
+ Failed getting a login token.
+ Notifications
+ Posts
+ Follows
+ Hidden domains
+ That type of file cannot be uploaded.
+ Federated
+ The upload failed.
+ Bookmarks
+ That file could not be opened.
+ Direct Messages
+ Followers
+ The post is too long!
+ An error occurred.
+ Local
+ Blocked users
+ Video files must be less than 40MB.
+ Tabs
+ Audio files must be less than 40MB.
+ Follow Requests
+ Home
+ Muted users
+ Thread
+ The file must be less than 8MB.
+ Error sending post.
+ This cannot be empty.
+ Permission to store media is required.
+ Invalid domain entered
+ With replies
+ Pinned
\ No newline at end of file
diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml
index 9c222afb5..f834d2ae9 100644
--- a/app/src/main/res/values-eo/strings.xml
+++ b/app/src/main/res/values-eo/strings.xml
@@ -26,9 +26,9 @@
Rektaj mesaĝoj
Langetoj
Mesaĝo
- Mesaĝoj
- Kun respondoj
- Alpinglitaj
+ Mesaĝoj
+ Kun respondoj
+ Alpinglitaj
Sekvatoj
Sekvantoj
Stelumoj
@@ -38,15 +38,15 @@
Redakti vian profilon
Malnetoj
Permesiloj
- \@%s
- %s diskonigis
- Tikla enhavo
- Kaŝitaj aŭdovidaĵoj
- Alklaki por vidi
- Montri pli
- Montri malpli
- Pligrandigi
- Malgrandigi
+ \@%s
+ %s diskonigis
+ Tikla enhavo
+ Kaŝitaj aŭdovidaĵoj
+ Alklaki por vidi
+ Montri pli
+ Montri malpli
+ Pligrandigi
+ Malgrandigi
Nenio ĉi tie.
Nenio ĉi tie. Tiru malsupren por aktualigi!
%s diskonigis vian mesaĝon
@@ -122,14 +122,14 @@
Konigi kiel …
Elŝuti aŭdovidaĵon
Elŝutante aŭdovidaĵo
- Konigi URL de mesaĝo al…
- Konigi mesaĝon al…
+ Konigi URL de mesaĝo al…
+ Konigi mesaĝon al…
Konigi aŭdovidaĵon al…
Sendita!
Malblokita uzanto
Malsilentigita uzanto
- Sendita!
- Respondi sukcese sendita.
+ Sendita!
+ Respondi sukcese sendita.
Kiu nodo?
Kio okazas?
Enhava averto
@@ -152,7 +152,7 @@
Elŝuti
Nuligi peton de sekvado?
Ne plu sekvi?
- Forigi ĉi tiun mesaĝon?
+ Forigi ĉi tiun mesaĝon?
Publika: afiŝi en publikaj tempolinioj
Nelistigita: Ne afiŝi en publikaj tempolinioj
Nur por sekvantoj: Afiŝi nur al sekvantoj
@@ -181,8 +181,8 @@
Uzi la integritan retumilon
Kâsi butonon de verko dum rulumado
Lingvo
- Filtrado de tempolinioj
- Langetoj
+ Filtrado de tempolinioj
+ Langetoj
Montri diskonigojn
Montri la respondojn
Elŝuti antaŭvidojn de aŭdovidaĵoj
@@ -198,12 +198,12 @@
Publika
Nelistigita
Nur por sekvantoj
- Grando de teksto de mesaĝoj
- La plej malgranda
- Malgranda
- Meza
- Granda
- La plej granda
+ Grando de teksto de mesaĝoj
+ La plej malgranda
+ Malgranda
+ Meza
+ Granda
+ La plej granda
Novaj mencioj
Sciigoj pri novajn menciojn
Novaj sekvantoj
@@ -239,10 +239,10 @@
https://github.com/accelforce/Yuito/issues
Profilo de Yuito
- Konigi enhavon de la mesaĝo
- Konigi ligilon al mesaĝo
- Bildoj
- Video
+ Konigi enhavon de la mesaĝo
+ Konigi ligilon al mesaĝo
+ Bildoj
+ Video
Sekvado petita
en %dj
@@ -292,11 +292,11 @@
Ŝlosi konton
Vi devas permane rajtigi sekvantojn
Konservi malneton?
- Sendante la mesaĝo…
- Eraro dum sendo de la mesaĝo
- Sendante la mesaĝoj
- Sendo nuligita
- Kopio de la mesaĝo estis konservita en viaj malnetoj
+ Sendante la mesaĝo…
+ Eraro dum sendo de la mesaĝo
+ Sendante la mesaĝoj
+ Sendo nuligita
+ Kopio de la mesaĝo estis konservita en viaj malnetoj
Verki
Via nodo %s ne havas proprajn emoĝiojn
Kopiita en tondujo
@@ -304,8 +304,8 @@
Sistema valoro
Vi unue devos elŝuti ĉi tiujn emoĝiarojn
Serĉante…
- Pligrandigi/malgrandigi ĉiujn mesaĝojn
- Malfermi mesaĝon
+ Pligrandigi/malgrandigi ĉiujn mesaĝojn
+ Malfermi mesaĝon
Restartigo necesas
Vi devos restartigi Yuito por apliki ĉi tiujn ŝanĝojn
Poste
@@ -347,15 +347,15 @@
- maksimumo da %1$d langeto atingita
- maksimumo da %1$d langetoj atingita
- Aŭdovidaĵo: %s
+ Aŭdovidaĵo: %s
- Enhava averto: %s
+ Enhava averto: %s
- Neniu priskribo
+ Neniu priskribo
- Diskonigita
+ Diskonigita
- Stelumita
+ Stelumita
Publika
@@ -365,7 +365,7 @@
Rekta
Nomo de la listo
Forigi kaj reskribi
- Ĉu forigi kaj reskribi ĉi-tiun mesaĝon\?
+ Ĉu forigi kaj reskribi ĉi-tiun mesaĝon\?
enketoj finiĝis
Montri indikilon por robotoj
Moviĝi GIF profilbildojn
@@ -404,7 +404,7 @@
Pliaj komentoj
Plusendi al %s
Signalo malsukcesis
- Venigo de statusoj malsukcesis
+ Venigo de statusoj malsukcesis
La signalo estos sendita al la kontrolantoj de via servilo. Vi povas doni klarigon pri kial vi signalas ĉi tiun konton sube:
La konto estas en alia servilo. Ĉu sendi sennomigitan kopion de la signalo ankaŭ tien\?
Montri filtrilon de Sciigoj
@@ -427,21 +427,21 @@
Elekton %d
Redakti
Legosignoj
- Planitaj mesaĝoj
+ Planitaj mesaĝoj
Aldoni al la legosignoj
Redakti
Legosignoj
- Planitaj mesaĝoj
- Plani mesaĝon
+ Planitaj mesaĝoj
+ Plani mesaĝon
Restarigi
Funkciigita de Tusky
- Aldonita al la legosignoj
+ Aldonita al la legosignoj
Elekti la liston
Listo
Eraro dum elserĉo de la mesaĝo %s
Aŭdia dosiero devas esti malpli ol 40MB.
Vi ne havas iun ajn malneton.
- Vi ne havas iun ajn planitan mesaĝon.
+ Vi ne havas iun ajn planitan mesaĝon.
Petoj de sekvado
Kradvortoj
@@ -490,10 +490,10 @@
Estas neniu anonco.
Ebligi ŝovumadon por ŝanĝi inter la langetoj
Mastodon havas minimuman intervalon de planado de 5 minutoj.
- Kunsendaĵoj
+ Kunsendaĵoj
iu kiun mi sekvas afiŝis novan mesaĝon
Ĉu vi vere volas forigi la liston %s\?
- Aŭdio
+ Aŭdio
Aboni
Malneto forigita
@@ -511,7 +511,7 @@
Forigi konversacion
%s ĵus afiŝis
Sciigoj kiam iu kiun vi sekvas afiŝis novan mesaĝon
- Sendo de ĉi-tiu mesaĝo malsukcesis!
+ Sendo de ĉi-tiu mesaĝo malsukcesis!
Kaŝi kvantecajn statistikaĵojn sur la mesaĝoj
Demandi konfirmon antaŭ ol stelumi
Bonstato
@@ -525,5 +525,5 @@
\n Puŝosciigoj ne estos influitaj, sed vi povas kontroli viajn sciigojn preferojn permane.
Kontroli la sciigojn
Limigi sciigojn pri tempolinio
- La mesaĝo al kiu ĉi tiu malneto respondas estis forigita
-
\ No newline at end of file
+ La mesaĝo al kiu ĉi tiu malneto respondas estis forigita
+
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 3d620a7a3..a33ea05b1 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -26,9 +26,9 @@
Mensajes Directos
Pestañas
Publicación
- Estados
- Con respuestas
- Fijado
+ Estados
+ Con respuestas
+ Fijado
Siguiendo
Seguidores
Favoritos
@@ -38,15 +38,15 @@
Editar tu perfil
Borradores
Licencias
- \@%s
- %s compartió
- Contenido sensible
- Material oculto
- Pulsa para ver
- Mostrar más
- Mostrar menos
- Expandir
- Ocultar
+ \@%s
+ %s compartió
+ Contenido sensible
+ Material oculto
+ Pulsa para ver
+ Mostrar más
+ Mostrar menos
+ Expandir
+ Ocultar
Nada aquí.
Nada por aquí. ¡Arrastra hacia abajo para recargar!
%s impulsó tu toot
@@ -108,14 +108,14 @@
Copiar el enlace
Abrir como %s
Compartir como…
- Compartir URL…
- Compartir contenido…
+ Compartir URL…
+ Compartir contenido…
Compartir medios a…
¡Enviado!
El usuario ya no está bloqueado
El usuario ya no está silenciado
- ¡Enviado!
- Respuesta enviada correctamente.
+ ¡Enviado!
+ Respuesta enviada correctamente.
¿Qué instancia\?
¿En qué estás pensando?
Aviso de contenido
@@ -142,7 +142,7 @@
Descargar
¿Cancelar petición de amistad?
¿Dejar de seguir esta cuenta?
- ¿Eliminar este toot\?
+ ¿Eliminar este toot\?
Público: Mostrar en historias públicas
Oculto: No mostrar en historias públicas
Privado: Sólo visible para seguidores
@@ -168,8 +168,8 @@
Navegador
Usar pestañas de Chrome
Ocultar botón de redacción al bajar
- Filtros de cronología
- Pestañas
+ Filtros de cronología
+ Pestañas
Mostrar impulsos
Mostrar respuestas
Previsualizar multimedia
@@ -185,12 +185,12 @@
Público
Oculto
Privado
- Tamaño del texto
- Diminuto
- Pequeño
- Medio
- Grande
- Enorme
+ Tamaño del texto
+ Diminuto
+ Pequeño
+ Medio
+ Grande
+ Enorme
Nuevas menciones
Notificaciones de nuevas menciones
Nuevos seguidores
@@ -226,10 +226,10 @@
https://github.com/accelforce/Yuito/issues
Perfil de Yuito
- Compartir contenido
- Compartir enlace
- Imágenes
- Video
+ Compartir contenido
+ Compartir enlace
+ Imágenes
+ Video
Solicitud enviada
en %dy
@@ -262,11 +262,11 @@
Proteger cuenta
Tendrá que admitir los seguidores manualmente
¿Guardar borrador?
- Enviando estado…
- Error al enviar el estado
- Enviando estado
- Envío cancelado
- Una copia del estado se ha guardado en borradores
+ Enviando estado…
+ Error al enviar el estado
+ Enviando estado
+ Envío cancelado
+ Una copia del estado se ha guardado en borradores
Redactar
Su instancia %s no ofrece emojis personalizados
Copiado al portapapeles
@@ -274,8 +274,8 @@
Sistema
Tendrás que descargarlos primero
Buscando…
- Expandir/ocultar todos los estados
- Abrir
+ Expandir/ocultar todos los estados
+ Abrir
Reinicio requerido
Tendrás que reiniciar la aplicación para aplicar estos cambios
Más tarde
@@ -332,7 +332,7 @@
Renombrar la lista
Añadir cuenta a la lista
Eliminar cuenta de la lista
- 1Favoritos
+ 1Favoritos
Seguidores
Aplicar
Mostrar indicador de bots
@@ -366,7 +366,7 @@
Enlaces
Abrir contenido #%d
Descargando contenido
- ¿Eliminar y devolver a borradores este toot\?
+ ¿Eliminar y devolver a borradores este toot\?
encuestas han terminado
Notificaciones sobre encuestas que han terminado
Cronologías públicas
@@ -381,10 +381,10 @@
Eliminar la lista
Editar la lista
Buscar personas que sigues
- Contenido: %s
- Aviso de contenido: %s
- Sin descripción
- Compartido
+ Contenido: %s
+ Aviso de contenido: %s
+ Sin descripción
+ Compartido
Público
Sin listar
Directo
@@ -419,7 +419,7 @@
Comentarios adicionales
Reenviar a %s
Reporte fallido
- Fallo al obtener estados
+ Fallo al obtener estados
El reporte será enviado a un moderador de tu servidor. Puedes añadir una explicación de por qué estás reportando esta cuenta a continuación:
La cuenta es de otro servidor. ¿Enviar una copia anónima del reporte\?
Mostrar filtro de notificaciones
@@ -439,22 +439,22 @@
Opciones múltiples
Opción %d
Editar
- Estados programados
+ Estados programados
Editar
- Estados programados
- Programar estado
+ Estados programados
+ Programar estado
Reiniciar
Error al buscar el post %s
Potenciado por Tusky
Marcadores
Marcador
Marcadores
- Marcado como favorito
+ Marcado como favorito
Seleccionar lista
Lista
Los ficheros de audio deben ser menores de 40MB.
No tienes ningún borrador.
- No tienes ningún estado programado.
+ No tienes ningún estado programado.
Mastodon tiene un intervalo de programación mínimo de 5 minutos.
Solicitudes
Bloquear @%s\?
@@ -506,15 +506,15 @@
\n- Estadísticas de seguidores e toots en perfiles
\n
\nLas notificaciones Push no serán afectadas, pero puedes revisar manualmente tus preferencias.
- El toot al que redactaste una respuesta ha sido eliminado
+ El toot al que redactaste una respuesta ha sido eliminado
Borrador eliminado
Error al cargar la información de respuesta
- ¡Este toot no se pudo enviar!
+ ¡Este toot no se pudo enviar!
¿Realmente quieres eliminar la lista %s\?
Indefinido
Duración
- Adjuntos
- Audio
+ Adjuntos
+ Audio
Limitar cronología de notificaciones
Quitar marcador
Aunque su cuenta no está bloqueada, el personal de %1$s pensó que podría querer revisar las solicitudes de seguimiento de estas cuentas manualmente.
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index 1cc56f7cd..8671a8be7 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -23,8 +23,8 @@
Lokala
Federatua
Tuta
- Tutak
- Erantzunekin
+ Tutak
+ Erantzunekin
Jarraitzen
Jarraitzaileak
Gogokoak
@@ -34,14 +34,14 @@
Profila editatu
Zirriborroak
Lizentziak
- %s(e)k bultzatu du
- Kontuz edukiarekin
- Ezkutuko multimedia
- Sakatu ikusteko
- Gehiago erakutsi
- Gutxiago erakutsi
- Zabaldu
- Bildu
+ %s(e)k bultzatu du
+ Kontuz edukiarekin
+ Ezkutuko multimedia
+ Sakatu ikusteko
+ Gehiago erakutsi
+ Gutxiago erakutsi
+ Zabaldu
+ Bildu
Edukirik ez. Arrastatu behera birkargatzeko!
%s(e)k zure tuta bultzatu du
%s(e)k zure tuta gogoko du
@@ -99,14 +99,14 @@
Emoji teklatua
%1$s jaisten
Lotura kopiatu
- Tutaren URLa partekatu…
- Tuta partekatu…
+ Tutaren URLa partekatu…
+ Tuta partekatu…
Partekatu media hona…
Bidalia!
Erabiltzailea desblokeatuta
Erabiltzailea isilgabetuta
- Bidalia!
- Erantzuna ongi bidali da.
+ Bidalia!
+ Erantzuna ongi bidali da.
Zein instantzia\?
Zer duzu buruan?
Edukiaren abisua
@@ -131,7 +131,7 @@
Jaitsi
Jarraipen-eskakizunari uko egin\?
Kontu hau jarraitzeari utzi\?
- Tuta ezabatu\?
+ Tuta ezabatu\?
Publikoa: Istorio publikoetan erakutsi
Ezkutukoa: Ez erakutsi istorio publikoetan
Pribatua: Jarraitzaileentzat soilik ikusgai
@@ -157,8 +157,8 @@
Nabigatzailea
Chromeko fitxak erabili
Tut egiteko botoia ezkutatu beherantz joaterakoan
- Denbora-lerro filtroak
- Fitxak
+ Denbora-lerro filtroak
+ Fitxak
Bultzadak erakutsi
Erakutsi erantzunak
Jaitsi mediaren aurreikuspenak
@@ -174,12 +174,12 @@
Publiko
Zerrendagabetuta
Jarraitzaileak soilik
- Status testuaren tamaina
- Oso txikia
- Txikia
- Erdikoa
- Handia
- Handiena
+ Status testuaren tamaina
+ Oso txikia
+ Txikia
+ Erdikoa
+ Handia
+ Handiena
Aipamen berriak
Aipamen berrien jakinarazpenak
Jarritzaile berriak
@@ -213,10 +213,10 @@
Akatsen berri-emateak eta hobekuntza-eskariak:
\n https://github.com/accelforce/Yuito/issues
Yuitoren profila
- Partekatu tutaren edukia
- Partekatu tutaren lotura
- Irudiak
- Bideoak
+ Partekatu tutaren edukia
+ Partekatu tutaren lotura
+ Irudiak
+ Bideoak
Eskaera bidalita
%du-an
@@ -246,11 +246,11 @@
Kontua babestu
Jarraitzaileak eskuz onartu beharko dituzu
Zirriborroa gorde?
- Tuta bidaltzen…
- Errorea tuta bidaltzerakoan
- Tuta bidaltzen
- Bidalketa ezeztatua
- Tutaren kopia zirriborroetan sartu da
+ Tuta bidaltzen…
+ Errorea tuta bidaltzerakoan
+ Tuta bidaltzen
+ Bidalketa ezeztatua
+ Tutaren kopia zirriborroetan sartu da
Idatzi
%s instantziak ez ditu emoji pertsonalizatuak eskaintzen
Arbelean kopiatua
@@ -258,8 +258,8 @@
Sistema
Lehenago jaitsi beharko dituzu
Bilatzen…
- Tut guztiak ezkutatu/zabaldu
- Ireki
+ Tut guztiak ezkutatu/zabaldu
+ Ireki
Berrabiaraztea beharrezkoa da
Aplikazioa berrabiarazi beharko duzu aldaketa ezartzeko
Beranduago
@@ -285,10 +285,10 @@
Sareko errore bat sortu da! Zure konexioa ziurta ezazu berriro, mesedez!
Mezu Zuzenak
Fitxak
- Lotuta
+ Lotuta
Ezkutuko domeinuak
- Programatutako tutak
- \@%s
+ Programatutako tutak
+ \@%s
Kilkerrak besterik ez hemen.
Bultzada kendu
Gogokoa kendu
@@ -297,8 +297,8 @@
Ezkutuko domeinuak
Galdeketa gehitu
Mututu %s
- Programatutako tutak
- Tuta programatu
+ Programatutako tutak
+ Tuta programatu
Berrezarri
Kategoria gehitu
Estekak
@@ -313,7 +313,7 @@
Media jaisten
Media jaisten
%s ez dago ezkutatua
- Tut hau ezabatu eta zirriborro berria egin\?
+ Tut hau ezabatu eta zirriborro berria egin\?
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.
Domeinu osoa ezkutatu
Galdeketak bukatu dira
@@ -370,11 +370,11 @@
- gehienezko %1$d fitxa iritsita
- gehienezko %1$d fitxa iritsita
- Media: %s
- Edukiaren abisua: %s
- Deskribapenik ez
- Birblogeatuta
- Gogotuta
+ Media: %s
+ Edukiaren abisua: %s
+ Deskribapenik ez
+ Birblogeatuta
+ Gogotuta
Publiko
Zerrendagabetuta
Jarraitzaileak
@@ -418,7 +418,7 @@
Iruzkin gehigarriak
%s(r)i birbidali
Txostena huts egin du
- Egoeren eskuratzea huts egin du
+ Egoeren eskuratzea huts egin du
Txostena zure zerbitzariaren moderatzaileari bidaliko zaio. Jarraian, kontu honen zergatia salatzen duzun azalpena eman dezakezu:
Kontua beste zerbitzari batekoa da. Bidali txostenaren kopia anonimatua hara ere\?
Kontuak
@@ -442,12 +442,12 @@
Laster-markak
Ireki bultzadaren egilea
Denbora lerro publikoak
- Laster-markatuta
+ Laster-markatuta
Audioak 40MB baino gutxiago izan behar ditu.
Aukeratu zerrenda
Zerrenda
Ez duzu zirriborrorik.
- Ez duzu tut programaturik.
+ Ez duzu tut programaturik.
Mastodonek gutxienez 5 minutuko programazio-tartea du.
Eskakizunak
Jarraitzeko eskaereri buruzko jakinarazpenak
@@ -480,16 +480,16 @@
Erakutsi baieztapen elkarrizketa-koadroa gogokoenetara gehitu aurretik
Zure kontua blokeatuta ez badago ere, %1$s-ko langileek kontu hauetako eskaerak eskuz berrikusi nahi dituzula pentsatu dute.
harpidedun naizen norbaitek tut berria argitaratu du
- Eranskinak
+ Eranskinak
Ziur %s zerrenda ezabatu nahi duzula\?
- Audioa
+ Audioa
Harpidetu
Elkarrizketa ezabatu nahi duzu\?
Animatu emoji pertsonalizatuak
Erantzunaren informazioa ezin izan da kargatu
Profiletan estatistika kuantitatiboak ezkutatu
Zirriborroa ezabatu da
- Erantzuna idatzi zenuen tuta ezabatu da
+ Erantzuna idatzi zenuen tuta ezabatu da
Ongizatea
- Ezin duzu multimedia eranskin %1$d baino gehiago kargatu.
@@ -511,7 +511,7 @@
Iragarpenak
Jakinarazpenak harpidetuta zauden norbaitek tut berria argitaratu duenean
Kontu honi buruzko zure ohar pribatua
- Tut honek ezin izan du bidali!
+ Tut honek ezin izan du bidali!
Zure ongizate mentalean eragina izan dezaketen zenbait informazio ezkutatuta egongo dira. Honek honako hauek ditu:
\n
\n - Gogokoak, bultzadak eta jarraitzaileen jakinarazpenak
@@ -521,4 +521,4 @@
\nPush-jakinarazpenek ez dute eraginik izango, baina jakinarazpenen hobespenak eskuz berrikus ditzakezu.
Mezuetan estatistika kuantitatiboak ezkutatu
Laster-marka kendu
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index f55829b5b..8ddeb49a3 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -23,8 +23,8 @@
محلّی
همگانی
بوق
- فرسته
- با پاسخ
+ فرسته
+ با پاسخ
دنبال شونده
پیگیر
برگزیدهها
@@ -34,14 +34,14 @@
ویرایش نمایهتان
پیشنویسها
پروانهها
- %s تقویت کرد
- محتوای حسّاس
- رسانهٔ نهفته
- کلیک برای نمایش
- نمایش بیشتر
- نمایش کمتر
- گسترش
- بستن
+ %s تقویت کرد
+ محتوای حسّاس
+ رسانهٔ نهفته
+ کلیک برای نمایش
+ نمایش بیشتر
+ نمایش کمتر
+ گسترش
+ بستن
اینجا هیچچیز نیست. برای تازهسازی، به پایین بکشید!
%s بوقتان را تقویت کرد
%s بوقتان را برگزید
@@ -98,14 +98,14 @@
صفحهکلید اموجی
درحال بارگیری %1$s
رونوشت از پیوند
- همرسانی نشانی بوق با…
- همرسانی بوق با…
+ همرسانی نشانی بوق با…
+ همرسانی بوق با…
همرسانی رسانه با…
فرستاده شد!
کاربرنامسدود شد
کاربر ناخموش شد
- فرستاده شد!
- پاسخ با موفّقیت فرستاده شد.
+ فرستاده شد!
+ پاسخ با موفّقیت فرستاده شد.
کدام نمونه؟
چه خبر؟
هشدار محتوا
@@ -130,7 +130,7 @@
بارگیری
درخواست دنبال کردن را لغو میکنید؟
ناپیگیری این حساب؟
- حذف این بوق؟
+ حذف این بوق؟
عمومی: فرستادن به خط زمانیهای عمومی
فهرستنشده: نشان ندادن در خط زمانیهای عمومی
تنها دنبالکنندگان:پست فقط به دنبالکنندگان
@@ -156,8 +156,8 @@
مرورگر
استفاده از زبانههای سفارشی کروم
نهفتن دکمهٔ ایجاد، هنگام پیمایش
- فیلتر کردن خط زمانی
- زبانهها
+ فیلتر کردن خط زمانی
+ زبانهها
نمایش تقویتها
نمایش پاسخها
بارگیری پیشنمایش رسانه
@@ -173,12 +173,12 @@
عمومی
فهرستنشده
فقط پیگیران
- اندازهٔ متن وضعیت
- کوچکترین
- کوچک
- متوسط
- بزرگ
- بزرگترین
+ اندازهٔ متن وضعیت
+ کوچکترین
+ کوچک
+ متوسط
+ بزرگ
+ بزرگترین
اشارههای جدید
آگاهیها دربارهٔ اشارههای جدید
پیگیران جدید
@@ -209,10 +209,10 @@
گزارش مشکلات و درخواست ویژگیها:
\n https://github.com/accelforce/Yuito/issues
نمایهٔ تاسکی
- همرسانی محتوای بوق
- همرسانی پیوند بوق
- تصویرها
- ویدیو
+ همرسانی محتوای بوق
+ همرسانی پیوند بوق
+ تصویرها
+ ویدیو
تقاضای پیگیری شد
در %d سال
@@ -241,11 +241,11 @@
قفل حساب
لازم است پیگیران را دستی تأیید کنید
ذخیرهٔ پیشنویس؟
- در حال فرستادن بوق…
- خطای فرستادن بوق
- در حال فرستادن بوقها
- فرستادن لغو شد
- رونوشتی از بوق در پیشنویسهایتان ذخیره شد
+ در حال فرستادن بوق…
+ خطای فرستادن بوق
+ در حال فرستادن بوقها
+ فرستادن لغو شد
+ رونوشتی از بوق در پیشنویسهایتان ذخیره شد
ایجاد
نمونهتان %s هیچ اموجی سفارشیای ندارد
در تختهگیره رونوشت شد
@@ -253,8 +253,8 @@
پیشگزیدهٔ سامانه
نخست باید این مجموعههای اموجی را بارگیری کنید
در حال جستوجو…
- گسترده/جمع کردن تمام وضعیتها
- گشودن بوق
+ گسترده/جمع کردن تمام وضعیتها
+ گشودن بوق
نیاز به آغاز دوبارهٔ کاره
برای اعمال این تغییرات، نیاز به شروع دوبارهٔ تاسکی دارید
بعداً
@@ -280,9 +280,9 @@
یک خطای شبکه رخ داد! لطفا اتصال خود را بررسی و دوباره تلاش کنید!
پیامهای مستقیم
زبانهها
- سنجاقشده
+ سنجاقشده
دامنههای نهفته
- \@%s
+ \@%s
اینجا هیچچیزی نیست.
برداشتن تقویت
برداشتن برگزیدگی
@@ -306,7 +306,7 @@
بارگیری رسانه
در حال بارگیری رسانه
%s نانهفته
- میخواهید این بوق را پاک و بازنویسی کنید؟
+ میخواهید این بوق را پاک و بازنویسی کنید؟
نهفتن تمام دامنه
پایان نظرسنجیها
پالایهها
@@ -360,11 +360,11 @@
- رسیده به بیشینهٔ %1$d زبانه
- رسیده به بیشینهٔ %1$d زبانه
- رسانه: %s
- هشدار محتوا: %s
- بدون هیچ توضیحی
- بازبوقیده
- برگزیده
+ رسانه: %s
+ هشدار محتوا: %s
+ بدون هیچ توضیحی
+ بازبوقیده
+ برگزیده
عمومی
فهرستنشده
پیگیران
@@ -402,7 +402,7 @@
نظرهای اضافی
هدایت به %s
شکست در گزارش
- شکست در واکشی وضعیتها
+ شکست در واکشی وضعیتها
حسابها
شکست در جستوجو
نمایش پالایهٔ آگاهیها
@@ -418,10 +418,10 @@
گزینههای چندگانه
گزینهٔ %d
ویرایش
- بوقهای زمانبسته
+ بوقهای زمانبسته
ویرایش
- بوقهای زمانبسته
- بوق زمانبسته
+ بوقهای زمانبسته
+ بوق زمانبسته
بازنشانی
مطمئنید میخواهید تمام %s را مسدود کنید؟ محتوای آن دامنه را در هیچیک از خط زمانیها یا در آگاهیهایتان نخواهید دید. پیگیرانتان از آن دامنه، برداشته خواهند شد.
هنگامی که کلیدواژه یا عبارت، فقط حروفعددی باشد، فقط اگر با تمام واژه مطابق باشد، اعمال خواهد شد
@@ -435,11 +435,11 @@
نشانکها
نشانک
نشانکها
- نشانشده
+ نشانشده
گزینش فهرست
فهرست
هیچ پیشنویسی ندارید.
- هیچ وضعیت زمانبستهای ندارید.
+ هیچ وضعیت زمانبستهای ندارید.
ماستودون، بازهٔ زمانبندیای با کمینهٔ ۵ دقیقه دارد.
نمایش گفتوگوی تأیید، پیش از تقویت
پیشنمایش پیوندها در خطزمانیها
@@ -484,21 +484,21 @@
عدم اشتراک
اشتراک
پیشنویس حذف شد
- فرستادن این بوق شکست خورد!
+ فرستادن این بوق شکست خورد!
نهفتن آمار کمی روی نمایهها
نهفتن آمار کمی روی فرستهها
محدود کردن آگاهیهای خطزمانی
بازبینی آگاهیها
سلامتی
طول
- پیوستها
- صدا
+ پیوستها
+ صدا
آگاهیها هنگام انتشار بوقی جدید از کسی که مشترکش هستید
بوقهای جدید
اموجیهای شخصی متحرّک
کسی که مشترکش شدهام، بوقی جدید منتشر کرد
%s چیزی فرستاد
- بوقی که پاسخی به آن را پیشنویس کردید، برداشته شده
+ بوقی که پاسخی به آن را پیشنویس کردید، برداشته شده
شکست در بار کردن اطّلاعات پاسخ
برخی اطّلاعات که ممکن است روی سلامتی ذهنیتان تأثیر بگذارد، پنهان خواهند شد. همچون:
\n
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 3638aeafc..cd3ada402 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -4,7 +4,7 @@
Animoi GIF-avatarit
Seuraa laitteen teemaa
Lopeta tilin seuraaminen\?
- Poista tuuttaus\?
+ Poista tuuttaus\?
Mikä on instanssi\?
Kopioi linkki
Avaa selaimessa
@@ -22,14 +22,14 @@
30 minuuttia
5 minuuttia
Lisää hashtag
- Ei kuvausta
+ Ei kuvausta
CC-BY-SA 4.0
CC-BY 4.0
Lataus epäonnistui
- Avaa tuuttaus
+ Avaa tuuttaus
Järjestelmän oletus
Emojien tyyli
- Lähetetään tuuttausta…
+ Lähetetään tuuttausta…
Tallennetaanko luonnoksena\?
Lukitse tili
Lisää tili
@@ -52,10 +52,10 @@
Lataa media
Näytä suosikit
Lisää välilehti
- Ajasta tuuttaus
+ Ajasta tuuttaus
Emoji-näppäimistö
Sisältövaroitus
- Ajastetut tuuttaukset
+ Ajastetut tuuttaukset
Muokkaa profiilia
Piilota media
Ota kuva
@@ -65,9 +65,9 @@
Estetyt tilit
Tiliasetukset
Kirjaudu ulos
- Näytä vähemmän
- Näytä lisää
- Media piilotettu
+ Näytä vähemmän
+ Näytä lisää
+ Media piilotettu
Seuraamispyynnöt
Estetyt tilit
Mykistetyt tilit
@@ -93,14 +93,14 @@
Listat
Päivitä
Poista
- Audio
- Video
- Kuvat
+ Audio
+ Video
+ Kuvat
Tietoja
Välityspalvelin
Vain seuraajat
Julkinen
- Välilehdet
+ Välilehdet
Kieli
Selain
Musta
@@ -152,17 +152,17 @@
Seuraa
TUUTAA!
Tuuttaus
- Ajastetut tuuttaukset
+ Ajastetut tuuttaukset
Vastaa
- \@%s
+ \@%s
Lisenssit
Luonnokset
Suosikit
Kirjanmerkit
Seuraajat
Seurataan
- Kiinnitetty
- Julkaisut
+ Kiinnitetty
+ Julkaisut
Välilehdet
Paikallinen
Ilmoitukset
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 7113ededd..8490c4cb9 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -9,14 +9,14 @@
Une erreur d’autorisation inconnue s’est produite.
Authentification refusée.
Impossible de récupérer le jeton d’authentification.
- Votre pouet est trop long !
+ Votre message est trop long !
Le fichier doit avoir moins de 8 Mo.
Les fichiers vidéos doivent avoir moins de 40 Mo.
Ce type de fichier ne peut pas être téléversé.
Le fichier ne peut pas être ouvert.
Permission requise pour lire le média.
Permission requise pour enregistrer le média.
- Un même pouet ne peut contenir à la fois une vidéo et une image.
+ Un même message ne peut contenir à la fois une vidéo et une image.
Échec d’envoi du média.
Erreur lors de l’envoi du message.
Accueil
@@ -25,10 +25,10 @@
Global
Messages directs
Onglets
- Pouet
- Messages
- Pouets & réponses
- Épinglés
+ Fil
+ Messages
+ Pouets & réponses
+ Épinglés
Abonnements
Abonné·e·s
Favoris
@@ -38,19 +38,19 @@
Modifier votre profil
Brouillons
Licences
- \@%s
- %s a partagé
- Contenu sensible
- Média caché
- Cliquer pour voir
- Voir plus
- Voir moins
- Déplier
- Replier
+ \@%s
+ %s a partagé
+ Contenu sensible
+ Média caché
+ Cliquer pour voir
+ Voir plus
+ Voir moins
+ Déplier
+ Replier
Rien ici.
Il n’y a aucun pouet ici pour l’instant. Glissez vers le bas pour actualiser !
- %s a partagé votre pouet
- %s a ajouté votre pouet à ses favoris
+ %s a partagé votre message
+ %s a ajouté votre message à ses favoris
%s vous suit
Signaler @%s
Commentaires additionnels \?
@@ -102,7 +102,7 @@
Refuser
Rechercher
Brouillons
- Visibilité du pouet
+ Visibilité du message
Contenu sensible
Clavier d’émojis
Ajouter un onglet
@@ -122,14 +122,14 @@
Partager comme …
Télécharger le média
Téléchargement du média
- Partager le lien de votre pouet avec…
- Partager le pouet avec…
+ Partager le lien du message avec…
+ Partager le mesage avec…
Partager l’image avec …
Envoyé !
Le compte est débloqué
Le compte n’est plus masqué
- Envoyé !
- Réponse envoyée avec succès.
+ Envoyé !
+ Réponse envoyée avec succès.
Quelle instance ?
Quoi de neuf ?
Contenu sensible
@@ -156,7 +156,7 @@
Télécharger
Révoquer la demande d’abonnement ?
Ne plus suivre ce compte ?
- Supprimer ce pouet ?
+ Supprimer ce pouet ?
Public : afficher dans les fils publics
Non listé : ne pas afficher dans les fils publics
Abonné·e·s uniquement : seul·e·s vos abonné·e·s verront vos statuts
@@ -170,8 +170,8 @@
Me notifier quand
on me mentionne
on vient de me suivre
- mes pouets sont partagés
- mes pouets sont mis en favoris
+ mes messages sont partagés
+ mes messages sont mis en favoris
Apparence
Thème de l’application
Fils chronologiques
@@ -185,8 +185,8 @@
Utiliser le navigateur intégré
Masquer le bouton de composition lors du défilement
Langue
- Filtrage des fils
- Onglets
+ Filtrage des fils
+ Onglets
Afficher les partages
Afficher les réponses
Montrer les miniatures des médias
@@ -202,20 +202,20 @@
Public
Non listé
Abonné·e·s uniquement
- Taille du texte pour les statuts
- Plus petit
- Petit
- Moyen
- Grand
- Plus grand
+ Taille du texte pour les statuts
+ Plus petit
+ Petit
+ Moyen
+ Grand
+ Plus grand
Nouvelles mentions
Notifications pour les nouvelles mentions
Nouveaux abonnés
Notifications pour les nouveaux abonnés
Partages
- Notifications quand vos pouets sont partagés
+ Notifications quand vos messages sont partagés
Favoris
- Notifications quand vos pouets sont mis en favoris
+ Notifications quand vos messages sont mis en favoris
%s vous a mentionné
%1$s, %2$s, %3$s et %4$d autres
%1$s, %2$s et %3$s
@@ -243,10 +243,10 @@
https://github.com/accelforce/Yuito/issues
Profil de Yuito
- Partager le contenu du pouet
- Partager le lien du pouet
- Images
- Vidéo
+ Partager le contenu du pouet
+ Partager le lien du pouet
+ Images
+ Vidéo
Demande d’abonnement effectuée
en %da
@@ -297,11 +297,11 @@
Verrouiller le compte
Vous devez approuvez manuellement les abonnements
Enregistrer comme brouillon ?
- Envoi du pouet…
- Erreur lors de l’envoi du pouet
- Envoi des pouets
- Envoi annulé
- Une copie du pouet a été sauvegardée dans vos brouillons
+ Envoi du pouet…
+ Erreur lors de l’envoi du pouet
+ Envoi des pouets
+ Envoi annulé
+ Une copie du pouet a été sauvegardée dans vos brouillons
Écrire
Votre instance %s n’a pas d’émojis personnalisés
Copié dans le presse-papier
@@ -309,8 +309,8 @@
Par défaut du système
Vous devez commencer par télécharger ces jeux d’émojis
Recherche en cours…
- Déplier/replier tout les statuts
- Ouvrir le pouet
+ Déplier/replier tout les statuts
+ Ouvrir le pouet
Un redémarrage de l’application est nécessaire
Vous devrez redémarrer Yuito pour appliquer ces modifications
Plus tard
@@ -352,15 +352,15 @@
- maximum de %1$d onglet atteint
- maximum de %1$d onglets atteint
- Média : %s
+ Média : %s
- Avertissement : %s
+ Avertissement : %s
- Pas de description
+ Pas de description
- Reblogué
+ Reblogué
- Mis en favoris
+ Mis en favoris
Public
@@ -374,12 +374,12 @@
Nettoyer
Filtrer
Appliquer
- Écrire un pouet
+ Écrire un message
Écrire
Afficher l\'indicateur de robots
Désirez-vous nettoyer toutes vos notifications de façon permanente \?
Effacer et ré-écrire
- Effacer et ré-écrire ce pouet \?
+ Effacer et ré-écrire ce pouet \?
Termina à %s
Terminé
Voter
@@ -389,19 +389,19 @@
Un sondage que vous avez créé est terminé
- %d jour restant
- - %d jours restant
+ - %d jours restants
- %d heure restant
- - %d heures restant
+ - %d heures restantes
- %d minute restant
- - %d minutes restant
+ - %d minutes restantes
- %d seconde restant
- - %d secondes restant
+ - %d secondes restantes
Activer l’animation des avatars
Actions pour l’image %s
@@ -420,7 +420,7 @@
Commentaires additionnels
Transférer à %s
Échec du signalement
- Échec de récupération des statuts
+ Échec de récupération des statuts
Le rapport sera envoyé aux modérateur·rice·s de votre instance. Vous pouvez expliquer pourquoi vous signalez le compte ci-dessous :
Êtes-vous sûr⋅e de vouloir bloquer %s en entier \? Vous ne verrez plus de contenu provenant de ce domaine, ni dans les fils publics, ni dans vos notifications. Vos abonné·e·s utilisant ce domaine seront retiré·e·s.
Terminé
@@ -430,7 +430,7 @@
Un mot-clé ou une phrase alphanumérique sera appliqué·e seulement s’il ou elle correspond au mot entier
Comptes
Échec de la recherche
- Toujours ouvrir les pouets avec un contenu sensible
+ Toujours ouvrir les messages ayant un contenu sensible
Ajouter un sondage
Sondage
5 minutes
@@ -444,22 +444,22 @@
Choix multiples
Choix %d
Éditer
- Pouets planifiés
+ Pouets planifiés
Éditer
- Pouets programmés
- Planifier le pouet
+ Pouets programmés
+ Planifier le pouet
Réinitialiser
Erreur lors de la recherche du post %s
Propulsé par Tusky
Signets
Marquer comme signet
Signets
- Ajouté aux signets
+ Ajouté aux signets
Sélectionner la liste
Liste
Les fichiers audio doivent avoir moins de 40 Mo.
Vous n’avez aucun brouillon.
- Vous n’avez aucun pouet planifié.
+ Vous n’avez aucun pouet planifié.
L’intervalle minimum de planification sur Mastodon est de 5 minutes.
Demandes d\'abonnement
Bloquer @%s \?
@@ -496,28 +496,28 @@
Votre note privée sur ce compte
Il n’y a pas d’annonce.
Annonces
- Certaines informations susceptibles d\'affecter votre bien-être mental seront cachées. Il s\'agit :
+ Certaines informations susceptibles d’affecter votre bien-être mental seront cachées. Il s’agit :
\n
\n - des notifications de favoris, de partage et de suivi
-\n - du compte des favoris/partages sur les pouets
+\n - du nombre des favoris/partages des messages
\n - des statistiques sur les profils
\n
-\n Les notifications \"push\" ne seront pas affectées, mais vous pouvez revoir vos préférences de notification manuellement.
- une personne que je suis a publié un nouveau pouet
+\n Les notifications « push » ne seront pas affectées, mais vous pouvez revoir vos préférences de notification manuellement.
+ un compte auquel je suis abonné·e a publié un nouveau message
%s vient de publier
Examiner les notifications
- Nouveaux pouets
+ Nouveaux messages
- - Vous ne pouvez pas téléverser plus de %1$d pièce jointe.
+ - Vous ne pouvez pas téléverser plus d’ %1$d pièce jointe.
- Vous ne pouvez pas téléverser plus de %1$d pièces jointes.
Bien-être
- Notifications quand quelqu\'un que vous suivez publie un nouveau pouet
- Limiter les notifications de la timeline
+ Notifications quand quelqu’un que vous suivez publie un nouveau message
+ Limiter les notifications du fil
Cacher les statistiques quantitatives sur les profils
Cacher les statistiques quantitatives sur les messages
Supprimer le marque-page
- Pièces jointes
+ Pièces jointes
Voulez-vous vraiment supprimer la liste %s \?
S’abonner
Supprimer cette conversation \?
@@ -527,10 +527,10 @@
Indéfinie
Se désabonner
Supprimer la conversation
- Audio
+ Audio
Demander confirmation avant de mettre en favoris
- Le message auquel répondait ce brouillon a été supprimé
- Échec d’envoi du pouet !
+ Le message auquel répondait ce brouillon a été supprimé
+ Échec d’envoi du pouet !
Bien que votre compte ne soit pas verrouillé, l’équipe de %1$s a pensé que vous voudriez valider manuellement les demandes de d’abonnement provenant de ces comptes.
Échec du chargement des informations de réponse
30 jours
@@ -539,4 +539,5 @@
365 jours
14 jours
180 jours
+ Rédiger un message
diff --git a/app/src/main/res/values-fy/strings.xml b/app/src/main/res/values-fy/strings.xml
index 69cc8b7dc..97ad4052e 100644
--- a/app/src/main/res/values-fy/strings.xml
+++ b/app/src/main/res/values-fy/strings.xml
@@ -6,10 +6,10 @@
Emoji styl
Nei it klemboerd kopiearre
Gearstelle
- Ferstjoeren ôfbrutsen
- Toots oan it ferstjoeren
- Flater by it ferstjoeren fan toot
- Toot oan it ferstjoeren…
+ Ferstjoeren ôfbrutsen
+ Toots oan it ferstjoeren
+ Flater by it ferstjoeren fan toot
+ Toot oan it ferstjoeren…
Skets bewarje\?
Fuortsmite
Ûnderskrift pleatse
@@ -42,12 +42,12 @@
oer %dm
oer %dh
oer %dd
- Taheaksels
- Lûd
- Fideo
- Ôfbyldingen
- Keppeling nei toot diele
- Ynhâld fan toot diele
+ Taheaksels
+ Lûd
+ Fideo
+ Ôfbyldingen
+ Keppeling nei toot diele
+ Ynhâld fan toot diele
Tusky %s
Oer
@@ -60,11 +60,11 @@
Favoriten
Folgfersyken
Nije Folgers
- Grutst
- Grut
- Gewoan
- Lyts
- Lytst
+ Grutst
+ Grut
+ Gewoan
+ Lyts
+ Lytst
Allinnich folgers
Iepenbier
Ûnder
@@ -78,7 +78,7 @@
Proksje
Media foarfertoaningen delhelje
Reaksjes sjen litte
- Ljepblêden
+ Ljepblêden
Taal
Webblêder
Systeem Opmaak Brûke
@@ -104,8 +104,8 @@
\@%s blokkearje\?
Folsleine domein ferbergje
Dit petear fuortsmite\?
- Dizze toot fuortsmite en opnij opstelle\?
- Dizze toot fuortsmite\?
+ Dizze toot fuortsmite en opnij opstelle\?
+ Dizze toot fuortsmite\?
Dit account net mear folgje\?
Folgfersyk ynlûke\?
Delhelje
@@ -117,15 +117,15 @@
Sykje…
Ynhâld warskôging
Wat bard der\?
- Reaksje mei sukses ferstjoerd.
- Ferstjoerd!
+ Reaksje mei sukses ferstjoerd.
+ Ferstjoerd!
%s net mear ferburgen
Brûker net mear negearre
Brûker net mear blokkearre
Ferstjoerd!
Media ferstjoere nei…
- Toot ferstjoere nei…
- Toot URL ferstjoere nei…
+ Toot ferstjoere nei…
+ Toot URL ferstjoere nei…
Media oan it delheljen
Media delhelje
Diele as…
@@ -137,11 +137,11 @@
Favoriten besjen
Keppelingen
Ljepblêd Tafoegje
- Toot ynplanne
+ Toot ynplanne
Emoji toetseboerd
Ynhâld warskôging
Toot sichtberheid
- Ynplanne toots
+ Ynplanne toots
Sketsen
Sykje
Net akseptearje
@@ -206,16 +206,16 @@
%s hat jo toot as favoryt oanmurken
Hjir is neat. Lûk nei ûnderen om te ferfarskjen!
Hjir is neat.
- Yntearre
- Ûttearre
- Minder sjen litte
- Mear sjen litte
- Klik om te besjen
- Media ferburgen
- Gefoelige ynhâld
- \@%s
+ Yntearre
+ Ûttearre
+ Minder sjen litte
+ Mear sjen litte
+ Klik om te besjen
+ Media ferburgen
+ Gefoelige ynhâld
+ \@%s
Lisinsjes
- Ynplanne toots
+ Ynplanne toots
Sketsen
Jo profyl oanpasse
Folgfersyken
@@ -226,9 +226,9 @@
Favoriten
Folgers
Folget
- Fêstset
- Mei reaksjes
- Berjochten
+ Fêstset
+ Mei reaksjes
+ Berjochten
Toot
Ljepblêden
Direkte Berjochten
diff --git a/app/src/main/res/values-ga/strings.xml b/app/src/main/res/values-ga/strings.xml
index f8730ab60..5cdf52f49 100644
--- a/app/src/main/res/values-ga/strings.xml
+++ b/app/src/main/res/values-ga/strings.xml
@@ -1,14 +1,14 @@
- Leathnaigh
- Taispeáin Níos Lú
- Taispeáin Níos Mó
- Cliceáil chun amharc
- Meáin i bhfolach
- Ábhar íogair
- threisigh %s
+ Leathnaigh
+ Taispeáin Níos Lú
+ Taispeáin Níos Mó
+ Cliceáil chun amharc
+ Meáin i bhfolach
+ Ábhar íogair
+ threisigh %s
Ceadúnais
- Tútanna sceidealta
+ Tútanna sceidealta
Cuir do phróifíl in eagar
Lean Iarrataí
Fearainn i bhfolach
@@ -17,8 +17,8 @@
Leabharmharcanna
Leanúna
Leanúna
- Greamaithe
- Le freagraí
+ Greamaithe
+ Le freagraí
Tút
Teachtaireachtaí Díreacha
Cónaidhme
@@ -64,8 +64,8 @@
Bloc @%s\?
Folaigh an fearann iomlán
An bhfuil tú cinnte gur mhaith leat gach %s a bhac\? Ní fheicfidh tú ábhar ón bhfearann sin in aon amlínte poiblí ná i d’fhógraí. Bainfear do leanúna ón bhfearann sin.
- An tút seo a scriosadh agus a dhréachtú\?
- Scrios an tút seo\?
+ An tút seo a scriosadh agus a dhréachtú\?
+ Scrios an tút seo\?
An cuntas seo a scaoileadh\?
An iarraidh seo a leanas a chúlghairm\?
Íoslódáil
@@ -81,15 +81,15 @@
Rabhadh ábhair
Cad atá ag tarlú\?
Cén cás\?
- Cuireadh an freagra go rathúil.
- Seolta!
+ Cuireadh an freagra go rathúil.
+ Seolta!
%s neamhcheangailte
Úsáideoir gan trácht
Úsáideoir gan bhac
Seolta!
Comhroinn na meáin le…
- Comhroinn tút chuig…
- Comhroinn URL tút chuig…
+ Comhroinn tút chuig…
+ Comhroinn URL tút chuig…
Meáin íoslódála
Íoslódáil na meáin
Comhroinn mar …
@@ -104,11 +104,11 @@
Buaicphointí
Naisc ghréasáin
Cuir Tab leis
- Tút a sceidealú
+ Tút a sceidealú
Méarchlár Emoji
Rabhadh ábhair
Infheictheacht tút
- Tútanna sceidealta
+ Tútanna sceidealta
Dréachtaí
Diúltaigh
Glac
@@ -182,9 +182,9 @@
Theip ar fhíordheimhniú leis an gcás sin.
Cad is sampla ann\?
Logáil isteach le Mastodon
- Íomhánna
- Comhroinn nasc le tút
- Comhroinn ábhar na tút
+ Íomhánna
+ Comhroinn nasc le tút
+ Comhroinn ábhar na tút
Próifíl Tusky
Is bogearraí foinse oscailte agus saor in aisce é Tusky. Tá sé ceadúnaithe faoi Leagan 3. Ceadúnas Poiblí Ginearálta GNU 3. Is féidir leat an ceadúnas a fheiceáil anseo: https://www.gnu.org/licenses/gpl-3.0.en.html
Cumhachtaithe ag Tusky
@@ -209,12 +209,12 @@
Leantóirí Nua
Fógraí faoi luanna nua
Tagairtí Nua
- Is mó
- Móra
- Mheán
- Beag
- Lúide
- Méid an téacs stádais
+ Is mó
+ Móra
+ Mheán
+ Beag
+ Lúide
+ Méid an téacs stádais
Leantóirí-amháin
Neamhliostaithe
Poiblí
@@ -233,7 +233,7 @@
Íoslódáil réamhamharcanna na meán
Taispeáin freagraí
Taispeáin borradh
- Scagadh amlíne
+ Scagadh amlíne
Taispeáin grádáin ildaite do na meáin i bhfolach
Beochan abhatár GIF
Taispeáin táscaire do róbónna
@@ -251,9 +251,9 @@
Chuir %s borradh faoi do tút
Níl aon rud anseo. Tarraingt anuas chun athnuachan a dhéanamh!
Níl aon rud anseo.
- Dlúth
+ Dlúth
Nuair atá an eochairfhocal nó an frása alfa-uimhriúil amháin, ní chuirfear i bhfeidhm é ach má oireann sé don fhocal iomlán
- Tútanna
+ Tútanna
Bhí %s i bhfabhar do tút
Unmute %s
Comhrá tost
@@ -270,7 +270,7 @@
\n https://tusky.app
Tuarascálacha ar fhabhtanna & iarratais ar ghnéithe:
\n https://github.com/tuskyapp/Tusky/issues
- Físeán
+ Físeán
Lean iarrtha
Leanann tú
Taispeáin ábhar íogair i gcónaí
@@ -287,7 +287,7 @@
Cuir scagaire in eagar
Bain
Amlínte poiblí
- Gach stádas a leathnú/a thit amach
+ Gach stádas a leathnú/a thit amach
Beidh ort Tusky a atosú chun na hathruithe seo a chur i bhfeidhm
Sraith emoji reatha Google
Tá cód agus sócmhainní ó na tionscadail foinse oscailte seo a leanas i Tusky:
@@ -307,7 +307,7 @@
- D\'imigh %d nóiméad
- D\'imigh %d nóiméad
- Theip ar stádas a fháil
+ Theip ar stádas a fháil
Seolfar an tuarascáil chuig do mhodhnóir freastalaí. Féadfaidh tú míniú a thabhairt ar an bhfáth go bhfuil tú ag tuairisciú an chuntais seo thíos:
Cuir Cuntas Mastodon nua leis
Liostaigh amlíne
@@ -332,11 +332,11 @@
Cuntas glasála
Éilíonn ort leanúna a cheadú de láimh
Sábháil dréacht\?
- Tút a sheoladh…
- Earráid agus an tút á sheoladh
- Tútanna a sheoladh
- Seoladh curtha ar ceal
- Sábháladh cóip den tút ar do dhréachtaí
+ Tút a sheoladh…
+ Earráid agus an tút á sheoladh
+ Tútanna a sheoladh
+ Seoladh curtha ar ceal
+ Sábháladh cóip den tút ar do dhréachtaí
Cum
Níl aon emojis saincheaptha ag do shampla %s
Cóipeáladh chuig an gearrthaisce
@@ -344,7 +344,7 @@
Réamhshocrú an chórais
Beidh ort na tacair emoji seo a íoslódáil ar dtús
Amharc taibhithe…
- Oscail tút
+ Oscail tút
Atosú aip de dhíth
Níos déanaí
Atosaigh
@@ -380,11 +380,11 @@
Ainmnithe ag
%1$s agus %2$s
%1$s, %2$s agus %3$d níos mó
- Meáin: %s
- Rabhadh ábhair: %s
- Gan tuairisc
- Ainmnithe
- Leabharmharcáilte
+ Meáin: %s
+ Rabhadh ábhair: %s
+ Gan tuairisc
+ Ainmnithe
+ Leabharmharcáilte
Poiblí
Neamhliostaithe
Leanúna
@@ -464,17 +464,17 @@
Cuir in Eagar
Earráid agus an post á lorg %s
Níl aon dréachtaí agat.
- Níl aon stádas sceidealta agat.
+ Níl aon stádas sceidealta agat.
Tá eatramh sceidealaithe íosta 5 nóiméad ag Mastodon.
Taispeáin réamhamhairc nasc in amlínte
Taispeáin dialóg dearbhaithe sula ndéantar borradh faoi
Cluaisíní
- \@%s
+ \@%s
Tost %s
Unmute %s
Comhrá unmute
Tost @%s\?
- Cluaisíní
+ Cluaisíní
in %dy
in %dd
in %dh
@@ -490,6 +490,6 @@
CC-BY-SA 4.0
Unpin
%1$s
- Reblogged
+ Reblogged
Hashtags
\ No newline at end of file
diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml
index 56576a155..b55faa6c2 100644
--- a/app/src/main/res/values-gd/strings.xml
+++ b/app/src/main/res/values-gd/strings.xml
@@ -55,12 +55,12 @@
Cuir crìoch air an fho-sgrìobhadh
Fo-sgrìobh
Beòthaich na h-Emojis gnàthaichte
- Bha againn ris a’ phost a bha thu airson freagairt dha a thoirt air falbh
+ Bha againn ris a’ phost a bha thu airson freagairt dha a thoirt air falbh
Chaidh an dreach a sguabadh às
Cha deach leinn fiosrachadh na freagairte a luchdadh
- Cha b’ urrainn dhuinn an dùd a chur!
- Ceanglachain
- Fuaim
+ Cha b’ urrainn dhuinn am post a chur!
+ Ceanglachain
+ Fuaim
A bheil thu cinnteach gu bheil thu airson an liosta %s a sguabadh às\?
7 làithean
3 làithean
@@ -81,12 +81,12 @@
Falaich an stadastaireachd àireamhail air postaichean
Cuingich na brathan mun loidhne-ama
Thoir sùil air na brathan
- Thèid cuid a dh’fhiosrachadh a dh’fhaodadh droch-bhuaidh a thoirt air d’ shlàinte-inntinn fhalach. Tha seo a’ gabhail a-staigh:
-\n
-\n - Brathan air annsachdan/brosnachaidhean/leantainn
-\n - Cunntas nan annsachdan/brosnachaidhean air postaichean
-\n - Stadastaireachd an luchd-leantainn/nam postaichean air pròifilean
-\n
+ Thèid cuid a dh’fhiosrachadh a dh’fhaodadh droch-bhuaidh a thoirt air d’ shlàinte-inntinn fhalach. Tha seo a’ gabhail a-staigh:
+\n
+\n - Brathan air annsachdan/brosnachaidhean/leanntainn
+\n - Cunntas nan annsachdan/brosnachaidhean air postaichean
+\n - Stadastaireachd an luchd-leantainn/nam postaichean air pròifilean
+\n
\n Cha doir seo buaidh air na brathan-putaidh ach ’s urrainn dhut roghainnean nam brathan agad atharrachadh a làimh.
Slàinte-inntinn
Brathan nuair a dh’fhoillsich cuideigin air a rinn mi fo-sgrìobhadh post ùr
@@ -103,8 +103,8 @@
Dì-mhùch na brathan o %s
Seall còmhradh dearbhaidh mus dèan thu brosnachadh
Seall ro-sheallaidhean air ceanglaichean sna loidhnichean-ama
- Feumaidh co-dhiù 5 mionaidean a bhith eadar staidean sgeidealaichte air Mastodon.
- Chan eil staid sam bith air an sgeideal agad.
+ Feumaidh co-dhiù 5 mionaidean a bhith eadar postaichean sgeidealaichte air Mastodon.
+ Chan eil post sam bith air an sgeideal agad.
Chan eil dreachd sam bith agad.
Thachair mearachd le lorg a’ phuist %s
Roghainn %d
@@ -117,7 +117,7 @@
Cunntasan
Chaidh an cunntas a chlàradh air frithealaiche eile. A bheil thu airson lethbhreac dhen ghearan a chur dha-san gun ainm cuideachd\?
Thèid do ghearan a chur gu maor an fhrithealaiche agad. ’S urrainn dhut mìneachadh a sholar air carson a tha thu a’ gearan mun chunntas gu h-ìosal:
- Cha b’ urrainn dhuinn na staidean fhaighinn
+ Cha b’ urrainn dhuinn na postaichean fhaighinn
Cha b’ urrainn dhuinn do ghearan a chlàradh
Sìn air adhart gu %s
Beachdan a bharrachd
@@ -180,12 +180,12 @@
Ainm na liosta
Cunntas-bheachd le roghainnean: %1$s, %2$s, %3$s, %4$s; %5$s
Dìreach
- ’Na chomharra-lìn
- ’Na annsachd
- Air ath-bhlogadh
- Gun tuairisgeul
- Rabhadh susbainte: %s
- Meadhan: %s
+ ’Na chomharra-lìn
+ ’Na annsachd
+ Air ath-bhlogadh
+ Gun tuairisgeul
+ Rabhadh susbainte: %s
+ Meadhan: %s
- ràinig thu na tha ceadaichte dhe %1$d taba
- ràinig thu na tha ceadaichte dhe %1$d thaba
@@ -233,26 +233,29 @@
Uaireigin eile
Feumaidh tu Tusky ath-thòiseachadh gus na roghainnean seo a chur an sàs
Feumaidh tu an aplacaid ath-thòiseachadh
- Fosgail am post
- Leudaich/Co-theannaich gach staid
+ Fosgail am post
+ Leudaich/Co-theannaich gach post
’Ga lorg…
Feumaidh tu na seataichean seo de dh’Emojis a luchdadh a-nuas an toiseach
Bun-roghainn an t-siostaim
Stoidhle nan Emojis
Chaidh lethbhreac dheth a chur air an stòr-bhòrd
Chan eil Emojis gnàthaichte aig an ionstans %s agad
- Chaidh lethbhreac dhen phost agad a shàbhaladh ’na dhreachd
- Chaidh sgur dhen chur
- A’ cur nam post
- Mearachd a’ cur a’ phuist
- A’ cur a’ phuist…
+ Chaidh lethbhreac dhen phost agad a shàbhaladh ’na dhreachd
+ Chaidh sgur dhen chur
+ A’ cur nam post
+ Mearachd a’ cur a’ phuist
+ A’ cur a’ phuist…
A bheil thu airson a shàbhaladh ’na dhreachd\?
Feumaidh tu gabhail ri luchd-leantainn ùr a làimh
Glais an cunntas
Suidhidh am fo-thiotal
- - Mìnich e dhan fheadhainn air a bheil cion-lèirsinn
+
- Mìnich e dhan fheadhainn air a bheil cion-lèirsinn
\n(%d caractar(an) air a char as fhaide)
+
+
+
Cha deach leinn am fo-thiotal a shuidheachadh
A’ postadh leis a’ chunntas %1$s
@@ -271,29 +274,29 @@
An abairt ri chriathradh
Mur eil ach litrichean is àireamhan san fhacal-luirg, cha dèid a chur an sàs ach ma bhios e a’ maidseadh an fhacail shlàin
Leudaich postaichean ris a bheil rabhadh susbainte an-còmhnaidh
- Co-roinn ceangal dhan phost
- Co-roinn susbaint a’ phuist
+ Co-roinn ceangal dhan phost
+ Co-roinn susbaint a’ phuist
’S e bathar-bog saor le bun-tùs fosgailte a th’ ann an Tusky. Tha e fo cheadachas GNU General Public License tionndadh 3. Chì thu an ceadachas an-seo: https://www.gnu.org/licenses/gpl-3.0.en.html
Brathan nuair a thèid post agad a chomharrachadh ’na annsachd
Brathan nuair a thèid post agad brosnachadh
- A bheil thu airson am post seo a sguabadh às is dreachd ùr a dhèanamh air\?
- A bheil thu airson am post seo a sguabadh às\?
- ’S urrainn dhut seòladh no àrainn-lìn aig ionstans sam bith a chur a-steach an-seo, can mastodon.social, icosahedron.website, social.tchncs.de agus a bharrachd!
+ A bheil thu airson am post seo a sguabadh às is dreachd ùr a dhèanamh air\?
+ A bheil thu airson am post seo a sguabadh às\?
+ ’S urrainn dhut seòladh no àrainn-lìn aig ionstans sam bith a chur a-steach an-seo, can mastodon.social, icosahedron.website, social.tchncs.de agus a bharrachd!
\n
\nMur eil cunntas agad fhathast, cuir a-steach ainm an ionstans sa bheil thu airson ballrachd fhaighinn airson cunntas a chruthachadh ann.
\n
-\n’S e an t-aon àite far an cruthaich thu cunntas a th’ ann an ionstans ud ’s a nì an t-òstadh dhan chunntas agad. Gidheadh, ’s urrainn dhut conaltradh le daoine a tha air ionstans eile agus leantainn orra mar gun robh sibh air an aon làrach.
+\n’S e an t-aon àite far an cruthaich thu cunntas a th’ ann an ionstans ud ’s a nì an t-òstadh dhan chunntas agad. Gidheadh, ’s urrainn dhut conaltradh le daoine a tha air ionstans eile agus leantainn orra mar gun robh sibh air an aon làrach.
\n
\nGheibh thu barrachd fiosrachaidh air joinmastodon.org.
- Co-roinn am post le…
- Co-roinn URL a’ phuist le…
- Cuir post air an sgeideal
+ Co-roinn am post le…
+ Co-roinn URL a’ phuist le…
+ Cuir post air an sgeideal
Faicsinneachd a’ phuist
- Postaichean air an sgeideal
+ Postaichean air an sgeideal
Chuir %s am post agad ris na h-annsachdan
Bhrosnaich %s am post agad
- Postaichean air an sgeideal
- Post
+ Postaichean air an sgeideal
+ Snàithlean
Mearachd a’ cur a’ phuist.
Dì-mhùch %s
Tagaichean hais
@@ -324,8 +327,8 @@
an ceann %dl
an ceann %db
Iarrar leantainn orm
- Videothan
- Dealbhan
+ Videothan
+ Dealbhan
Pròifil Tusky
Aithrisean air bugaichean ⁊ iarrtasan air gleusan:
\n https://github.com/tuskyapp/Tusky/issues
@@ -353,12 +356,12 @@
Luchd-leantainn ùr
Brathan mu iomraidhean ùra
Iomraidhean ùra
- As motha
- Mòr
- Meadhanach
- Beag
- As lugha
- Meud teacsa na staid
+ As motha
+ Mòr
+ Meadhanach
+ Beag
+ As lugha
+ Meud teacsa nam post
Luchd-leantainn a-mhàin
Neo-liostaichte
Poblach
@@ -376,8 +379,8 @@
Progsaidh
Luchdaich a-nuas ro-sheallaidhean air meadhanan
Seall na freagairtean
- Tabaichean
- Criathradh na loidhne-ama
+ Tabaichean
+ Criathradh na loidhne-ama
Seall caiseadan dathte an àite meadhanan falaichte
Beothaich avataran GIF
Seall taisbeanair do bhotaichean
@@ -423,8 +426,8 @@
Avatar
Chan eil toradh ann
Cò an t-ionstans\?
- Chaidh an fhreagairt a chur.
- Chaidh a chur!
+ Chaidh an fhreagairt a chur.
+ Chaidh a chur!
Chan eil %s falaichte tuilleadh
Chaidh an cleachdaiche dhì-mhùchadh
Chaidh an cleachdaiche a dhì-bhacadh
@@ -485,15 +488,15 @@
Lean %s ort
Chan eil dad an-seo. Tarraing a-nuas airson ath-nuadhachadh!
Chan eil dad an-seo.
- Co-theannaich
- Leudaich
- Seall nas lugha dheth
- Seall barrachd dheth
- Briog air gus a shealltainn
- Meadhanan falaichte
- Susbaint fhrionasach
- ’Ga bhrosnachadh le %s
- \@%s
+ Co-theannaich
+ Leudaich
+ Seall nas lugha dheth
+ Seall barrachd dheth
+ Briog air gus a shealltainn
+ Meadhanan falaichte
+ Susbaint fhrionasach
+ ’Ga bhrosnachadh le %s
+ \@%s
Ceadachasan
Iarrtasan leantainn
Àrainnean falaichte
@@ -502,16 +505,16 @@
Comharran-lìn
Luchd-leantainn
A’ leantainn air
- Prìnichte
- Le freagairt
- Postaichean
+ Prìnichte
+ Le freagairt
+ Postaichean
Tabaichean
Teachdaireachdan dìreach
Co-naisgte
Ionadail
Dachaigh
Dh’fhàillig leis an luchdadh suas.
- Chan urrainn dhut an dà chuid dealbhan is videothan a cheangal ris an aon staid.
+ Chan urrainn dhut an dà chuid dealbhan is videothan a cheangal ris an aon phost.
Tha feum air cead gus meadhanan a stòradh.
Tha feum air cead gus meadhanan a leughadh.
Cha b’ urrainn dhuinn am faidhle sin fhosgladh.
@@ -519,7 +522,7 @@
Feumaidh faidhlichean fuaime a bhith nas lugha na 40MB.
Feumaidh faidhlichean video a bhith nas lugha na 40MB.
Feumaidh am faidhle a bhith nas lugha na 8MB.
- Tha an staid ro fhada!
+ Tha am post ro fhada!
Cha deach leinn tòcan clàraidh a-steach fhaighinn.
Chaidh an t-ùghdarrachadh a dhiùltadh.
Thachair mearachd leis an ùghdarrachadh nach do dh’aithnich sinn.
@@ -540,4 +543,5 @@
365 latha
14 làithean
60 latha
+ Sgrìobh post
\ No newline at end of file
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index dbf0f5b85..e99b718a8 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -1,8 +1,8 @@
Aviso sobre o contido
- Visibilidade do toot
- Toots programados
+ Visibilidade da publicación
+ Toots programados
Borradores
Buscar
Rexeitar
@@ -69,22 +69,22 @@
%s publicou agora
%s solicitou seguirte
%s seguiute
- %s fixo favorito o teu toot
- %s promoveu o teu toot
+ %s fixo favorita a publicación
+ %s promoveu a túa publicación
Nada por aquí. Arrastra hacia abaixo para actualizar!
Nada por aquí.
- Pregar
- Expandir
- Amosar menos
- Amosar máis
- Click para ver
- Multimedia agochado
- Contido sensible
- %s promoveu
- \@%s
+ Pregar
+ Expandir
+ Ver menos
+ Ver máis
+ Click para ver
+ Multimedia agochado
+ Contido sensible
+ %s promoveu
+ \@%s
Licenzas
Anuncios
- Toots programados
+ Toots programados
Borradores
Edita o teu perfil
Solicitudes de seguimento
@@ -95,19 +95,19 @@
Favoritos
Seguidoras
Segue
- Fixado
- Con resposta
- Publicacións
- Toot
+ Fixado
+ Con resposta
+ Publicacións
+ Fío
Lapelas
Mensaxes directas
Federada
Local
Notificacións
Inicio
- Erro ao enviar o toot.
+ Erro ao enviar a publicación.
Fallou a subida.
- As imaxes e vídeo non poden engadirse simultáneamente a un mesmo estado.
+ As imaxes e vídeo non poden engadirse simultáneamente á mesma publicación.
Requírese o permiso de almacenaxe do multimedia.
Requírese o permiso de lectura do multimedia.
Non se puido abrir o ficheiro.
@@ -115,7 +115,7 @@
Os ficheiros de audio teñen que ser menores de 40MB.
Os ficheiros de vídeo teñen que ser menores de 40MB.
O ficheiro debe ser menor de 8MB.
- O estado é demasiado longo!
+ A publicación é demasiado longa!
Fallou a obtención do token de conexión.
A autorización foi rexeitada.
Aconteceu un erro non identificado de autorización.
@@ -128,7 +128,7 @@
%1$s
Desubscribir
Subscribir
- Eliminouse o toot para o que redactaches a resposta
+ Eliminouse o toot para o que redactaches a resposta
Sen límite
Duración
Enquisa
@@ -138,7 +138,7 @@
Contas
A conta pertence a outro servidor. Queres enviar unha copia anónima da denuncia alí tamén\?
A denuncia vaise enviar á moderación do teu servidor. Podes engadir algunha explicación ou razón pola que estás denunciando a conta:
- Fallou a obtención dos estados
+ Fallou a obtención dos estados
Fallo ao realizar a denuncia
Reenviar a %s
Comentarios adicionais
@@ -179,7 +179,7 @@
Accións para a imaxe %s
Tes a certeza de que queres borrar permanentemente todas as notificacións\?
Redactar
- Redactar Toot
+ Redactar publicación
Aplicar
Filtrar
Despexar
@@ -194,12 +194,12 @@
Seguidoras
Non listado
Público
- Marcado
- Favorecido
- Repetido
- Sen descrición
- Aviso sobre o contido: %s
- Multimedia: %s
+ Marcado
+ Favorecido
+ Repetido
+ Sen descrición
+ Aviso sobre o contido: %s
+ Multimedia: %s
- acadouse o máximo de %1$d lapela
- acadouse o máximo de %1$d lapelas
@@ -241,8 +241,8 @@
Máis tarde
Deberás reiniciar Tusky para aplicar os cambios
Require reiniciar app
- Abrir toot
- Expandir/Pregar tódolos estados
+ Abrir toot
+ Expandir/Pregar tódolos estados
Realizando a busca…
Deberás descargar primeiro estos conxuntos de emojis
Por defecto no sistema
@@ -250,11 +250,11 @@
Copiado ao portapapeis
A túa instancia %s non ten emojis personalizados
Redactar
- Gardouse unha copia do toot nos borradores
- Envío cancelado
- Enviando Toots
- Erro ao enviar o toot
- Enviando Toot…
+ Gardouse unha copia do toot nos borradores
+ Envío cancelado
+ Enviando Toots
+ Erro ao enviar o toot
+ Enviando Toot…
Gardar borrador\?
Require que aprobes manualmente as seguidoras
Bloquear conta
@@ -293,7 +293,7 @@
cargar máis
Respondendo a @%s
Multimedia
- Expandir sempre toots marcados con avisos sobre o contido
+ Despregar sempre publicacións marcadas con avisos sobre o contido
Mostrar sempre contido sensible
Séguete
%ds
@@ -307,12 +307,12 @@
en %dd
en %dy
Seguimento solicitado
- Anexos
- Audio
- Vídeo
- Imaxes
- Compartir ligazón ao toot
- Compartir contido do toot
+ Anexos
+ Audio
+ Vídeo
+ Imaxes
+ Compartir ligazón ao toot
+ Compartir contido do toot
Perfil de Tusky
Informar de fallos e solicitar funcións:
\n https://github.com/tuskyapp/Tusky/issues
@@ -331,13 +331,13 @@
%1$s, %2$s, e %3$s
%1$s, %2$s, %3$s e %4$d outras
%s mencionoute
- Notificacións cando alguén a quen estás subscrita publica un novo toot
- Novos toots
+ Notificacións cando alguén a quen estás subscrita publica novo contido
+ Novas publicacións
Notificacións cando rematan as enquisas
Enquisas
- Notificacións cando os teus toots son marcados como favoritos
+ Notificacións cando as túas publicacións son favorecidas
Favoritos
- Notificacións cando os teus toots son promovidos
+ Notificacións cando as túas publicacións sexan promovidas
Promocións
Notificación acerca de solicitudes de seguimento
Solicitudes de seguimento
@@ -345,12 +345,12 @@
Novas seguidoras
Notificación de novas mencións
Novas mencións
- O máis grande
- Grande
- Medio
- Pequeno
- O máis pequeno
- Tamaño do texto do estado
+ O máis grande
+ Grande
+ Medio
+ Pequeno
+ O máis pequeno
+ Tamaño do texto do estado
Só seguidoras
Non listado
Público
@@ -369,8 +369,8 @@
Descarga vista previa do multimedia
Mostar respostas
Mostrar promocións
- Lapelas
- Filtros na cronoloxía
+ Lapelas
+ Filtros na cronoloxía
Animar emojis personalizados
Mostra gradientes coloridos para multimedia oculto
Animar avatares GIF
@@ -388,7 +388,7 @@
Cronoloxías
Decorado da app
Aparencia
- alguén a quen eu siga publique un toot
+ alguén a quen eu siga publique novo contido
rematen as enquisas
marquen un toot meu como favorito
promocionen un dos meus toots
@@ -411,8 +411,8 @@
Bloquear @%s\?
Agochar todo o dominio
Tes a certeza de querer bloquear a todo %s\? Non verás o contido dese dominio en ningunha cronoloxía pública ou nas notificacións. As túas seguidoras nese dominio serán eliminadas.
- Eliminar e reescribir este toot\?
- Eliminar este toot\?
+ Eliminar e reescribir este toot\?
+ Eliminar este toot\?
Deixar de seguir esta conta\?
Revogar a solicitude de seguimento\?
Descargar
@@ -438,7 +438,7 @@
Que contas\?
Borrador eliminado
Fallou a carga da información da Resposta
- Fallou o envío do toot!
+ Fallou o envío do toot!
Tes a certeza de querer eliminar a listaxe %s\?
- Non podes subir máis de %1$d anexo multimedia.
@@ -451,7 +451,7 @@
Agocharemos algunha información que podería afectar ao teu benestar mental. Esto inclúe:
\n
\n- Notificacións acerca de Favoritos/Promocións/Seguimentos
-\n- Número de Favoritos/Promocións nos toots
+\n- Número de Favoritos/Promocións nas publicacións
\n- Estatísticas de Seguidoras/Publicacións nos perfís
\n
\nAs notificacións tipo push non estarán afectadas, mais podes revisar as preferencias de notificacións manualmente.
@@ -459,11 +459,11 @@
Nota privada acerca desta conta
Benestar
Agochar o título da barra de ferramentas superior
- Amosar diálogo de confirmación antes de promover
- Amosar vista previa das ligazóns nas cronoloxías
+ Pedir confirmación antes de promover
+ Ver vista previa das ligazóns nas cronoloxías
Mastodon ten un intervalo mínimo de 5 minutos para as programacións.
Non hai anuncios.
- Non tes estados programados.
+ Non tes estados programados.
Non tes borradores.
Erro ao buscar publicación %s
Editar
@@ -478,15 +478,15 @@
30 minutos
5 minutos
En que instancia\?
- Resposta enviada correctamente.
- Enviado!
+ Resposta enviada correctamente.
+ Enviado!
%s visible
Usuaria reactivada
Usuaria desbloqueada
Enviado!
Compartir multimedia en…
- Compartir toot en…
- Compartir URL do toot a…
+ Compartir toot en…
+ Compartir URL do toot a…
Descargando multimedia
Descargar multimedia
Compartir como …
@@ -505,11 +505,18 @@
Ligazóns
Engadir lapela
Restablecer
- Programar Toot
+ Programar Toot
Teclado Emoji
Aínda que a túa conta non está bloqueada, a administración de %1$s opina que debes revisar manualmente as peticións de seguimento destas contas.
Eliminar esta conversa\?
Eliminar conversa
Eliminar marcador
Mostrar diálogo de confirmación antes de favorecer
+ 14 días
+ 30 días
+ 60 días
+ 90 días
+ 180 días
+ 365 días
+ Redactar publicación
\ No newline at end of file
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index ddd50890a..d6b7f8ca8 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -9,7 +9,7 @@
प्रोफाइल एडिट करें
खोज
के बारे में
- उत्तरों के साथ
+ उत्तरों के साथ
अनुगामी
उत्तर दें
फ़ॉलो
@@ -60,8 +60,8 @@
वोट
बन्द है
लिखें
- पिन की गई
- पोस्ट
+ पिन की गई
+ पोस्ट
घर
टस्की में निम्नलिखित ओपन सोर्स परियोजनाओं से कोड और संपत्ति हैं:
इन परिवर्तनों को लागू करने के लिए आपको टस्की को पुनः आरंभ करना होगा
@@ -79,11 +79,11 @@
%1$s, %2$s, %3$s तथा %4$d अन्य लोग
जनमत
पसंदीदा
- सबसे बड़ा
- बड़ा
- मध्यम
- छोटा
- सबसे छोटा
+ सबसे बड़ा
+ बड़ा
+ मध्यम
+ छोटा
+ सबसे छोटा
असूचीबद्ध
सार्वजनिक
सबसे नीचे
@@ -94,7 +94,7 @@
डिफ़ॉल्ट पोस्ट गोपनीयता
मीडिया पूर्वावलोकन डाउनलोड करें
जवाब दिखाएँ
- टैब्स
+ टैब्स
छिपे हुए मीडिया के लिए रंगीन ग्रेडिएंट दिखाएं
बॉट्स के लिए संकेतक दिखाएं
भाषा
@@ -132,8 +132,8 @@
प्रदर्शित होने वाला नाम
विषय वस्तु चेतावनी
क्या हो रहा है\?
- उत्तर सफलतापूर्वक भेजा गया।
- भेज दिया!
+ उत्तर सफलतापूर्वक भेजा गया।
+ भेज दिया!
भेज दिया!
मीडिया डाउनलोड हो रहा है
मीडिया डाउनलोड करें
@@ -146,11 +146,11 @@
हैशटैग
ज़िक्र
ऐड टैब
- अनुसूची टूट
+ अनुसूची टूट
इमोजी कीबोर्ड
विषय वस्तु चेतावनी
टूट दृश्यता
- अनुसूचित टूट
+ अनुसूचित टूट
स्वीकार करें
ड्राफ्ट
अस्वीकार करें
@@ -180,15 +180,15 @@
%s ने आपके टूट को बढावा दिया
यहाँ कुछ नहीं। ताज़ा करने के लिए नीचे खींचो!
यहाँ कुछ नहीं।
- कम दिखाएं
- और दिखाओ
- देखने के लिए क्लिक करें
- मीडिया छिपा हुआ
- संवेदनशील विषय वस्तु
- \@%s
+ कम दिखाएं
+ और दिखाओ
+ देखने के लिए क्लिक करें
+ मीडिया छिपा हुआ
+ संवेदनशील विषय वस्तु
+ \@%s
लाइसेंस
टूट
- अनुसूचित टूट
+ अनुसूचित टूट
छिपे हुए डोमेन
म्यूट किए गए उपयोगकर्ता
बुकमार्क
@@ -229,22 +229,22 @@
हैशटैग
%1$s • %2$s
सूची
- बुकमार्क किया हुआ
+ बुकमार्क किया हुआ
सूची का नाम
- कोई विवरण नहीं
- मीडिया: %s
+ कोई विवरण नहीं
+ मीडिया: %s
जानकारी जोड़ें
CC-BY-SA 4.0
CC-BY 4.0
प्रोफ़ाइल मेटाडेटा
डाउनलोड विफल
- टूट खोलें
+ टूट खोलें
देखने की क्रिया जारी…
सिस्टम डिफ़ॉल्ट
इमोजी का अंदाज
- भेजना रद्द हो गया
- टूट भेज रहे
- टूट भेज रहे…
+ भेजना रद्द हो गया
+ टूट भेज रहे
+ टूट भेज रहे…
लिखने को सुरक्षित करें\?
खाता लॉक करें
कैप्शन सेट करें
@@ -279,7 +279,7 @@
प्रत्यक्ष
असूचीबद्ध
सार्वजनिक
- विषय वस्तु चेतावनी: %s
+ विषय वस्तु चेतावनी: %s
- अधिकतम %1$d टैब तक पहुंच गऐ
@@ -308,8 +308,8 @@
आपको पहले इस इमोजी सेट को डाउनलोड करना होगा
क्लिपबोर्ड पर कॉपी किया गया
लिखें
- टूट की एक प्रति आपके ड्राफ्ट में सहेज ली गई है
- टूट भेजने में त्रुटि
+ टूट की एक प्रति आपके ड्राफ्ट में सहेज ली गई है
+ टूट भेजने में त्रुटि
हटाएँ
हटा दें
@@ -339,10 +339,10 @@
आपको फॉलो करते है
फ़ॉलो करने का अनुरोध किया
फ़ॉलो करने का अनुरोध किया हुआ
- वीडियो
- तस्वीरें
- टूट का लिंक साझा करें
- टूट की विषय वस्तु साझा करें
+ वीडियो
+ तस्वीरें
+ टूट का लिंक साझा करें
+ टूट की विषय वस्तु साझा करें
%s ने आपका जिक्र किया
जनमत खत्म होने के बारे में सूचनाएं
सूचनाएं जब आपके टूट पसंद किये जाये
@@ -356,7 +356,7 @@
एच टी टी पी प्रॉक्सी सक्षम करें
एच टी टी पी प्रॉक्सी
प्रॉक्सी
- टाइमलाइन छानने का काम
+ टाइमलाइन छानने का काम
प्रकाश
टाइमलाइन
एप्लिकेशन थीम
@@ -368,8 +368,8 @@
उपयोगकर्ता अनम्यूट किए गए
उपयोगकर्ता अनब्लॉक किए गए
मीडिया को साझा करें …
- टूट को साझा करें …
- टूट यूआरएल को साझा करें …
+ टूट को साझा करें …
+ टूट यूआरएल को साझा करें …
साझा करें …
%s के रूप में खोलें
%1$s डाउनलोड हो रहा है
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 820a69242..b6ace6eef 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -26,9 +26,9 @@
Közvetlen üzenetek
Fülek
Tülk
- Tülkök
- Válaszokkal
- Rögzített
+ Tülkök
+ Válaszokkal
+ Rögzített
Követett
Követő
Kedvencek
@@ -38,15 +38,15 @@
Profilod szerkesztése
Piszkozatok
Licenszek
- \@%s
- %s megtolta
- Kényes tartalom
- Rejtett média
- Kattints a megnézéshez
- Mutass többet
- Mutass kevesebbet
- Kibontás
- Összecsukás
+ \@%s
+ %s megtolta
+ Kényes tartalom
+ Rejtett média
+ Kattints a megnézéshez
+ Mutass többet
+ Mutass kevesebbet
+ Kibontás
+ Összecsukás
Nincs itt semmi.
Üres tartalom. Húzd le a frissítéshez!
%s megtolta a tülködet
@@ -115,13 +115,13 @@
Link másolása
Megnyitás mint %s
Megosztás mint …
- Tülk URL megosztása…
- Tülk megosztása…
+ Tülk URL megosztása…
+ Tülk megosztása…
Elküldve!
Felhasználó letiltása feloldva
Felhasználó némítása feloldva
- Elküldve!
- Válasz sikeresen elküldve.
+ Elküldve!
+ Válasz sikeresen elküldve.
Melyik példány\?
Mi jár a fejedben\?
Tartalom figyelmeztetés
@@ -146,7 +146,7 @@
Letöltés
Visszavonod a követési kérelmet?
Követés megszüntetése?
- Törlöd ezt a tülköt?
+ Törlöd ezt a tülköt?
Nyilvános: Tülkölés nyilvános idővonalra
Listázatlan: Nem jelenik meg a nyilvános idővonalon
Csak követőknek: Tülkölés csak követőknek
@@ -171,8 +171,8 @@
Böngésző
Linkek megnyitása applikáción belül
Szerkesztés gomb elrejtése görgetés közben
- Idővonal szűrése
- Fülek
+ Idővonal szűrése
+ Fülek
Megtolások mutatása
Válaszok mutatása
Média előnézet mutatása
@@ -187,12 +187,12 @@
Nyilvános
Listázatlan
Csak követőknek
- Tülkölés szöveg mérete
- Legkisebb
- Kicsi
- Közepes
- Nagy
- Legnagyobb
+ Tülkölés szöveg mérete
+ Legkisebb
+ Kicsi
+ Közepes
+ Nagy
+ Legnagyobb
Új említések
Értesítések új említések esetén
Új követők
@@ -224,10 +224,10 @@
Hibajelentés & új funkciók igénylése:
\n https://github.com/accelforce/Yuito/issues
Yuito profilja
- Tülk tartalmának megosztása
- Tülk linkjének megosztása
- Képek
- Videók
+ Tülk tartalmának megosztása
+ Tülk linkjének megosztása
+ Képek
+ Videók
Követés kérelmezve
Követ téged
@@ -241,11 +241,11 @@
Törlés
Fiók zárolása
Elmented a piszkozatot\?
- Tülk elküldése…
- A tülk elküldése nem sikerült
- Tülkök elküldése
- Küldés megszakítva
- A tülk másolatát elmentettük a piszkozataid közé
+ Tülk elküldése…
+ A tülk elküldése nem sikerült
+ Tülkök elküldése
+ Küldés megszakítva
+ A tülk másolatát elmentettük a piszkozataid közé
Szerkesztés
A %s szervernek nincsenek egyedi emoji-jai
Vágólapra másolva
@@ -253,7 +253,7 @@
Rendszer alapértelmezés
Először le kell töltened ezeket az emoji készleteket
Keresés…
- Tülk megnyitása
+ Tülk megnyitása
Az app újraindítása szükséges
A beállítások érvényesítéséhez újra kell indítani a Tuskyt
Később
@@ -280,7 +280,7 @@
- elérted a fülek maximális számát (%1$d)
- elérted a fülek maximális számát (%1$d)
- Nincs leírás
+ Nincs leírás
Nyilvános
Követők
@@ -290,7 +290,7 @@
Média letöltése
Média letöltése
Média megosztása következővel…
- Törlöd és újraírod ezt a tülköt\?
+ Törlöd és újraírod ezt a tülköt\?
befejeződött egy szavazás
Szűrők
Rendszer téma használata
@@ -350,7 +350,7 @@
Cím beállítása
Minden követődet külön engedélyezned kell
- Minden tülk kibontása/összecsukása
+ Minden tülk kibontása/összecsukása
A Google jelenlegi emodzsi készlete
Megtolás az eredeti közönségnek
Megtolás visszavonása
@@ -367,10 +367,10 @@
%1$s
%1$s, %2$s és még %3$d
- Média: %s
- Tartalom figyelmeztetés: %s
- Megtolt
- Kedvelt
+ Média: %s
+ Tartalom figyelmeztetés: %s
+ Megtolt
+ Kedvelt
Listázatlan
Közvetlen
Szavazás válaszokkal: %1$s, %2$s, %3$s, %4$s; %5$s
@@ -416,7 +416,7 @@
Egyéb megjegyzések
Továbbítás neki %s
Nem sikerült a bejelentés
- Nem sikerült a tülkök letöltése
+ Nem sikerült a tülkök letöltése
A bejelentést a szervered moderátorának küldjük el. Alább megadhatsz egy magyarázatot arra, hogy miért jelented be ezt a fiókot:
A fiók egy másik szerverről származik. Küldjünk oda is egy anonimizált másolatot a bejelentésről\?
Értesítések szűrőjének mutatása
@@ -436,22 +436,22 @@
Több lehetőség
Válasz %d
Szerkesztés
- Időzített tülkök
+ Időzített tülkök
Szerkesztés
- Időzített tülkök
- Tülk Időzítése
+ Időzített tülkök
+ Tülk Időzítése
Visszaállítás
Nem találjuk ezt a tülköt %s
Könyvjelzők
Könyvjelzőzés
Könyvjelzők
Tusky által hajtva
- Könyvjelzőzve
+ Könyvjelzőzve
Lista kiválasztása
Lista
A hangfájloknak kisebbnek kell lenniük, mint 40 MB.
Nincs egy piszkozatod sem.
- Nincs egy ütemezett tülköd sem.
+ Nincs egy ütemezett tülköd sem.
A Mastodonban a legrövidebb ütemezhető időintervallum 5 perc.
Követési kérelmek
Jóváhagyó ablak mutatása megtolás előtt
@@ -484,10 +484,10 @@
Saját, mások számára nem látható megjegyzés erről a fiókról
Nincsenek közlemények.
Közlemények
- A tülköt, melyre válaszul piszkozatot készítettél törölték
+ A tülköt, melyre válaszul piszkozatot készítettél törölték
Piszkozat törölve
Nem sikerült a Válasz információit betölteni
- Ez a tülk nem küldődött el!
+ Ez a tülk nem küldődött el!
Tényleg le akarod törölni a %s listát\?
- Nem tölthetsz fel %1$d médiacsatolmányból többet.
@@ -506,8 +506,8 @@
\nA Push-értesítéseket ez nem befolyásolja, de kézzel átállíthatod az értesítési beállításaidat.
Végtelen
Időtartam
- Csatolmányok
- Audio
+ Csatolmányok
+ Audio
Értesítések általam követett személy új tülkjeiről
Új tülkök
valaki, akit követek újat tülkölt
diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml
index 262064d34..be5ee7524 100644
--- a/app/src/main/res/values-is/strings.xml
+++ b/app/src/main/res/values-is/strings.xml
@@ -38,9 +38,9 @@
Bein skilaboð
Flipar
Tíst
- Færslur
- Með svörum
- Fest
+ Færslur
+ Með svörum
+ Fest
Fylgist með
Fylgjendur
Bókamerki
@@ -49,17 +49,17 @@
Falin lén
Fylgjendabeiðnir
Breyta notandasniðinu þínu
- Áætluð tíst
+ Áætluð tíst
Notkunarleyfi
- \@%s
- %s endurbirti
- Viðkvæmt efni
- Myndefni er falið
- Ýttu til að skoða
- Sýna meira
- Sýna minna
- Fletta út
- Fella saman
+ \@%s
+ %s endurbirti
+ Viðkvæmt efni
+ Myndefni er falið
+ Ýttu til að skoða
+ Sýna meira
+ Sýna minna
+ Fletta út
+ Fella saman
Ekkert hér.
Ekkert hér. Togaðu niður til að endurhlaða!
%s endurbirti tístið þitt
@@ -116,11 +116,11 @@
Samþykkja
Hafna
Drög
- Áætluð tíst
+ Áætluð tíst
Sýnileiki tísts
Aðvörun vegna efnis
Lyklaborð með tjáningartáknum
- Tímasetja tíst
+ Tímasetja tíst
Frumstilla
Bæta við flipa
Tenglar
@@ -139,15 +139,15 @@
Deila sem …
Sækja myndefni
Næ í myndefni
- Deila slóð á tíst til…
- Deila tísti með…
+ Deila slóð á tíst til…
+ Deila tísti með…
Deila myndefni með…
Sent!
Hætt að útiloka notanda
Hætt að þagga niður í notanda
Hætt að fela %s
- Sent!
- Það tókst að senda svarið.
+ Sent!
+ Það tókst að senda svarið.
Hvaða tilvik\?
Hvað er í gangi hérna\?
Aðvörun vegna efnis
@@ -171,8 +171,8 @@
Sækja
Afturkalla beiðni um að fylgjast með\?
Hætta að fylgjast með þessum aðgangi\?
- Eyða þessu tísti\?
- Eyða og endurvinna þetta tíst\?
+ Eyða þessu tísti\?
+ Eyða og endurvinna þetta tíst\?
Ertu alveg algjörlega viss um að þú viljir loka á allt %s\? Þú munt ekki sjá efni frá þessu léni í neinum opinberum tímalínum eða í tilkynningunum þínum. Fylgjendur þínir frá þessu léni verða fjarlægðir.
Fela allt lénið
Opinbert: Senda á opinberar tímalínur
@@ -206,8 +206,8 @@
Tungumál
Birta merki á róbótum
Sýna hreyfingar GIF-auðkennismynda
- Síun tímalínu
- Flipar
+ Síun tímalínu
+ Flipar
Sýna endurbirtingar
Sýna svör
Sækja forskoðanir á myndefni
@@ -223,12 +223,12 @@
Opinbert
Óskráð
Einungis fylgjendur
- Textastærð stöðufærslu
- Minnstu
- Lítið
- Miðlungs
- Stórt
- Stærst
+ Textastærð stöðufærslu
+ Minnstu
+ Lítið
+ Miðlungs
+ Stórt
+ Stærst
Nýjar tilvísanir
Tilkynningar um nýjar tilvísanir
Nýir fylgjendur
@@ -256,10 +256,10 @@
Villutilkynningar og beiðnir um nýja eiginleika:
\n https://github.com/tuskyapp/Tusky/issues
Notandasnið Tusky
- Deila efni úr tísti
- Deila tengli á tíst
- Myndir
- Myndskeið
+ Deila efni úr tísti
+ Deila tengli á tíst
+ Myndir
+ Myndskeið
Beðið um að fylgja
eftir %dár
eftir %dd
@@ -310,11 +310,11 @@
Læsa notandaaðgangi
Krefst þess að þú samþykkir fylgjendur handvirkt
Vista drög\?
- Sendi tíst…
- Villa við að senda tíst
- Sendi tíst
- Aflýsti sendingu
- Afrit af tístinu þínu hefur verið vistað drögunum þínum
+ Sendi tíst…
+ Villa við að senda tíst
+ Sendi tíst
+ Aflýsti sendingu
+ Afrit af tístinu þínu hefur verið vistað drögunum þínum
Semja skilaboð
Tilvikið þitt %s er ekki með nein sérsniðin tjáningartákn
Afritað á klippispjald
@@ -322,8 +322,8 @@
Sjálfgefið í kerfinu
Þú þarft fyrst að ná í þessi táknmyndasett
Framkvæmi uppflettingu…
- Þenja út / Fella saman allar stöðufærslur
- Opna tíst
+ Þenja út / Fella saman allar stöðufærslur
+ Opna tíst
Endurræsing forrits er nauðsynleg
Það þarf að endurræsa Tusky til að breytingarnar taki gildi
Seinna
@@ -358,12 +358,12 @@
- hámarksfjölda %1$d flipa náð
- hámarksfjölda %1$d flipa náð
- Myndefni: %s
- Aðvörun vegna efnis: %s
- Engin lýsing
- Endurbloggað
- Í eftirlætum
- Bókamerkt
+ Myndefni: %s
+ Aðvörun vegna efnis: %s
+ Engin lýsing
+ Endurbloggað
+ Í eftirlætum
+ Bókamerkt
Opinbert
Óskráð
Fylgjendur
@@ -397,7 +397,7 @@
Aðrar athugasemdir
Áframsenda til %s
Mistókst að kæra
- Mistókst að sækja stöðufærslur
+ Mistókst að sækja stöðufærslur
Kæran verður send á umsjónarmenn vefþjónsins þíns. Þú getur gefið skýringu hér fyrir neðan á því af hverju þú ert að kæra þennan notandaaðgang:
Notandaaðgangurinn er af öðrum vefþjóni. Á einnig að senda nafnlaust afrit af kærunni þangað\?
Notandaaðgangar
@@ -417,7 +417,7 @@
Breyta
Villa við að fletta upp færslunni %s
Þú ert ekki með nein drög.
- Þú ert ekki með neinar áætlaðar stöðufærslur.
+ Þú ert ekki með neinar áætlaðar stöðufærslur.
Hljóðskrár verða að vera minni en 40MB.
Mastodon er með 5 mínútna lágmarksbil fyrir áætlaðar aðgerðir.
Fylgjendabeiðnir
@@ -485,12 +485,12 @@
Segja upp áskrift
Gerast áskrifandi
Hreyfa sérsniðin tjáningartákn
- Tístið sem þú gerðir drög að svari við hefur veriið fjarlægt
+ Tístið sem þú gerðir drög að svari við hefur veriið fjarlægt
Eyddi drögum
Mistókst að hlaða inn svarupplýsingum
- Mistókst að senda þetta tíst!
- Viðhengi
- Hljóð
+ Mistókst að senda þetta tíst!
+ Viðhengi
+ Hljóð
Ertu viss um að þú viljir eyða %s listanum\?
Ótiltekið
Tímalengd
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 76520ddc3..32abc3240 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -26,11 +26,11 @@
Messaggi Diretti
Schede
Toot
- Post
- Con risposte
- Fissati in alto
- Seguono
- Ti seguono
+ Post
+ Con risposte
+ Fissati in alto
+ Seguiti
+ Seguono
Preferiti
Utenti silenziati
Utenti bloccati
@@ -38,15 +38,15 @@
Modifica il tuo profilo
Bozze
Licenze
- \@%s
- %s ha boostato
- Contenuto sensibile
- Media nascosto
- Clicca per visualizzare
- Mostra di Più
- Mostra Meno
- Espandi
- Riduci
+ \@%s
+ %s ha boostato
+ Contenuto sensibile
+ Media nascosto
+ Clicca per visualizzare
+ Mostra di Più
+ Mostra Meno
+ Espandi
+ Riduci
Qui non c\'è niente.
Qui non c\'è niente. Trascina verso il basso per aggiornare!
%s ha boostato il tuo toot
@@ -120,14 +120,14 @@
Copia il link
Apri come %s
Condividi come …
- Condividi URL del toot su…
- Condividi toot su…
+ Condividi URL del toot su…
+ Condividi toot su…
Condividi media su…
Inviato!
Utente sbloccato
Utente non più silenziato
- Inviato!
- Risposta inviata con successo.
+ Inviato!
+ Risposta inviata con successo.
Quale istanza?
Cosa succede?
Avviso di contenuto sensibile
@@ -152,7 +152,7 @@
Scarica
Revocare la richiesta di seguire?
Smettere di seguire questo account?
- Eliminare questo toot?
+ Eliminare questo toot?
Pubblico: visibile sulla timeline pubblica
Non Elencato: non visibile sulla timeline pubblica e locale
Solo Follower: visibile solo dai tuoi follower
@@ -181,8 +181,8 @@
Usa Tab Personalizzate di Chrome
Nascondi il pulsante componi mentre scorri
Lingua
- Filtraggio della timeline
- Schede
+ Filtraggio della timeline
+ Schede
Mostra boost
Mostra risposte
Mostra anteprime media
@@ -198,12 +198,12 @@
Pubblico
Non elencato
Solo per chi ti segue
- Dimensione del testo degli stati
- Piccolissimo
- Piccolo
- Normale
- Grande
- Grandissimo
+ Dimensione del testo degli stati
+ Piccolissimo
+ Piccolo
+ Normale
+ Grande
+ Grandissimo
Nuove Menzioni
Notifiche quando qualcuno ti menziona
Nuove persone che ti seguono
@@ -237,10 +237,10 @@
Segnala problemi & richiedi funzionalità:\n
https://github.com/accelforce/Yuito/issues
Profilo di Yuito
- Condividi contenuto del toot
- Condividi link al toot
- Immagini
- Video
+ Condividi contenuto del toot
+ Condividi link al toot
+ Immagini
+ Video
In attesa di approvazione
in %d a
@@ -290,11 +290,11 @@
Blocca account
Richiede la tua approvazione manuale di chi ti segue
Salvare bozza?
- Inviando il Toot…
- Errore durante l\'invio
- Invio Toot
- Invio annullato
- Una copia del toot è stata salvata nelle tue bozze
+ Inviando il Toot…
+ Errore durante l\'invio
+ Invio Toot
+ Invio annullato
+ Una copia del toot è stata salvata nelle tue bozze
Componi
La tua istanza %s non ha nessuna emoji personalizzata
Copiato negli appunti
@@ -302,8 +302,8 @@
Predefiniti del sistema
Dovrai prima scaricare questo pacchetto di emoji
Eseguendo una ricerca…
- Espandi/Riduci tutti gli stati
- Apri toot
+ Espandi/Riduci tutti gli stati
+ Apri toot
Riavvio dell\'app richiesto
Devi riavviare Yuito per applicare queste modifiche
Più tardi
@@ -345,15 +345,15 @@
- limite massimo di %1$d tab raggiunto
- limite massimo di %1$d tab raggiunto
- Media: %s
+ Media: %s
- Contenuto sensibile: %s
+ Contenuto sensibile: %s
- Nessuna descrizione
+ Nessuna descrizione
- Ribloggato
+ Ribloggato
- Apprezzato
+ Apprezzato
Pubblico
@@ -374,7 +374,7 @@
Mostra indicatore per bot
Sei sicuro di voler permanentemente eliminare tutte le tue notifiche\?
Cancella e riscrivi
- Cancellare e riscrivere questo toot\?
+ Cancellare e riscrivere questo toot\?
- %s voto
- %s voti
@@ -402,7 +402,7 @@
Aggiungi sondaggio
Fatto con Tusky
Espandi sempre i toot segnalati come contenuto sensibile
- Messo nei segalibri
+ Messo nei segalibri
Sondaggio con scelte: %1$s, %2$s, %3$s, %4$s; %5$s
Scegli lista
Lista
@@ -432,7 +432,7 @@
Altri commenti
Inoltra a %s
Errore durante l\'invio
- Errore durante lo scaricamento degli aggiornamenti
+ Errore durante lo scaricamento degli aggiornamenti
La segnalazione sarà inviata al moderatore del tuo server. Puoi spiegare perchè vuoi segnalare questo utente qui sotto:
L\'utente è su un altro server. Mandare una copia della segnalazione anche lì\?
Utenti
@@ -451,9 +451,9 @@
Scelta %d
Modifica
Errore nella ricerca del post %s
- Toot programmati
- Toot programmati
- Programma un toot
+ Toot programmati
+ Toot programmati
+ Programma un toot
RIpristina
%1$s • %2$s
Non hai bozze.
@@ -479,7 +479,7 @@
Mostra le anteprime dei collegamenti nelle timelines
Mastodon ha un intervallo minimo di programmazione di 5 minuti.
Non ci sono annunci.
- Non hai stati pianificati.
+ Non hai stati pianificati.
Abilita il gesto di scorrimento per passare da una scheda all\'altra
Notifiche sulle richieste di essere seguiti
Parte inferiore
@@ -504,13 +504,34 @@
- Non puoi caricare più di %1$d allegato multimediale.
- Non puoi caricare più di %1$d allegati multimediali.
- Il toot a cui hai scritto una risposta è stato rimosso
+ Il toot a cui hai scritto una risposta è stato rimosso
Bozza cancellata
- L\'invio di questo toot è fallito!
+ L\'invio di questo toot è fallito!
Sei sicuro di voler cancellare la lista %s\?
Indefinita
Durata
- Allegati
- Audio
+ Allegati
+ Audio
Mostra le animazioni delle emojis personalizzate
-
\ No newline at end of file
+ Iscriviti
+ Rimuovere questa conversazione\?
+ Errore nel recuperare le informazioni sulla risposta
+ Disiscriviti
+ Rimuovi conversazione
+ Alcune informazioni che potrebbero influenzare il tuo benessere mentale saranno nascoste. Questo include:
+\n
+\n - Notifiche riguardo a Preferiti/Boost/Following
+\n - Conteggio dei Preferiti/Boost nei toot
+\n - Statistiche riguardo a Preferiti e Post nei profili
+\n
+\n Le notifiche push non saranno influenzate, ma puoi rivedere le tue impostazioni delle notifiche manualmente.
+ Rimuovi segnalibro
+ Chiedi conferma prima di boostare
+ 14 giorni
+ 30 giorni
+ 60 giorni
+ 90 giorni
+ 180 giorni
+ 365 giorni
+ Anche se il tuo account non è bloccato, lo staff di %1$s ha pensato che potresti voler controllare queste richieste di following da parte questi account manualmente.
+
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 5cf3ffbed..41fcc31fb 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -25,9 +25,9 @@
ダイレクトメッセージ
タブ
スレッド
- 投稿
- 投稿と返信
- ピン留め
+ 投稿
+ 投稿と返信
+ ピン留め
フォロー
フォロワー
お気に入り
@@ -37,14 +37,14 @@
プロフィールを編集
下書き
ライセンス
- %sさんがブーストしました
- 閲覧注意
- 非表示のメディア
- タップして表示
- 続きを表示
- 続きを隠す
- 続きを読む
- 閉じる
+ %sさんがブーストしました
+ 閲覧注意
+ 非表示のメディア
+ タップして表示
+ 続きを表示
+ 続きを隠す
+ 続きを読む
+ 閉じる
このトゥートには%d件のメディアが存在します。
何もありません。
現在トゥートはありません。更新するにはプルダウンしてください!
@@ -113,14 +113,14 @@
リンクをコピー
%s として開く
共有先…
- トゥートのURLを共有…
- トゥートを共有…
+ トゥートのURLを共有…
+ トゥートを共有…
メディアを共有…
送信しました!
ブロックを解除しました
ミュートを解除しました
- 送信しました!
- 返信しました。
+ 送信しました!
+ 返信しました。
インスタンス
今なにしてる?
注意書き
@@ -146,7 +146,7 @@
ダウンロード
フォローリクエストを取り消しますか?
このアカウントをフォロー解除しますか?
- 本当に削除しますか?
+ 本当に削除しますか?
公開:公開タイムラインに投稿する
未収載:公開タイムラインには表示しない
フォロワー限定:フォロワーだけに公開
@@ -180,8 +180,8 @@
Chrome Custom Tabsを使用する
スクロール中は投稿ボタンを隠す
言語
- タイムラインのフィルタリング
- タブ
+ タイムラインのフィルタリング
+ タブ
ブーストを表示
返信を表示
メディアのプレビューを表示する
@@ -197,12 +197,12 @@
公開
未収載
フォロワーに限定
- トゥートのテキストサイズ
- 最小
- 小
- 中
- 大
- 最大
+ トゥートのテキストサイズ
+ 最小
+ 小
+ 中
+ 大
+ 最大
新しい返信
新しい返信の通知
新しいフォロワー
@@ -237,10 +237,10 @@
https://github.com/accelforce/Yuito/issues
Yuito公式アカウント
- トゥートの内容を共有
- トゥートへのリンクを共有
- 画像
- 動画
+ トゥートの内容を共有
+ トゥートへのリンクを共有
+ 画像
+ 動画
フォローリクエスト中
%d年後
@@ -277,11 +277,11 @@
アカウントをロック
フォロワーを手動で承認する必要があります
下書きを保存しますか?
- トゥートを送信中です…
- トゥート送信エラー
- トゥートの送信
- 送信がキャンセルされました
- トゥートのコピーが下書きに保存されました
+ トゥートを送信中です…
+ トゥート送信エラー
+ トゥートの送信
+ 送信がキャンセルされました
+ トゥートのコピーが下書きに保存されました
新規投稿
インスタンス %s にはカスタム絵文字がありません
クリップボードにコピーされました
@@ -289,8 +289,8 @@
システムのデフォルト
最初にこれらの絵文字セットをダウンロードする必要があります
検索中…
- 全て開く/閉じる
- トゥートを開く
+ 全て開く/閉じる
+ トゥートを開く
アプリの再起動が必要です
これらの変更を適用するには、Yuitoの再起動が必要になります
後で
@@ -335,7 +335,7 @@
リスト名
ネットワークエラーが発生しました!接続を確認してもう一度試してください!
- \@%s
+ \@%s
ブーストを解除
お気に入りを解除
ブーストを表示
@@ -372,7 +372,7 @@
投票
返信
返信
- このトゥートを削除し、下書きに戻しますか?
+ このトゥートを削除し、下書きに戻しますか?
削除
更新
リストを作成できませんでした
@@ -399,7 +399,7 @@
ボットマークを表示
GIFアバターを動かす
公開タイムライン
- 閲覧注意:%s
+ 閲覧注意:%s
適用
投票終了
アカウント
@@ -411,21 +411,21 @@
ブックマーク
編集
ブックマーク
- 予約トゥート
- 予約トゥート
- 予約トゥート
+ 予約トゥート
+ 予約トゥート
+ 予約トゥート
フォロワー
%1$sさん、%2$sさん
フォローリクエスト
%sさんのミュートを解除
%sさんがあなたにフォローリクエストしました
\@%sさんを通報しました
- 予約した投稿はありません。
+ 予約した投稿はありません。
下書きはありません。
項目 %d
このアカウントは外部のサーバーにあります。匿名化された通報の複製をそちらにも送信しますか?
通報をサーバーのモデレーターに送信します。以下にこのアカウントを通報理由を入力できます:
- 投稿を取得できませんでした
+ 投稿を取得できませんでした
完了
戻る
続ける
@@ -434,8 +434,8 @@
リスト
ハッシュタグ
ハッシュタグを追加
- 説明なし
- メディア: %s
+ 説明なし
+ メディア: %s
%1$sさん、%2$sさんと他%3$d人
%1$sさん
フィルターする語句
@@ -475,7 +475,7 @@
%sさんがトゥートしました
お知らせ
本当に %s のすべてをブロックするのですか? そのドメインからのコンテンツは、公開タイムラインや通知に表示されなくなります。また、そのドメインのフォロワーは削除されます。
- 音声
+ 音声
ドメイン全体を非表示
Tuskyによって提供されています
簡易投稿欄を表示
diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml
index 6129f4564..fc7b0f238 100644
--- a/app/src/main/res/values-kab/strings.xml
+++ b/app/src/main/res/values-kab/strings.xml
@@ -11,16 +11,16 @@
Ɣef
Tabdart
Tabdarin
- Tijewwiqt-ik aṭas i ɣuzzifet!
+ Izen-ik·im aṭas i ɣezzif!
Agejdan
Iccaren
- Tijewwiqt
- Iznan
- S tririyin
+ Sensla
+ Iznan
+ S tririyin
Ẓreg amaɣnu-ik
- \@%s
- Zeṛ ugar
- Zeṛ kra kan
+ \@%s
+ Zeṛ ugar
+ Zeṛ kra kan
Ulac walu da.
%s yeṭṭafar-ik·ikem-id
Err
@@ -64,29 +64,29 @@
Nɣel aseɣwen
Ldi amzun d %s
Bḍu amzun d…
- Bḍu aseɣwen n tijewwiq s…
- Bḍu tijewwiqt d…
+ Bḍu aseɣwen n tijewwiq s…
+ Bḍu tijewwiqt d…
Anta tummant\?
d-acu i gellan d amaynut\?
Nadi…
Tiririn…
Tugna n umaɣnu
Sider
- Kkes tijewwiqt-a\?
+ Kkes tijewwiqt-a\?
Ẓreg tilɣa
Agrudem
Aceɛlal
Aberkan
Tutlayt
- Iccaren
+ Iccaren
Apṛuksi
%1$s, %2$s, %3$s d %4$d nniḍen
%1$s, %2$s, akked %3$s
%1$s akked %2$s
Tusky %s
Amaɣnu n Tusky
- Tugniwin
- Tibidyutin
+ Tugniwin
+ Tibidyutin
Yeṭṭafar-ik·ikem-id
Kkes
Lqem
@@ -94,7 +94,7 @@
Rnu yiwen umiḍan amaynut n Maṣṭudun
Aru
Tummant-ik·im %s ur tesɛi ara imujiyen udmawanen
- Ldi tijewwiqt
+ Ldi tijewwiqt
CC-BY 4.0
CC-BY-SA 4.0
Senṭeḍ
@@ -113,14 +113,14 @@
Kkes
Azen
Ẓreg
- Yettwanṭḍen
+ Yettwanṭḍen
Rnu amidya
Rnu assenqed
Ṭef tugna
- Timeẓriwt n tijewwaqt
- Sɣiwes tijewwaqt-a
- Bḍu agbur n tijewwiqt-a
- Bḍu aseɣwen ɣer tijewwiqt
+ Timeẓriwt n yizen
+ Sɣiwes tijewwaqt-a
+ Bḍu agbur n tijewwiqt-a
+ Bḍu aseɣwen ɣer tijewwiqt
Rnu amsizdeg
Ẓreg amsizdeg
Snulfu-d tabdart
@@ -168,7 +168,7 @@
%1$s
%1$s akked %2$s
%1$s, %2$s akked %3$d nniḍen
- Aru tijewwiqt
+ Aru izen
%1$s • %2$s
- %s n wedɣar
@@ -213,10 +213,10 @@
Tibdarin
Iseɣwan
Yettwaceyyeɛ!
- Yettwaceyyaɛ!
+ Yettwaceyyaɛ!
Ula d yiwen n ugmuḍ
I yimeḍfaṛen kan
- Teɣzi n weḍṛis
+ Teɣzi n weḍṛis
Yettwamdemmar s Tusky
Asmel Web n usenfaṛ:
\n https://tusky.app
@@ -226,7 +226,7 @@
Sekles amzun d arewway\?
Ticki
Aṛubut
- Yettwarna ɣer ticṛad
+ Yettwarna ɣer ticṛad
deg %dsr
deg %dtsd
deg %dtsn
@@ -234,16 +234,16 @@
- %d n tasint id yugran
- %d n tasinin id yugran
- Agbur amḥulfu
+ Agbur amḥulfu
Creḍ allal n teywalt amzun d amḥulfu
Wennez tikkelt-nniḍen
Asali ur yeddi ara.
Tuccḍa deg tuzna n tijewwiqt.
Adigan
Turagin
- Yebḍa-t %s
- %s yebḍa tijewwiqt-ik·im
- %s yerna tijewwiqt-ik·im ɣer ismenyafen-is
+ Yebḍa-t %s
+ %s yebḍa izen-ik·im
+ %s yerna izen-ik·im ɣer ismenyafen-is
Tiririt taruradt
Bḍu
Kkes beṭu
@@ -268,9 +268,9 @@
Bren-it ɣer %s
Asentel n wesnas
- Ulac ɣur-k·m ula d yiwet n tjewwiqt yettwasɣawsen.
- Tijewwiqin yettwasɣawsen
- Tijewwiqin yettwasɣawsen
+ Ulac ɣur-k·m ula d yiwet n tjewwiqt yettwasɣawsen.
+ Tijewwiqin yettwasɣawsen
+ Tijewwiqin yettwasɣawsen
Sken-d beṭuyat
Ihacṭagen
Isuturen n teḍfeṛt
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index b4e2bf624..24cfbdad1 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -26,9 +26,9 @@
다이렉트 메시지
탭
툿
- 툿
- 툿과 답장
- 고정된 툿
+ 툿
+ 툿과 답장
+ 고정된 툿
팔로우
팔로워
즐겨찾기
@@ -39,15 +39,15 @@
프로필 편집
임시 저장
라이선스
- \@%s
- %s님이 부스트 했습니다
- 민감한 미디어
- 미디어 숨겨짐
- 클릭하여 보기
- 더 보기
- 숨기기
- 더 보기
- 줄이기
+ \@%s
+ %s님이 부스트 했습니다
+ 민감한 미디어
+ 미디어 숨겨짐
+ 클릭하여 보기
+ 더 보기
+ 숨기기
+ 더 보기
+ 줄이기
메시지가 없습니다.
게시물이 없습니다. 아래로 당겨서 새로고침하세요!
%s님이 부스트 했습니다
@@ -125,15 +125,15 @@
공유
다운로드
미디어 다운로드 중
- 툿 URL 공유
- 툿 공유
+ 툿 URL 공유
+ 툿 공유
미디어 공유
신고를 보냈습니다!
차단이 해제됨
뮤트가 해제됨
%s 숨김 해제됨
- 보냈습니다!
- 답장을 보냈습니다.
+ 보냈습니다!
+ 답장을 보냈습니다.
인스턴스 주소
지금 무엇을 하고 있나요\?
열람 주의
@@ -158,12 +158,12 @@
다운로드
팔로우 요청을 취소하시겠습니까\?
이 계정을 팔로우 해제하시겠습니까\?
- 이 툿을 삭제하시겠습니까\?
- 이 툿을 지우고 다시 작성하시겠습니까\?
+ 이 툿을 삭제하시겠습니까\?
+ 이 툿을 지우고 다시 작성하시겠습니까\?
정말로 %s 전체를 숨기시겠습니까\? 모든 공개 타임라인과 알림에서 해당 도메인에서 작성된 컨텐츠를 보지 못합니다. 해당 도메인 팔로워와의 관계가 사라집니다.
도메인 전체를 숨기기
공개: 공개 타임라인에 표시
- "비표시: 공개 타임라인에 표시하지 않음 "
+ 비표시: 공개 타임라인에 표시하지 않음
비공개: 팔로워에게만 공개
다이렉트: 멘션한 사용자에게만 공개
알림
@@ -193,8 +193,8 @@
언어/Language
봇 식별자 추가
GIF 아바타 애니메이션 보이기
- 타임라인 필터링
- 탭
+ 타임라인 필터링
+ 탭
부스트 보이기
답장 보이기
미디어 미리보기 다운로드
@@ -210,12 +210,12 @@
공개
타임라인에 비표시
비공개
- 게시물 글자 크기
- 매우 작게
- 작게
- 보통
- 크게
- 매우 크게
+ 게시물 글자 크기
+ 매우 작게
+ 작게
+ 보통
+ 크게
+ 매우 크게
멘션
누군가 나를 멘션할 때 알림
팔로우
@@ -248,10 +248,10 @@
버그 신고/건의사항:
\n https://github.com/tuskyapp/Tusky/issues
Tusky 공식 계정
- 이 툿의 내용 공유
- 이 툿의 링크 공유
- 사진
- 비디오
+ 이 툿의 내용 공유
+ 이 툿의 링크 공유
+ 사진
+ 비디오
팔로우 요청함
%d년 후
@@ -304,11 +304,11 @@
계정 잠금
팔로워를 수동으로 승인합니다
작성 중인 내용을 저장하시겠습니까\?
- 툿을 보내고 있습니다…
- 툿을 보낼 수 없습니다
- 툿을 보내고 있습니다
- 보내기 취소됨
- 복사본이 임시 저장에 저장되었습니다
+ 툿을 보내고 있습니다…
+ 툿을 보낼 수 없습니다
+ 툿을 보내고 있습니다
+ 보내기 취소됨
+ 복사본이 임시 저장에 저장되었습니다
글쓰기
이 인스턴스 %s 은(는) 커스텀 이모지가 없습니다.
클립보드에 복사되었습니다
@@ -316,8 +316,8 @@
시스템 기본
시스템 기본 외의 이모지를 설정하시려면 우선 다운로드해야 합니다
탐색하고 있습니다…
- 모두 보이기/줄이기
- 툿 열기
+ 모두 보이기/줄이기
+ 툿 열기
어플리케이션 재시작 필요
변경 사항을 적용하려면 Tusky를 재시작해야 합니다
다음에
@@ -357,11 +357,11 @@
- 최대 탭 수 %1$d에 도달했습니다
- 미디어: %s
- 열람주의: %s
- 설명 없음
- 부스트함
- 즐겨찾기함
+ 미디어: %s
+ 열람주의: %s
+ 설명 없음
+ 부스트함
+ 즐겨찾기함
공개
타임라인에 비표시
비공개
@@ -405,7 +405,7 @@
부가 설명
%s에 포워딩
신고하지 못했습니다
- 게시물을 불러오지 못했습니다
+ 게시물을 불러오지 못했습니다
인스턴스 관리자에게 신고합니다. 이 계정을 신고하려는 이유를 작성하실 수 있습니다:
이 유저는 다른 인스턴스에 속해 있습니다. 그 인스턴스에도 익명으로 신고 내용을 보내시겠습니까\?
알림 필터 보이기
diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml
index 86549097e..951ed4757 100644
--- a/app/src/main/res/values-ml/strings.xml
+++ b/app/src/main/res/values-ml/strings.xml
@@ -38,9 +38,9 @@
നേരേയുള്ള സന്ദേശങ്ങൾ
ടാബുകൾ
ടൂട്ട്
- പോസ്റ്റുകൾ
- മറുപടികളോടൊപ്പം
- പിൻ ചെയ്തത്
+ പോസ്റ്റുകൾ
+ മറുപടികളോടൊപ്പം
+ പിൻ ചെയ്തത്
പിന്തുടരലുകൾ
പിന്തുടരുന്നവർ
നിശ്ശബ്ദരാക്കിയ ഉപയോക്താക്കൾ
@@ -61,15 +61,15 @@
പിന്തുടരുന്നവർ
പുതിയത് ലഭിക്കാൻ താഴേക്ക് വലിക്കുക
ലഭ്യമല്ല
- ചുരുക്കുക
- വിപുലപ്പെടുത്തുക
- അൽപ്പം കാണിക്കൂ
- കൂടുതൽ കാണിക്കൂ
- തുറന്ന് കാണുവാൻ
- മറയ്ക്കപ്പെട്ട മീഡിയ
- സെൻസിറ്റീവ് ഉള്ളടക്കം
+ ചുരുക്കുക
+ വിപുലപ്പെടുത്തുക
+ അൽപ്പം കാണിക്കൂ
+ കൂടുതൽ കാണിക്കൂ
+ തുറന്ന് കാണുവാൻ
+ മറയ്ക്കപ്പെട്ട മീഡിയ
+ സെൻസിറ്റീവ് ഉള്ളടക്കം
അനുവാദം
- മുന്നിശ്ചയിച്ച ടൂറ്റ്സ്
+ മുന്നിശ്ചയിച്ച ടൂറ്റ്സ്
ബുക് മാർക്ക്
പുനഃക്രമീകരിക്കുക
ബ്രൗസറിൽ തുറക്കുക
@@ -105,16 +105,16 @@
എഴുതുക
പിന്തുടാനുള്ള അപേക്ഷകൾ
ബൂട്ട്സ് കാണിക്കുക
- മുന്നിശ്ചയിച്ച ടൂറ്റ്സ്
+ മുന്നിശ്ചയിച്ച ടൂറ്റ്സ്
കരടുകൾ
തിരുത്ത്
അറിയിപ്പുകൾ
- ടാബുകൾ
+ ടാബുകൾ
അറിയിപ്പുകൾ
പ്രഖ്യാപനങ്ങൾ
പിന്നീട്
സംരക്ഷിച്ചു!
- %s ബൂസ്റ്റ് ചെയ്തു
+ %s ബൂസ്റ്റ് ചെയ്തു
ഫലങ്ങൾ ഒന്നും ഇല്ല
അയച്ചൂ!
പങ്കിടുക
@@ -130,7 +130,7 @@
നിങ്ങളെ പിന്തുടരുന്നു
ഫോട്ടോ എടുക്കുക
തിരയുക…
- ചിത്രങ്ങൾ
+ ചിത്രങ്ങൾ
കൂടുതൽ ലഭ്യമാക്കുക
സൂചനകൾ
ബയോ
@@ -157,8 +157,8 @@
പുതുക്കുക
അവതാർ
ലിങ്കുകൾ
- \@%s
- വിഡിയോ
+ \@%s
+ വിഡിയോ
സൂചിപ്പിക്കുക
നീക്കം ചെയ്യുക
\ No newline at end of file
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 7c607452b..13e62b104 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -26,9 +26,9 @@
Directe berichten
Tabs
Toot
- Toots
- Met reacties
- Vastgezet
+ Toots
+ Met reacties
+ Vastgezet
Volgend
Volgers
Favorieten
@@ -38,15 +38,15 @@
Profiel bewerken
Concepten
Licenties
- \@%s
- %s boostte
- Gevoelige inhoud
- Verborgen media
- Klik om te bekijken
- Meer tonen
- Minder tonen
- Uitklappen
- Inklappen
+ \@%s
+ %s boostte
+ Gevoelige inhoud
+ Verborgen media
+ Klik om te bekijken
+ Meer tonen
+ Minder tonen
+ Uitklappen
+ Inklappen
Hier is niets.
Niets te zien. Swipe naar beneden om te verversen!
%s boostte jouw toot
@@ -120,14 +120,14 @@
Link kopiëren
Als %s openen
Delen als …
- Link van de toot delen
- Inhoud van de toot delen met…
+ Link van de toot delen
+ Inhoud van de toot delen met…
Media delen met …
Verzonden!
Gebruiker is gedeblokkeerd
Gebruiker wordt niet langer genegeerd
- Verzonden!
- Reactie succesvol verzonden.
+ Verzonden!
+ Reactie succesvol verzonden.
Welke Mastodonserver?
Wat wil je kwijt?
Tekstwaarschuwing
@@ -152,7 +152,7 @@
Downloaden
Het volgverzoek intrekken?
Dit account ontvolgen?
- Deze toot verwijderen?
+ Deze toot verwijderen?
Openbaar: op openbare tijdlijnen tonen
Minder openbaar: niet op openbare tijdlijnen tonen
Alleen volgers: alleen aan jouw volgers tonen
@@ -180,8 +180,8 @@
Aangepaste tabbladen gebruiken
Verberg zwevende tootknop tijdens scrollen
Taal
- Filteren
- Tijdlijnen
+ Filteren
+ Tijdlijnen
Boosts tonen
Reacties tonen
Voorbeelden van media tonen
@@ -197,12 +197,12 @@
Openbaar
Minder openbaar
Alleen volgers
- Tekstgrootte van toots
- Kleinst
- Klein
- Standaard
- Groot
- Grootst
+ Tekstgrootte van toots
+ Kleinst
+ Klein
+ Standaard
+ Groot
+ Grootst
Nieuwe vermeldingen
Meldingen over nieuwe vermeldingen
Nieuwe volgers
@@ -234,10 +234,10 @@
Foutmeldingen & nieuwe functies aanvragen:\n
https://github.com/accelforce/Yuito/issues
Yuito\'s profiel
- Deel de inhoud van de toot
- Deel de link van de toot
- Afbeeldingen
- Video
+ Deel de inhoud van de toot
+ Deel de link van de toot
+ Afbeeldingen
+ Video
Volgverzoek verzonden
over %dj
@@ -270,11 +270,11 @@
Account besloten maken
Handmatige goedkeuring vereist voor volgers
Concept bewaren?
- Toot aan het verzenden…
- Verzenden van toot mislukt
- Toots aan het verzenden
- Verzenden geannuleerd
- Een kopie van de toot werd opgeslagen als concept
+ Toot aan het verzenden…
+ Verzenden van toot mislukt
+ Toots aan het verzenden
+ Verzenden geannuleerd
+ Een kopie van de toot werd opgeslagen als concept
Toot schrijven
Jouw server %s heeft geen lokale emojis
Naar het klembord gekopieerd
@@ -282,8 +282,8 @@
Systeemstandaard
Je moet eerst deze emoji-sets downloaden
Aan het zoeken…
- Alle toots in- of uitklappen
- Toot openen
+ Alle toots in- of uitklappen
+ Toot openen
Herstarten app vereist
Je moet Yuito herstarten om deze veranderingen te kunnen doorvoeren
Later
@@ -325,15 +325,15 @@
- maximum van %1$d tab bereikt
- maximum van %1$d tabs bereikt
- Media: %s
+ Media: %s
- Inhoudswaarschuwing: %s
+ Inhoudswaarschuwing: %s
- Geen omschrijving
+ Geen omschrijving
- Geboost
+ Geboost
- Aan favorieten toegevoegd
+ Aan favorieten toegevoegd
Openbaar
@@ -366,7 +366,7 @@
Naam van lijst
Hashtag zonder #
Verwijderen en herschrijven
- Deze toot verwijderen en herschrijven\?
+ Deze toot verwijderen en herschrijven\?
Leegmaken
Filter
Toepassen
@@ -420,7 +420,7 @@
Extra opmerkingen
Verder naar %s
Het rapporteren is mislukt
- Het ophalen van toots is mislukt
+ Het ophalen van toots is mislukt
Deze rapportage wordt naar jouw servermoderator(en) gestuurd. Je kunt hieronder een uitleg geven over waarom je het account wilt rapporteren:
Het account is van een andere server. Wil je ook een geanonimiseerde kopie van de rapportage daarnaartoe sturen\?
Meldingenfilter tonen
@@ -439,17 +439,17 @@
Bewerken
Geluidsbestanden moeten minder dan 40MB zijn.
Bladwijzers
- Ingeplande toots
+ Ingeplande toots
Bladwijzer
Bewerken
Bladwijzers
Poll toevoegen
- Ingeplande toots
- Ingeplande toot
+ Ingeplande toots
+ Ingeplande toot
Herstellen
Powered by Tusky
Altijd toots met tekstwaarschuwingen uitklappen
- Als bladwijzer toegevoegd
+ Als bladwijzer toegevoegd
Kies een lijst
Lijst
Accounts
@@ -457,16 +457,16 @@
Poll
Fout tijdens opzoeken toot %s
Je hebt nog geen concepten
- Je hebt nog geen ingeplande toots
+ Je hebt nog geen ingeplande toots
Om in te plannen moet je in Mastodon een minimum interval van 5 minuten gebruiken.
Volgverzoeken
Hashtags
- Bijlagen
+ Bijlagen
volgverzoek verstuurd
Afmelden
Abonneren
- De toot waarvoor jij een reactie had opgesteld, is verwijderd
- Het versturen van deze toot is mislukt!
+ De toot waarvoor jij een reactie had opgesteld, is verwijderd
+ Het versturen van deze toot is mislukt!
Weet je zeker dat je de lijst %s wilt verwijderen\?
- Je kan niet meer dan %1$d mediabijlage uploaden.
@@ -488,7 +488,7 @@
- %s personen
Hashtag toevoegen
- Geluid
+ Geluid
Meldingen wanneer iemand waar je op bent geabonneerd een nieuwe toot plaatst
Nieuwe toots
Meldingen over volgverzoeken
@@ -525,4 +525,4 @@
\n- Volger/Bericht statistieken op profielen
\n
\nPush-notificaties zullen niet worden beïnvloed, maar uw kunt uw notificatie voorkeuren handmatig wijzigen.
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-no-rNB/strings.xml b/app/src/main/res/values-no-rNB/strings.xml
index 4d762adb9..9c2ce9aa3 100644
--- a/app/src/main/res/values-no-rNB/strings.xml
+++ b/app/src/main/res/values-no-rNB/strings.xml
@@ -9,26 +9,26 @@
En ukjent autoriseringsfeil oppsto.
Autorisasjon ble nektet.
Henting av logintoken feilet.
- Statusen er for lang!
+ Innlegget er for langt!
Filen må være mindre enn 8MB.
Videofiler må være mindre enn 40MB.
Den filtypen kan ikke lastes opp.
Den filen kunne ikke åpnes.
Trenger tillatelse til å lese media.
Trenger tillatelse for å lagre media.
- Bilder og videoer kan ikke kobles til samme status.
+ Bilder og videoer kan ikke kobles til samme innlegg.
Opplastingen feilet.
- En feil oppsto under sending av tootet.
+ En feil oppsto under sending av innlegget.
Hjem
Varsler
Lokal
Forent
Direktemeldinger
Faner
- Toot
- Toots
- Med svar
- Festet
+ Tråd
+ Innlegg
+ Med svar
+ Festet
Følger
Følgere
Favoritter
@@ -38,19 +38,19 @@
Endre profilen din
Kladder
Lisenser
- \@%s
- %s boostet
- Sensitivt innhold
- Media skjult
- Klikk for å vise
- Vis mer
- Vis mindre
- Utvid
- Kollaps
+ \@%s
+ %s boostet
+ Sensitivt innhold
+ Media skjult
+ Klikk for å vise
+ Vis mer
+ Vis mindre
+ Utvid
+ Kollaps
Her er det ingenting.
Her er det ingenting. Dra ned for å oppdatere!
- %s boostet tootet ditt
- %s favoriserte tootet ditt
+ %s boostet innlegget ditt
+ %s favoriserte innlegget ditt
%s følger deg
Rapporter @%s
Ytterligere kommentarer\?
@@ -102,7 +102,7 @@
Avvis
Søk
Kladder
- Toot-synlighet
+ Synlighet på innlegg
Innholdsadvarsel
Emoji-tastatur
Legg til fane
@@ -122,14 +122,14 @@
Del som …
Last ned media
Laster ned media
- Del toot-URL til…
- Del toot til…
+ Del innlegg-URL til…
+ Del innlegg til…
Del media til…
Sendt!
Fjernet blokkering av bruker
Fjernet demping av bruker
- Sendt!
- Svaret ble sendt.
+ Sendt!
+ Svaret ble sendt.
Hvilken instanse\?
Hva skjer\?
Innholdsadvarsel
@@ -154,7 +154,7 @@
Last ned
Trekk tilbake følgeforespørselen\?
Slutte å følge denne kontoen\?
- Slette dette tootet\?
+ Slette dette tootet\?
Offentlig: Vis i offentlig tidslinjer
Ikke oppført: Ikke vis i offentlige tidslinjer
Bare følgere: Vis bare til følgere
@@ -178,8 +178,8 @@
Bruke Chrome tilpassede faner
Skjul skriv-knappen under scrolling
Språk
- Tidslinjefiltrering
- Faner
+ Tidslinjefiltrering
+ Faner
Vis boosts
Vis svar
Last ned forhåndsvisning av media
@@ -191,13 +191,13 @@
Marker alltid media som sensitivt
Publiserer (synkronisert med server)
Synkronisering av innstillinger feilet
- Størrelse på statustekst
+ Størrelse på statustekst
Nye følgere
Varsler om nye følgere
Booster
- Varsler når tootene dine blir boostet
+ Varsler når innleggene dine blir boostet
Favoritter
- Varsler når tootene dine blir favorisert
+ Varsler når innleggene dine blir favorisert
%s nevnte deg
%1$s, %2$s, %3$s og %4$d anre
%1$s, %2$s, og %3$s
@@ -212,10 +212,10 @@
Rapporter feil og ønsker om funksjonalitet her:
\n https://github.com/accelforce/Yuito/issues
Yuitos Mastodon-profil
- Del inneholdet i tootet
- Del link til toot
- Bilder
- Video
+ Del inneholdet i innlegget
+ Del link til innlegget
+ Bilder
+ Video
Forespørsel sendt
om %dd
om %dh
@@ -271,11 +271,11 @@
Lås konto
Krever at du manuelt godkjenner nye følgere
Lagre kladd\?
- Sender Toot…
- Det oppsto en feil under sending av tootet
- Sender Toots
- Sending avbrutt
- En kopi av tootet er lagret i kladdene dine
+ Sender toot…
+ Det oppsto en feil under sending av tootet
+ Sender toots
+ Sending avbrutt
+ En kopi av tootet er lagret i kladdene dine
Skriv
Instansen %s har ingen egendefinerte emojis
Kopiert til utklippstavlen
@@ -283,8 +283,8 @@
Systemstandard
Du må laste ned emoji-samlingene før de kan brukes
Gjennomfører oppslag…
- Utvid/kollaps alle statuser
- Åpne toot
+ Utvid/kollaps alle statuser
+ Åpne toot
Omstart av applikasjonen er påkrevd
Du må starte Yuito på nytt for at endringene skal bli aktive
Senere
@@ -326,11 +326,11 @@
- grensen på %1$d fane er nådd
- grensen på %1$d faner er nådd
- Media: %s
- Innholdsadvarsel: %s
- Ingen beskrivelse
- Reblogged
- Favorisert
+ Media: %s
+ Innholdsadvarsel: %s
+ Ingen beskrivelse
+ Reblogget
+ Favorisert
Offentlig
Ikke listet
Følgere
@@ -340,12 +340,12 @@
Fjern
Filter
Bruk
- Skriv Toot
+ Skriv innlegg
Skriv
Vis at konto er en robot
Er du sikker på at du vil slette alle varsler\?
Slett og skriv på nytt
- Vil du slette dette tottet og skrive det på nytt\?
+ Vil du slette dette tottet og skrive det på nytt\?
%1$s • %2$s
- %s stemme
@@ -362,11 +362,11 @@
Offentlig
Ikke listet
Kun følgere
- Minste
- Liten
- Medium
- Stor
- Størst
+ Minste
+ Liten
+ Medium
+ Stor
+ Størst
Avstemminger er avsluttet
Avstemminger
Varsler om avstemminger som er avsluttet
@@ -399,7 +399,7 @@
Flere kommentarer
Videresend til %s
Klarte ikke å rapportere
- Klarte ikke å hente statuser
+ Klarte ikke å hente innlegg
Rapporten vil bli sendt til instansmoderatoren. Under kan du skrive en forklaring på hvorfor du rapporterer denne kontoen:
Kontoen tilhører en annen instans. Vil du også sende en anonymisert kopi av rapporten dit\?
Skjulte domener
@@ -413,7 +413,7 @@
Når nøkkelordet kun inneholder bokstaver og tall, vil det bare brukes dersom det stemmer overens med hele ordet
Kontoer
Klarte ikke å søke
- Ekspander alltid toots markert med innholdsadvarsel
+ Ekspander alltid innlegg markert med innholdsadvarsel
Legg til avstemming
Avstemming
5 minutter
@@ -427,20 +427,20 @@
Flere valg
Valg %d
Endre
- Planlagte toots
+ Planlagte toots
Rediger
- Planlagte toots
- Planlegg toot
+ Planlagte toots
+ Planlegg toot
Tilbakestill
Det oppsto en feil under henting av %s
Drevet av Tusky
Bokmerker
Bokmerke
Bokmerker
- Bokmerke lagt til
+ Bokmerke lagt til
Velg liste
Liste
- Du har ingen planlagte statuser.
+ Du har ingen planlagte innlegg.
Du har ikke lagret noen kladder.
Lydfiler må være mindre enn 40MB.
Mastodon har et minimums planleggingsinterval på 5 minutter.
@@ -482,14 +482,14 @@
Informasjon som kan påvirke ditt mentale velvære vil bli skjult. Dette inkluderer:
\n
\n - Varsler om favorisering, boosts og følgere
-\n - Antall favoriseringer og boots på toots
-\n - Antall følgere og toots på profiler
+\n - Antall favoriseringer og boots på innlegg
+\n - Antall følgere og innlegg på profiler
\n
\n Push-varsler vil ikke påvirkes, men du kan se over dine varselinnstillinger manuelt.
Velvære
- Varsler når noen jeg følger publiserer en ny toot
- Nye toots
- noen jeg følger publiserer en ny toot
+ Varsler når noen jeg følger publiserer et nytt innlegg
+ Nye innlegg
+ noen jeg følger publiserer et nytt innlegg
%s tootet akkurat
- Du kan ikke laste opp flere enn %1$d mediavedlegg.
@@ -498,12 +498,12 @@
Uendelig
Varighet
Er du sikker på at du vil slette listen %s\?
- Vedlegg
- Lyd
- Tootet du kladdet et svar til har blitt fjernet
+ Vedlegg
+ Lyd
+ Tootet du kladdet et svar til har blitt fjernet
Kladd slettet
Lasting av svarinformasjon feilet
- Sending av toot feilet!
+ Sending av toot feilet!
Animer egendefinerte emojis
Avslutt abonnementet
Abonner
@@ -518,4 +518,5 @@
180 dager
365 dager
14 dager
-
\ No newline at end of file
+ Komponer toot
+
diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml
index 3bbae2ffe..2cfd37109 100644
--- a/app/src/main/res/values-oc/strings.xml
+++ b/app/src/main/res/values-oc/strings.xml
@@ -22,8 +22,8 @@
Notificacions
Federacion
Tut
- Pòstes
- Amb responsas
+ Pòstes
+ Amb responsas
Abonament
Seguidors
Preferits
@@ -33,14 +33,14 @@
Modificar lo perfil
Borrolhons
Licéncias
- %s partejat
- Contengut sensible
- Mèdia amagat
- Clicar per mostrar
- Mostrar mai
- Mostrar mens
- Desplegar
- Replegar
+ %s partejat
+ Contengut sensible
+ Mèdia amagat
+ Clicar per mostrar
+ Mostrar mai
+ Mostrar mens
+ Desplegar
+ Replegar
I a pas res aquí. Davalatz per actualizar !
%s a partajat vòstre tut
%s a aimat vòstre tut
@@ -97,14 +97,14 @@
Clavièr Emoji
Telecargament %1$s
Copiar lo ligam
- Partejar l\'URL del tut amb…
- Partejar vòstre tut amb…
+ Partejar l\'URL del tut amb…
+ Partejar vòstre tut amb…
Partejar l’imatge amb…
Enviat !
Utilizaire desblocat
Utilizaire sortit del silenci
- Enviat !
- Responsa ben enviada.
+ Enviat !
+ Responsa ben enviada.
Quina instància ?
A de qué pensatz ?
Avís de contengut
@@ -128,7 +128,7 @@
Telecargar
Anullar la demandar d’abonament ?
Volètz quitar de seguir aqueste compte ?
- Suprimir aqueste tut \?
+ Suprimir aqueste tut \?
Publica : es visibla a la cronologia publica
Pas listada :es pas visibla a las cronologias publicas
Solament seguidors : pas que visibla pels vòstres seguidors
@@ -153,8 +153,8 @@
Navegador
Onglets personalizats de Chrome
Amagar lo boton de redaccion en desplaçament
- Filtre de la cronologia
- Onglets
+ Filtre de la cronologia
+ Onglets
Mostrar los retuts
Mostrar las responsas
Mostrar los apercebuts
@@ -167,12 +167,12 @@
Publica
Pas listat
Seguidors solament
- Talha de text de l\'estatut
- Mendre
- Pichona
- Mejana
- Granda
- Grandassa
+ Talha de text de l\'estatut
+ Mendre
+ Pichona
+ Mejana
+ Granda
+ Grandassa
Mencions nòvas
Notificacions de mencions noves
Seguidors nòus
@@ -207,10 +207,10 @@
https://github.com/accelforce/Yuito/issues
Perfil de Yuito
- Partejar lo contengut del tut
- Partejar lo ligam del tut
- Imatges
- Vidèo
+ Partejar lo contengut del tut
+ Partejar lo ligam del tut
+ Imatges
+ Vidèo
Demanda d’abonament
en %d ans
@@ -236,11 +236,11 @@
Clavar lo compte
Demanda que validetz manualament los seguidors
Salvar lo borrolhon ?
- Mandadís del tut…
- Error en enviar lo tut
- Mandadís dels tuts
- Mandadís anullat
- Una còpia del tut es estat salvat dins los borrolhons
+ Mandadís del tut…
+ Error en enviar lo tut
+ Mandadís dels tuts
+ Mandadís anullat
+ Una còpia del tut es estat salvat dins los borrolhons
Redactar
L’instància %s es pas compatibla amb los emoji personalizats
Copiat al quichapapièr
@@ -248,8 +248,8 @@
Çò del sistèma
D’en primièr vos cal telecargar los emojis seguents
Recèrca…
- Desplegar/Plegar totes los estatuts
- Dobrir lo tut
+ Desplegar/Plegar totes los estatuts
+ Dobrir lo tut
Reaviada necessària
Vos caldrà reaviar Yuito per aplicar aquestes cambiaments
Mai tard
@@ -276,8 +276,8 @@
Local
Messatges dirèctes
Onglets
- Penjats
- \@%s
+ Penjats
+ \@%s
Pas res aicí.
Suprimir lo partatge
Suprimir lo favorit
@@ -349,11 +349,11 @@
- nombre maximum d’onglet %1$d atengut
- nombre maximum d’onglets %1$d atengut
- Mèdia : %s
- Avertiment : %s
- Cap de descripcion
- Repartajat
- Mes en favorit
+ Mèdia : %s
+ Avertiment : %s
+ Cap de descripcion
+ Repartajat
+ Mes en favorit
Public
Pas listada
Seguidors
@@ -363,7 +363,7 @@
Escriure un tut
Redactar
Suprimir e reformular
- Suprimir e reformular aqueste tut \?
+ Suprimir e reformular aqueste tut \?
Utilizar lo tèma sistèma
Netejar
Filtrar
@@ -410,7 +410,7 @@
Comentaris suplementaris
Transferir a %s
Fracàs del senhalament
- Recuperacion dels estatuts impossibla
+ Recuperacion dels estatuts impossibla
Lo senhalament serà enviat a vòstre moderator de servidor. Podètz fornir una explicacion de perque senhalatz lo compte çai-jos :
Aqueste compte es en un autre servidor. Enviar una còpia anonimizada del senhalament \?
Domenis resconduts
@@ -438,22 +438,22 @@
Opcions multiplas
Opcion %d
Modificar
- Tuts planificats
+ Tuts planificats
Modificar
- Tuts planificats
- Planificar de tuts
+ Tuts planificats
+ Planificar de tuts
Escafar
Error en cercant la publicacion %s
Propulsat per Tusky
Marcapaginas
Ajustar als marcapaginas
Marcapaginas
- Ajustat als marcapaginas
+ Ajustat als marcapaginas
Seleccionar la list
Lista
Los fichièrs àudio devon èsser inferiors a 40 Mo.
Avètz pas cap de borrolhon.
- Avètz pas cap de tut planificat.
+ Avètz pas cap de tut planificat.
L’interval minimum de planificacion sus Mastodon e de 5 minutas.
Demandas d’abonament
Etiquetas
@@ -469,7 +469,7 @@
Seguir
Borrolhon suprimit
Fracàs del cargament de las info de responsa
- Fracàs de l’enviament !
+ Fracàs de l’enviament !
Volètz vertadièrament suprimir la lista %s \?
Repassar las notificacions
Enregistrat !
@@ -482,8 +482,8 @@
- %s personas
Apondre hashtag
- Pèças juntas
- Àudio
+ Pèças juntas
+ Àudio
Tuts novèls
Notificacions de demandas de seguiment
Enbàs
@@ -510,4 +510,4 @@
Limitar las notificacions de la cronologia
Amagar lo títol ennaut de la barra
Afichar una fenèstra de confirmacion abans de partejar
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index c834bf092..4c38795d6 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -22,8 +22,8 @@
Lokalne
Globalne
Wątek
- Wpisy
- Z odpowiedziami
+ Wpisy
+ Z odpowiedziami
Śledzeni
Śledzący
Ulubione
@@ -33,12 +33,12 @@
Edytuj profil
Szkice
Licencje
- %s podbił
- Wrażliwe treści
- Ukryto zawartość multimedialną
- Naciśnij, aby wyświetlić
- Pokaż więcej
- Ukryj
+ %s podbił
+ Wrażliwe treści
+ Ukryto zawartość multimedialną
+ Naciśnij, aby wyświetlić
+ Pokaż więcej
+ Ukryj
Pusto tutaj. Pociągnij, aby odświeżyć!
%s podbił(-a) Twój wpis
%s dodał Twój post do ulubionych
@@ -95,13 +95,13 @@
Klawiatura emoji
Pobieranie %1$s
Skopiuj odnośnik
- Udostępnij odnośnik do wpisu…
- Udostępnij wpis do…
+ Udostępnij odnośnik do wpisu…
+ Udostępnij wpis do…
Wyślij!
Odblokowano użytkownika
Cofnięto wyciszenie użytkownika
- Wyślij!
- Pomyślnie wysłano odpowiedź.
+ Wyślij!
+ Pomyślnie wysłano odpowiedź.
Jaka instancja?
Co Ci chodzi po głowie?
Ostrzeżenie o zawartości
@@ -150,8 +150,8 @@
Przeglądarka
Używaj niestandardowych kart Chrome
Ukryj przycisk śledzenia podczas przewijania
- Filtrowanie osi czasu
- Zakładki
+ Filtrowanie osi czasu
+ Zakładki
Pokaż podbicia
Pokazuj odpowiedzi
Pokazuj podgląd zawartości multimedialnej
@@ -164,12 +164,12 @@
Publiczne
Niewypisane
Tylko dla śledzonych
- Rozmiar tekstu wpisów
- Najmniejszy
- Mały
- Średni
- Duży
- Ogromny
+ Rozmiar tekstu wpisów
+ Najmniejszy
+ Mały
+ Średni
+ Duży
+ Ogromny
Nowe wspomnienia
Powiadomienia o nowych wspomnieniach
Nowi śledzący
@@ -204,10 +204,10 @@
https://github.com/accelforce/Yuito/issues
Profil Tusky’ego
- Udostępnij zawartość wpisu
- Udostępnij link do postu
- Obrazy
- Wideo
+ Udostępnij zawartość wpisu
+ Udostępnij link do postu
+ Obrazy
+ Wideo
Wysłano prośbę o możliwość śledzenia
w %d lata
@@ -237,11 +237,11 @@
Zablokuj konto
Wymaga od Ciebie ręcznej akceptacji próśb o śledzenie
Czy chcesz zapisać szkic?
- Wysyłanie wpisu…
- Wystąpił błąd podczas wysyłania wpisu
- Wysyłanie wpisów
- Anulowano wysyłanie
- Kopia wpisu została zapisana jako szkic
+ Wysyłanie wpisu…
+ Wystąpił błąd podczas wysyłania wpisu
+ Wysyłanie wpisów
+ Anulowano wysyłanie
+ Kopia wpisu została zapisana jako szkic
Nowy wpis
Twoja instancja %s nie używa żadnych niestandardowych emoji
Skopiowano do schowka
@@ -249,8 +249,8 @@
Domyślny systemu
Musisz najpierw pobrać te zestawy emoji
Wyszukiwanie…
- Rozwiń/zwiń wszystkie wpisy
- Otwórz wpis
+ Rozwiń/zwiń wszystkie wpisy
+ Otwórz wpis
Wymagane jest ponowne uruchomienie
Musisz uruchomić ponownie Tuskyego, aby zastosować zmiany
Później
@@ -271,9 +271,9 @@
Wystąpił problem z łącznością! Sprawdź swoje połączenie internetowe i spróbuj ponownie!
Pliki wideo muszą być mniejsze niż 40MB.
Wiadomości bezpośrednie
- Przypięte
- Rozwiń
- Zwiń
+ Przypięte
+ Rozwiń
+ Zwiń
Nic tu nie ma.
Usuń z ulubionych
Usuń i przeredaguj
@@ -289,7 +289,7 @@
Udostępnij jako …
Zakładki
Ukryte domeny
- \@%s
+ \@%s
Cofnij podbicie
Ukryte domeny
Dodaj głosowanie
@@ -302,8 +302,8 @@
Pobieranie mediów
Wyślij media do…
Domena %s nie jest już schowana
- Usunąć ten wpis\?
- Usunąć i napisać ponownie ten wpis\?
+ Usunąć ten wpis\?
+ Usunąć i napisać ponownie ten wpis\?
Czy jesteś pewien/pewna że chcesz zablokować wszystko z domeny %s\? Nie będziesz widzieć zawartości z tej domeny w żadnej osi czasu ani w twoich powiadomieniach. Twoi obserwujący z tej domeny nie będą usunięci.
Schowaj całą domenę
głosowania zostały zakończone
@@ -373,11 +373,11 @@
- maksymalna liczba zakładek (%1$d) osiągnięta
- maksymalna liczba zakładek (%1$d) osiągnięta
- Media: %s
- Ostrzeżenie o zawartości: %s
- Brak opisu
- Podbity
- Polubiony
+ Media: %s
+ Ostrzeżenie o zawartości: %s
+ Brak opisu
+ Podbity
+ Polubiony
Publiczny
Niewidoczne
Śledzący
@@ -435,7 +435,7 @@
Dodatkowe komentarze
Wyślij zgłoszenie do %s
Zgłoszenie nie powiodło się
- Pobieranie wpisów nie powiodło się
+ Pobieranie wpisów nie powiodło się
Zgłoszenie zostanie przesłąne do moderatora twojego serwera. Możesz podać przyczynę zgłoszenia tego konta poniżej:
To konto jest na innym serwerze. Czy przesłać anonimizowaną kopię zgłoszenia na ten serwer\?
Konta
@@ -453,22 +453,22 @@
Kilka wyborów
Opcja %d
Edytuj
- Zaplanowane wpisy
+ Zaplanowane wpisy
Edytuj
- Zaplanowane wpisy
- Zaplanuj wpis
+ Zaplanowane wpisy
+ Zaplanuj wpis
Resetuj
Napędzane przez Tusky
Błąd przy wyszukiwaniu wpisu %s
Zakładki
Dodaj do zakładek
Zakładki
- Dodane do zakładek
+ Dodane do zakładek
Wybierz listę
Lista
Pliki audio muszą być mniejsze niż 40MB.
Nie masz żadnych szkiców.
- Nie masz żadnych zaplanowanych wpisów.
+ Nie masz żadnych zaplanowanych wpisów.
Mastodon umożliwia wysłanie minimalnie 5 minut od zaplanowania.
Prośby o możliwość śledzenia
Pytaj o potwierdzenie przed podbiciem
@@ -500,7 +500,7 @@
- Nie możesz przesłać więcej niż %1$d załączników.
Nie udało się załadować informacji o odpowiedzi
- Przesłanie wpisu nie powiodło się!
+ Przesłanie wpisu nie powiodło się!
Czy na pewno chcesz usunąć listę %s\?
Nie ma ogłoszeń.
Ogranicz liczbę powiadomień o zmianach na osi czasu
@@ -514,7 +514,7 @@
\n
\nNie będzie to miało wpływu na powiadomienia typu push, ale możesz zmienić ustawienia powiadomień ręcznie.
Włącz gest przesuwania by przełączać między zakładkami
- Załączniki
+ Załączniki
Powiadomienia o prośbach o obserwowanie
ktoś kogo zasubskrybowałem/zasubskrybowałam opublikował nowy wpis
Wysłano prośbę o obserwowanie
@@ -523,7 +523,7 @@
Anuluj subskrypcję
Zasubskrybuj
Mimo tego, że twoje konto nie jest zablokowane, administracja %1$s uznała, że możesz chcieć ręcznie przejrzeć te prośby o możliwość śledzenia od tych kont.
- Wpis dla którego naszkicowałeś/naszkicowałaś odpowiedź został usunięty
+ Wpis dla którego naszkicowałeś/naszkicowałaś odpowiedź został usunięty
Usunięto szkic
Ukryj ilościowe statystyki na profilach
Ukryj ilościowe statystyki na postach
@@ -531,7 +531,7 @@
Zapisano!
Twoja prywatna notatka o tym koncie
Czas nieokreślony
- Dźwięk
+ Dźwięk
Powiadomienia o opublikowaniu nowego wpisu przez kogoś, kogo obserwujesz
Pozycja głównego paska nawigacji
Animuj niestandardowe emoji
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 6e7453aea..bac0c960a 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -25,8 +25,8 @@
Mensagens Diretas
Editar abas
Conversa
- Toots
- Com respostas
+ Toots
+ Com respostas
Segue
Seguidores
Favoritos
@@ -36,18 +36,18 @@
Editar perfil
Rascunhos
Licenças
- %s deu boost
- Mídia sensível
- Mídia sensível
- Toque para ver
- Expandir
- Ocultar
+ %s deu boost
+ Mídia sensível
+ Mídia sensível
+ Toque para ver
+ Expandir
+ Ocultar
Nada aqui. Arraste para atualizar!
%s deu boost no teu toot
%s favoritou teu toot
%s te seguiu
Denunciar @%s
- Mais comentários\?
+ Comentários adicionais aqui
Resposta rápida
Responder
Dar boost
@@ -109,14 +109,14 @@
Copiar link
Abrir como %s
Compartilhar como…
- Compartilhar link do toot em…
- Compartilhar toot em…
+ Compartilhar link do toot em…
+ Compartilhar toot em…
Compartilhar mídia via…
Enviado!
Usuário desbloqueado
Usuário dessilenciado
- Enviado!
- Resposta enviada com sucesso.
+ Enviado!
+ Resposta enviada com sucesso.
Qual instância?
No que você está pensando?
Aviso de Conteúdo aqui
@@ -141,7 +141,7 @@
Baixar
Cancelar solicitação para seguir\?
Deixar de seguir esta conta?
- Excluir este toot?
+ Excluir este toot?
Público: Postar em linhas públicas
Não-listado: Não postar em linhas públicas
Privado: Postar só para seguidores
@@ -168,8 +168,8 @@
Navegador
Usar abas do Chrome
Ocultar compositor ao rolar a tela
- Filtro da linha do tempo
- Abas
+ Filtro da linha do tempo
+ Abas
Mostrar boosts
Mostrar respostas
Mostrar prévias de mídia
@@ -184,12 +184,12 @@
Erro ao sincronizar configurações
Público
Não-listado
- Tamanho da fonte
- Menor
- Pequeno
- Médio
- Grande
- Maior
+ Tamanho da fonte
+ Menor
+ Pequeno
+ Médio
+ Grande
+ Maior
Menções
Notificações sobre menções
Seguidores
@@ -221,10 +221,10 @@
Reporte bugs e solicite funcionalidades:
\n https://github.com/accelforce/Yuito/issues
Perfil do Tusky
- Compartilhar conteúdo do toot
- Compartilhar link do toot
- Imagens
- Vídeo
+ Compartilhar conteúdo do toot
+ Compartilhar link do toot
+ Imagens
+ Vídeo
Solicitação enviada
em %dy
@@ -254,11 +254,11 @@
Trancar perfil
Requer aprovação manual de seguidores
Salvar rascunho?
- Enviando toot…
- Erro ao enviar toot
- Enviando toots
- Envio cancelado
- Uma cópia do toot foi salva nos seus rascunhos
+ Enviando toot…
+ Erro ao enviar toot
+ Enviando toots
+ Envio cancelado
+ Uma cópia do toot foi salva nos seus rascunhos
Compor
A sua instância %s não possui emojis personalizados
Copiado para a área de transferência
@@ -266,8 +266,8 @@
Padrão do sistema
É necessário baixar estes pacotes de emojis primeiro
Carregando…
- Expandir/Ocultar todos os toots
- Abrir toot
+ Expandir/Ocultar todos os toots
+ Abrir toot
É necessário reiniciar o aplicativo
É necessário reiniciar o aplicativo para aplicar as alterações
Depois
@@ -292,10 +292,10 @@
Público
Privado
Ocorreu um erro de conexão! Por favor, verifique sua internet e tente novamente!
- Fixado
- \@%s
- Mostrar mais
- Mostrar menos
+ Fixado
+ \@%s
+ Mostrar mais
+ Mostrar menos
Nada aqui.
Excluir e rascunhar
Preferências da conta
@@ -305,7 +305,7 @@
Abrir mídia #%d
Baixar mídia
Baixando mídia
- Excluir e rascunhar este toot\?
+ Excluir e rascunhar este toot\?
enquetes terminarem
Filtros
Idioma
@@ -353,11 +353,11 @@
- excedeu o máximo de %1$d aba
- excedeu o máximo de %1$d abas
- Mídia: %s
- Aviso de Conteúdo: %s
- Sem descrição
- Você deu boost
- Favoritado
+ Mídia: %s
+ Aviso de Conteúdo: %s
+ Sem descrição
+ Você deu boost
+ Favoritado
Não-listado
Direto
Nome da lista
@@ -406,7 +406,7 @@
Comentários adicionais
Encaminhar para %s
Erro ao denunciar
- Erro ao carregar toots
+ Erro ao carregar toots
A denúncia será enviada aos moderadores da instância. Explique por que denunciou a conta:
A conta está em outra instância. Enviar uma cópia anônima da denúncia para lá\?
Instâncias bloqueadas
@@ -434,20 +434,20 @@
Múltiplas opções
Opção %d
Editar
- Agendados
+ Agendados
Editar
- Agendados
- Agendar toot
+ Agendados
+ Agendar toot
Cancelar
Erro ao pesquisar %s
Salvos
Salvar
Salvos
Desenvolvido por Tusky
- Salvo
+ Salvo
Selecionar lista
Lista
- Sem toots agendados.
+ Sem toots agendados.
O áudio deve ser menor que 40MB.
Sem rascunhos.
Mastodon possui um intervalo mínimo de 5 minutos para agendar.
@@ -481,8 +481,8 @@
Notificar sobre toots de quem me interessa
quem me interessa tootar
Erro ao carregar toot para responder
- Erro ao enviar o toot!
- O toot em que se rascunhou uma resposta foi excluído
+ Erro ao enviar o toot!
+ O toot em que se rascunhou uma resposta foi excluído
Rascunho excluído
- Não é possível anexar mais de %1$d arquivo de mídia.
@@ -505,8 +505,8 @@
Sem comunicados.
Indefinido
Duração
- Anexos
- Áudio
+ Anexos
+ Áudio
Novos toots
%s recém tootou
Comunicados
@@ -517,6 +517,12 @@
Excluir esta conversa\?
Excluir conversa
Deseja excluir a lista %s\?
- Remover favorito
- Mostrar janela de confirmação antes de favoritar
+ Remover do Salvos
+ Solicitar confirmação antes de favoritar
+ 30 dias
+ 60 dias
+ 90 dias
+ 180 dias
+ 14 dias
+ 365 dias
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index eff15022d..9ceb5a6c6 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -26,9 +26,9 @@
Личные сообщения
Вкладки
Кутеж
- Посты
- Посты и ответы
- Закреплённые
+ Посты
+ Посты и ответы
+ Закреплённые
Подписки
Подписчики
Избранное
@@ -38,15 +38,15 @@
Редактировать профиль
Черновики
Лицензии
- \@%s
- %s продвинул(а)
- Чувствительный контент
- Медиа скрыто
- Нажмите для просмотра
- Показать больше
- Показать меньше
- Развернуть
- Свернуть
+ \@%s
+ %s продвинул(а)
+ Чувствительный контент
+ Медиа скрыто
+ Нажмите для просмотра
+ Показать больше
+ Показать меньше
+ Развернуть
+ Свернуть
Ничего нет.
Ничего нет. Потяните вниз, чтобы обновить!
%s продвинул(а) вашу запись
@@ -123,14 +123,14 @@
Поделиться как…
Скачать медиафайл
Скачивание медиафайла
- Поделиться ссылкой на гудок…
- Поделиться гудком с…
+ Поделиться ссылкой на гудок…
+ Поделиться гудком с…
Поделиться медифайлом…
Отправить!
Пользователь разблокирован
Пользователь включен
- Отправлено!
- Ответ успешно отправлен.
+ Отправлено!
+ Ответ успешно отправлен.
Какой узел?
Что тут происходит\?
Предупреждение о содержании
@@ -155,8 +155,8 @@
Скачать
Отозвать запрос на подписку\?
Отписаться от этого аккаунта?
- Удалить гудок\?
- Удалить гудок и превратить его в черновик\?
+ Удалить гудок\?
+ Удалить гудок и превратить его в черновик\?
Публичный: Показать в публичных лентах
Неизвестно: Не показывать в публичных лентах
Только подписчики: Показать только подписчикам
@@ -185,8 +185,8 @@
Используйте пользовательские вкладки Chrome
Скрывать кнопку композиционирования гудка при прокрутке ленты
Язык
- Фильтрование ленты
- Вкладки
+ Фильтрование ленты
+ Вкладки
Показывать продвижения
Показывать ответы
Загрузить предпросмотр медиаконтента
@@ -202,12 +202,12 @@
Публичные
Неизвестно
Для подписчиков
- Размер текста статусов
- Крохотный
- Маленький
- Средний
- Большой
- Огромный
+ Размер текста статусов
+ Крохотный
+ Маленький
+ Средний
+ Большой
+ Огромный
Новые Упоминания
Уведомлять о новых упоминаниях
Новые подписчики
@@ -239,10 +239,10 @@
Отчеты об ошибках и ваши пожелания:
\n https://github.com/accelforce/Yuito/issues
Профиль Yuito
- Поделиться содержанием гудка
- Поделиться ссылкой на гудок
- Изображения
- Видео
+ Поделиться содержанием гудка
+ Поделиться ссылкой на гудок
+ Изображения
+ Видео
Запрошенные подписки
через %dг
@@ -317,11 +317,11 @@
Закрыть аккаунт
Вам придётся вручную подтверждать подписчиков
Сохранить черновик?
- Отправка гудка…
- Ошибка при отправке гудка
- Отправка гудков
- Отправка отменена
- Копия поста сохранена в ваши черновики
+ Отправка гудка…
+ Ошибка при отправке гудка
+ Отправка гудков
+ Отправка отменена
+ Копия поста сохранена в ваши черновики
Сочинить
У вашего узла %s нет собственных эмодзи
Скопировано в буфер обмена
@@ -329,8 +329,8 @@
Системный
Сперва эти наборы эмодзи нужно скачать
Производится поиск…
- Раскрыть/свернуть все статусы
- Открыть гудок
+ Раскрыть/свернуть все статусы
+ Открыть гудок
Необходимо перезапустить приложение
Вам нужно перезапустить Yuito для применения изменений
Позже
@@ -378,15 +378,15 @@
- достигнут лимит в %1$d вкладок
- достигнут лимит в %1$d вкладок
-
+
Медиафайл: %s
- Предупреждение о содержании: %s
-
+ Предупреждение о содержании: %s
+
Без описания
- Реблогнуто
- Понравилось
+ Реблогнуто
+ Понравилось
Публичный
@@ -436,7 +436,7 @@
Жалоба на @%s отправлена
Переслать в %s
Не удалось пожаловаться
- Не удалось получить статусы
+ Не удалось получить статусы
Жалоба будет отправлена модератору вашего узла. Ниже вы можете добавить пояснение о причинах жалобы:
Этот аккаунт расположен на другом узле. Отправить анонимную копию жалобы туда\?
Показать фильтр уведомлений
@@ -456,22 +456,22 @@
Множественный выбор
Вариант %d
Изменить
- Запланированные гудки
+ Запланированные гудки
Редактировать
- Запланированные гудки
- Запланировать гудок
+ Запланированные гудки
+ Запланировать гудок
Сброс
Закладки
Добавить в закладки
Закладки
Работает на Tusky
- Добавлено в закладки
+ Добавлено в закладки
Выбрать список
Список
Аудиофайлы должны быть меньше 40МБ.
Ошибка поиска поста %s
У вас нет черновиков.
- У вас нет запланированный статусов.
+ У вас нет запланированный статусов.
Минимальный интервал планирования в Mastodon составляет 5 минут.
Показывать диалог подтверждения перед продвижением
Показывать предпросмотр ссылок в лентах
@@ -516,8 +516,8 @@
Самочувствие
Неопределённая
Продолжительность
- Вложения
- Аудио
+ Вложения
+ Аудио
%s только что опубликовал(а)
Несмотря на то, что ваша учетная запись не закрыта, наши сотрудники %1$s решили, что вы, возможно, захотите просмотреть запросы на отслеживание от этих учетных записей вручную.
@@ -529,10 +529,10 @@
Скрыть количественную статистику по постам
Отписаться
Подписаться
- Гудок который Вы записали в черновик был удален
+ Гудок который Вы записали в черновик был удален
Не удалось загрузить информацию об ответе
Черновик удалён
- Этот гудок не удалось отправить!
+ Этот гудок не удалось отправить!
Вы действительно хотите удалить список %s\?
Скрыть количественную статистику по профилям пользователей
Ограничение уведомлений в ленте
diff --git a/app/src/main/res/values-sa/strings.xml b/app/src/main/res/values-sa/strings.xml
index 29994122c..b69336ede 100644
--- a/app/src/main/res/values-sa/strings.xml
+++ b/app/src/main/res/values-sa/strings.xml
@@ -25,17 +25,17 @@
दोषो जातः ।
न किमप्यत्र । नवीकरणार्थमाकृष्यतामधः !
न किमप्यत्र ।
- संनिपत्यताम्
- विस्तार्यताम्
- स्वल्पं दृश्यताम्
- अधिकं दृश्यताम्
- द्रष्टुमत्र नुद्यताम्
- प्रच्छन्नसामग्र्यः
- संवेदनशीलो विषयः
- %s अप्रकाशयत्
- \@%s
+ संनिपत्यताम्
+ विस्तार्यताम्
+ स्वल्पं दृश्यताम्
+ अधिकं दृश्यताम्
+ द्रष्टुमत्र नुद्यताम्
+ प्रच्छन्नसामग्र्यः
+ संवेदनशीलो विषयः
+ %s अप्रकाशयत्
+ \@%s
अनुज्ञापत्राणि
- कालबद्धदौत्यानि
+ कालबद्धदौत्यानि
लेखविकर्षाः
स्वीयव्यक्तिविवरणं सम्पाद्यताम्
अनुसरणार्थमनुरोधाः
@@ -46,9 +46,9 @@
प्रियाः
अनुसर्तारः
अनुसरति
- कीलिताः
- सप्रत्युत्तरम्
- प्रकटनानि
+ कीलिताः
+ सप्रत्युत्तरम्
+ प्रकटनानि
दौत्यम्
पीठिकाः
प्रत्यक्षसन्देशाः
@@ -106,8 +106,8 @@
चित्रं गृह्यताम्
मतदानं युज्यताम्
सामग्र्यस्मै विभाज्यताम् …
- दौत्यमस्मै विभाज्यताम् …
- दौत्यजालस्थलमस्मै विभाज्यताम् …
+ दौत्यमस्मै विभाज्यताम् …
+ दौत्यजालस्थलमस्मै विभाज्यताम् …
सामग्री अवारोप्यमाणा
सामग्री अवारोप्यताम्
एवं विभाज्यताम् …
@@ -126,11 +126,11 @@
जालस्थलानि
पीठिका युज्यताम्
पुनरारम्भः
- कालबद्धदौत्यं क्रियताम्
+ कालबद्धदौत्यं क्रियताम्
भावचिह्नटङ्कणफलकम्
विषयप्रत्यादेशः
दौत्यसुदर्शता
- कालबद्धदौत्यानि
+ कालबद्धदौत्यानि
लेखविकर्षाः
अन्विष्यताम्
अस्वीक्रियताम्
@@ -161,8 +161,8 @@
विषयप्रत्यादेशः
किं वर्तमानमस्ति \?
किं विशिष्टस्थलम् \?
- सफलं प्रत्युत्तरप्रेषणम् ।
- प्रेषितम्!
+ सफलं प्रत्युत्तरप्रेषणम् ।
+ प्रेषितम्!
%s अनावृतः
सूच्यतां मे यदा
ज्योत्या सूच्यताम्
@@ -180,8 +180,8 @@
किल अवरुध्यताम् @%s\?
प्रदेशः छाद्यताम्
निश्चियेन सर्वमेव निषिद्धं भवेदेतस्य जनस्य %s \? कोऽपि विषयो न द्रष्टुं शक्यते तत्प्रदेशात् कस्यामपि समयतालिकायामुत वा ते सूचनापेटिकायाम् । भवदनुसर्तारः तस्मात्प्रदेशान्निष्क्रियन्ते ।
- विनश्य पुनः लिख्यताम् \?
- दौत्यमेतन्नश्यताम्\?
+ विनश्य पुनः लिख्यताम् \?
+ दौत्यमेतन्नश्यताम्\?
अनुसरणं नश्यताम् \?
अवारोप्यताम्
उपारोप्यमाणम्…
@@ -233,10 +233,10 @@
%dd दि
%dy वर्ष
अनुसरणं निवेदितम्
- चलचित्राणि
- चित्राणि
- दौत्याय जालस्थानं विभाज्यताम्
- दौत्यविषयो विभाज्यताम्
+ चलचित्राणि
+ चित्राणि
+ दौत्याय जालस्थानं विभाज्यताम्
+ दौत्यविषयो विभाज्यताम्
टस्कीवर्यस्य व्यक्तिगतविवरणम्
अशुद्धीनामावेदनं वैशिष्ट्यनिवेदनञ्च
\n https://github.com/tuskyapp/Tusky/issues
@@ -266,12 +266,12 @@
नवानुसर्तृृन्नधिकृत्य सूचनाः
नवानुसर्तारः
नवोल्लेखाः
- स्थूलतमः
- स्थूलः
- मध्यमः
- सूक्ष्मः
- सूक्ष्मतमः
- दौत्यस्य / स्थितेरक्षराकारः
+ स्थूलतमः
+ स्थूलः
+ मध्यमः
+ सूक्ष्मः
+ सूक्ष्मतमः
+ दौत्यस्य / स्थितेरक्षराकारः
केवलमनुसर्तृभ्यः
अनिर्दिष्टम्
सार्वजनिकम्
@@ -290,8 +290,8 @@
सामग्रीणां पूर्वोद्घाटनमवारोप्यताम्
प्रत्युत्तराणि दृश्यन्ताम्
प्रकाशनानि दृश्यन्ताम्
- पीठिकाः
- समयतालिका-शोधनम्
+ पीठिकाः
+ समयतालिका-शोधनम्
छादितसामग्रीभ्यो बहुवर्णयुतचित्रं दर्शयतु
सञ्जीवितावतारः क्रियताम्
स्वचालितयन्त्रेभ्यः सूचको दृश्यताम्
@@ -320,11 +320,11 @@
अंशफलकेऽनुसृतम्
भवदीयं विशिष्टस्थलं %s स्वीयानुकूलभावचिह्नरहितं वर्तते
लिख्यताम्
- दौत्यप्रतिलिपिस्तत्र विकर्षेसु रक्षिता
- प्रेषणं निराकृतम्
- प्रेष्यमाणानि
- दौत्यप्रेषणे दोषः
- दौत्यं प्रेष्यमाणम्…
+ दौत्यप्रतिलिपिस्तत्र विकर्षेसु रक्षिता
+ प्रेषणं निराकृतम्
+ प्रेष्यमाणानि
+ दौत्यप्रेषणे दोषः
+ दौत्यं प्रेष्यमाणम्…
रक्षणीयम् \?
स्वयमेवाऽनुसर्तॄणां कृतेऽनुमतिर्दातव्या
लेखा अवरुध्यताम्
@@ -348,8 +348,8 @@
पश्चात्
पुनश्च टस्कीप्रारम्भोऽपेक्षितो वर्तते परिवर्तनानुसरेण चलितुम्
अनुप्रयोगप्रारम्भः आवश्यकः
- दौत्यमुद्घाट्यताम्
- विस्तार्यन्तां नश्यन्तां वा स्थतयः
+ दौत्यमुद्घाट्यताम्
+ विस्तार्यन्तां नश्यन्तां वा स्थतयः
अन्वेषणं भवद्वर्तते…
कीलयतु
कीलनं नश्यताम्
@@ -372,7 +372,7 @@
प्रकाशनात् प्राक् पुष्टिसंवादमञ्जूषा दर्शनीया
जालस्थानप्रदर्शनं समयतालिकायां दर्शयतु
मास्टोडोने पञ्चनिमेषपरिमितो न्यूनतमः कालबद्धसमयः ।
- न ते कालबद्धदौत्यानि सन्ति ।
+ न ते कालबद्धदौत्यानि सन्ति ।
सम्पाद्यताम्
मतम् %d
बहूनि मतानि
@@ -391,7 +391,7 @@
व्यक्तित्वविवरणलेखाः
अन्यजालवितारकादियं व्यक्तित्वविवरणलेखा । आवेदनस्य रक्षितप्रतिलिपिरपि प्रेष्यतां वा \?
आवेदनमिदं जालवितारकाय प्रेष्यते । स्वीयविवरणमस्मिन् विषयेऽधो लेखितुं शक्नोषि-:
- दौत्यानि गृहीतुं विफलता
+ दौत्यानि गृहीतुं विफलता
आवेदनप्रेषणे विफलता
अस्मै पुरस्क्रियताम् %s
अन्याः टिप्पण्यः
@@ -447,12 +447,12 @@
अनुसर्तारः
अनिर्दिष्टम्
सार्वजनिकम्
- पुटचिह्नं कृतम्
- प्रीतिर्दत्ता
- पुनर्लिखितम्
- विवरणं नास्ति
- विषयपूर्वसतर्कता: %s
- सामग्र्यः %s
+ पुटचिह्नं कृतम्
+ प्रीतिर्दत्ता
+ पुनर्लिखितम्
+ विवरणं नास्ति
+ विषयपूर्वसतर्कता: %s
+ सामग्र्यः %s
- अधिकतमपीठिकासङ्ख्या %1$d भूता
diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml
index 5b88bf6f1..df654a291 100644
--- a/app/src/main/res/values-si/strings.xml
+++ b/app/src/main/res/values-si/strings.xml
@@ -14,7 +14,7 @@
දවස් 1
දවස් 7
සංස්කරණය
- පිළිතුරු සමඟ
+ පිළිතුරු සමඟ
අවහිර කළ පරිශීලකයින්
කටුපිටපත්
කිසිවක් නැත. නැවුම් කිරීමට පහළට අදින්න!
@@ -28,26 +28,26 @@
සම්බන්ධ වෙමින්…
දැනුම්දීම්
ප්රසිද්ධ
- ඇමුණුම්
+ ඇමුණුම්
නව සැඳහුම්
රචනා කරන්න
- තව පෙන්වන්න
- ටූට් හි පිටපතක් ඔබගේ කටුපිටපත් තුළට සුරකින ලදි
+ තව පෙන්වන්න
+ ටූට් හි පිටපතක් ඔබගේ කටුපිටපත් තුළට සුරකින ලදි
මාධ්ය සඟවන්න
පැතිකඩ සංස්කරණය
යැවිණි!
යළි සකසන්න
- අඩුවෙන් පෙන්වන්න
+ අඩුවෙන් පෙන්වන්න
තත්. %d කින්
නිහඬ කළ පරිශීලකයින්
බෙදාගන්න
%1$s ගෙන ගොස් ඇත:
- ටූට් වෙත සබැඳියක් බෙදාගන්න
+ ටූට් වෙත සබැඳියක් බෙදාගන්න
බලපත්ර
පැතිකඩ සංස්කරණය
දර්ශන නාමය
- මධ්යම
- ශ්රව්ය
+ මධ්යම
+ ශ්රව්ය
දැනුම්දීම් පෙරහන පෙන්වන්න
දව. %d
නික්මෙන්න
@@ -58,8 +58,8 @@
%1$s • %2$s
යළි උත්සාහය
ගිණුම අගුළුලන්න
- මාධ්ය සැඟවී ඇත
- පිළිතුර සාර්ථකව යැවිණි.
+ මාධ්ය සැඟවී ඇත
+ පිළිතුර සාර්ථකව යැවිණි.
ඒකාබද්ධ
උඩුගත වෙමින්…
ගිණුම එකතු කරන්න
@@ -73,10 +73,10 @@
\@%s වාර්තා කරන්න
අතිරේක අදහස්\?
සඳහන් කළ
- වෙත ටූට් ඒ.ස.නි. බෙදාගන්න…
+ වෙත ටූට් ඒ.ස.නි. බෙදාගන්න…
දීප්ත
කටුපිටපත සුරකින්නද\?
- සංවේදී අන්තර්ගතයකි
+ සංවේදී අන්තර්ගතයකි
ස්වයංක්රමලේඛය
පොත්යොමුව
ගූගල් හි වත්මන් ඉමෝජි කට්ටලය
@@ -118,18 +118,18 @@
දැනුම්දීම්
පරිශීලක අනවහිර කෙරිණි
දත්ත එක්කරන්න
- වෙත ටූට් බෙදාගන්න…
- යැවීම අවලංගු කෙරිණි
+ වෙත ටූට් බෙදාගන්න…
+ යැවීම අවලංගු කෙරිණි
අනවහිර
ටූට්!
ප්රියතමයන්
%1$s බාගත වෙමින්
- තත්ව ගෙන ඒමට අසමත් විය
- මාධ්ය: %s
+ තත්ව ගෙන ඒමට අසමත් විය
+ මාධ්ය: %s
සංවාදය නිහඬ කරන්න
- ටූට්ස් යැවෙමින්
+ ටූට්ස් යැවෙමින්
සංවාද
- විශාල
+ විශාල
ප්රසිද්ධ
නව මාස්ටඩන් ගිණුමක් එක්කරන්න
මාධ්ය උඩුගත වීම අහවර වෙමින්
@@ -142,7 +142,7 @@
ප්රියතමයන්
පිළිතුරු…
කාලරේඛා දැනුම්දීම් සීමාකරන්න
- ටූට් යැවීමේ දෝෂයකි
+ ටූට් යැවීමේ දෝෂයකි
පෙරහන එකතු කරන්න
සැමවිටම මාධ්ය සංවේදී ලෙස සලකුණු කරන්න
යෙදුම යළි ඇරඹීම ඇවැසිය
@@ -152,7 +152,7 @@
මෙම වෙනස්කම් යෙදීමට ඔබ ටුස්කි නැවත ඇරඹිය යුතුය
සංස්කරණය
ඉදිරියට
- කාලරේඛාව පෙරීම
+ කාලරේඛාව පෙරීම
%1$s, %2$s සහ තවත් %3$d
කාලරේඛා
%s නිහඬ කරන්න
@@ -161,10 +161,10 @@
අවහිර
මාධ්ය බාගන්න
සැඟවුනු වසම්
- කුඩා
+ කුඩා
අන්තර්ගත අවවාද සමඟ ඇති ටූට්ස් සැමවිටම විහිදන්න
පෙරසේ
- විහිදන්න
+ විහිදන්න
නිහඬ කරන්න
ටුස්කි %s
වියමන අඩවිය:
@@ -177,7 +177,7 @@
මාධ්ය එකතු කරන්න
ද. %d කින්
%1$s, %2$s, %3$s සහ වෙනත් %4$d
- ටූට් විවෘත කරන්න
+ ටූට් විවෘත කරන්න
සැඟවුනු වසම්
පැය %d
සැකසුම් සමමුහූර්ත වීමට අසමත් විය
@@ -202,7 +202,7 @@
භාෂාව
සුරැකිණි!
ටුස්කි\'හි පැතිකඩ
- ටූට්හි අන්තර්ගතය බෙදාගන්න
+ ටූට්හි අන්තර්ගතය බෙදාගන්න
අන්තර්ගතය
නව ටූට්ස්
#%d මාධ්ය විවෘත කරන්න
@@ -213,9 +213,9 @@
වෙත මාධ්ය බෙදාගන්න…
ප්රසිද්ධ කාලරේඛා
- කුඩාම
+ කුඩාම
මත විමසුම්
- දැකීමට ඔබන්න
+ දැකීමට ඔබන්න
වසා ඇත
- දවස් %d ක් ඉතිරිය
@@ -248,23 +248,23 @@
මෙම ගිණුම පිළිබඳව ඔබගේ පෞද්ගලික සටහන
වසන්න
දැනුම්දීම්
- \@%s
- යැවිණි!
+ \@%s
+ යැවිණි!
මාස්ටඩන් සමඟ පිවිසෙන්න
ජන්දය
මුළු වචනය
- මෙම ටූට් යැවීමට අසමත් විය!
- දෘශ්යකය
+ මෙම ටූට් යැවීමට අසමත් විය!
+ දෘශ්යකය
පසුව
සංස්කරණය
අඳුරු
කිසිවක් නැත.
- ටූට් යැවෙමින්…
+ ටූට් යැවෙමින්…
පද්ධති පෙරනිමිය
සඳැහුම
ඉවත් කරන්න
දැනුම්දීම් සඟවන්න
- තත්ව පාඨයේ ප්රමාණය
+ තත්ව පාඨයේ ප්රමාණය
කාලරේඛාවෙහි සබැඳි පෙරදසුන් පෙන්වන්න
සබැඳි
අතිරික්සුව
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 5b026442f..15d05945c 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -12,18 +12,18 @@
Vyskytla sa chyba.
Oznámenia
Priame správy
- S odpoveďmi
- Pripnuté
+ S odpoveďmi
+ Pripnuté
Sledujúci
Záložky
Licencie
- \@%s
- Citlivý obsah
- Kliknite pre zobrazenie
- Zobraziť viac
- Zobraziť menej
- Rozbaliť
- Zabaliť
+ \@%s
+ Citlivý obsah
+ Kliknite pre zobrazenie
+ Zobraziť viac
+ Zobraziť menej
+ Rozbaliť
+ Zabaliť
Nahlásiť používateľa @%s
Rýchla odpoveď
Odpovedať
@@ -63,8 +63,8 @@
Otvoriť ako %s
Odoslané!
Používateľ bol odblokovaný
- Odoslané!
- Odpoveď bola úspešne odoslaná.
+ Odoslané!
+ Odpoveď bola úspešne odoslaná.
Ktorý server\?
Zobrazované meno
O vás
@@ -85,24 +85,24 @@
TOOT
TOOT!
Viditeľnosť tootu
- Naplánovať toot
- Vymazať tento toot\?
- Vymazať a prepísať tento toot\?
- Zdieľať obsah tootu
- Zdieľať odkaz tootu
- Odosielanie tootu…
- Chyba pri odosielaní tootu
- Kópia vášho tootu bola uložená do konceptov
- Otvoriť toot
+ Naplánovať toot
+ Vymazať tento toot\?
+ Vymazať a prepísať tento toot\?
+ Zdieľať obsah tootu
+ Zdieľať odkaz tootu
+ Odosielanie tootu…
+ Chyba pri odosielaní tootu
+ Kópia vášho tootu bola uložená do konceptov
+ Otvoriť toot
Napísať toot
- Plánované tooty
- Plánované tooty
+ Plánované tooty
+ Plánované tooty
Avatar
Odstrániť
Uzamknúť účet
Uložiť koncept\?
- Odosielanie tootov
- Odosielanie bolo zrušené
+ Odosielanie tootov
+ Odosielanie bolo zrušené
Vyhľadávanie…
Neskôr
Reštartovať
@@ -114,7 +114,7 @@
Obsah
%1$s
%1$s a %2$s
- Žiadny popis
+ Žiadny popis
Verejný
Podporiť
Prestať podporovať
@@ -131,5 +131,5 @@
Obľúbené
Odstrániť
Obľúbené
- Panely
+ Panely
\ No newline at end of file
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index ec9ee863f..81847ab9d 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -24,9 +24,9 @@
Neposredna Sporočila
Zavihki
Tut
- Objave
- Z odgovori
- Pripeto
+ Objave
+ Z odgovori
+ Pripeto
Sledi
Sledilci
Priljubljene
@@ -36,18 +36,18 @@
Uredi svoj profil
Osnutki
Licence
- \@%s
- Občutljiva vsebina
- Medij je skrit
- Kliknite za ogled
- Pokaži več
- Pokaži manj
- Razširi
- Strni
+ \@%s
+ Občutljiva vsebina
+ Medij je skrit
+ Kliknite za ogled
+ Pokaži več
+ Pokaži manj
+ Razširi
+ Strni
Tukaj ni ničesar.
Tukaj ni ničesar. Potegnite navzdol za osvežitev!
%s je spodbudil tvoj tut
- % je vzljubil vaš tut
+ %s je vzljubil vaš tut
%s vam sledi
Prijavi @%s
Dodatni komentarji\?
@@ -115,12 +115,12 @@
Deli kot …
Prenos medija
Prejemanje medija
- Deli URL tuta z…
- Deli tut z…
+ Deli URL tuta z…
+ Deli tut z…
Deli medij z…
Pošlji!
- Pošlji!
- Odgovor je bil uspešno poslan.
+ Pošlji!
+ Odgovor je bil uspešno poslan.
Kaj se dogaja\?
Opozorilo o vsebini
Prikazano ime
@@ -153,7 +153,7 @@
Prejmi
Želite preklicati to zahtevo\?
Prenehajte slediti temu računu\?
- Želite izbrisati ta tut\?
+ Želite izbrisati ta tut\?
Javno: Objavi v javnih časovnicah
Ni prikazano: Ne prikaže v javnih časovnicah
Samo sledilci: Objavi samo sledilcem
@@ -177,8 +177,8 @@
Uporabi Chromove zavihke po meri
Med pomikanjem skrij gumb za sestavljanje
Jezik
- Filtriranje časovnice
- Zavihki
+ Filtriranje časovnice
+ Zavihki
Pokaži spodbude
Pokaži odgovore
Prenesi predoglede medijev
@@ -191,7 +191,7 @@
Vedno označite medije kot občutljive
Objavljanje (sinhronizirano s strežnikom)
Nastavitev ni bilo mogoče sinhronizirati
- Velikost besedila statusa
+ Velikost besedila statusa
Nove omembe
Obvestila o novih omembah
Novi sledilci
@@ -216,10 +216,10 @@
Poročila o napakah in želje za nove funkcije:
\nhttps://github.com/accelforce/Yuito/issues
Profil Yuito
- Deli vsebino tuta
- Deli povezavo do tuta
- Slike
- Video
+ Deli vsebino tuta
+ Deli povezavo do tuta
+ Slike
+ Video
Prošnja za sledenje
v %dy
v %dd
@@ -269,11 +269,11 @@
Zakleni račun
Zahtevana je ročna potrditev sledilcev
Shrani osnutek\?
- Pošiljanje tuta…
- napaka pri pošiljanju tuta
- Pošiljanje tutov
- Pošiljanje je preklicano
- Kopija tuta je bila shranjena v osnutke
+ Pošiljanje tuta…
+ napaka pri pošiljanju tuta
+ Pošiljanje tutov
+ Pošiljanje je preklicano
+ Kopija tuta je bila shranjena v osnutke
Sestavi
Vaše vozlišče %s nima emotikonov po meri
Kopirano v odložišče
@@ -281,13 +281,13 @@
Privzete nastavitve sistema
Najprej boste morali prenesti te emotikone
Izvajanje iskanja…
- Razširi/Strni vse statuse
- Odpri tut
+ Razširi/Strni vse statuse
+ Odpri tut
Potreben je ponovni zagon aplikacije
Če želite uveljaviti te spremembe, morate znova zagnati Yuito
Kasneje
Znova zaženi
- "Privzeti komplet emotikonov vaše naprave "
+ Privzeti komplet emotikonov vaše naprave
Blob emotikoni so znani od Android 4.4-7.1
Mastodonov privzeti komplet emotikonov
Prenos ni uspel
@@ -321,11 +321,11 @@
- doseženih maksimalnih %1$d zavihkov
- Mediji: %s
- Opozorila o vsebini: %s
- Brez opisa
- Ponovno objavljen
- Priljubljene
+ Mediji: %s
+ Opozorila o vsebini: %s
+ Brez opisa
+ Ponovno objavljen
+ Priljubljene
Javno
Ni prikazano
Sledilci
@@ -340,7 +340,7 @@
Prikaži kazalnik za robote
Ali ste prepričani, da želite trajno izbrisati vsa obvestila\?
Izbriši in preoblikuj
- Izbriši in preoblikuj tut\?
+ Izbriši in preoblikuj tut\?
%1$s • %2$s
- %s glas
@@ -360,11 +360,11 @@
Javno
Ni prikazano
Samo za sledilce
- Najmanjša
- Majhna
- Srednja
- Velika
- Največja
+ Najmanjša
+ Majhna
+ Srednja
+ Velika
+ Največja
Ankete
Obvestilo o anketah, ki so se končale
Dejanje za sliko %s
@@ -404,7 +404,7 @@
Dodatni komentarji
Posreduj %s
Prijava je bila neuspešna
- Statusov ni bilo mogoče pridobiti
+ Statusov ni bilo mogoče pridobiti
Poročilo bo poslano moderatorju strežnika. Spodaj lahko navedete, zakaj prijavljate ta račun:
Račun je iz drugega strežnika. Pošljem anonimno kopijo poročila tudi na drugi strežnik\?
Skrite domene
@@ -432,14 +432,14 @@
Več izbir
Izbira %d
Uredi
- Napovedani tuti
+ Napovedani tuti
Uredi
- Napovedani tuti
+ Napovedani tuti
Ponastavi
- Napovej tut
+ Napovej tut
Napaka pri iskanju objave %s
Poganja ga Tusky
- %s spodbudil
+ %s spodbudil
Ključniki
Zahteve za Sledenje
@@ -448,4 +448,4 @@
- %1$s Priljubljene
- %1$s Priljubljenih
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 7bcddcfc6..fd54e2d5a 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -26,9 +26,9 @@
Direkta meddelanden
Flikar
Toot
- Inlägg
- Med svar
- Fastnålade
+ Inlägg
+ Med svar
+ Fastnålade
Följer
Följare
Favoriter
@@ -38,15 +38,15 @@
Ändra din profil
Utkast
Licenser
- \@%s
- %s knuffade
- Känsligt innehåll
- Dold media
- Tryck för att visa
- Visa mer
- Visa mindre
- Expandera
- Dölj
+ \@%s
+ %s knuffade
+ Känsligt innehåll
+ Dold media
+ Tryck för att visa
+ Visa mer
+ Visa mindre
+ Expandera
+ Dölj
Ingenting här.
Inget här. Dra ner för att uppdatera!
%s knuffade din toot
@@ -120,14 +120,14 @@
Kopiera länk
Öppna med %s
Dela som …
- Dela toot-URL till…
- Dela toot till…
+ Dela toot-URL till…
+ Dela toot till…
Dela media till…
Skickat!
Användare avblockerad
Användaren är inte tystad längre
- Skickat!
- Svar skickades framgångsrikt.
+ Skickat!
+ Svar skickades framgångsrikt.
Vilken instans?
Vad händer?
Innehållsvarning
@@ -153,7 +153,7 @@
Ladda ned
Återkalla följningsförfrågan?
Sluta följ detta konto\?
- Radera denna toot?
+ Radera denna toot?
Offentlig: Skicka till offentliga tidslinjer
Olistad: Visa inte i offentliga tidslinjer
Enbart-följare: Ses enbart av följare
@@ -182,8 +182,8 @@
Använd Chrome-anpassade flikar
Dölj skriv-knappen vid skrollning
Språk
- Filtrering av tidslinje
- Flikar
+ Filtrering av tidslinje
+ Flikar
Visa knuffar
Visa svar
Visa en förhandsgranskning
@@ -199,12 +199,12 @@
Offentlig
Olistad
Endast följare
- Textstorlek på status
- Minsta
- Liten
- Mellan
- Stor
- Största
+ Textstorlek på status
+ Minsta
+ Liten
+ Mellan
+ Stor
+ Största
Nya omnämnanden
Aviseringar om nya omnämnanden
Nya följare
@@ -237,10 +237,10 @@
https://github.com/accelforce/Yuito/issues
Tuskys Profil
- Dela innehåll av toot
- Dela länk till toot
- Bilder
- Video
+ Dela innehåll av toot
+ Dela länk till toot
+ Bilder
+ Video
Följarförfrågan
om %dy
@@ -290,11 +290,11 @@
Lås konto
Kräver att du manuellt godkänner följare
Spara utkast?
- Skickar toot…
- Kunde inte skicka toot
- Skickar toot
- Sändning avbruten
- En kopia av tooten har sparats i dina utkast
+ Skickar toot…
+ Kunde inte skicka toot
+ Skickar toot
+ Sändning avbruten
+ En kopia av tooten har sparats i dina utkast
Skriv
Din instans %s har inga anpassade emojis
Kopierat till urklipp
@@ -302,8 +302,8 @@
Systemstandard
Du behöver ladda ned dessa emojis först
Utför sökning…
- Expandera/Dölj alla statusar
- Öppna toot
+ Expandera/Dölj alla statusar
+ Öppna toot
Omstart av appen krävs
Du måste starta om Yuito för att tillämpa ändringarna
Senare
@@ -344,14 +344,14 @@
- max antal flikar %1$d uppnådd
- Media: %s
+ Media: %s
- Innehållsvarning: %s
- Ingen beskrivning
+ Innehållsvarning: %s
+ Ingen beskrivning
- Knuffad
+ Knuffad
- Favoriserad
+ Favoriserad
Publik
@@ -373,7 +373,7 @@
Visa robotindikator
Är du säker på att du vill rensa dina aviseringar permanent\?
Radera och skriv på nytt
- Radera och skriv ny toot\?
+ Radera och skriv ny toot\?
%1$s • %2$s
- %s röst
@@ -420,7 +420,7 @@
Ytterligare kommentarer
Vidarebefordra till %s
Misslyckades att anmäla
- Misslyckades att hämta status
+ Misslyckades att hämta status
Anmälan kommer att skickas till din servermoderator. Du kan beskriva varför du anmäler kontot nedan:
Kontot är från en annan server. Skicka en anonym kopia av anmälan dit också\?
Visa notifikationsfilter
@@ -442,20 +442,20 @@
Flerval
Val %d
Redigera
- Schemalagda toots
+ Schemalagda toots
Ändra
- Schemalagda toots
- Schemalägg toot
+ Schemalagda toots
+ Schemalägg toot
Återställ
Fel vid uppslagning av status %s
Bokmärken
Bokmärk
Bokmärken
Drivs av Tusky
- Bokmärkt
+ Bokmärkt
Välj lista
Lista
- Du har inga schemalagda statusar.
+ Du har inga schemalagda statusar.
Ljudfiler måste vara mindre än 40MB.
Du har inga utkast.
Mastodon har ett minimalt schemaläggningsintervall på 5 minuter.
diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml
index 6d1091299..980a23807 100644
--- a/app/src/main/res/values-ta/strings.xml
+++ b/app/src/main/res/values-ta/strings.xml
@@ -20,8 +20,8 @@
அறிவிப்புகள்
அருகாமயில்
ஒருங்கிணைந்த
- பதிவுகள்
- பதிலளிக்கபட்டவை
+ பதிவுகள்
+ பதிலளிக்கபட்டவை
பின்பற்றுகிறீர்
பின்பற்றுபவர்கள்
விரும்பியவை
@@ -30,12 +30,12 @@
பின்பற்ற கோரிக்கை
சுயவிவரத்தை திருத்த
வரைவுகள்
- %s மேலேற்றப்பட்டது
- உணர்ச்சிகரமான உள்ளடக்கம்
- ஊடகம் மறைக்கப்பட்டது
- பார்வையிட சொடுக்கவும்
- அதிகமாக்கு
- கம்மியாக்கு
+ %s மேலேற்றப்பட்டது
+ உணர்ச்சிகரமான உள்ளடக்கம்
+ ஊடகம் மறைக்கப்பட்டது
+ பார்வையிட சொடுக்கவும்
+ அதிகமாக்கு
+ கம்மியாக்கு
இங்கு எதுவுமில்லை. புதுப்பிக்க கீழே இழுக்கவும்!
%s தங்களின் toot உயர்த்தப்பட்டுள்ளது
%s தங்களின் toot பிடித்தவையானது
@@ -90,14 +90,14 @@
Emoji விசைபலகை
பதிவிறக்கப்படுகிறது %1$s
இணைப்பை நகலெடுக்கவும்
- Toot URL-யை பகிர…
- Toot உள்ளடக்கத்தை பகிர…
+ Toot URL-யை பகிர…
+ Toot உள்ளடக்கத்தை பகிர…
Mediaவை பகிர…
அனுப்பு!
பயனர் முடக்கம் நீக்கப்பட்டது
பயனர் ஒலிக்க செய்யபட்டது
- அனுப்பு!
- வெற்றிகரமாக பதிலளிக்கபட்டது.
+ அனுப்பு!
+ வெற்றிகரமாக பதிலளிக்கபட்டது.
எந்த instance(களம்)?
என்ன நடக்கிறது?
உள்ளடக்க எச்சரிக்கை
@@ -143,8 +143,8 @@
உலாவி
Chrome தனிப்பயன் கீற்றை பயன்படுத்து
உருளலின் போது எழுது பொத்தானை மறை
- காலவரிசை வடிகட்டல்
- கீற்றுகள்
+ காலவரிசை வடிகட்டல்
+ கீற்றுகள்
மேலேற்றத்தை காண்பி
பதில்களைக் காண்பி
ஊடக மாதிரிக்காட்சிகளைக் காண்பி
@@ -158,7 +158,7 @@
அனைவருக்கும்
பட்டியலிடப்படாதவர்களுக்கு
பின்பற்றுபவர்களுக்கு மட்டும்
- நிலை உரை அளவு
+ நிலை உரை அளவு
புதிய குறிப்புகள்
புதிய குறிப்புகள் பற்றிய அறிவிப்புகள்
புதிய பின்பற்றுபவர்கள்
@@ -191,10 +191,10 @@
https://github.com/accelforce/Yuito/issues
Yuito-ன் கணக்கு
- Toot உள்ளடக்கத்தைப் பகிர்
- Toot இணைப்பைப் பகிர்
- படங்கள்
- காணொளி
+ Toot உள்ளடக்கத்தைப் பகிர்
+ Toot இணைப்பைப் பகிர்
+ படங்கள்
+ காணொளி
கோரிக்கையைப் பின்பற்றவும்
%dஆ-முன்
@@ -224,11 +224,11 @@
கணக்கை முடக்கு
நீங்களாக பின்பற்றுபவர்களை அங்கீகரிக்க
வரைவை சேமிக்கவா?
- Toot அனுப்பபடுகிறது…
- Toot அனுப்புவதில் பிழை
- Toots அனுப்பபடுகிறது
- Toot அனுப்பபல் நீக்கபட்டது
- நகலெடுக்கபட்ட toot வரைவில் சேமிக்கபட்டது
+ Toot அனுப்பபடுகிறது…
+ Toot அனுப்புவதில் பிழை
+ Toots அனுப்பபடுகிறது
+ Toot அனுப்பபல் நீக்கபட்டது
+ நகலெடுக்கபட்ட toot வரைவில் சேமிக்கபட்டது
எழுது
தங்கள் %s instance(களம்)-ல் எந்தவொரு custom emojis-ம் இல்லை
பிடிப்புப்பலகையில் நகலெடுக்க
@@ -236,8 +236,8 @@
அமைப்பின் இயல்புநிலை
தாங்கள் முதலில் இந்த Emoji sets-னை பதிவிறக்கவேண்டும்
சேயல்பாட்டு தேடல்…
- அதிகமாக்கு/கம்மியாக்கு பற்றிய நிலைகள்
- Tootயை திற
+ அதிகமாக்கு/கம்மியாக்கு பற்றிய நிலைகள்
+ Tootயை திற
செயலி மறுதொடக்கம் தேவைபடுகிறது
இந்த மாறுதல்கள் செயற்படுத்த செயலியை மறுதொடக்கம் செய்ய வேண்டும்
பிறகு
@@ -266,7 +266,7 @@
டூத் அனுப்புவதில் பிழை ஏற்பட்டுள்ளது
நேரடி தகவல்
பட்டைகள்
- பொருத்தப்பட்டது
+ பொருத்தப்பட்டது
1 நாள்
3 நாட்கள்
7 நாட்கள்
@@ -281,4 +281,4 @@
பட்டியலிடப்படாதவர்களுக்கு
அனைவருக்கும்
எழுது
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml
index 1bf9649e6..b45f96582 100644
--- a/app/src/main/res/values-th/strings.xml
+++ b/app/src/main/res/values-th/strings.xml
@@ -15,7 +15,7 @@
บัญชี
บัญชีนี้มาจากเซิร์ฟเวอร์อื่น ส่งสำเนารายงานที่ไม่ระบุชื่อไปที่นั่นด้วยหรือไม่\?
รายงานจะถูกส่งไปยังผู้ดูแลเซิร์ฟเวอร์ของคุณ สามารถให้คำอธิบายว่าทำไมจึงรายงานบัญชีนี้ด้านล่าง:
- ดึงข้อมูลสถานะล้มเหลว
+ ดึงข้อมูลสถานะล้มเหลว
รายงานล้มเหลว
ส่งต่อไปยัง %s
ความคิดเห็นเพิ่มเติม
@@ -65,12 +65,12 @@
ผู้ติดตาม
ไม่อยู่ในรายการ
สาธารณะ
- คั่นหน้า
- ชื่นชอบ
- ได้ถูกเขียนใหม่
- ไม่มีคำอธิบาย
- เตือนเนื้อหา : %s
- สื่อ: %s
+ คั่นหน้า
+ ชื่นชอบ
+ ได้ถูกเขียนใหม่
+ ไม่มีคำอธิบาย
+ เตือนเนื้อหา : %s
+ สื่อ: %s
- ถึงจำนวนแท็บสูงสุดคือ %1$d แล้ว
@@ -110,8 +110,8 @@
ภายหลัง
จำเป็นต้องเริ่ม Tusky ใหม่ เพื่อใช้การเปลี่ยนแปลงเหล่านี้
จำเป็นต้องเริ่มแอปใหม่
- เปิด Toot
- ขยาย/ย่อทั้งหมด
+ เปิด Toot
+ ขยาย/ย่อทั้งหมด
กำลังค้นหา…
ต้องดาวน์โหลดชุดเอโมจิเหล่านี้ก่อน
ค่าปริยายของระบบ
@@ -119,11 +119,11 @@
คัดลอกไปยังคลิบบอร์ดแล้ว
Instance %s ไม่มีเอโมจิแบบกำหนดเอง
เขียน
- สำเนา Toot บันทึกเป็นฉบับร่างแล้ว
- การส่งถูกยกเลิก
- ส่ง Toot
- การส่ง Toot เกิดข้อผิดผลาด
- กำลังส่ง Toot…
+ สำเนา Toot บันทึกเป็นฉบับร่างแล้ว
+ การส่งถูกยกเลิก
+ ส่ง Toot
+ การส่ง Toot เกิดข้อผิดผลาด
+ กำลังส่ง Toot…
บันทึกฉบับร่าง\?
ต้องอนุมัติผู้ติดตามด้วยตัวเอง
ล็อกบัญชี
@@ -174,10 +174,10 @@
ใน %d วัน
ใน %d ปี
กำลังขอติดตาม
- วิดีทัศน์
- ภาพ
- แบ่งปันลิงก์ Toot
- แบ่งปันเนื้อหา Toot
+ วิดีทัศน์
+ ภาพ
+ แบ่งปันลิงก์ Toot
+ แบ่งปันเนื้อหา Toot
บัญชีทางการของ Tusky
รายงานช่องโหว่ และ ขอฟีเจอร์ (ภาษาอังกฤษ):
\nhttps://github.com/tuskyapp/Tusky/issues
@@ -206,12 +206,12 @@
ผู้ติดตามใหม่
การกล่าวถึงใหม่
การแจ้งเตือนเกี่ยวกับการกล่าวถึงใหม่
- ใหญ่มาก
- ใหญ่
- กลาง
- เล็ก
- เล็กมาก
- ขนาดอักษร Toot
+ ใหญ่มาก
+ ใหญ่
+ กลาง
+ เล็ก
+ เล็กมาก
+ ขนาดอักษร Toot
เฉพาะผู้ติดตาม
ไม่อยู่ในรายการ
สาธารณะ
@@ -227,8 +227,8 @@
ดาวน์โหลดตัวอย่างสื่อ
แสดงการตอบกลับ
แสดงบูสต์
- แท็บ
- คัดกรองไทม์ไลน์
+ แท็บ
+ คัดกรองไทม์ไลน์
อวตาร GIF เคลื่อนไหวได้
แสดงสัญลักษณ์ว่าเป็นบอต
ภาษา
@@ -265,8 +265,8 @@
บล็อก @%s\?
ซ่อนทั้งโดเมน
ต้องการบล็อกทุกอย่างจาก %s \? คุณจะไม่เห็นเนื้อหาจากโดเมนนั้นในไทม์ไลน์สาธารณะหรือในการแจ้งเตือน ผู้ติดตามของคุณจากโดเมนนั้นจะถูกลบออก
- ลบ แล้ว ร่าง Toot นี้ใหม่\?
- ลบ Toot นี้\?
+ ลบ แล้ว ร่าง Toot นี้ใหม่\?
+ ลบ Toot นี้\?
เลิกติดตามผู้ใช้นี้\?
ยกเลิกคำขอติดตาม\?
ดาวน์โหลด
@@ -290,15 +290,15 @@
คำเตือนเนื้อหา
เกิดอะไรขึ้นเอย\?
Instance ไหน\?
- ตอบกลับสำเร็จ
- ส่งแล้ว!
+ ตอบกลับสำเร็จ
+ ส่งแล้ว!
เลิกซ่อน %s แล้ว
เลิกบล็อกผู้ใช้แล้ว
เลิกปิดเสียงผู้ใช้นี้แล้ว
ส่งแล้ว!
แบ่งปันสื่อไป…
- แบ่งปัน Toot ไป…
- แชร์ URL Toot ไป…
+ แบ่งปัน Toot ไป…
+ แชร์ URL Toot ไป…
กำลังดาวน์โหลดสื่อ
ดาวน์โหลดสื่อ
แบ่งปันโดย…
@@ -316,11 +316,11 @@
โต้ตอบ
ลิงก์
เพิ่มแท็บ
- Toot แบบตั้งเวลา
+ Toot แบบตั้งเวลา
คีย์บอร์ดเอโมจิ
เตือนเนื้อหา
การมองเห็น Toot
- Toot แบบตั้งเวลา
+ Toot แบบตั้งเวลา
ฉบับร่าง
ปฏิเสธ
ยอมรับ
@@ -380,17 +380,17 @@
%s ได้ดันโพสต์ของคุณ
ไม่มีอะไรที่นี่ ลากลงเพื่อรีเฟรช!
ไม่มีอะไรที่นี่
- ย่อ
- ขยาย
- แสดงน้อยลง
- แสดงเพิ่มเติม
- แตะเพื่อดู
- ซ่อนสื่ออยู่
- เนื้อหาอ่อนไหว
- %s ได้ดัน
- \@%s
+ ย่อ
+ ขยาย
+ แสดงน้อยลง
+ แสดงเพิ่มเติม
+ แตะเพื่อดู
+ ซ่อนสื่ออยู่
+ เนื้อหาอ่อนไหว
+ %s ได้ดัน
+ \@%s
สัญญาอนุญาต
- โพสต์แบบกำหนดเวลา
+ โพสต์แบบกำหนดเวลา
แก้ไขโปรไฟล์
คำขอติดตาม
โดเมนที่ซ่อนไว้
@@ -399,9 +399,9 @@
ที่คั่นหน้า
ผู้ติดตาม
ติดตาม
- ปักหมุด
- โพสต์และตอบกลับ
- โพสต์
+ ปักหมุด
+ โพสต์และตอบกลับ
+ โพสต์
โพสต์
แท็บ
ข้อความโดยตรง
@@ -446,7 +446,7 @@
แสดงข้อความยืนยันก่อนที่จะบูสต์
แสดงตัวอย่างลิงก์ในไทม์ไลน์
Mastodon กำหนดเวลาขั้นต่ำ 5 นาที
- ไม่มีสถานะแบบตั้งเวลาใด ๆ
+ ไม่มีสถานะแบบตั้งเวลาใด ๆ
ไม่มีฉบับร่างใด ๆ
การค้นหาโพสต์ %s เกิดข้อผิดผลาด
แก้ไข
@@ -461,7 +461,7 @@
ซ่อนการแจ้งเตือน
ปิดเสียงการแจ้งเตือนจาก %s
ซ่อนหัวข้อของแถบเครื่องมือด้านบน
- ล้มเหลวในการส่งโพสต์นี้!
+ ล้มเหลวในการส่งโพสต์นี้!
ข้อมูลบางอย่างที่อาจส่งผลต่อสุขภาพจิตของคุณจะถูกซ่อนไว้ซึ่งรวมถึง:
\n
\n- การแจ้งเตือน ชื่นชอบ/ดัน/ติดตาม
@@ -477,7 +477,7 @@
สุขภาวะ
บันทึกส่วนตัวของคุณเกี่ยวกับบัญชีนี้
แจ้งเตือน เมื่อคนที่คุณติดตาม ได้เผยแพร่โพสต์ใหม่
- โพสต์ที่คุณได้ร่างตอบไว้ ถูกลบแลัว
+ โพสต์ที่คุณได้ร่างตอบไว้ ถูกลบแลัว
ลบฉบับร่างแล้ว
ล้มเหลวในการโหลดข้อมูลตอบกลับ
คุณต้องการลบลิสต์ %s ใช่ไหม\?
@@ -488,8 +488,8 @@
ไม่มีประกาศ
ไม่มีกำหนด
ระยะเวลา
- ไฟล์แนบ
- เสียง
+ ไฟล์แนบ
+ เสียง
โพสต์ใหม่
%s เพิ่งโพสต์
ประกาศ
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index d4b0c0944..c0c6e3067 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -26,9 +26,9 @@
Direkt mesajlar
Sekmeler
Toot
- Gönderiler
- Yanıtlarıyla
- Sabitlenmiş
+ Gönderiler
+ Yanıtlarıyla
+ Sabitlenmiş
Takip edilenler
Takipçiler
Favoriler
@@ -38,15 +38,15 @@
Profili düzenle
Taslaklar
Lisanslar
- \@%s
- %s yineledi
- Hasas medya
- Gizlenmiş medya
- Görüntülemek için dokunun
- Daha fazla göster
- Daha az göster
- Genişlet
- Daralt
+ \@%s
+ %s yineledi
+ Hasas medya
+ Gizlenmiş medya
+ Görüntülemek için dokunun
+ Daha fazla göster
+ Daha az göster
+ Genişlet
+ Daralt
Burada hiçbir şey yok.
Burada henüz hiç birşey yok. Yenilemek için aşağıya çekin!
%s tootunuzu yineledi
@@ -108,14 +108,14 @@
Bağlantıyı kopyala
Farklı aç %s
Olarak paylaş …
- Durumun adresini paylaş…
- Tootu paylaş…
+ Durumun adresini paylaş…
+ Tootu paylaş…
Medyayı paylaş…
Gönderildi!
Kullanıcının engeli kaldırıldı
Kullanıcının sesi açıldı
- İletildi!
- Yanıt başarıyla gönderildi.
+ İletildi!
+ Yanıt başarıyla gönderildi.
Hangi sunucu\?
Neler oluyor?
İçerik uyarısı
@@ -140,7 +140,7 @@
İndir
Takip isteğini iptal et\?
Takibi bırakmak istiyor musun\?
- Bu durumu silmek istiyor musunuz\?
+ Bu durumu silmek istiyor musunuz\?
Kamu: Herkese açık ve sosyal çizelgelerinde çıkar
Listelenmemiş: Genel zaman çizelgelerinde gösterme
Özel: Sadece takipçiler ve bahsedilenlere açık
@@ -166,8 +166,8 @@
Tarayıcı
Chrome Özel Şekmelerini Kullan
Kaydırırken takip düğmesi gizlensin
- Zaman çizelgesi filtreleme
- Sekmeler
+ Zaman çizelgesi filtreleme
+ Sekmeler
Yükseltilenleri göster
Yanıtları göster
Medya önizlemelerini indir
@@ -183,12 +183,12 @@
Herkese açık
Liste dışı
Sadece takipçiler
- Durum metin boyutu
- Çok küçük
- Küçük
- Orta
- Büyük
- En büyük
+ Durum metin boyutu
+ Çok küçük
+ Küçük
+ Orta
+ Büyük
+ En büyük
Yeni Bahsetmeler
Yeni bahsetmeler hakkında bildirim
Yeni Takipçiler
@@ -219,10 +219,10 @@
& özellik istekleri hata raporları:
\n https://github.com/accelforce/Yuito/issues
Yuito\'nin Profili
- İletinin içeriğini paylaş
- İletinin adresini paylaş
- Görseller
- Video
+ İletinin içeriğini paylaş
+ İletinin adresini paylaş
+ Görseller
+ Video
Takip edebilme istendi
%dy
@@ -254,11 +254,11 @@
Hesabı Kilitle
Takipçileri elle onaylamanız gerekir
Taslaklara kaydedilsin mi\?
- Toot gönderiliyor…
- Toot gönderilirken hata oluştu
- Toot Gönderiliyor
- Gönderme iptal edildi
- Tootun bir kopyası taslaklara kaydedildi
+ Toot gönderiliyor…
+ Toot gönderilirken hata oluştu
+ Toot Gönderiliyor
+ Gönderme iptal edildi
+ Tootun bir kopyası taslaklara kaydedildi
Oluştur
%s örneğinizin herhangi bir özel ifadesi yok
Panoya kopyalandı
@@ -266,8 +266,8 @@
Sistem varsayılanı
Önce bu ifade paketini indirmeniz gerekecek
Araştırılıyor…
- Tüm durumları Genişlet/Küçült
- Durumu aç
+ Tüm durumları Genişlet/Küçült
+ Durumu aç
Uygulamayı yeniden başlatmanız lazım
Bu değişiklikleri uygulamak için Tusky\'yi yeniden başlatmanız gerekecek
Sonra
@@ -346,11 +346,11 @@
Listeye hesap ekle
Hesabı listeden kaldır
Google\'ın mevcut ifade paketi
- Medya: %s
- İçerik uyarısı: %s
- Açıklama yok
- Yeniden blogladı
- Favorilendi
+ Medya: %s
+ İçerik uyarısı: %s
+ Açıklama yok
+ Yeniden blogladı
+ Favorilendi
Herkese açık
Liste dışı
Takipçiler
@@ -396,7 +396,7 @@
\@%s başarıyla bildirildi
Ek Yorumlar
%s adresine ilet
- Durumlar getirilemedi
+ Durumlar getirilemedi
Bildirim sunucu yöneticinize gönderilecektir. Bu hesabı neden bildirdiğinizle ilgili açıklama yapabilirsiniz:
Hesap başka bir sunucudan. Raporun anonim bir kopyasını da oraya gönderilsin mi\?
Bildirim filtresini göster
@@ -406,19 +406,19 @@
Bahsedenler
#%d medyayı aç
Yer imleri
- Zamanlanmış tootlar
+ Zamanlanmış tootlar
Yer imi
Düzenle
Sil ve düzenle
Yer imleri
Anket ekle
- Zamanlanmış tootlar
- Tootu zamanla
+ Zamanlanmış tootlar
+ Tootu zamanla
Sıfırla
- Bu durumu silip yeniden düzenlemek istiyor musunuz\?
+ Bu durumu silip yeniden düzenlemek istiyor musunuz\?
Botlar için işaret göster
Tusky tarafından desteklenmektedir
- Yerimine eklendi
+ Yerimine eklendi
Liste seç
Liste
Hesaplar
@@ -444,7 +444,7 @@
Seçenek %d
%s gönderisi aranırken hata oluştu
Hiç taslağınız yok.
- Zamanlanmış durumunuz yok.
+ Zamanlanmış durumunuz yok.
Kendi kitlenize yükseltin
Hashtags\'ler
Boost etmeden önce onay iletişim kutusunu göster
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 0a684c9f7..0c78cfa83 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -1,21 +1,21 @@
Сталася помилка.
- \@%s
+ \@%s
Ліцензії
Редагувати профіль
Запити на підписку
Закладки
Підписники
Підписки
- Прикріплені
- З відповідями
+ Прикріплені
+ З відповідями
Загальні
Локальні
Приватні повідомлення
Сповіщення
Головна
- Помилка надіслання допису.
+ Помилка надсилання допису.
Зображення та відео не можуть бути прикріплені до статусу одночасно.
Потрібен дозвіл на зберігання медіа.
Потрібен дозвіл на читання медіа.
@@ -45,7 +45,7 @@
Пошук…
Про себе
Що відбувається\?
- Надіслати!
+ Надіслати!
Надіслано!
Поділитися як …
Відкрити як %s
@@ -57,7 +57,7 @@
Згадки
Посилання
Попередження про вміст
- Заплановані дмухи
+ Заплановані дмухи
Чернетки
Відхилити
Прийняти
@@ -101,16 +101,16 @@
%s підписується на вас
Тут нічого немає. Потягніть вниз, щоб оновити!
Тут нічого немає.
- Згорнути
- Розгорнути
- Натисніть для перегляду
- Медіа приховано
+ Згорнути
+ Розгорнути
+ Натисніть для перегляду
+ Медіа приховано
Попередження про вміст
Змінити
Написати
Скасувати приглушення розмови
Заглушити розмову
- Заплановані дмухи
+ Заплановані дмухи
Підписники
Написати
Медіа
@@ -130,16 +130,16 @@
Розгорнути
Прибрати просування
Просунути
- %s вподобує ваш дмух
- %s просуває ваш дмух
- Згорнути
- Розгорнути
- Делікатний вміст
- %s просуває
+ %s вподобує ваш допис
+ %s просуває ваш допис
+ Згорнути
+ Розгорнути
+ Делікатний вміст
+ %s просуває
Приховані домени
Заглушені користувачі
- Дописи
- Дмухнути
+ Дописи
+ Тред
Вкладки
Не вдалося відвантажити.
Не вдалося отримати токен входу.
@@ -149,17 +149,17 @@
Введено недійсний домен
Показати просування
Показати просування
- Вкладки
+ Вкладки
Не глушити %s
- Видимість дмухів
+ Видимість дописів
Деякі відомості, які можуть вплинути на ваше психічний стан, буде приховано. Це включає:
\n
\n - Вподобання/Просування/Сповіщення про підписки
-\n - Вподобання/Кількість просувань дмухів
+\n - Вподобання/Кількість просувань дописів
\n - Статистика підписників/Публікацій у профілях
\n
\n На push-сповіщення це не вплине, але ви можете переглянути налаштування сповіщень вручну.
- Вподобано
+ Вподобано
Вподобали
- %1$s вподобання
@@ -167,7 +167,7 @@
- %1$s вподобань
- %1$s вподобань
- Сповіщати про вподобання кимось дмухів
+ Сповіщати про вподобання кимось дописів
мої дописи вподобано
Сховати медіа
Заглушити сповіщення від %s
@@ -256,9 +256,9 @@
- %s голосів
%1$s • %2$s
- Без опису
- Попередження про вміст: %s
- Медіа: %s
+ Без опису
+ Попередження про вміст: %s
+ Медіа: %s
Просунули
Вміст
CC-BY-SA 4.0
@@ -268,13 +268,13 @@
Пізніше
Вам потрібно буде перезапустити Tusky, щоб застосувати ці зміни
Необхідно перезапустити застосунок
- Відкрити дмух
- Розгорнути/згорнути всі статуси
- Копію дмуху збережено до ваших чернеток
- Надсилання скасовано
- Надсилання дмухів
- Помилка надсилання дмуху
- Надсилання дмуху…
+ Відкрити дмух
+ Розгорнути/згорнути всі статуси
+ Копію дмуху збережено до ваших чернеток
+ Надсилання скасовано
+ Надсилання дмухів
+ Помилка надсилання дмуху
+ Надсилання дмуху…
Оприлюднення з облікового запису %1$s
Вилучити обліковий запис зі списку
Додати обліковий запис до списку
@@ -302,7 +302,7 @@
Загальнодоступні стрічки
завантажити ще
Відповідь для @%s
- Завжди розгортати дмухи, з попередженнями про вміст
+ Завжди розгортати допис, з попередженнями про вміст
Підписники
Завжди показувати делікатний вміст
%dс
@@ -316,12 +316,12 @@
за %dдн
за %dр.
Запит на підписку надіслано
- Вкладення
- Звуки
- Відео
- Зображення
- Поділитися посиланням на дмух
- Поділитися вмістом дмуху
+ Вкладення
+ Звуки
+ Відео
+ Зображення
+ Поділитися посиланням на допис
+ Поділитися вмістом допису
Профіль Tusky
Звіти про вади та запити функцій:
\n https://github.com/tuskyapp/Tusky/issues
@@ -344,23 +344,23 @@
%1$s, %2$s, та %3$s
%1$s, %2$s, %3$s та %4$d інших
%s згадує вас
- Сповіщати про нові дмухи осіб, на яких ви підписалися
- Нові дмухи
+ Сповіщати про нові дописи осіб, на яких ви підписалися
+ Нові дописи
Сповіщати про завершення опитувань
Опитування
- Сповіщати про просування кимось
+ Сповіщати про просування кимось допису
Просування
Сповіщати про нові запити на підписки
Сповіщати про нових підписників
Нові підписники
Сповіщати про нові згадки
Нові згадки
- Найбільший
- Великий
- Середній
- Маленький
- Найменший
- Розмір шрифту статусу
+ Найбільший
+ Великий
+ Середній
+ Маленький
+ Найменший
+ Розмір шрифту статусу
Лише для підписників
Приховано
Приховано
@@ -380,7 +380,7 @@
Проксі
Завантаження попереднього перегляду медіа
Показати відповіді
- Фільтрування стрічки
+ Фільтрування стрічки
Анімувати власні емодзі
Показувати барвисті градієнти замість прихованих медіа
Анімовані GIF-аватарки
@@ -398,7 +398,7 @@
Стрічки
Тема застосунку
Вигляд
- хтось, на кого мене підписано, публікує новий дмух
+ хтось, на кого мене підписано, публікує новий допис
опитування завершено
мої дописи просунуто
отримано запит на підписку
@@ -418,8 +418,8 @@
Заблокувати @%s\?
Сховати весь домен
Ви впевнені, що хочете заблокувати все з %s\? Ви не побачите вміст із цього домену в жодних загальнодоступних стрічках або у своїх сповіщеннях. Ваших підписників з цього домену буде видалено.
- Видалити й переписати цей дмух\?
- Видалити цей дмух\?
+ Видалити й переписати цей дмух\?
+ Видалити цей дмух\?
Не стежити за цим обліковим записом\?
Відкликати запит на підписку\?
Завантаження
@@ -438,13 +438,13 @@
Аватар
Відповісти…
Показуване ім\'я
- Відповідь успішно надіслано.
+ Відповідь успішно надіслано.
%s показано
Глушіння користувача прибрано
Користувача розблоковано
Поділитися медіа з…
- Поділитися дмухом з…
- Поділитися URL-адресою дмуха з…
+ Поділитися дописом з…
+ Поділитися URL-адресою допису з…
Завантаження медіа
Завантажити медіа
Відкрити медіа #%d
@@ -453,12 +453,12 @@
Хештеги
Відкрити автора просування
Додати вкладку
- Запланувати дмух
+ Запланувати дмух
Клавіотура емодзі
- Дмух, для якого ви створили чернетку відповіді, вилучено
+ Дмух, для якого ви створили чернетку відповіді, вилучено
Чернетку видалено
Не вдалося завантажити дані відповіді
- Не вдалося надіслати цей дмух!
+ Не вдалося надіслати цей дмух!
Ви дійсно хочете видалити список %s\?
- Ви не можете завантажити більше ніж %1$d медіавкладення.
@@ -477,7 +477,7 @@
Показувати попередній перегляд посилань у стрічках
Найкоротший час планування Mastodon становить 5 хвилин.
Оголошень немає.
- Черга статусів порожня.
+ Черга статусів порожня.
У вас немає чернеток.
Помилка пошуку допису %s
Увімкнути перемикання між вкладками жестом проведення пальцем
@@ -485,11 +485,11 @@
Не вдалося здійснити пошук
Обліковий запис з іншого сервера. Надіслати анонімізовану копію звіту й туди\?
Скаргу буде надіслано вашому модератору сервера. Ви можете надати пояснення, чому ви повідомляєте про цей обліковий запис знизу:
- Не вдалося отримати статуси
+ Не вдалося отримати статуси
Переслати до %s
Дії для зображення %s
Ви впевнені, що хочете остаточно очистити всі сповіщення\?
- Створити дмух
+ Створити допис
Застосувати
Фільтр
Очистити
@@ -500,8 +500,8 @@
Назва списку
Опитування з варіантами: %1$s, %2$s, %3$s, %4$s; %5$s
Безпосередньо
- Додано до закладок
- Просунуто
+ Додано до закладок
+ Просунуто
- досягнено обмеження %1$d вкладка
- досягнено обмеження %1$d вкладки
@@ -540,4 +540,5 @@
90 днів
180 днів
365 днів
+ Створити допис
\ No newline at end of file
diff --git a/app/src/main/res/values-v27/styles.xml b/app/src/main/res/values-v27/styles.xml
index 78d327474..586c7f348 100644
--- a/app/src/main/res/values-v27/styles.xml
+++ b/app/src/main/res/values-v27/styles.xml
@@ -1,15 +1,5 @@
-
-
-
diff --git a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt
index ff0af12f6..19066f42e 100644
--- a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt
@@ -19,9 +19,9 @@ import android.text.SpannedString
import android.widget.LinearLayout
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.google.android.material.bottomsheet.BottomSheetBehavior
-import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.SearchResult
import com.keylesspalace.tusky.entity.Status
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.network.MastodonApi
import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.mock
@@ -57,19 +57,13 @@ class BottomSheetActivityTest {
private val emptyCallback = Single.just(SearchResult(emptyList(), emptyList(), emptyList()))
private val testScheduler = TestScheduler()
- private val account = Account(
+ private val account = TimelineAccount(
id = "1",
localUsername = "admin",
username = "admin",
displayName = "Ad Min",
- note = SpannedString(""),
url = "http://mastodon.foo.bar",
- avatar = "",
- header = "",
- locked = false,
- followersCount = 0,
- followingCount = 0,
- statusesCount = 0
+ avatar = ""
)
private val accountSingle = Single.just(SearchResult(listOf(account), emptyList(), emptyList()))
diff --git a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt
index 410522324..e7b3a1a91 100644
--- a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt
@@ -242,12 +242,12 @@ class ComposeActivityTest {
}
@Test
- fun whenTextContainsMultipleUrls_onlyEllipsizedURLIsCounted() {
+ fun whenTextContainsShortUrls_allUrlsGetEllipsized() {
val shortUrl = "https://tusky.app"
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
val additionalContent = " Check out this @image #search result: "
insertSomeTextInContent(shortUrl + additionalContent + url)
- assertEquals(activity.calculateTextLength(), additionalContent.length + shortUrl.length + DEFAULT_MAXIMUM_URL_LENGTH)
+ assertEquals(activity.calculateTextLength(), additionalContent.length + (DEFAULT_MAXIMUM_URL_LENGTH * 2))
}
@Test
@@ -271,7 +271,7 @@ class ComposeActivityTest {
}
@Test
- fun whenTextContainsMultipleUrls_onlyEllipsizedURLIsCounted_withCustomConfiguration() {
+ fun whenTextContainsShortUrls_allUrlsGetEllipsized_withCustomConfiguration() {
val shortUrl = "https://tusky.app"
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
val additionalContent = " Check out this @image #search result: "
@@ -280,7 +280,7 @@ class ComposeActivityTest {
setupActivity()
shadowOf(getMainLooper()).idle()
insertSomeTextInContent(shortUrl + additionalContent + url)
- assertEquals(activity.calculateTextLength(), additionalContent.length + shortUrl.length + customUrlLength)
+ assertEquals(activity.calculateTextLength(), additionalContent.length + (customUrlLength * 2))
}
@Test
diff --git a/app/src/test/java/com/keylesspalace/tusky/StatusComparisonTest.kt b/app/src/test/java/com/keylesspalace/tusky/StatusComparisonTest.kt
new file mode 100644
index 000000000..ed06e27c6
--- /dev/null
+++ b/app/src/test/java/com/keylesspalace/tusky/StatusComparisonTest.kt
@@ -0,0 +1,216 @@
+package com.keylesspalace.tusky
+
+import android.text.Spanned
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.gson.GsonBuilder
+import com.keylesspalace.tusky.entity.Status
+import com.keylesspalace.tusky.json.SpannedTypeAdapter
+import com.keylesspalace.tusky.viewdata.StatusViewData
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
+
+@Config(sdk = [28])
+@RunWith(AndroidJUnit4::class)
+class StatusComparisonTest {
+
+ @Test
+ fun `two equal statuses - should be equal`() {
+ assertEquals(createStatus(), createStatus())
+ }
+
+ @Test
+ fun `status with different id - should not be equal`() {
+ assertNotEquals(createStatus(), createStatus(id = "987654321"))
+ }
+
+ @Test
+ fun `status with different content - should not be equal`() {
+ val content: String = """
+ \u003cp\u003e\u003cspan class=\"h-card\"\u003e\u003ca href=\"https://mastodon.social/@ConnyDuck\" class=\"u-url mention\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e@\u003cspan\u003eConnyDuck@mastodon.social\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e 123\u003c/p\u003e
+ """.trimIndent()
+ assertNotEquals(createStatus(), createStatus(content = content))
+ }
+
+ @Test
+ fun `accounts with different notes in json - should be equal because notes are not relevant for timelines`() {
+ assertEquals(createStatus(note = "Test"), createStatus(note = "Test 123456"))
+ }
+
+ private val gson = GsonBuilder().registerTypeAdapter(
+ Spanned::class.java, SpannedTypeAdapter()
+ ).create()
+
+ @Test
+ fun `two equal status view data - should be equal`() {
+ val viewdata1 = StatusViewData.Concrete(
+ status = createStatus(),
+ isExpanded = false,
+ isShowingContent = false,
+ isCollapsible = false,
+ isCollapsed = false
+ )
+ val viewdata2 = StatusViewData.Concrete(
+ status = createStatus(),
+ isExpanded = false,
+ isShowingContent = false,
+ isCollapsible = false,
+ isCollapsed = false
+ )
+ assertEquals(viewdata1, viewdata2)
+ }
+
+ @Test
+ fun `status view data with different isExpanded - should not be equal`() {
+ val viewdata1 = StatusViewData.Concrete(
+ status = createStatus(),
+ isExpanded = true,
+ isShowingContent = false,
+ isCollapsible = false,
+ isCollapsed = false
+ )
+ val viewdata2 = StatusViewData.Concrete(
+ status = createStatus(),
+ isExpanded = false,
+ isShowingContent = false,
+ isCollapsible = false,
+ isCollapsed = false
+ )
+ assertNotEquals(viewdata1, viewdata2)
+ }
+
+ @Test
+ fun `status view data with different statuses- should not be equal`() {
+ val viewdata1 = StatusViewData.Concrete(
+ status = createStatus(content = "whatever"),
+ isExpanded = true,
+ isShowingContent = false,
+ isCollapsible = false,
+ isCollapsed = false
+ )
+ val viewdata2 = StatusViewData.Concrete(
+ status = createStatus(),
+ isExpanded = false,
+ isShowingContent = false,
+ isCollapsible = false,
+ isCollapsed = false
+ )
+ assertNotEquals(viewdata1, viewdata2)
+ }
+
+ private fun createStatus(
+ id: String = "123456",
+ content: String = """
+ \u003cp\u003e\u003cspan class=\"h-card\"\u003e\u003ca href=\"https://mastodon.social/@ConnyDuck\" class=\"u-url mention\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e@\u003cspan\u003eConnyDuck@mastodon.social\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e Hi\u003c/p\u003e
+ """.trimIndent(),
+ note: String = ""
+ ): Status {
+ val statusJson = """
+ {
+ "id": "$id",
+ "created_at": "2022-02-26T09:54:45.000Z",
+ "in_reply_to_id": null,
+ "in_reply_to_account_id": null,
+ "sensitive": false,
+ "spoiler_text": "",
+ "visibility": "public",
+ "language": null,
+ "uri": "https://pixelfed.social/p/connyduck/403124983655733325",
+ "url": "https://pixelfed.social/p/connyduck/403124983655733325",
+ "replies_count": 3,
+ "reblogs_count": 28,
+ "favourites_count": 6,
+ "edited_at": null,
+ "favourited": true,
+ "reblogged": false,
+ "muted": false,
+ "bookmarked": false,
+ "content": "$content",
+ "reblog": null,
+ "account": {
+ "id": "419352",
+ "username": "connyduck",
+ "acct": "connyduck@pixelfed.social",
+ "display_name": "Conny Duck",
+ "locked": false,
+ "bot": false,
+ "discoverable": false,
+ "group": false,
+ "created_at": "2018-08-14T00:00:00.000Z",
+ "note": "$note",
+ "url": "https://pixelfed.social/connyduck",
+ "avatar": "https://files.mastodon.social/cache/accounts/avatars/000/419/352/original/31ce660c53962e0c.jpeg",
+ "avatar_static": "https://files.mastodon.social/cache/accounts/avatars/000/419/352/original/31ce660c53962e0c.jpeg",
+ "header": "https://mastodon.social/headers/original/missing.png",
+ "header_static": "https://mastodon.social/headers/original/missing.png",
+ "followers_count": 2,
+ "following_count": 0,
+ "statuses_count": 70,
+ "last_status_at": "2022-03-07",
+ "emojis": [],
+ "fields": []
+ },
+ "media_attachments": [
+ {
+ "id": "107863694400783337",
+ "type": "image",
+ "url": "https://files.mastodon.social/cache/media_attachments/files/107/863/694/400/783/337/original/71c5bad1756bbc8f.jpg",
+ "preview_url": "https://files.mastodon.social/cache/media_attachments/files/107/863/694/400/783/337/small/71c5bad1756bbc8f.jpg",
+ "remote_url": "https://pixelfed-prod.nyc3.cdn.digitaloceanspaces.com/public/m/_v2/1138/affc38a2b-1c5f41/JRKoMNoj6dKa/9mXs0Fetvj4KwRbKypt8C1PZNVd7d3dQqod4roLZ.jpg",
+ "preview_remote_url": null,
+ "text_url": null,
+ "meta": {
+ "original": {
+ "width": 1371,
+ "height": 1080,
+ "size": "1371x1080",
+ "aspect": 1.2694444444444444
+ },
+ "small": {
+ "width": 451,
+ "height": 355,
+ "size": "451x355",
+ "aspect": 1.2704225352112677
+ }
+ },
+ "description": "Oilpainting of a kingfisher, photographed on my easel",
+ "blurhash": "UUG91|?wxHV@WTkDs.V?xZa_I:WBNFR*WBRk"
+ },
+ {
+ "id": "107863694727565058",
+ "type": "image",
+ "url": "https://files.mastodon.social/cache/media_attachments/files/107/863/694/727/565/058/original/68daef05be7ac6b6.jpg",
+ "preview_url": "https://files.mastodon.social/cache/media_attachments/files/107/863/694/727/565/058/small/68daef05be7ac6b6.jpg",
+ "remote_url": "https://pixelfed-prod.nyc3.cdn.digitaloceanspaces.com/public/m/_v2/1138/affc38a2b-1c5f41/nBVJUnrEIjfO/M6i8GSP44Iv230KWXnMpvVobOqASXY3EkImyxySS.jpg",
+ "preview_remote_url": null,
+ "text_url": null,
+ "meta": {
+ "original": {
+ "width": 1087,
+ "height": 1080,
+ "size": "1087x1080",
+ "aspect": 1.0064814814814815
+ },
+ "small": {
+ "width": 401,
+ "height": 398,
+ "size": "401x398",
+ "aspect": 1.0075376884422111
+ }
+ },
+ "description": "Oilpainting of a kingfisher",
+ "blurhash": "U89u4pPJ4:SoJ6NNnkoxoBtSx0Von-RiNgt8"
+ }
+ ],
+ "mentions": [],
+ "tags": [],
+ "emojis": [],
+ "card": null,
+ "poll": null
+ }
+ """.trimIndent()
+ return gson.fromJson(statusJson, Status::class.java)
+ }
+}
diff --git a/app/src/test/java/com/keylesspalace/tusky/StringUtilsTest.kt b/app/src/test/java/com/keylesspalace/tusky/StringUtilsTest.kt
index 30cc971a6..6910a365f 100644
--- a/app/src/test/java/com/keylesspalace/tusky/StringUtilsTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/StringUtilsTest.kt
@@ -1,9 +1,7 @@
package com.keylesspalace.tusky
-import com.keylesspalace.tusky.util.dec
-import com.keylesspalace.tusky.util.inc
import com.keylesspalace.tusky.util.isLessThan
-import org.junit.Assert.assertEquals
+import com.keylesspalace.tusky.util.isLessThanOrEqual
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
@@ -25,39 +23,16 @@ class StringUtilsTest {
}
@Test
- fun inc() {
- listOf(
- "10786565059022968z" to "107865650590229690",
- "122" to "123",
- "12A" to "12B",
- "11z" to "120",
- "0zz" to "100",
- "zz" to "000",
- "4zzbz" to "4zzc0",
- "" to "0",
+ fun isLessThanOrEqual() {
+ val lessList = listOf(
+ "abc" to "bcd",
+ "ab" to "abc",
+ "cb" to "abc",
"1" to "2",
- "0" to "1",
- "AGdxwSQqT3pW4xrLJA" to "AGdxwSQqT3pW4xrLJB",
- "AGdfqi1HnlBFVl0tkz" to "AGdfqi1HnlBFVl0tl0"
- ).forEach { (l, r) -> assertEquals("$l + 1 = $r", r, l.inc()) }
- }
-
- @Test
- fun dec() {
- listOf(
- "" to "",
- "107865650590229690" to "10786565059022968z",
- "123" to "122",
- "12B" to "12A",
- "120" to "11z",
- "100" to "0zz",
- "000" to "zz",
- "4zzc0" to "4zzbz",
- "0" to "",
- "2" to "1",
- "1" to "0",
- "AGdxwSQqT3pW4xrLJB" to "AGdxwSQqT3pW4xrLJA",
- "AGdfqi1HnlBFVl0tl0" to "AGdfqi1HnlBFVl0tkz"
- ).forEach { (l, r) -> assertEquals("$l - 1 = $r", r, l.dec()) }
+ "abc" to "abc",
+ )
+ lessList.forEach { (l, r) -> assertTrue("$l < $r", l.isLessThanOrEqual(r)) }
+ val notLessList = lessList.filterNot { (l, r) -> l == r }.map { (l, r) -> r to l }
+ notLessList.forEach { (l, r) -> assertFalse("not $l < $r", l.isLessThanOrEqual(r)) }
}
}
diff --git a/app/src/test/java/com/keylesspalace/tusky/components/timeline/CachedTimelineRemoteMediatorTest.kt b/app/src/test/java/com/keylesspalace/tusky/components/timeline/CachedTimelineRemoteMediatorTest.kt
index 4fbeb5d4b..462b0a4a0 100644
--- a/app/src/test/java/com/keylesspalace/tusky/components/timeline/CachedTimelineRemoteMediatorTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/components/timeline/CachedTimelineRemoteMediatorTest.kt
@@ -139,7 +139,75 @@ class CachedTimelineRemoteMediatorTest {
@Test
@ExperimentalPagingApi
- fun `should refresh and insert placeholder`() {
+ fun `should refresh and insert placeholder when a whole page with no overlap to existing statuses is loaded`() {
+
+ val statusesAlreadyInDb = listOf(
+ mockStatusEntityWithAccount("3"),
+ mockStatusEntityWithAccount("2"),
+ mockStatusEntityWithAccount("1"),
+ )
+
+ db.insert(statusesAlreadyInDb)
+
+ val remoteMediator = CachedTimelineRemoteMediator(
+ accountManager = accountManager,
+ api = mock {
+ on { homeTimeline(limit = 3) } doReturn Single.just(
+ Response.success(
+ listOf(
+ mockStatus("8"),
+ mockStatus("7"),
+ mockStatus("5")
+ )
+ )
+ )
+ on { homeTimeline(maxId = "3", limit = 3) } doReturn Single.just(
+ Response.success(
+ listOf(
+ mockStatus("3"),
+ mockStatus("2"),
+ mockStatus("1")
+ )
+ )
+ )
+ },
+ db = db,
+ gson = Gson()
+ )
+
+ val state = state(
+ pages = listOf(
+ PagingSource.LoadResult.Page(
+ data = statusesAlreadyInDb,
+ prevKey = null,
+ nextKey = 0
+ )
+ ),
+ pageSize = 3
+ )
+
+ val result = runBlocking { remoteMediator.load(LoadType.REFRESH, state) }
+
+ assertTrue(result is RemoteMediator.MediatorResult.Success)
+ assertEquals(false, (result as RemoteMediator.MediatorResult.Success).endOfPaginationReached)
+
+ db.assertStatuses(
+ listOf(
+ mockStatusEntityWithAccount("8"),
+ mockStatusEntityWithAccount("7"),
+ TimelineStatusWithAccount().apply {
+ status = Placeholder("5", loading = false).toEntity(1)
+ },
+ mockStatusEntityWithAccount("3"),
+ mockStatusEntityWithAccount("2"),
+ mockStatusEntityWithAccount("1"),
+ )
+ )
+ }
+
+ @Test
+ @ExperimentalPagingApi
+ fun `should refresh and not insert placeholder when less than a whole page is loaded`() {
val statusesAlreadyInDb = listOf(
mockStatusEntityWithAccount("3"),
@@ -176,7 +244,7 @@ class CachedTimelineRemoteMediatorTest {
)
val state = state(
- listOf(
+ pages = listOf(
PagingSource.LoadResult.Page(
data = statusesAlreadyInDb,
prevKey = null,
@@ -195,9 +263,6 @@ class CachedTimelineRemoteMediatorTest {
mockStatusEntityWithAccount("8"),
mockStatusEntityWithAccount("7"),
mockStatusEntityWithAccount("5"),
- TimelineStatusWithAccount().apply {
- status = Placeholder("4", loading = false).toEntity(1)
- },
mockStatusEntityWithAccount("3"),
mockStatusEntityWithAccount("2"),
mockStatusEntityWithAccount("1"),
@@ -207,7 +272,7 @@ class CachedTimelineRemoteMediatorTest {
@Test
@ExperimentalPagingApi
- fun `should refresh and not insert placeholders`() {
+ fun `should refresh and not insert placeholders when there is overlap with existing statuses`() {
val statusesAlreadyInDb = listOf(
mockStatusEntityWithAccount("3"),
@@ -220,7 +285,7 @@ class CachedTimelineRemoteMediatorTest {
val remoteMediator = CachedTimelineRemoteMediator(
accountManager = accountManager,
api = mock {
- on { homeTimeline(limit = 20) } doReturn Single.just(
+ on { homeTimeline(limit = 3) } doReturn Single.just(
Response.success(
listOf(
mockStatus("6"),
@@ -229,7 +294,7 @@ class CachedTimelineRemoteMediatorTest {
)
)
)
- on { homeTimeline(maxId = "3", limit = 20) } doReturn Single.just(
+ on { homeTimeline(maxId = "3", limit = 3) } doReturn Single.just(
Response.success(
listOf(
mockStatus("3"),
@@ -250,7 +315,8 @@ class CachedTimelineRemoteMediatorTest {
prevKey = null,
nextKey = 0
)
- )
+ ),
+ pageSize = 3
)
val result = runBlocking { remoteMediator.load(LoadType.REFRESH, state) }
@@ -487,11 +553,14 @@ class CachedTimelineRemoteMediatorTest {
)
}
- private fun state(pages: List> = emptyList()) = PagingState(
+ private fun state(
+ pages: List> = emptyList(),
+ pageSize: Int = 20
+ ) = PagingState(
pages = pages,
anchorPosition = null,
config = PagingConfig(
- pageSize = 20
+ pageSize = pageSize
),
leadingPlaceholderCount = 0
)
diff --git a/app/src/test/java/com/keylesspalace/tusky/components/timeline/NetworkTimelineRemoteMediatorTest.kt b/app/src/test/java/com/keylesspalace/tusky/components/timeline/NetworkTimelineRemoteMediatorTest.kt
index 601fc00a4..74d0fe257 100644
--- a/app/src/test/java/com/keylesspalace/tusky/components/timeline/NetworkTimelineRemoteMediatorTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/components/timeline/NetworkTimelineRemoteMediatorTest.kt
@@ -27,7 +27,7 @@ import org.junit.runner.RunWith
import org.robolectric.annotation.Config
import retrofit2.HttpException
import retrofit2.Response
-import java.lang.RuntimeException
+import java.io.IOException
@Config(sdk = [29])
@RunWith(AndroidJUnit4::class)
@@ -66,7 +66,7 @@ class NetworkTimelineRemoteMediatorTest {
val timelineViewModel: NetworkTimelineViewModel = mock {
on { statusData } doReturn mutableListOf()
- onBlocking { fetchStatusesForKind(anyOrNull(), anyOrNull(), anyOrNull()) } doThrow RuntimeException()
+ onBlocking { fetchStatusesForKind(anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException()
}
val remoteMediator = NetworkTimelineRemoteMediator(accountManager, timelineViewModel)
@@ -74,7 +74,7 @@ class NetworkTimelineRemoteMediatorTest {
val result = runBlocking { remoteMediator.load(LoadType.REFRESH, state()) }
assertTrue(result is RemoteMediator.MediatorResult.Error)
- assertTrue((result as RemoteMediator.MediatorResult.Error).throwable is RuntimeException)
+ assertTrue((result as RemoteMediator.MediatorResult.Error).throwable is IOException)
}
@Test
@@ -217,8 +217,7 @@ class NetworkTimelineRemoteMediatorTest {
val newStatusData = mutableListOf(
mockStatusViewData("10"),
mockStatusViewData("9"),
- mockStatusViewData("7"),
- StatusViewData.Placeholder("6", false),
+ StatusViewData.Placeholder("7", false),
mockStatusViewData("3"),
mockStatusViewData("2"),
mockStatusViewData("1"),
diff --git a/app/src/test/java/com/keylesspalace/tusky/components/timeline/StatusMocker.kt b/app/src/test/java/com/keylesspalace/tusky/components/timeline/StatusMocker.kt
index 57a6cfebd..13a7b338a 100644
--- a/app/src/test/java/com/keylesspalace/tusky/components/timeline/StatusMocker.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/components/timeline/StatusMocker.kt
@@ -3,8 +3,8 @@ package com.keylesspalace.tusky.components.timeline
import android.text.SpannedString
import com.google.gson.Gson
import com.keylesspalace.tusky.db.TimelineStatusWithAccount
-import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Status
+import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.viewdata.StatusViewData
import java.util.ArrayList
import java.util.Date
@@ -14,15 +14,13 @@ private val fixedDate = Date(1638889052000)
fun mockStatus(id: String = "100") = Status(
id = id,
url = "https://mastodon.example/@ConnyDuck/$id",
- account = Account(
+ account = TimelineAccount(
id = "1",
localUsername = "connyduck",
username = "connyduck@mastodon.example",
displayName = "Conny Duck",
- note = SpannedString(""),
url = "https://mastodon.example/@ConnyDuck",
- avatar = "https://mastodon.example/system/accounts/avatars/000/150/486/original/ab27d7ddd18a10ea.jpg",
- header = "https://mastodon.example/system/accounts/header/000/106/476/original/e590545d7eb4da39.jpg"
+ avatar = "https://mastodon.example/system/accounts/avatars/000/150/486/original/ab27d7ddd18a10ea.jpg"
),
inReplyToId = null,
inReplyToAccountId = null,
diff --git a/app/src/test/java/com/keylesspalace/tusky/components/timeline/TimelineViewModelTest.kt b/app/src/test/java/com/keylesspalace/tusky/components/timeline/TimelineViewModelTest.kt
deleted file mode 100644
index 8e82e26cc..000000000
--- a/app/src/test/java/com/keylesspalace/tusky/components/timeline/TimelineViewModelTest.kt
+++ /dev/null
@@ -1,218 +0,0 @@
-package com.keylesspalace.tusky.components.timeline
-
-import android.os.Looper
-import androidx.arch.core.executor.testing.InstantTaskExecutorRule
-import androidx.paging.AsyncPagingDataDiffer
-import androidx.paging.ExperimentalPagingApi
-import androidx.recyclerview.widget.ListUpdateCallback
-import androidx.room.Room
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.google.gson.Gson
-import com.keylesspalace.tusky.appstore.EventHub
-import com.keylesspalace.tusky.components.timeline.TimelinePagingAdapter.Companion.TimelineDifferCallback
-import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel
-import com.keylesspalace.tusky.components.timeline.viewmodel.NetworkTimelineViewModel
-import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel
-import com.keylesspalace.tusky.db.AccountEntity
-import com.keylesspalace.tusky.db.AccountManager
-import com.keylesspalace.tusky.db.AppDatabase
-import com.keylesspalace.tusky.db.Converters
-import com.keylesspalace.tusky.network.FilterModel
-import com.keylesspalace.tusky.network.MastodonApi
-import com.keylesspalace.tusky.network.TimelineCases
-import com.nhaarman.mockitokotlin2.doReturn
-import com.nhaarman.mockitokotlin2.mock
-import io.reactivex.rxjava3.core.Single
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.flow.take
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.TestCoroutineDispatcher
-import kotlinx.coroutines.test.TestCoroutineScope
-import kotlinx.coroutines.test.resetMain
-import kotlinx.coroutines.test.setMain
-import okhttp3.Headers
-import org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.Shadows.shadowOf
-import org.robolectric.annotation.Config
-import retrofit2.Response
-import java.util.concurrent.Executors
-
-@ExperimentalCoroutinesApi
-@Config(sdk = [29])
-@RunWith(AndroidJUnit4::class)
-class TimelineViewModelTest {
-
- @get:Rule
- val instantRule = InstantTaskExecutorRule()
-
- private val testDispatcher = TestCoroutineDispatcher()
- private val testScope = TestCoroutineScope(testDispatcher)
-
- private val accountManager: AccountManager = mock {
- on { activeAccount } doReturn AccountEntity(
- id = 1,
- domain = "mastodon.example",
- accessToken = "token",
- isActive = true
- )
- }
-
- private val eventHub = EventHub()
-
- private lateinit var db: AppDatabase
-
- @Before
- fun setup() {
- Dispatchers.setMain(testDispatcher)
-
- shadowOf(Looper.getMainLooper()).idle()
-
- val context = InstrumentationRegistry.getInstrumentation().targetContext
- db = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
- .addTypeConverter(Converters(Gson()))
- .setTransactionExecutor(Executors.newSingleThreadExecutor())
- .allowMainThreadQueries()
- .build()
- }
-
- @After
- fun tearDown() {
- Dispatchers.resetMain()
- testDispatcher.cleanupTestCoroutines()
- db.close()
- }
-
- @Test
- @ExperimentalPagingApi
- fun shouldLoadNetworkTimeline() = runBlocking {
-
- val api: MastodonApi = mock {
- on { publicTimeline(local = true, maxId = null, sinceId = null, limit = 30) } doReturn Single.just(
- Response.success(
- listOf(
- mockStatus("6"),
- mockStatus("5"),
- mockStatus("4")
- ),
- Headers.headersOf(
- "Link", "; rel=\"next\", ; rel=\"prev\""
- )
- )
- )
-
- on { publicTimeline(local = true, maxId = "1", sinceId = null, limit = 30) } doReturn Single.just(
- Response.success(emptyList())
- )
-
- on { getFilters() } doReturn Single.just(emptyList())
- }
-
- val viewModel = NetworkTimelineViewModel(
- TimelineCases(api, eventHub),
- api,
- eventHub,
- accountManager,
- mock(),
- FilterModel(),
- mock(),
- )
-
- viewModel.init(TimelineViewModel.Kind.PUBLIC_LOCAL, null, emptyList(), false)
-
- val differ = AsyncPagingDataDiffer(
- diffCallback = TimelineDifferCallback,
- updateCallback = NoopListCallback(),
- workerDispatcher = testDispatcher
- )
-
- viewModel.statuses.take(2).collectLatest {
- testScope.launch {
- differ.submitData(it)
- }
- }
-
- assertEquals(
- listOf(
- mockStatusViewData("6"),
- mockStatusViewData("5"),
- mockStatusViewData("4")
- ),
- differ.snapshot().items
- )
- }
-
- // ToDo: Find out why Room & coroutines are not playing nice here
- // @Test
- @ExperimentalPagingApi
- fun shouldLoadCachedTimeline() = runBlocking {
-
- val api: MastodonApi = mock {
- on { homeTimeline(limit = 30) } doReturn Single.just(
- Response.success(
- listOf(
- mockStatus("6"),
- mockStatus("5"),
- mockStatus("4")
- )
- )
- )
-
- on { homeTimeline(maxId = "1", sinceId = null, limit = 30) } doReturn Single.just(
- Response.success(emptyList())
- )
-
- on { getFilters() } doReturn Single.just(emptyList())
- }
-
- val viewModel = CachedTimelineViewModel(
- TimelineCases(api, eventHub),
- api,
- eventHub,
- accountManager,
- mock(),
- FilterModel(),
- db,
- Gson(),
- mock(),
- )
-
- viewModel.init(TimelineViewModel.Kind.HOME, null, emptyList(), false)
-
- val differ = AsyncPagingDataDiffer(
- diffCallback = TimelineDifferCallback,
- updateCallback = NoopListCallback(),
- workerDispatcher = testDispatcher
- )
-
- viewModel.statuses.take(1000).collectLatest {
- testScope.launch {
- differ.submitData(it)
- }
- }
-
- assertEquals(
- listOf(
- mockStatusViewData("6"),
- mockStatusViewData("5"),
- mockStatusViewData("4")
- ),
- differ.snapshot().items
- )
- }
-}
-
-class NoopListCallback : ListUpdateCallback {
- override fun onChanged(position: Int, count: Int, payload: Any?) {}
- override fun onMoved(fromPosition: Int, toPosition: Int) {}
- override fun onInserted(position: Int, count: Int) {}
- override fun onRemoved(position: Int, count: Int) {}
-}
diff --git a/build.gradle b/build.gradle
index 18b1872a3..c93117011 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ buildscript {
gradlePluginPortal()
}
dependencies {
- classpath "com.android.tools.build:gradle:7.0.4"
+ classpath "com.android.tools.build:gradle:7.1.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jlleitschuh.gradle:ktlint-gradle:10.1.0"
}
diff --git a/fastlane/metadata/android/en-US/changelogs/89.txt b/fastlane/metadata/android/en-US/changelogs/89.txt
new file mode 100644
index 000000000..4b666c353
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/89.txt
@@ -0,0 +1,7 @@
+Tusky v17.0
+
+- "Open as..." is now also available in the menu on account profiles when using multiple accounts
+- Login is now handled in a WebView within the app
+- Support for Android 12
+- support for the new Mastodon instance configuration API
+- and a lot of other small fixes and improvements
diff --git a/fastlane/metadata/android/gl/changelogs/87.txt b/fastlane/metadata/android/gl/changelogs/87.txt
new file mode 100644
index 000000000..1a7e99d14
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/87.txt
@@ -0,0 +1,8 @@
+Tusky v16.0
+
+- Cambiamos completamente a lóxica de carga da cronoloxía para facela máis rápida, con menos fallos e doada de manter.
+- Tusky pode animar os emojis personalizados en APNG & formato WebP Animado.
+- Arranxamos moitos problemas.
+- Soporte para Android 11
+- Novas traducións: Gaélico de Escocia, Galego, Ucraíno
+- Mellora nas traducións
diff --git a/fastlane/metadata/android/gl/changelogs/89.txt b/fastlane/metadata/android/gl/changelogs/89.txt
new file mode 100644
index 000000000..238ea8c6b
--- /dev/null
+++ b/fastlane/metadata/android/gl/changelogs/89.txt
@@ -0,0 +1,7 @@
+Tusky v17.0
+
+- "Abrir como..." agora está dispoñible no menú dos perfís da conta ao usar varias contas
+- O Acceso agora xestionase mediante WebView dentro da app
+- Soporte para Android 12
+- Soporte para a nova cofiguración da API das instancias de Mastodon
+- e un feixe de pequenas melloras e arranxos
diff --git a/fastlane/metadata/android/nb-NO/changelogs/89.txt b/fastlane/metadata/android/nb-NO/changelogs/89.txt
new file mode 100644
index 000000000..af8e6e6c7
--- /dev/null
+++ b/fastlane/metadata/android/nb-NO/changelogs/89.txt
@@ -0,0 +1,7 @@
+Tusky v17.0
+
+- "Åpne som..." er nå også tilgjengelig i profil-menyen når flere profiler er i bruk
+- Innlogging blir nå gjort ved hjelp av WebView i applikasjonen
+- Støtte for Android 12
+- Støtte for Mastodons nye instanskonfigurasjons-APIet
+- og mange andre små fikser og forbedringer
diff --git a/fastlane/metadata/android/vi/changelogs/89.txt b/fastlane/metadata/android/vi/changelogs/89.txt
new file mode 100644
index 000000000..c77487c78
--- /dev/null
+++ b/fastlane/metadata/android/vi/changelogs/89.txt
@@ -0,0 +1,7 @@
+Tusky v17.0
+
+- Hiện "Mở bằng..." trong menu Tài khoản kể cả khi dùng nhiều tài khoản
+- Hiện đăng nhập bằng WebView ngay trong app
+- Hỗ trợ Android 12
+- Hỗ trợ thiết lập API máy chủ Mastodon mới
+- Sửa lỗi nhỏ và cải thiện
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c02..7454180f2 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 669386b87..d7e66b5c6 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0c8..3da45c161 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright ? 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?,
+# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?;
+# * compound commands having a testable exit status, especially ?case?;
+# * various built-in commands including ?command?, ?set?, and ?ulimit?.
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
- fi
- i=`expr $i + 1`
- done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"