Merge remote-tracking branch 'tuskyapp/develop'
This commit is contained in:
commit
1370eedc10
|
@ -103,11 +103,11 @@ project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.lifecycleVersion = "2.2.0"
|
ext.lifecycleVersion = "2.2.0"
|
||||||
ext.roomVersion = '2.2.4'
|
ext.roomVersion = '2.2.5'
|
||||||
ext.retrofitVersion = '2.7.1'
|
ext.retrofitVersion = '2.8.1'
|
||||||
ext.okhttpVersion = '4.3.1'
|
ext.okhttpVersion = '4.4.0'
|
||||||
ext.glideVersion = '4.10.0'
|
ext.glideVersion = '4.11.0'
|
||||||
ext.daggerVersion = '2.26'
|
ext.daggerVersion = '2.27'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -120,12 +120,12 @@ dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.2.0"
|
implementation "androidx.core:core-ktx:1.2.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.2.0-alpha02"
|
implementation "androidx.appcompat:appcompat:1.2.0-beta01"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.2.2"
|
implementation "androidx.fragment:fragment-ktx:1.2.4"
|
||||||
implementation "androidx.browser:browser:1.2.0"
|
implementation "androidx.browser:browser:1.2.0"
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||||
implementation "androidx.exifinterface:exifinterface:1.1.0"
|
implementation "androidx.exifinterface:exifinterface:1.2.0"
|
||||||
implementation "androidx.cardview:cardview:1.0.0"
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
implementation "androidx.preference:preference:1.1.0"
|
implementation "androidx.preference:preference:1.1.0"
|
||||||
implementation "androidx.sharetarget:sharetarget:1.0.0-rc01"
|
implementation "androidx.sharetarget:sharetarget:1.0.0-rc01"
|
||||||
|
@ -135,7 +135,7 @@ dependencies {
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
||||||
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycleVersion"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
|
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
|
||||||
implementation "androidx.paging:paging-runtime-ktx:2.1.1"
|
implementation "androidx.paging:paging-runtime-ktx:2.1.2"
|
||||||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||||
implementation "androidx.room:room-runtime:$roomVersion"
|
implementation "androidx.room:room-runtime:$roomVersion"
|
||||||
implementation "androidx.room:room-rxjava2:$roomVersion"
|
implementation "androidx.room:room-rxjava2:$roomVersion"
|
||||||
|
@ -150,7 +150,7 @@ dependencies {
|
||||||
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:$okhttpVersion"
|
implementation "com.squareup.okhttp3:logging-interceptor:$okhttpVersion"
|
||||||
|
|
||||||
implementation "org.conscrypt:conscrypt-android:2.2.1"
|
implementation "org.conscrypt:conscrypt-android:2.4.0"
|
||||||
|
|
||||||
implementation "com.github.bumptech.glide:glide:$glideVersion"
|
implementation "com.github.bumptech.glide:glide:$glideVersion"
|
||||||
implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion"
|
implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion"
|
||||||
|
@ -168,7 +168,7 @@ dependencies {
|
||||||
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
|
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
|
||||||
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
|
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
|
||||||
|
|
||||||
implementation "com.github.connyduck:sparkbutton:3.0.0"
|
implementation "com.github.connyduck:sparkbutton:4.0.0"
|
||||||
|
|
||||||
implementation "com.github.chrisbanes:PhotoView:2.3.0"
|
implementation "com.github.chrisbanes:PhotoView:2.3.0"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,735 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 22,
|
||||||
|
"identityHash": "eaa3c4d012fe743948343983fe1ae493",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "TootEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER, `poll` TEXT)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "uid",
|
||||||
|
"columnName": "uid",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "text",
|
||||||
|
"columnName": "text",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "urls",
|
||||||
|
"columnName": "urls",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "descriptions",
|
||||||
|
"columnName": "descriptions",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "contentWarning",
|
||||||
|
"columnName": "contentWarning",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToId",
|
||||||
|
"columnName": "inReplyToId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToText",
|
||||||
|
"columnName": "inReplyToText",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToUsername",
|
||||||
|
"columnName": "inReplyToUsername",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "visibility",
|
||||||
|
"columnName": "visibility",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "poll",
|
||||||
|
"columnName": "poll",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"uid"
|
||||||
|
],
|
||||||
|
"autoGenerate": true
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "AccountEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `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": "notificationSound",
|
||||||
|
"columnName": "notificationSound",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationVibration",
|
||||||
|
"columnName": "notificationVibration",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationLight",
|
||||||
|
"columnName": "notificationLight",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "defaultPostPrivacy",
|
||||||
|
"columnName": "defaultPostPrivacy",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "defaultMediaSensitivity",
|
||||||
|
"columnName": "defaultMediaSensitivity",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "alwaysShowSensitiveMedia",
|
||||||
|
"columnName": "alwaysShowSensitiveMedia",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "alwaysOpenSpoiler",
|
||||||
|
"columnName": "alwaysOpenSpoiler",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "mediaPreviewEnabled",
|
||||||
|
"columnName": "mediaPreviewEnabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastNotificationId",
|
||||||
|
"columnName": "lastNotificationId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "activeNotifications",
|
||||||
|
"columnName": "activeNotifications",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojis",
|
||||||
|
"columnName": "emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tabPreferences",
|
||||||
|
"columnName": "tabPreferences",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationsFilter",
|
||||||
|
"columnName": "notificationsFilter",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"autoGenerate": true
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_AccountEntity_domain_accountId",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"domain",
|
||||||
|
"accountId"
|
||||||
|
],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "InstanceEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, `maxPollOptions` INTEGER, `maxPollOptionLength` INTEGER, `version` TEXT, PRIMARY KEY(`instance`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "instance",
|
||||||
|
"columnName": "instance",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojiList",
|
||||||
|
"columnName": "emojiList",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "maximumTootCharacters",
|
||||||
|
"columnName": "maximumTootCharacters",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "maxPollOptions",
|
||||||
|
"columnName": "maxPollOptions",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "maxPollOptionLength",
|
||||||
|
"columnName": "maxPollOptionLength",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "version",
|
||||||
|
"columnName": "version",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"instance"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "TimelineStatusEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `bookmarked` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT, `visibility` INTEGER, `attachments` TEXT, `mentions` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, `poll` TEXT, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "serverId",
|
||||||
|
"columnName": "serverId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timelineUserId",
|
||||||
|
"columnName": "timelineUserId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "authorServerId",
|
||||||
|
"columnName": "authorServerId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToId",
|
||||||
|
"columnName": "inReplyToId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToAccountId",
|
||||||
|
"columnName": "inReplyToAccountId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "content",
|
||||||
|
"columnName": "content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdAt",
|
||||||
|
"columnName": "createdAt",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojis",
|
||||||
|
"columnName": "emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogsCount",
|
||||||
|
"columnName": "reblogsCount",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "favouritesCount",
|
||||||
|
"columnName": "favouritesCount",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogged",
|
||||||
|
"columnName": "reblogged",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bookmarked",
|
||||||
|
"columnName": "bookmarked",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "favourited",
|
||||||
|
"columnName": "favourited",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "sensitive",
|
||||||
|
"columnName": "sensitive",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "spoilerText",
|
||||||
|
"columnName": "spoilerText",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "visibility",
|
||||||
|
"columnName": "visibility",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "attachments",
|
||||||
|
"columnName": "attachments",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "mentions",
|
||||||
|
"columnName": "mentions",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "application",
|
||||||
|
"columnName": "application",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogServerId",
|
||||||
|
"columnName": "reblogServerId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogAccountId",
|
||||||
|
"columnName": "reblogAccountId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "poll",
|
||||||
|
"columnName": "poll",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"serverId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"authorServerId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "TimelineAccountEntity",
|
||||||
|
"onDelete": "NO ACTION",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"authorServerId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"serverId",
|
||||||
|
"timelineUserId"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "TimelineAccountEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, `bot` INTEGER NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "serverId",
|
||||||
|
"columnName": "serverId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timelineUserId",
|
||||||
|
"columnName": "timelineUserId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "localUsername",
|
||||||
|
"columnName": "localUsername",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "username",
|
||||||
|
"columnName": "username",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "displayName",
|
||||||
|
"columnName": "displayName",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "avatar",
|
||||||
|
"columnName": "avatar",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojis",
|
||||||
|
"columnName": "emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bot",
|
||||||
|
"columnName": "bot",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"serverId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "ConversationEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `id` TEXT NOT NULL, `accounts` TEXT NOT NULL, `unread` INTEGER NOT NULL, `s_id` TEXT NOT NULL, `s_url` TEXT, `s_inReplyToId` TEXT, `s_inReplyToAccountId` TEXT, `s_account` TEXT NOT NULL, `s_content` TEXT NOT NULL, `s_createdAt` INTEGER NOT NULL, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_favourited` INTEGER NOT NULL, `s_bookmarked` INTEGER NOT NULL, `s_sensitive` INTEGER NOT NULL, `s_spoilerText` TEXT NOT NULL, `s_attachments` TEXT NOT NULL, `s_mentions` TEXT NOT NULL, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsible` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, `s_poll` TEXT, PRIMARY KEY(`id`, `accountId`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "accountId",
|
||||||
|
"columnName": "accountId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "accounts",
|
||||||
|
"columnName": "accounts",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "unread",
|
||||||
|
"columnName": "unread",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.id",
|
||||||
|
"columnName": "s_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.url",
|
||||||
|
"columnName": "s_url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.inReplyToId",
|
||||||
|
"columnName": "s_inReplyToId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.inReplyToAccountId",
|
||||||
|
"columnName": "s_inReplyToAccountId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.account",
|
||||||
|
"columnName": "s_account",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.content",
|
||||||
|
"columnName": "s_content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.createdAt",
|
||||||
|
"columnName": "s_createdAt",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.emojis",
|
||||||
|
"columnName": "s_emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.favouritesCount",
|
||||||
|
"columnName": "s_favouritesCount",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.favourited",
|
||||||
|
"columnName": "s_favourited",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.bookmarked",
|
||||||
|
"columnName": "s_bookmarked",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.sensitive",
|
||||||
|
"columnName": "s_sensitive",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.spoilerText",
|
||||||
|
"columnName": "s_spoilerText",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.attachments",
|
||||||
|
"columnName": "s_attachments",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.mentions",
|
||||||
|
"columnName": "s_mentions",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.showingHiddenContent",
|
||||||
|
"columnName": "s_showingHiddenContent",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.expanded",
|
||||||
|
"columnName": "s_expanded",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.collapsible",
|
||||||
|
"columnName": "s_collapsible",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.collapsed",
|
||||||
|
"columnName": "s_collapsed",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.poll",
|
||||||
|
"columnName": "s_poll",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id",
|
||||||
|
"accountId"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'eaa3c4d012fe743948343983fe1ae493')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,741 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 23,
|
||||||
|
"identityHash": "03a7436643ef356198742c5f8e054f5f",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "TootEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER, `poll` TEXT)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "uid",
|
||||||
|
"columnName": "uid",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "text",
|
||||||
|
"columnName": "text",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "urls",
|
||||||
|
"columnName": "urls",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "descriptions",
|
||||||
|
"columnName": "descriptions",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "contentWarning",
|
||||||
|
"columnName": "contentWarning",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToId",
|
||||||
|
"columnName": "inReplyToId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToText",
|
||||||
|
"columnName": "inReplyToText",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToUsername",
|
||||||
|
"columnName": "inReplyToUsername",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "visibility",
|
||||||
|
"columnName": "visibility",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "poll",
|
||||||
|
"columnName": "poll",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"uid"
|
||||||
|
],
|
||||||
|
"autoGenerate": true
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "AccountEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `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": "notificationSound",
|
||||||
|
"columnName": "notificationSound",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationVibration",
|
||||||
|
"columnName": "notificationVibration",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationLight",
|
||||||
|
"columnName": "notificationLight",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "defaultPostPrivacy",
|
||||||
|
"columnName": "defaultPostPrivacy",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "defaultMediaSensitivity",
|
||||||
|
"columnName": "defaultMediaSensitivity",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "alwaysShowSensitiveMedia",
|
||||||
|
"columnName": "alwaysShowSensitiveMedia",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "alwaysOpenSpoiler",
|
||||||
|
"columnName": "alwaysOpenSpoiler",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "mediaPreviewEnabled",
|
||||||
|
"columnName": "mediaPreviewEnabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastNotificationId",
|
||||||
|
"columnName": "lastNotificationId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "activeNotifications",
|
||||||
|
"columnName": "activeNotifications",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojis",
|
||||||
|
"columnName": "emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tabPreferences",
|
||||||
|
"columnName": "tabPreferences",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationsFilter",
|
||||||
|
"columnName": "notificationsFilter",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"autoGenerate": true
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_AccountEntity_domain_accountId",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"domain",
|
||||||
|
"accountId"
|
||||||
|
],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "InstanceEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, `maxPollOptions` INTEGER, `maxPollOptionLength` INTEGER, `version` TEXT, PRIMARY KEY(`instance`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "instance",
|
||||||
|
"columnName": "instance",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojiList",
|
||||||
|
"columnName": "emojiList",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "maximumTootCharacters",
|
||||||
|
"columnName": "maximumTootCharacters",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "maxPollOptions",
|
||||||
|
"columnName": "maxPollOptions",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "maxPollOptionLength",
|
||||||
|
"columnName": "maxPollOptionLength",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "version",
|
||||||
|
"columnName": "version",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"instance"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "TimelineStatusEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `bookmarked` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT, `visibility` INTEGER, `attachments` TEXT, `mentions` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, `poll` TEXT, `muted` INTEGER, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "serverId",
|
||||||
|
"columnName": "serverId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timelineUserId",
|
||||||
|
"columnName": "timelineUserId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "authorServerId",
|
||||||
|
"columnName": "authorServerId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToId",
|
||||||
|
"columnName": "inReplyToId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "inReplyToAccountId",
|
||||||
|
"columnName": "inReplyToAccountId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "content",
|
||||||
|
"columnName": "content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "createdAt",
|
||||||
|
"columnName": "createdAt",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojis",
|
||||||
|
"columnName": "emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogsCount",
|
||||||
|
"columnName": "reblogsCount",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "favouritesCount",
|
||||||
|
"columnName": "favouritesCount",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogged",
|
||||||
|
"columnName": "reblogged",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bookmarked",
|
||||||
|
"columnName": "bookmarked",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "favourited",
|
||||||
|
"columnName": "favourited",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "sensitive",
|
||||||
|
"columnName": "sensitive",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "spoilerText",
|
||||||
|
"columnName": "spoilerText",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "visibility",
|
||||||
|
"columnName": "visibility",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "attachments",
|
||||||
|
"columnName": "attachments",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "mentions",
|
||||||
|
"columnName": "mentions",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "application",
|
||||||
|
"columnName": "application",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogServerId",
|
||||||
|
"columnName": "reblogServerId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reblogAccountId",
|
||||||
|
"columnName": "reblogAccountId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "poll",
|
||||||
|
"columnName": "poll",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "muted",
|
||||||
|
"columnName": "muted",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"serverId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"authorServerId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "TimelineAccountEntity",
|
||||||
|
"onDelete": "NO ACTION",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"authorServerId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"serverId",
|
||||||
|
"timelineUserId"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "TimelineAccountEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, `bot` INTEGER NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "serverId",
|
||||||
|
"columnName": "serverId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timelineUserId",
|
||||||
|
"columnName": "timelineUserId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "localUsername",
|
||||||
|
"columnName": "localUsername",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "username",
|
||||||
|
"columnName": "username",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "displayName",
|
||||||
|
"columnName": "displayName",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "avatar",
|
||||||
|
"columnName": "avatar",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "emojis",
|
||||||
|
"columnName": "emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bot",
|
||||||
|
"columnName": "bot",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"serverId",
|
||||||
|
"timelineUserId"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "ConversationEntity",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `id` TEXT NOT NULL, `accounts` TEXT NOT NULL, `unread` INTEGER NOT NULL, `s_id` TEXT NOT NULL, `s_url` TEXT, `s_inReplyToId` TEXT, `s_inReplyToAccountId` TEXT, `s_account` TEXT NOT NULL, `s_content` TEXT NOT NULL, `s_createdAt` INTEGER NOT NULL, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_favourited` INTEGER NOT NULL, `s_bookmarked` INTEGER NOT NULL, `s_sensitive` INTEGER NOT NULL, `s_spoilerText` TEXT NOT NULL, `s_attachments` TEXT NOT NULL, `s_mentions` TEXT NOT NULL, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsible` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, `s_poll` TEXT, PRIMARY KEY(`id`, `accountId`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "accountId",
|
||||||
|
"columnName": "accountId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "accounts",
|
||||||
|
"columnName": "accounts",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "unread",
|
||||||
|
"columnName": "unread",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.id",
|
||||||
|
"columnName": "s_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.url",
|
||||||
|
"columnName": "s_url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.inReplyToId",
|
||||||
|
"columnName": "s_inReplyToId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.inReplyToAccountId",
|
||||||
|
"columnName": "s_inReplyToAccountId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.account",
|
||||||
|
"columnName": "s_account",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.content",
|
||||||
|
"columnName": "s_content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.createdAt",
|
||||||
|
"columnName": "s_createdAt",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.emojis",
|
||||||
|
"columnName": "s_emojis",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.favouritesCount",
|
||||||
|
"columnName": "s_favouritesCount",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.favourited",
|
||||||
|
"columnName": "s_favourited",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.bookmarked",
|
||||||
|
"columnName": "s_bookmarked",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.sensitive",
|
||||||
|
"columnName": "s_sensitive",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.spoilerText",
|
||||||
|
"columnName": "s_spoilerText",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.attachments",
|
||||||
|
"columnName": "s_attachments",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.mentions",
|
||||||
|
"columnName": "s_mentions",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.showingHiddenContent",
|
||||||
|
"columnName": "s_showingHiddenContent",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.expanded",
|
||||||
|
"columnName": "s_expanded",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.collapsible",
|
||||||
|
"columnName": "s_collapsible",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.collapsed",
|
||||||
|
"columnName": "s_collapsed",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastStatus.poll",
|
||||||
|
"columnName": "s_poll",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"columnNames": [
|
||||||
|
"id",
|
||||||
|
"accountId"
|
||||||
|
],
|
||||||
|
"autoGenerate": false
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '03a7436643ef356198742c5f8e054f5f')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.1 KiB |
|
@ -52,8 +52,6 @@ import com.keylesspalace.tusky.components.compose.ComposeActivity
|
||||||
import com.keylesspalace.tusky.components.report.ReportActivity
|
import com.keylesspalace.tusky.components.report.ReportActivity
|
||||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||||
import com.keylesspalace.tusky.entity.Account
|
import com.keylesspalace.tusky.entity.Account
|
||||||
import com.keylesspalace.tusky.entity.Field
|
|
||||||
import com.keylesspalace.tusky.entity.IdentityProof
|
|
||||||
import com.keylesspalace.tusky.entity.Relationship
|
import com.keylesspalace.tusky.entity.Relationship
|
||||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
|
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
|
||||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||||
|
@ -311,7 +309,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
* Subscribe to data loaded at the view model
|
* Subscribe to data loaded at the view model
|
||||||
*/
|
*/
|
||||||
private fun subscribeObservables() {
|
private fun subscribeObservables() {
|
||||||
viewModel.accountData.observe(this, Observer<Resource<Account>> {
|
viewModel.accountData.observe(this, Observer {
|
||||||
when (it) {
|
when (it) {
|
||||||
is Success -> onAccountChanged(it.data)
|
is Success -> onAccountChanged(it.data)
|
||||||
is Error -> {
|
is Error -> {
|
||||||
|
@ -321,7 +319,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
viewModel.relationshipData.observe(this, Observer<Resource<Relationship>> {
|
viewModel.relationshipData.observe(this, Observer {
|
||||||
val relation = it?.data
|
val relation = it?.data
|
||||||
if (relation != null) {
|
if (relation != null) {
|
||||||
onRelationshipChanged(relation)
|
onRelationshipChanged(relation)
|
||||||
|
@ -334,7 +332,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
viewModel.accountFieldData.observe(this, Observer<List<Either<IdentityProof, Field>>> {
|
viewModel.accountFieldData.observe(this, Observer {
|
||||||
accountFieldAdapter.fields = it
|
accountFieldAdapter.fields = it
|
||||||
accountFieldAdapter.notifyDataSetChanged()
|
accountFieldAdapter.notifyDataSetChanged()
|
||||||
|
|
||||||
|
@ -681,6 +679,30 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun toggleBlock() {
|
||||||
|
if (viewModel.relationshipData.value?.data?.blocking != true) {
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setMessage(getString(R.string.dialog_block_warning, loadedAccount?.username))
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ -> viewModel.changeBlockState() }
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
} else {
|
||||||
|
viewModel.changeBlockState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleMute() {
|
||||||
|
if (viewModel.relationshipData.value?.data?.muting != true) {
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setMessage(getString(R.string.dialog_mute_warning, loadedAccount?.username))
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ -> viewModel.changeMuteState() }
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
} else {
|
||||||
|
viewModel.changeMuteState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun mention() {
|
private fun mention() {
|
||||||
loadedAccount?.let {
|
loadedAccount?.let {
|
||||||
val intent = ComposeActivity.startIntent(this,
|
val intent = ComposeActivity.startIntent(this,
|
||||||
|
@ -727,11 +749,11 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_block -> {
|
R.id.action_block -> {
|
||||||
viewModel.changeBlockState()
|
toggleBlock()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_mute -> {
|
R.id.action_mute -> {
|
||||||
viewModel.changeMuteState()
|
toggleMute()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_mute_domain -> {
|
R.id.action_mute_domain -> {
|
||||||
|
|
|
@ -77,7 +77,7 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NORMAL, R.style.TuskyDialogFragmentStyle)
|
setStyle(STYLE_NORMAL, R.style.TuskyDialogFragmentStyle)
|
||||||
viewModel = viewModelFactory.create(AccountsInListViewModel::class.java)
|
viewModel = viewModelFactory.create(AccountsInListViewModel::class.java)
|
||||||
val args = arguments!!
|
val args = requireArguments()
|
||||||
listId = args.getString(LIST_ID_ARG)!!
|
listId = args.getString(LIST_ID_ARG)!!
|
||||||
listName = args.getString(LIST_NAME_ARG)!!
|
listName = args.getString(LIST_NAME_ARG)!!
|
||||||
|
|
||||||
|
@ -255,12 +255,12 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
||||||
loadAvatar(account.avatar, avatar, radius, animateAvatar)
|
loadAvatar(account.avatar, avatar, radius, animateAvatar)
|
||||||
|
|
||||||
rejectButton.apply {
|
rejectButton.apply {
|
||||||
if (inAList) {
|
contentDescription = if (inAList) {
|
||||||
setImageResource(R.drawable.ic_reject_24dp)
|
setImageResource(R.drawable.ic_reject_24dp)
|
||||||
contentDescription = getString(R.string.action_remove_from_list)
|
getString(R.string.action_remove_from_list)
|
||||||
} else {
|
} else {
|
||||||
setImageResource(R.drawable.ic_plus_24dp)
|
setImageResource(R.drawable.ic_plus_24dp)
|
||||||
contentDescription = getString(R.string.action_add_to_list)
|
getString(R.string.action_add_to_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ class ListsActivity : BaseActivity(), Injectable, HasAndroidInjector {
|
||||||
|
|
||||||
val positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE)
|
val positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE)
|
||||||
editText.onTextChanged { s, _, _, _ ->
|
editText.onTextChanged { s, _, _, _ ->
|
||||||
positiveButton.isEnabled = !s.isNullOrBlank()
|
positiveButton.isEnabled = !s.isBlank()
|
||||||
}
|
}
|
||||||
editText.setText(list?.title)
|
editText.setText(list?.title)
|
||||||
editText.text?.let { editText.setSelection(it.length) }
|
editText.text?.let { editText.setSelection(it.length) }
|
||||||
|
|
|
@ -129,7 +129,7 @@ class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreference
|
||||||
|
|
||||||
}
|
}
|
||||||
"statusTextSize", "absoluteTimeView", "showBotOverlay", "animateGifAvatars",
|
"statusTextSize", "absoluteTimeView", "showBotOverlay", "animateGifAvatars",
|
||||||
"useBlurhash", "viewPagerOffScreenLimit" -> {
|
"useBlurhash", "showCardsInTimelines", "confirmReblogs", "viewPagerOffScreenLimit" -> {
|
||||||
restartActivitiesOnExit = true
|
restartActivitiesOnExit = true
|
||||||
}
|
}
|
||||||
"language" -> {
|
"language" -> {
|
||||||
|
|
|
@ -277,7 +277,7 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
|
||||||
addTabAdapter.updateData(addableTabs)
|
addTabAdapter.updateData(addableTabs)
|
||||||
|
|
||||||
maxTabsInfo.visible(addableTabs.size == 0 || currentTabs.size >= MAX_TAB_COUNT)
|
maxTabsInfo.visible(addableTabs.size == 0 || currentTabs.size >= MAX_TAB_COUNT)
|
||||||
currentTabsAdapter.setRemoveButtonVisible(currentTabs.size > MIN_TAB_COUNT);
|
currentTabsAdapter.setRemoveButtonVisible(currentTabs.size > MIN_TAB_COUNT)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartDelete(viewHolder: RecyclerView.ViewHolder) {
|
override fun onStartDelete(viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.keylesspalace.tusky.adapter
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.text.BidiFormatter
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.keylesspalace.tusky.R
|
||||||
|
import com.keylesspalace.tusky.entity.Account
|
||||||
|
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||||
|
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
||||||
|
import com.keylesspalace.tusky.util.loadAvatar
|
||||||
|
import com.keylesspalace.tusky.util.visible
|
||||||
|
import kotlinx.android.synthetic.main.item_follow_request_notification.view.*
|
||||||
|
|
||||||
|
internal class FollowRequestViewHolder(itemView: View, private val showHeader: Boolean) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
private var id: String? = null
|
||||||
|
private val animateAvatar: Boolean = PreferenceManager.getDefaultSharedPreferences(itemView.context)
|
||||||
|
.getBoolean("animateGifAvatars", false)
|
||||||
|
|
||||||
|
fun setupWithAccount(account: Account, formatter: BidiFormatter?) {
|
||||||
|
id = account.id
|
||||||
|
val wrappedName = formatter?.unicodeWrap(account.name) ?: account.name
|
||||||
|
val emojifiedName: CharSequence = CustomEmojiHelper.emojifyString(wrappedName, account.emojis, itemView)
|
||||||
|
itemView.displayNameTextView.text = emojifiedName
|
||||||
|
if (showHeader) {
|
||||||
|
itemView.notificationTextView?.text = itemView.context.getString(R.string.notification_follow_request_format, emojifiedName)
|
||||||
|
}
|
||||||
|
itemView.notificationTextView?.visible(showHeader)
|
||||||
|
val format = itemView.context.getString(R.string.status_username_format)
|
||||||
|
val formattedUsername = String.format(format, account.username)
|
||||||
|
itemView.usernameTextView.text = formattedUsername
|
||||||
|
val avatarRadius = itemView.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
|
||||||
|
loadAvatar(account.avatar, itemView.avatar, avatarRadius, animateAvatar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setupActionListener(listener: AccountActionListener) {
|
||||||
|
itemView.acceptButton.setOnClickListener {
|
||||||
|
val position = adapterPosition
|
||||||
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
|
listener.onRespondToFollowRequest(true, id, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemView.rejectButton.setOnClickListener {
|
||||||
|
val position = adapterPosition
|
||||||
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
|
listener.onRespondToFollowRequest(false, id, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemView.avatar.setOnClickListener { listener.onViewAccount(id) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,19 +18,12 @@ package com.keylesspalace.tusky.adapter;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
|
||||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
|
||||||
|
|
||||||
public class FollowRequestsAdapter extends AccountAdapter {
|
public class FollowRequestsAdapter extends AccountAdapter {
|
||||||
|
|
||||||
|
@ -46,7 +39,7 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
||||||
case VIEW_TYPE_ACCOUNT: {
|
case VIEW_TYPE_ACCOUNT: {
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.item_follow_request, parent, false);
|
.inflate(R.layout.item_follow_request, parent, false);
|
||||||
return new FollowRequestViewHolder(view);
|
return new FollowRequestViewHolder(view, false);
|
||||||
}
|
}
|
||||||
case VIEW_TYPE_FOOTER: {
|
case VIEW_TYPE_FOOTER: {
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
@ -60,57 +53,8 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
||||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
if (getItemViewType(position) == VIEW_TYPE_ACCOUNT) {
|
if (getItemViewType(position) == VIEW_TYPE_ACCOUNT) {
|
||||||
FollowRequestViewHolder holder = (FollowRequestViewHolder) viewHolder;
|
FollowRequestViewHolder holder = (FollowRequestViewHolder) viewHolder;
|
||||||
holder.setupWithAccount(accountList.get(position));
|
holder.setupWithAccount(accountList.get(position), null);
|
||||||
holder.setupActionListener(accountActionListener);
|
holder.setupActionListener(accountActionListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class FollowRequestViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
private ImageView avatar;
|
|
||||||
private TextView username;
|
|
||||||
private TextView displayName;
|
|
||||||
private ImageButton accept;
|
|
||||||
private ImageButton reject;
|
|
||||||
private String id;
|
|
||||||
private boolean animateAvatar;
|
|
||||||
|
|
||||||
FollowRequestViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
avatar = itemView.findViewById(R.id.avatar);
|
|
||||||
username = itemView.findViewById(R.id.usernameTextView);
|
|
||||||
displayName = itemView.findViewById(R.id.displayNameTextView);
|
|
||||||
accept = itemView.findViewById(R.id.acceptButton);
|
|
||||||
reject = itemView.findViewById(R.id.rejectButton);
|
|
||||||
animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext())
|
|
||||||
.getBoolean("animateGifAvatars", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
|
||||||
id = account.getId();
|
|
||||||
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(), account.getEmojis(), displayName);
|
|
||||||
displayName.setText(emojifiedName);
|
|
||||||
String format = username.getContext().getString(R.string.status_username_format);
|
|
||||||
String formattedUsername = String.format(format, account.getUsername());
|
|
||||||
username.setText(formattedUsername);
|
|
||||||
int avatarRadius = avatar.getContext().getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
|
||||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupActionListener(final AccountActionListener listener) {
|
|
||||||
accept.setOnClickListener(v -> {
|
|
||||||
int position = getAdapterPosition();
|
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
|
||||||
listener.onRespondToFollowRequest(true, id, position);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
reject.setOnClickListener(v -> {
|
|
||||||
int position = getAdapterPosition();
|
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
|
||||||
listener.onRespondToFollowRequest(false, id, position);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
avatar.setOnClickListener(v -> listener.onViewAccount(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,10 @@ import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.entity.Emoji;
|
import com.keylesspalace.tusky.entity.Emoji;
|
||||||
import com.keylesspalace.tusky.entity.Notification;
|
import com.keylesspalace.tusky.entity.Notification;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
import com.keylesspalace.tusky.util.LinkHelper;
|
import com.keylesspalace.tusky.util.LinkHelper;
|
||||||
|
@ -75,8 +77,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
private static final int VIEW_TYPE_STATUS = 0;
|
private static final int VIEW_TYPE_STATUS = 0;
|
||||||
private static final int VIEW_TYPE_STATUS_NOTIFICATION = 1;
|
private static final int VIEW_TYPE_STATUS_NOTIFICATION = 1;
|
||||||
private static final int VIEW_TYPE_FOLLOW = 2;
|
private static final int VIEW_TYPE_FOLLOW = 2;
|
||||||
private static final int VIEW_TYPE_PLACEHOLDER = 3;
|
private static final int VIEW_TYPE_FOLLOW_REQUEST = 3;
|
||||||
private static final int VIEW_TYPE_UNKNOWN = 4;
|
private static final int VIEW_TYPE_PLACEHOLDER = 4;
|
||||||
|
private static final int VIEW_TYPE_UNKNOWN = 5;
|
||||||
|
|
||||||
private static final InputFilter[] COLLAPSE_INPUT_FILTER = new InputFilter[]{SmartLengthInputFilter.INSTANCE};
|
private static final InputFilter[] COLLAPSE_INPUT_FILTER = new InputFilter[]{SmartLengthInputFilter.INSTANCE};
|
||||||
private static final InputFilter[] NO_INPUT_FILTER = new InputFilter[0];
|
private static final InputFilter[] NO_INPUT_FILTER = new InputFilter[0];
|
||||||
|
@ -85,6 +88,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
private StatusDisplayOptions statusDisplayOptions;
|
private StatusDisplayOptions statusDisplayOptions;
|
||||||
private StatusActionListener statusListener;
|
private StatusActionListener statusListener;
|
||||||
private NotificationActionListener notificationActionListener;
|
private NotificationActionListener notificationActionListener;
|
||||||
|
private AccountActionListener accountActionListener;
|
||||||
private BidiFormatter bidiFormatter;
|
private BidiFormatter bidiFormatter;
|
||||||
private AdapterDataSource<NotificationViewData> dataSource;
|
private AdapterDataSource<NotificationViewData> dataSource;
|
||||||
|
|
||||||
|
@ -92,13 +96,15 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
AdapterDataSource<NotificationViewData> dataSource,
|
AdapterDataSource<NotificationViewData> dataSource,
|
||||||
StatusDisplayOptions statusDisplayOptions,
|
StatusDisplayOptions statusDisplayOptions,
|
||||||
StatusActionListener statusListener,
|
StatusActionListener statusListener,
|
||||||
NotificationActionListener notificationActionListener) {
|
NotificationActionListener notificationActionListener,
|
||||||
|
AccountActionListener accountActionListener) {
|
||||||
|
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.statusDisplayOptions = statusDisplayOptions;
|
this.statusDisplayOptions = statusDisplayOptions;
|
||||||
this.statusListener = statusListener;
|
this.statusListener = statusListener;
|
||||||
this.notificationActionListener = notificationActionListener;
|
this.notificationActionListener = notificationActionListener;
|
||||||
|
this.accountActionListener = accountActionListener;
|
||||||
bidiFormatter = BidiFormatter.getInstance();
|
bidiFormatter = BidiFormatter.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +128,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
.inflate(R.layout.item_follow, parent, false);
|
.inflate(R.layout.item_follow, parent, false);
|
||||||
return new FollowViewHolder(view, statusDisplayOptions);
|
return new FollowViewHolder(view, statusDisplayOptions);
|
||||||
}
|
}
|
||||||
|
case VIEW_TYPE_FOLLOW_REQUEST: {
|
||||||
|
View view = inflater
|
||||||
|
.inflate(R.layout.item_follow_request_notification, parent, false);
|
||||||
|
return new FollowRequestViewHolder(view, true);
|
||||||
|
}
|
||||||
case VIEW_TYPE_PLACEHOLDER: {
|
case VIEW_TYPE_PLACEHOLDER: {
|
||||||
View view = inflater
|
View view = inflater
|
||||||
.inflate(R.layout.item_status_placeholder, parent, false);
|
.inflate(R.layout.item_status_placeholder, parent, false);
|
||||||
|
@ -218,6 +229,13 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VIEW_TYPE_FOLLOW_REQUEST: {
|
||||||
|
if (payloadForHolder == null) {
|
||||||
|
FollowRequestViewHolder holder = (FollowRequestViewHolder) viewHolder;
|
||||||
|
holder.setupWithAccount(concreteNotificaton.getAccount(), bidiFormatter);
|
||||||
|
holder.setupActionListener(accountActionListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +252,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
mediaPreviewEnabled,
|
mediaPreviewEnabled,
|
||||||
statusDisplayOptions.useAbsoluteTime(),
|
statusDisplayOptions.useAbsoluteTime(),
|
||||||
statusDisplayOptions.showBotOverlay(),
|
statusDisplayOptions.showBotOverlay(),
|
||||||
statusDisplayOptions.useBlurhash()
|
statusDisplayOptions.useBlurhash(),
|
||||||
|
CardViewMode.NONE,
|
||||||
|
statusDisplayOptions.confirmReblogs()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +279,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
case FOLLOW: {
|
case FOLLOW: {
|
||||||
return VIEW_TYPE_FOLLOW;
|
return VIEW_TYPE_FOLLOW;
|
||||||
}
|
}
|
||||||
|
case FOLLOW_REQUEST: {
|
||||||
|
return VIEW_TYPE_FOLLOW_REQUEST;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return VIEW_TYPE_UNKNOWN;
|
return VIEW_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.entity.Emoji
|
import com.keylesspalace.tusky.entity.Emoji
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
||||||
import com.keylesspalace.tusky.util.HtmlUtils
|
|
||||||
import com.keylesspalace.tusky.util.visible
|
import com.keylesspalace.tusky.util.visible
|
||||||
import com.keylesspalace.tusky.viewdata.PollOptionViewData
|
import com.keylesspalace.tusky.viewdata.PollOptionViewData
|
||||||
import com.keylesspalace.tusky.viewdata.buildDescription
|
import com.keylesspalace.tusky.viewdata.buildDescription
|
||||||
|
@ -36,12 +35,19 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
|
||||||
|
|
||||||
private var pollOptions: List<PollOptionViewData> = emptyList()
|
private var pollOptions: List<PollOptionViewData> = emptyList()
|
||||||
private var voteCount: Int = 0
|
private var voteCount: Int = 0
|
||||||
|
private var votersCount: Int? = null
|
||||||
private var mode = RESULT
|
private var mode = RESULT
|
||||||
private var emojis: List<Emoji> = emptyList()
|
private var emojis: List<Emoji> = emptyList()
|
||||||
|
|
||||||
fun setup(options: List<PollOptionViewData>, voteCount: Int, emojis: List<Emoji>, mode: Int) {
|
fun setup(
|
||||||
|
options: List<PollOptionViewData>,
|
||||||
|
voteCount: Int,
|
||||||
|
votersCount: Int?,
|
||||||
|
emojis: List<Emoji>,
|
||||||
|
mode: Int) {
|
||||||
this.pollOptions = options
|
this.pollOptions = options
|
||||||
this.voteCount = voteCount
|
this.voteCount = voteCount
|
||||||
|
this.votersCount = votersCount
|
||||||
this.emojis = emojis
|
this.emojis = emojis
|
||||||
this.mode = mode
|
this.mode = mode
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
|
@ -71,7 +77,7 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
|
||||||
|
|
||||||
when(mode) {
|
when(mode) {
|
||||||
RESULT -> {
|
RESULT -> {
|
||||||
val percent = calculatePercent(option.votesCount, voteCount)
|
val percent = calculatePercent(option.votesCount, votersCount, voteCount)
|
||||||
val emojifiedPollOptionText = CustomEmojiHelper.emojifyText(buildDescription(option.title, percent, holder.resultTextView.context), emojis, holder.resultTextView)
|
val emojifiedPollOptionText = CustomEmojiHelper.emojifyText(buildDescription(option.title, percent, holder.resultTextView.context), emojis, holder.resultTextView)
|
||||||
holder.resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
holder.resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
||||||
|
|
||||||
|
|
|
@ -8,31 +8,38 @@ import android.text.Spanned;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
import androidx.core.text.HtmlCompat;
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners;
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Attachment;
|
import com.keylesspalace.tusky.entity.Attachment;
|
||||||
import com.keylesspalace.tusky.entity.Attachment.Focus;
|
import com.keylesspalace.tusky.entity.Attachment.Focus;
|
||||||
import com.keylesspalace.tusky.entity.Attachment.MetaData;
|
import com.keylesspalace.tusky.entity.Attachment.MetaData;
|
||||||
|
import com.keylesspalace.tusky.entity.Card;
|
||||||
import com.keylesspalace.tusky.entity.Emoji;
|
import com.keylesspalace.tusky.entity.Emoji;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
import com.keylesspalace.tusky.util.HtmlUtils;
|
|
||||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
import com.keylesspalace.tusky.util.LinkHelper;
|
import com.keylesspalace.tusky.util.LinkHelper;
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||||
|
@ -92,6 +99,12 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
private TextView pollDescription;
|
private TextView pollDescription;
|
||||||
private Button pollButton;
|
private Button pollButton;
|
||||||
|
|
||||||
|
private LinearLayout cardView;
|
||||||
|
private LinearLayout cardInfo;
|
||||||
|
private ImageView cardImage;
|
||||||
|
private TextView cardTitle;
|
||||||
|
private TextView cardDescription;
|
||||||
|
private TextView cardUrl;
|
||||||
private PollAdapter pollAdapter;
|
private PollAdapter pollAdapter;
|
||||||
|
|
||||||
private SimpleDateFormat shortSdf;
|
private SimpleDateFormat shortSdf;
|
||||||
|
@ -152,6 +165,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
pollDescription = itemView.findViewById(R.id.status_poll_description);
|
pollDescription = itemView.findViewById(R.id.status_poll_description);
|
||||||
pollButton = itemView.findViewById(R.id.status_poll_button);
|
pollButton = itemView.findViewById(R.id.status_poll_button);
|
||||||
|
|
||||||
|
cardView = itemView.findViewById(R.id.status_card_view);
|
||||||
|
cardInfo = itemView.findViewById(R.id.card_info);
|
||||||
|
cardImage = itemView.findViewById(R.id.card_image);
|
||||||
|
cardTitle = itemView.findViewById(R.id.card_title);
|
||||||
|
cardDescription = itemView.findViewById(R.id.card_description);
|
||||||
|
cardUrl = itemView.findViewById(R.id.card_link);
|
||||||
|
|
||||||
pollAdapter = new PollAdapter();
|
pollAdapter = new PollAdapter();
|
||||||
pollOptions.setAdapter(pollAdapter);
|
pollOptions.setAdapter(pollAdapter);
|
||||||
pollOptions.setLayoutManager(new LinearLayoutManager(pollOptions.getContext()));
|
pollOptions.setLayoutManager(new LinearLayoutManager(pollOptions.getContext()));
|
||||||
|
@ -200,7 +220,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
contentWarningDescription.setVisibility(View.VISIBLE);
|
contentWarningDescription.setVisibility(View.VISIBLE);
|
||||||
contentWarningButton.setVisibility(View.VISIBLE);
|
contentWarningButton.setVisibility(View.VISIBLE);
|
||||||
setContentWarningButtonText(expanded);
|
setContentWarningButtonText(expanded);
|
||||||
contentWarningButton.setOnClickListener( view -> {
|
contentWarningButton.setOnClickListener(view -> {
|
||||||
contentWarningDescription.invalidate();
|
contentWarningDescription.invalidate();
|
||||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||||
listener.onExpandedChange(!expanded, getAdapterPosition());
|
listener.onExpandedChange(!expanded, getAdapterPosition());
|
||||||
|
@ -218,7 +238,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setContentWarningButtonText(boolean expanded) {
|
private void setContentWarningButtonText(boolean expanded) {
|
||||||
if(expanded) {
|
if (expanded) {
|
||||||
contentWarningButton.setText(R.string.status_content_warning_show_less);
|
contentWarningButton.setText(R.string.status_content_warning_show_less);
|
||||||
} else {
|
} else {
|
||||||
contentWarningButton.setText(R.string.status_content_warning_show_more);
|
contentWarningButton.setText(R.string.status_content_warning_show_more);
|
||||||
|
@ -673,8 +693,12 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
sensitiveMediaShow.setVisibility(View.GONE);
|
sensitiveMediaShow.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setupButtons(final StatusActionListener listener, final String accountId,
|
protected void setupButtons(final StatusActionListener listener,
|
||||||
final boolean isNotestock, final String acct) {
|
final String accountId,
|
||||||
|
final String statusContent,
|
||||||
|
final boolean isNotestock,
|
||||||
|
final String acct,
|
||||||
|
StatusDisplayOptions statusDisplayOptions) {
|
||||||
|
|
||||||
avatar.setOnClickListener(v -> {
|
avatar.setOnClickListener(v -> {
|
||||||
if (isNotestock) {
|
if (isNotestock) {
|
||||||
|
@ -702,9 +726,18 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
replyButton.setClickable(!isNotestock);
|
replyButton.setClickable(!isNotestock);
|
||||||
if (reblogButton != null) {
|
if (reblogButton != null) {
|
||||||
reblogButton.setEventListener((button, buttonState) -> {
|
reblogButton.setEventListener((button, buttonState) -> {
|
||||||
|
// return true to play animaion
|
||||||
int position = getAdapterPosition();
|
int position = getAdapterPosition();
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
listener.onReblog(buttonState, position);
|
if (statusDisplayOptions.confirmReblogs()) {
|
||||||
|
showConfirmReblogDialog(listener, statusContent, buttonState, position);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
listener.onReblog(!buttonState, position);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -712,8 +745,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
favouriteButton.setEventListener((button, buttonState) -> {
|
favouriteButton.setEventListener((button, buttonState) -> {
|
||||||
int position = getAdapterPosition();
|
int position = getAdapterPosition();
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
listener.onFavourite(buttonState, position);
|
listener.onFavourite(!buttonState, position);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
favouriteButton.setEnabled(!isNotestock);
|
favouriteButton.setEnabled(!isNotestock);
|
||||||
|
@ -731,8 +765,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
bookmarkButton.setEventListener((button, buttonState) -> {
|
bookmarkButton.setEventListener((button, buttonState) -> {
|
||||||
int position = getAdapterPosition();
|
int position = getAdapterPosition();
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
listener.onBookmark(buttonState, position);
|
listener.onBookmark(!buttonState, position);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
moreButton.setOnClickListener(v -> {
|
moreButton.setOnClickListener(v -> {
|
||||||
|
@ -757,6 +792,23 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
itemView.setOnClickListener(viewThreadListener);
|
itemView.setOnClickListener(viewThreadListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showConfirmReblogDialog(StatusActionListener listener,
|
||||||
|
String statusContent,
|
||||||
|
boolean buttonState,
|
||||||
|
int position) {
|
||||||
|
int okButtonTextId = buttonState ? R.string.action_unreblog : R.string.action_reblog;
|
||||||
|
new AlertDialog.Builder(reblogButton.getContext())
|
||||||
|
.setMessage(statusContent)
|
||||||
|
.setPositiveButton(okButtonTextId, (__, ___) -> {
|
||||||
|
listener.onReblog(!buttonState, position);
|
||||||
|
if (!buttonState) {
|
||||||
|
// Play animation only when it's reblog, not unreblog
|
||||||
|
reblogButton.playAnimation();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
StatusDisplayOptions statusDisplayOptions) {
|
StatusDisplayOptions statusDisplayOptions) {
|
||||||
this.setupWithStatus(status, listener, statusDisplayOptions, null);
|
this.setupWithStatus(status, listener, statusDisplayOptions, null);
|
||||||
|
@ -799,8 +851,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
hideSensitiveMediaWarning();
|
hideSensitiveMediaWarning();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupButtons(listener, status.getSenderId(), status.isNotestock(), status.getNickname());
|
if (cardView != null) {
|
||||||
setRebloggingEnabled(status.getRebloggingEnabled() && !status.isNotestock(), status.getVisibility());
|
setupCard(status, statusDisplayOptions.cardViewMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
setupButtons(listener, status.getSenderId(), status.getContent().toString(),
|
||||||
|
status.isNotestock(), status.getNickname(), statusDisplayOptions);
|
||||||
|
setRebloggingEnabled(status.getRebloggingEnabled(), status.getVisibility());
|
||||||
setQuoteEnabled(status.getRebloggingEnabled() && !status.isNotestock(), status.getVisibility());
|
setQuoteEnabled(status.getRebloggingEnabled() && !status.isNotestock(), status.getVisibility());
|
||||||
|
|
||||||
setSpoilerAndContent(status.isExpanded(), status.getContent(), status.getSpoilerText(), status.getMentions(), status.getStatusEmojis(), status.getPoll(), statusDisplayOptions, listener, status.getQuote() != null);
|
setSpoilerAndContent(status.isExpanded(), status.getContent(), status.getSpoilerText(), status.getMentions(), status.getStatusEmojis(), status.getPoll(), statusDisplayOptions, listener, status.getQuote() != null);
|
||||||
|
@ -934,7 +991,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
List<PollOptionViewData> options = poll.getOptions();
|
List<PollOptionViewData> options = poll.getOptions();
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
if (i < options.size()) {
|
if (i < options.size()) {
|
||||||
int percent = PollViewDataKt.calculatePercent(options.get(i).getVotesCount(), poll.getVotesCount());
|
int percent = PollViewDataKt.calculatePercent(options.get(i).getVotesCount(), poll.getVotersCount(), poll.getVotesCount());
|
||||||
args[i] = buildDescription(options.get(i).getTitle(), percent, context);
|
args[i] = buildDescription(options.get(i).getTitle(), percent, context);
|
||||||
} else {
|
} else {
|
||||||
args[i] = "";
|
args[i] = "";
|
||||||
|
@ -949,7 +1006,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected CharSequence getFavsText(Context context, int count) {
|
protected CharSequence getFavsText(Context context, int count) {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
String countString = numberFormat.format(count);
|
String countString = numberFormat.format(count);
|
||||||
return HtmlUtils.fromHtml(context.getResources().getQuantityString(R.plurals.favs, count, countString));
|
return HtmlCompat.fromHtml(context.getResources().getQuantityString(R.plurals.favs, count, countString), HtmlCompat.FROM_HTML_MODE_LEGACY);
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -958,7 +1015,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected CharSequence getReblogsText(Context context, int count) {
|
protected CharSequence getReblogsText(Context context, int count) {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
String countString = numberFormat.format(count);
|
String countString = numberFormat.format(count);
|
||||||
return HtmlUtils.fromHtml(context.getResources().getQuantityString(R.plurals.reblogs, count, countString));
|
return HtmlCompat.fromHtml(context.getResources().getQuantityString(R.plurals.reblogs, count, countString), HtmlCompat.FROM_HTML_MODE_LEGACY);
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -977,12 +1034,12 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
if (expired || poll.getVoted()) {
|
if (expired || poll.getVoted()) {
|
||||||
// no voting possible
|
// no voting possible
|
||||||
pollAdapter.setup(poll.getOptions(), poll.getVotesCount(), emojis, PollAdapter.RESULT);
|
pollAdapter.setup(poll.getOptions(), poll.getVotesCount(), poll.getVotersCount(), emojis, PollAdapter.RESULT);
|
||||||
|
|
||||||
pollButton.setVisibility(View.GONE);
|
pollButton.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
// voting possible
|
// voting possible
|
||||||
pollAdapter.setup(poll.getOptions(), poll.getVotesCount(), emojis, poll.getMultiple() ? PollAdapter.MULTIPLE : PollAdapter.SINGLE);
|
pollAdapter.setup(poll.getOptions(), poll.getVotesCount(), poll.getVotersCount(), emojis, poll.getMultiple() ? PollAdapter.MULTIPLE : PollAdapter.SINGLE);
|
||||||
|
|
||||||
pollButton.setVisibility(View.VISIBLE);
|
pollButton.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
@ -1009,8 +1066,14 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
private CharSequence getPollInfoText(long timestamp, PollViewData poll,
|
private CharSequence getPollInfoText(long timestamp, PollViewData poll,
|
||||||
StatusDisplayOptions statusDisplayOptions,
|
StatusDisplayOptions statusDisplayOptions,
|
||||||
Context context) {
|
Context context) {
|
||||||
String votes = numberFormat.format(poll.getVotesCount());
|
String votesText;
|
||||||
String votesText = context.getResources().getQuantityString(R.plurals.poll_info_votes, poll.getVotesCount(), votes);
|
if(poll.getVotersCount() == null) {
|
||||||
|
String voters = numberFormat.format(poll.getVotesCount());
|
||||||
|
votesText = context.getResources().getQuantityString(R.plurals.poll_info_votes, poll.getVotesCount(), voters);
|
||||||
|
} else {
|
||||||
|
String voters = numberFormat.format(poll.getVotersCount());
|
||||||
|
votesText = context.getResources().getQuantityString(R.plurals.poll_info_people, poll.getVotersCount(), voters);
|
||||||
|
}
|
||||||
CharSequence pollDurationInfo;
|
CharSequence pollDurationInfo;
|
||||||
if (poll.getExpired()) {
|
if (poll.getExpired()) {
|
||||||
pollDurationInfo = context.getString(R.string.poll_info_closed);
|
pollDurationInfo = context.getString(R.string.poll_info_closed);
|
||||||
|
@ -1028,6 +1091,80 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
return pollDescription.getContext().getString(R.string.poll_info_format, votesText, pollDurationInfo);
|
return pollDescription.getContext().getString(R.string.poll_info_format, votesText, pollDurationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setupCard(StatusViewData.Concrete status, CardViewMode cardViewMode) {
|
||||||
|
if (cardViewMode != CardViewMode.NONE && status.getAttachments().size() == 0 && status.getCard() != null && !TextUtils.isEmpty(status.getCard().getUrl())) {
|
||||||
|
final Card card = status.getCard();
|
||||||
|
cardView.setVisibility(View.VISIBLE);
|
||||||
|
cardTitle.setText(card.getTitle());
|
||||||
|
if (TextUtils.isEmpty(card.getDescription()) && TextUtils.isEmpty(card.getAuthorName())) {
|
||||||
|
cardDescription.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
cardDescription.setVisibility(View.VISIBLE);
|
||||||
|
if (TextUtils.isEmpty(card.getDescription())) {
|
||||||
|
cardDescription.setText(card.getAuthorName());
|
||||||
|
} else {
|
||||||
|
cardDescription.setText(card.getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cardUrl.setText(card.getUrl());
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(card.getImage())) {
|
||||||
|
|
||||||
|
int topLeftRadius = 0;
|
||||||
|
int topRightRadius = 0;
|
||||||
|
int bottomRightRadius = 0;
|
||||||
|
int bottomLeftRadius = 0;
|
||||||
|
|
||||||
|
int radius = cardImage.getContext().getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.card_radius);
|
||||||
|
|
||||||
|
if (card.getWidth() > card.getHeight()) {
|
||||||
|
cardView.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
cardImage.getLayoutParams().height = cardImage.getContext().getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.card_image_vertical_height);
|
||||||
|
cardImage.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
topLeftRadius = radius;
|
||||||
|
topRightRadius = radius;
|
||||||
|
} else {
|
||||||
|
cardView.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
cardImage.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
cardImage.getLayoutParams().width = cardImage.getContext().getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.card_image_horizontal_width);
|
||||||
|
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
topLeftRadius = radius;
|
||||||
|
bottomLeftRadius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Glide.with(cardImage)
|
||||||
|
.load(card.getImage())
|
||||||
|
.transform(
|
||||||
|
new CenterCrop(),
|
||||||
|
new GranularRoundedCorners(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius)
|
||||||
|
)
|
||||||
|
.into(cardImage);
|
||||||
|
} else {
|
||||||
|
cardView.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
cardImage.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
cardImage.getLayoutParams().width = cardImage.getContext().getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.card_image_horizontal_width);
|
||||||
|
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
cardImage.setImageResource(R.drawable.card_image_placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
cardView.setOnClickListener(v -> LinkHelper.openLink(card.getUrl(), v.getContext()));
|
||||||
|
cardView.setClipToOutline(true);
|
||||||
|
} else {
|
||||||
|
cardView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String formatDuration(double durationInSeconds) {
|
private static String formatDuration(double durationInSeconds) {
|
||||||
int seconds = (int) Math.round(durationInSeconds) % 60;
|
int seconds = (int) Math.round(durationInSeconds) % 60;
|
||||||
int minutes = (int) durationInSeconds % 3600 / 60;
|
int minutes = (int) durationInSeconds % 3600 / 60;
|
||||||
|
|
|
@ -5,26 +5,19 @@ import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
|
||||||
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners;
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.ViewThreadActivity;
|
import com.keylesspalace.tusky.ViewThreadActivity;
|
||||||
import com.keylesspalace.tusky.entity.Card;
|
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
import com.keylesspalace.tusky.util.LinkHelper;
|
import com.keylesspalace.tusky.util.LinkHelper;
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||||
|
@ -37,27 +30,13 @@ import java.util.regex.Pattern;
|
||||||
class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
private TextView reblogs;
|
private TextView reblogs;
|
||||||
private TextView favourites;
|
private TextView favourites;
|
||||||
private LinearLayout cardView;
|
|
||||||
private LinearLayout cardInfo;
|
|
||||||
private ImageView cardImage;
|
|
||||||
private TextView cardTitle;
|
|
||||||
private TextView cardDescription;
|
|
||||||
private TextView cardUrl;
|
|
||||||
private View infoDivider;
|
private View infoDivider;
|
||||||
|
|
||||||
StatusDetailedViewHolder(View view) {
|
StatusDetailedViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
reblogs = view.findViewById(R.id.status_reblogs);
|
reblogs = view.findViewById(R.id.status_reblogs);
|
||||||
favourites = view.findViewById(R.id.status_favourites);
|
favourites = view.findViewById(R.id.status_favourites);
|
||||||
cardView = view.findViewById(R.id.card_view);
|
|
||||||
cardInfo = view.findViewById(R.id.card_info);
|
|
||||||
cardImage = view.findViewById(R.id.card_image);
|
|
||||||
cardTitle = view.findViewById(R.id.card_title);
|
|
||||||
cardDescription = view.findViewById(R.id.card_description);
|
|
||||||
cardUrl = view.findViewById(R.id.card_link);
|
|
||||||
infoDivider = view.findViewById(R.id.status_info_divider);
|
infoDivider = view.findViewById(R.id.status_info_divider);
|
||||||
|
|
||||||
cardView.setClipToOutline(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,6 +110,7 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
StatusDisplayOptions statusDisplayOptions,
|
StatusDisplayOptions statusDisplayOptions,
|
||||||
@Nullable Object payloads) {
|
@Nullable Object payloads) {
|
||||||
super.setupWithStatus(status, listener, statusDisplayOptions, payloads);
|
super.setupWithStatus(status, listener, statusDisplayOptions, payloads);
|
||||||
|
setupCard(status, CardViewMode.FULL_WIDTH); // Always show card for detailed status
|
||||||
if (payloads == null) {
|
if (payloads == null) {
|
||||||
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
||||||
|
|
||||||
|
@ -149,97 +129,6 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
|
|
||||||
content.setOnLongClickListener(longClickListener);
|
content.setOnLongClickListener(longClickListener);
|
||||||
contentWarningDescription.setOnLongClickListener(longClickListener);
|
contentWarningDescription.setOnLongClickListener(longClickListener);
|
||||||
|
|
||||||
if (status.getAttachments().size() == 0 && status.getCard() != null && !TextUtils.isEmpty(status.getCard().getUrl())) {
|
|
||||||
final Card card = status.getCard();
|
|
||||||
cardView.setVisibility(View.VISIBLE);
|
|
||||||
cardTitle.setText(card.getTitle());
|
|
||||||
if (TextUtils.isEmpty(card.getDescription()) && TextUtils.isEmpty(card.getAuthorName())) {
|
|
||||||
cardDescription.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
cardDescription.setVisibility(View.VISIBLE);
|
|
||||||
if (TextUtils.isEmpty(card.getDescription())) {
|
|
||||||
cardDescription.setText(card.getAuthorName());
|
|
||||||
} else {
|
|
||||||
cardDescription.setText(card.getDescription());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cardUrl.setText(card.getUrl());
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(card.getImage())) {
|
|
||||||
|
|
||||||
int topLeftRadius = 0;
|
|
||||||
int topRightRadius = 0;
|
|
||||||
int bottomRightRadius = 0;
|
|
||||||
int bottomLeftRadius = 0;
|
|
||||||
|
|
||||||
int radius = cardImage.getContext().getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.card_radius);
|
|
||||||
|
|
||||||
if (card.getWidth() > card.getHeight()) {
|
|
||||||
cardView.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
|
|
||||||
cardImage.getLayoutParams().height = cardImage.getContext().getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.card_image_vertical_height);
|
|
||||||
cardImage.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
|
||||||
topLeftRadius = radius;
|
|
||||||
topRightRadius = radius;
|
|
||||||
} else {
|
|
||||||
cardView.setOrientation(LinearLayout.HORIZONTAL);
|
|
||||||
cardImage.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
cardImage.getLayoutParams().width = cardImage.getContext().getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.card_image_horizontal_width);
|
|
||||||
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
|
||||||
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
topLeftRadius = radius;
|
|
||||||
bottomLeftRadius = radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Glide.with(cardImage)
|
|
||||||
.load(card.getImage())
|
|
||||||
.transform(
|
|
||||||
new CenterCrop(),
|
|
||||||
new GranularRoundedCorners(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius)
|
|
||||||
)
|
|
||||||
.into(cardImage);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
cardView.setOrientation(LinearLayout.HORIZONTAL);
|
|
||||||
cardImage.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
cardImage.getLayoutParams().width = cardImage.getContext().getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.card_image_horizontal_width);
|
|
||||||
cardInfo.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
|
||||||
cardInfo.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
|
|
||||||
cardImage.setImageResource(R.drawable.card_image_placeholder);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
cardView.setOnClickListener(v -> {
|
|
||||||
String url = card.getUrl();
|
|
||||||
String regex = ".*/users/[^/]+/statuses/([0-9]+)";
|
|
||||||
String replace = "$1";
|
|
||||||
Pattern p = Pattern.compile(regex);
|
|
||||||
Matcher m = p.matcher(url);
|
|
||||||
if (m.find()) {
|
|
||||||
String id = m.replaceAll(replace);
|
|
||||||
Intent intent = new Intent(v.getContext(), ViewThreadActivity.class);
|
|
||||||
intent.putExtra("id", id);
|
|
||||||
intent.putExtra("url", url);
|
|
||||||
v.getContext().startActivity(intent);
|
|
||||||
} else {
|
|
||||||
LinkHelper.openLink(url, v.getContext());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
cardView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,9 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
||||||
mediaPreviewEnabled,
|
mediaPreviewEnabled,
|
||||||
statusDisplayOptions.useAbsoluteTime(),
|
statusDisplayOptions.useAbsoluteTime(),
|
||||||
statusDisplayOptions.showBotOverlay(),
|
statusDisplayOptions.showBotOverlay(),
|
||||||
statusDisplayOptions.useBlurhash()
|
statusDisplayOptions.useBlurhash(),
|
||||||
|
statusDisplayOptions.cardViewMode(),
|
||||||
|
statusDisplayOptions.confirmReblogs()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.keylesspalace.tusky.entity.Status
|
||||||
data class FavoriteEvent(val statusId: String, val favourite: Boolean) : Dispatchable
|
data class FavoriteEvent(val statusId: String, val favourite: Boolean) : Dispatchable
|
||||||
data class ReblogEvent(val statusId: String, val reblog: Boolean) : Dispatchable
|
data class ReblogEvent(val statusId: String, val reblog: Boolean) : Dispatchable
|
||||||
data class BookmarkEvent(val statusId: String, val bookmark: Boolean) : Dispatchable
|
data class BookmarkEvent(val statusId: String, val bookmark: Boolean) : Dispatchable
|
||||||
|
data class MuteConversationEvent(val statusId: String, val mute: Boolean) : Dispatchable
|
||||||
data class UnfollowEvent(val accountId: String) : Dispatchable
|
data class UnfollowEvent(val accountId: String) : Dispatchable
|
||||||
data class BlockEvent(val accountId: String) : Dispatchable
|
data class BlockEvent(val accountId: String) : Dispatchable
|
||||||
data class MuteEvent(val accountId: String) : Dispatchable
|
data class MuteEvent(val accountId: String) : Dispatchable
|
||||||
|
|
|
@ -252,15 +252,14 @@ class ComposeActivity : BaseActivity(),
|
||||||
if (action != null && action == Intent.ACTION_SEND) {
|
if (action != null && action == Intent.ACTION_SEND) {
|
||||||
val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT)
|
val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT)
|
||||||
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
|
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||||
val shareBody = if (subject != null && text != null) {
|
val shareBody = text ?: subject
|
||||||
if (subject != text && !text.contains(subject)) {
|
|
||||||
String.format("%s\n%s", subject, text)
|
|
||||||
} else {
|
|
||||||
text
|
|
||||||
}
|
|
||||||
} else text ?: subject
|
|
||||||
|
|
||||||
if (shareBody != null) {
|
if (shareBody != null) {
|
||||||
|
if (!subject.isNullOrBlank() && subject !in shareBody) {
|
||||||
|
composeContentWarningField.setText(subject)
|
||||||
|
viewModel.showContentWarning.value = true
|
||||||
|
}
|
||||||
|
|
||||||
val start = composeEditField.selectionStart.coerceAtLeast(0)
|
val start = composeEditField.selectionStart.coerceAtLeast(0)
|
||||||
val end = composeEditField.selectionEnd.coerceAtLeast(0)
|
val end = composeEditField.selectionEnd.coerceAtLeast(0)
|
||||||
val left = min(start, end)
|
val left = min(start, end)
|
||||||
|
|
|
@ -271,7 +271,7 @@ class ComposeViewModel
|
||||||
text,
|
text,
|
||||||
spoilerText,
|
spoilerText,
|
||||||
statusVisibility.value!!.serverString(),
|
statusVisibility.value!!.serverString(),
|
||||||
mediaUris.isNotEmpty() && markMediaAsSensitive.value!!,
|
mediaUris.isNotEmpty() && (markMediaAsSensitive.value!! || showContentWarning.value!!),
|
||||||
mediaIds,
|
mediaIds,
|
||||||
mediaUris.map { it.toString() },
|
mediaUris.map { it.toString() },
|
||||||
mediaDescriptions,
|
mediaDescriptions,
|
||||||
|
|
|
@ -18,26 +18,19 @@ package com.keylesspalace.tusky.components.compose.view
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
import android.widget.RadioGroup
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.entity.Status
|
import com.keylesspalace.tusky.entity.Status
|
||||||
import kotlinx.android.synthetic.main.view_compose_options.view.*
|
import kotlinx.android.synthetic.main.view_compose_options.view.*
|
||||||
|
|
||||||
|
class ComposeOptionsView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : RadioGroup(context, attrs) {
|
||||||
class ComposeOptionsView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) {
|
|
||||||
|
|
||||||
var listener: ComposeOptionsListener? = null
|
var listener: ComposeOptionsListener? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.view_compose_options, this)
|
inflate(context, R.layout.view_compose_options, this)
|
||||||
|
|
||||||
publicRadioButton.setButtonDrawable(R.drawable.ic_public_24dp)
|
setOnCheckedChangeListener { _, checkedId ->
|
||||||
unlistedRadioButton.setButtonDrawable(R.drawable.ic_lock_open_24dp)
|
|
||||||
privateRadioButton.setButtonDrawable(R.drawable.ic_lock_outline_24dp)
|
|
||||||
unleakableRadioButton.setButtonDrawable(R.drawable.ic_low_vision_24dp)
|
|
||||||
directRadioButton.setButtonDrawable(R.drawable.ic_email_24dp)
|
|
||||||
|
|
||||||
visibilityRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
|
||||||
val visibility = when (checkedId) {
|
val visibility = when (checkedId) {
|
||||||
R.id.publicRadioButton ->
|
R.id.publicRadioButton ->
|
||||||
Status.Visibility.PUBLIC
|
Status.Visibility.PUBLIC
|
||||||
|
@ -80,7 +73,7 @@ class ComposeOptionsView @JvmOverloads constructor(context: Context, attrs: Attr
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visibilityRadioGroup.check(selectedButton)
|
check(selectedButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,9 @@ public class ComposeScheduleView extends ConstraintLayout {
|
||||||
private void onDateSet(long selection) {
|
private void onDateSet(long selection) {
|
||||||
initializeSuggestedTime();
|
initializeSuggestedTime();
|
||||||
Calendar newDate = getCalendar();
|
Calendar newDate = getCalendar();
|
||||||
|
// working around bug in DatePicker where date is UTC #1720
|
||||||
|
// see https://github.com/material-components/material-components-android/issues/882
|
||||||
|
newDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
newDate.setTimeInMillis(selection);
|
newDate.setTimeInMillis(selection);
|
||||||
scheduleDateTime.set(newDate.get(Calendar.YEAR), newDate.get(Calendar.MONTH), newDate.get(Calendar.DATE));
|
scheduleDateTime.set(newDate.get(Calendar.YEAR), newDate.get(Calendar.MONTH), newDate.get(Calendar.DATE));
|
||||||
openPickTimeDialog();
|
openPickTimeDialog();
|
||||||
|
|
|
@ -157,6 +157,7 @@ data class ConversationStatusEntity(
|
||||||
mentions = mentions,
|
mentions = mentions,
|
||||||
application = null,
|
application = null,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
|
muted = false,
|
||||||
poll = poll,
|
poll = poll,
|
||||||
card = null,
|
card = null,
|
||||||
quote = null)
|
quote = null)
|
||||||
|
|
|
@ -104,7 +104,8 @@ public class ConversationViewHolder extends StatusBaseViewHolder {
|
||||||
hideSensitiveMediaWarning();
|
hideSensitiveMediaWarning();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupButtons(listener, account.getId(), false, account.getUsername());
|
setupButtons(listener, account.getId(), status.getContent().toString(),
|
||||||
|
false, account.getUsername(), statusDisplayOptions);
|
||||||
|
|
||||||
setSpoilerAndContent(status.getExpanded(), status.getContent(), status.getSpoilerText(),
|
setSpoilerAndContent(status.getExpanded(), status.getContent(), status.getSpoilerText(),
|
||||||
status.getMentions(), status.getEmojis(),
|
status.getMentions(), status.getEmojis(),
|
||||||
|
|
|
@ -36,10 +36,7 @@ import com.keylesspalace.tusky.di.ViewModelFactory
|
||||||
import com.keylesspalace.tusky.fragment.SFragment
|
import com.keylesspalace.tusky.fragment.SFragment
|
||||||
import com.keylesspalace.tusky.interfaces.ReselectableFragment
|
import com.keylesspalace.tusky.interfaces.ReselectableFragment
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
||||||
import com.keylesspalace.tusky.util.NetworkState
|
import com.keylesspalace.tusky.util.*
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
|
||||||
import com.keylesspalace.tusky.util.ThemeUtils
|
|
||||||
import com.keylesspalace.tusky.util.hide
|
|
||||||
import kotlinx.android.synthetic.main.fragment_timeline.*
|
import kotlinx.android.synthetic.main.fragment_timeline.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -68,7 +65,9 @@ class ConversationsFragment : SFragment(), StatusActionListener, Injectable, Res
|
||||||
mediaPreviewEnabled = accountManager.activeAccount?.mediaPreviewEnabled ?: true,
|
mediaPreviewEnabled = accountManager.activeAccount?.mediaPreviewEnabled ?: true,
|
||||||
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
|
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
|
||||||
showBotOverlay = preferences.getBoolean("showBotOverlay", true),
|
showBotOverlay = preferences.getBoolean("showBotOverlay", true),
|
||||||
useBlurhash = preferences.getBoolean("useBlurhash", true)
|
useBlurhash = preferences.getBoolean("useBlurhash", true),
|
||||||
|
cardViewMode = CardViewMode.NONE,
|
||||||
|
confirmReblogs = preferences.getBoolean("confirmReblogs", false)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,7 @@ import com.keylesspalace.tusky.di.Injectable
|
||||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
import com.keylesspalace.tusky.entity.Status
|
import com.keylesspalace.tusky.entity.Status
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
import com.keylesspalace.tusky.util.*
|
||||||
import com.keylesspalace.tusky.util.ThemeUtils
|
|
||||||
import com.keylesspalace.tusky.util.hide
|
|
||||||
import com.keylesspalace.tusky.util.show
|
|
||||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||||
import kotlinx.android.synthetic.main.fragment_report_statuses.*
|
import kotlinx.android.synthetic.main.fragment_report_statuses.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -119,7 +116,9 @@ class ReportStatusesFragment : Fragment(), Injectable, AdapterHandler {
|
||||||
mediaPreviewEnabled = accountManager.activeAccount?.mediaPreviewEnabled ?: true,
|
mediaPreviewEnabled = accountManager.activeAccount?.mediaPreviewEnabled ?: true,
|
||||||
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
|
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
|
||||||
showBotOverlay = false,
|
showBotOverlay = false,
|
||||||
useBlurhash = preferences.getBoolean("useBlurhash", true)
|
useBlurhash = preferences.getBoolean("useBlurhash", true),
|
||||||
|
cardViewMode = CardViewMode.NONE,
|
||||||
|
confirmReblogs = preferences.getBoolean("confirmReblogs", false)
|
||||||
)
|
)
|
||||||
|
|
||||||
adapter = StatusesAdapter(statusDisplayOptions,
|
adapter = StatusesAdapter(statusDisplayOptions,
|
||||||
|
|
|
@ -243,7 +243,7 @@ class SearchViewModel @Inject constructor(
|
||||||
return accountManager.getAllAccountsOrderedByActive()
|
return accountManager.getAllAccountsOrderedByActive()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun muteAcount(accountId: String) {
|
fun muteAccount(accountId: String) {
|
||||||
timelineCases.mute(accountId)
|
timelineCases.mute(accountId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +263,18 @@ class SearchViewModel @Inject constructor(
|
||||||
search(currentQuery)
|
search(currentQuery)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun muteConversation(status: Pair<Status, StatusViewData.Concrete>, mute: Boolean) {
|
||||||
|
val idx = loadedStatuses.indexOf(status)
|
||||||
|
if (idx >= 0) {
|
||||||
|
val newPair = Pair(status.first, StatusViewData.Builder(status.second).setMuted(mute).createStatusViewData())
|
||||||
|
loadedStatuses[idx] = newPair
|
||||||
|
repoResultStatus.value?.refresh?.invoke()
|
||||||
|
}
|
||||||
|
timelineCases.muteConversation(status.first, mute)
|
||||||
|
.onErrorReturnItem(status.first)
|
||||||
|
.subscribe()
|
||||||
|
.autoDispose()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "SearchViewModel"
|
private const val TAG = "SearchViewModel"
|
||||||
|
|
|
@ -49,8 +49,10 @@ import com.keylesspalace.tusky.components.search.adapter.SearchStatusesAdapter
|
||||||
import com.keylesspalace.tusky.db.AccountEntity
|
import com.keylesspalace.tusky.db.AccountEntity
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
import com.keylesspalace.tusky.entity.Status
|
import com.keylesspalace.tusky.entity.Status
|
||||||
|
import com.keylesspalace.tusky.entity.Status.Mention
|
||||||
import com.keylesspalace.tusky.interfaces.AccountSelectionListener
|
import com.keylesspalace.tusky.interfaces.AccountSelectionListener
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
||||||
|
import com.keylesspalace.tusky.util.CardViewMode
|
||||||
import com.keylesspalace.tusky.util.NetworkState
|
import com.keylesspalace.tusky.util.NetworkState
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||||
|
@ -70,7 +72,7 @@ open class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.C
|
||||||
get() = viewModel.statuses
|
get() = viewModel.statuses
|
||||||
|
|
||||||
private val searchAdapter
|
private val searchAdapter
|
||||||
get() = super.adapter as SearchStatusesAdapter
|
get() = super.adapter as SearchStatusesAdapter
|
||||||
|
|
||||||
override fun createAdapter(): PagedListAdapter<Pair<Status, StatusViewData.Concrete>, *> {
|
override fun createAdapter(): PagedListAdapter<Pair<Status, StatusViewData.Concrete>, *> {
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(searchRecyclerView.context)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(searchRecyclerView.context)
|
||||||
|
@ -79,7 +81,9 @@ open class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.C
|
||||||
mediaPreviewEnabled = viewModel.mediaPreviewEnabled,
|
mediaPreviewEnabled = viewModel.mediaPreviewEnabled,
|
||||||
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
|
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
|
||||||
showBotOverlay = preferences.getBoolean("showBotOverlay", true),
|
showBotOverlay = preferences.getBoolean("showBotOverlay", true),
|
||||||
useBlurhash = preferences.getBoolean("useBlurhash", true)
|
useBlurhash = preferences.getBoolean("useBlurhash", true),
|
||||||
|
cardViewMode = CardViewMode.NONE,
|
||||||
|
confirmReblogs = preferences.getBoolean("confirmReblogs", false)
|
||||||
)
|
)
|
||||||
|
|
||||||
searchRecyclerView.addItemDecoration(DividerItemDecoration(searchRecyclerView.context, DividerItemDecoration.VERTICAL))
|
searchRecyclerView.addItemDecoration(DividerItemDecoration(searchRecyclerView.context, DividerItemDecoration.VERTICAL))
|
||||||
|
@ -250,12 +254,9 @@ open class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.C
|
||||||
val loggedInAccountId = viewModel.activeAccount?.accountId
|
val loggedInAccountId = viewModel.activeAccount?.accountId
|
||||||
|
|
||||||
val popup = PopupMenu(view.context, view)
|
val popup = PopupMenu(view.context, view)
|
||||||
|
val statusIsByCurrentUser = loggedInAccountId?.equals(accountId) == true
|
||||||
// Give a different menu depending on whether this is the user's own toot or not.
|
// Give a different menu depending on whether this is the user's own toot or not.
|
||||||
if (loggedInAccountId == null || loggedInAccountId != accountId) {
|
if (statusIsByCurrentUser) {
|
||||||
popup.inflate(R.menu.status_more)
|
|
||||||
val menu = popup.menu
|
|
||||||
menu.findItem(R.id.status_download_media).isVisible = status.attachments.isNotEmpty()
|
|
||||||
} else {
|
|
||||||
popup.inflate(R.menu.status_more_for_user)
|
popup.inflate(R.menu.status_more_for_user)
|
||||||
val menu = popup.menu
|
val menu = popup.menu
|
||||||
menu.findItem(R.id.status_open_as).isVisible = !statusUrl.isNullOrBlank()
|
menu.findItem(R.id.status_open_as).isVisible = !statusUrl.isNullOrBlank()
|
||||||
|
@ -273,6 +274,10 @@ open class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.C
|
||||||
Status.Visibility.UNKNOWN, Status.Visibility.UNLEAKABLE, Status.Visibility.DIRECT -> {
|
Status.Visibility.UNKNOWN, Status.Visibility.UNLEAKABLE, Status.Visibility.DIRECT -> {
|
||||||
} //Ignore
|
} //Ignore
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
popup.inflate(R.menu.status_more)
|
||||||
|
val menu = popup.menu
|
||||||
|
menu.findItem(R.id.status_download_media).isVisible = status.attachments.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
val openAsItem = popup.menu.findItem(R.id.status_open_as)
|
val openAsItem = popup.menu.findItem(R.id.status_open_as)
|
||||||
|
@ -288,6 +293,19 @@ open class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.C
|
||||||
}
|
}
|
||||||
openAsItem.title = openAsTitle
|
openAsItem.title = openAsTitle
|
||||||
|
|
||||||
|
val mutable = statusIsByCurrentUser || accountIsInMentions(viewModel.activeAccount, status.mentions)
|
||||||
|
val muteConversationItem = popup.menu.findItem(R.id.status_mute_conversation).apply {
|
||||||
|
isVisible = mutable
|
||||||
|
}
|
||||||
|
if (mutable) {
|
||||||
|
muteConversationItem.setTitle(
|
||||||
|
if (status.muted == true) {
|
||||||
|
R.string.action_unmute_conversation
|
||||||
|
} else {
|
||||||
|
R.string.action_mute_conversation
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener { item ->
|
popup.setOnMenuItemClickListener { item ->
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.status_share_content -> {
|
R.id.status_share_content -> {
|
||||||
|
@ -325,12 +343,18 @@ open class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.C
|
||||||
requestDownloadAllMedia(status)
|
requestDownloadAllMedia(status)
|
||||||
return@setOnMenuItemClickListener true
|
return@setOnMenuItemClickListener true
|
||||||
}
|
}
|
||||||
|
R.id.status_mute_conversation -> {
|
||||||
|
searchAdapter.getItem(position)?.let { foundStatus ->
|
||||||
|
viewModel.muteConversation(foundStatus, status.muted != true)
|
||||||
|
}
|
||||||
|
return@setOnMenuItemClickListener true
|
||||||
|
}
|
||||||
R.id.status_mute -> {
|
R.id.status_mute -> {
|
||||||
viewModel.muteAcount(accountId)
|
onMute(accountId, accountUsername)
|
||||||
return@setOnMenuItemClickListener true
|
return@setOnMenuItemClickListener true
|
||||||
}
|
}
|
||||||
R.id.status_block -> {
|
R.id.status_block -> {
|
||||||
viewModel.blockAccount(accountId)
|
onBlock(accountId, accountUsername)
|
||||||
return@setOnMenuItemClickListener true
|
return@setOnMenuItemClickListener true
|
||||||
}
|
}
|
||||||
R.id.status_report -> {
|
R.id.status_report -> {
|
||||||
|
@ -363,6 +387,28 @@ open class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.C
|
||||||
popup.show()
|
popup.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onBlock(accountId: String, accountUsername: String) {
|
||||||
|
AlertDialog.Builder(requireContext())
|
||||||
|
.setMessage(getString(R.string.dialog_block_warning, accountUsername))
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ -> viewModel.blockAccount(accountId) }
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onMute(accountId: String, accountUsername: String) {
|
||||||
|
AlertDialog.Builder(requireContext())
|
||||||
|
.setMessage(getString(R.string.dialog_mute_warning, accountUsername))
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ -> viewModel.muteAccount(accountId) }
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun accountIsInMentions(account: AccountEntity?, mentions: Array<Mention>): Boolean {
|
||||||
|
return mentions.firstOrNull {
|
||||||
|
account?.username == it.username && account.domain == Uri.parse(it.url)?.host
|
||||||
|
} != null
|
||||||
|
}
|
||||||
|
|
||||||
private fun showOpenAsDialog(statusUrl: String, dialogTitle: CharSequence) {
|
private fun showOpenAsDialog(statusUrl: String, dialogTitle: CharSequence) {
|
||||||
bottomSheetActivity?.showAccountChooserDialog(dialogTitle, false, object : AccountSelectionListener {
|
bottomSheetActivity?.showAccountChooserDialog(dialogTitle, false, object : AccountSelectionListener {
|
||||||
override fun onAccountSelected(account: AccountEntity) {
|
override fun onAccountSelected(account: AccountEntity) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ data class AccountEntity(@field:PrimaryKey(autoGenerate = true) var id: Long,
|
||||||
var notificationsEnabled: Boolean = true,
|
var notificationsEnabled: Boolean = true,
|
||||||
var notificationsMentioned: Boolean = true,
|
var notificationsMentioned: Boolean = true,
|
||||||
var notificationsFollowed: Boolean = true,
|
var notificationsFollowed: Boolean = true,
|
||||||
|
var notificationsFollowRequested: Boolean = false,
|
||||||
var notificationsReblogged: Boolean = true,
|
var notificationsReblogged: Boolean = true,
|
||||||
var notificationsFavorited: Boolean = true,
|
var notificationsFavorited: Boolean = true,
|
||||||
var notificationsPolls: Boolean = true,
|
var notificationsPolls: Boolean = true,
|
||||||
|
@ -54,7 +55,7 @@ data class AccountEntity(@field:PrimaryKey(autoGenerate = true) var id: Long,
|
||||||
var activeNotifications: String = "[]",
|
var activeNotifications: String = "[]",
|
||||||
var emojis: List<Emoji> = emptyList(),
|
var emojis: List<Emoji> = emptyList(),
|
||||||
var tabPreferences: List<TabData> = defaultTabs(),
|
var tabPreferences: List<TabData> = defaultTabs(),
|
||||||
var notificationsFilter: String = "[]") {
|
var notificationsFilter: String = "[\"follow_request\"]") {
|
||||||
|
|
||||||
val identifier: String
|
val identifier: String
|
||||||
get() = "$domain:$accountId"
|
get() = "$domain:$accountId"
|
||||||
|
|
|
@ -30,7 +30,7 @@ import androidx.annotation.NonNull;
|
||||||
|
|
||||||
@Database(entities = {TootEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class,
|
@Database(entities = {TootEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class,
|
||||||
TimelineAccountEntity.class, ConversationEntity.class
|
TimelineAccountEntity.class, ConversationEntity.class
|
||||||
}, version = 21)
|
}, version = 23)
|
||||||
public abstract class AppDatabase extends RoomDatabase {
|
public abstract class AppDatabase extends RoomDatabase {
|
||||||
|
|
||||||
public abstract TootDao tootDao();
|
public abstract TootDao tootDao();
|
||||||
|
@ -326,4 +326,18 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static final Migration MIGRATION_21_22 = new Migration(21, 22) {
|
||||||
|
@Override
|
||||||
|
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||||
|
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `notificationsFollowRequested` INTEGER NOT NULL DEFAULT 0");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Migration MIGRATION_22_23 = new Migration(22, 23) {
|
||||||
|
@Override
|
||||||
|
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||||
|
database.execSQL("ALTER TABLE `TimelineStatusEntity` ADD COLUMN `muted` INTEGER");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -16,6 +16,8 @@
|
||||||
package com.keylesspalace.tusky.db
|
package com.keylesspalace.tusky.db
|
||||||
|
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
|
import androidx.core.text.toHtml
|
||||||
import androidx.room.TypeConverter
|
import androidx.room.TypeConverter
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
|
@ -27,7 +29,6 @@ import com.keylesspalace.tusky.entity.Emoji
|
||||||
import com.keylesspalace.tusky.entity.Poll
|
import com.keylesspalace.tusky.entity.Poll
|
||||||
import com.keylesspalace.tusky.entity.Status
|
import com.keylesspalace.tusky.entity.Status
|
||||||
import com.keylesspalace.tusky.json.SpannedTypeAdapter
|
import com.keylesspalace.tusky.json.SpannedTypeAdapter
|
||||||
import com.keylesspalace.tusky.util.HtmlUtils
|
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -128,7 +129,7 @@ class Converters {
|
||||||
if(spanned == null) {
|
if(spanned == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return HtmlUtils.toHtml(spanned)
|
return spanned.toHtml()
|
||||||
}
|
}
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
|
@ -136,7 +137,7 @@ class Converters {
|
||||||
if(spannedString == null) {
|
if(spannedString == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return HtmlUtils.fromHtml(spannedString)
|
return spannedString.parseAsHtml()
|
||||||
}
|
}
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
|
|
|
@ -51,7 +51,8 @@ data class TimelineStatusEntity(
|
||||||
val application: String?,
|
val application: String?,
|
||||||
val reblogServerId: String?, // if it has a reblogged status, it's id is stored here
|
val reblogServerId: String?, // if it has a reblogged status, it's id is stored here
|
||||||
val reblogAccountId: String?,
|
val reblogAccountId: String?,
|
||||||
val poll: String?
|
val poll: String?,
|
||||||
|
val muted: Boolean?
|
||||||
)
|
)
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
|
|
|
@ -29,8 +29,6 @@ import com.keylesspalace.tusky.db.AppDatabase
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.keylesspalace.tusky.network.TimelineCases
|
import com.keylesspalace.tusky.network.TimelineCases
|
||||||
import com.keylesspalace.tusky.network.TimelineCasesImpl
|
import com.keylesspalace.tusky.network.TimelineCasesImpl
|
||||||
import com.keylesspalace.tusky.util.HtmlConverter
|
|
||||||
import com.keylesspalace.tusky.util.HtmlConverterImpl
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -79,13 +77,9 @@ class AppModule {
|
||||||
AppDatabase.MIGRATION_11_12, AppDatabase.MIGRATION_12_13, AppDatabase.MIGRATION_10_13,
|
AppDatabase.MIGRATION_11_12, AppDatabase.MIGRATION_12_13, AppDatabase.MIGRATION_10_13,
|
||||||
AppDatabase.MIGRATION_13_14, AppDatabase.MIGRATION_14_15, AppDatabase.MIGRATION_15_16,
|
AppDatabase.MIGRATION_13_14, AppDatabase.MIGRATION_14_15, AppDatabase.MIGRATION_15_16,
|
||||||
AppDatabase.MIGRATION_16_17, AppDatabase.MIGRATION_17_18, AppDatabase.MIGRATION_18_19,
|
AppDatabase.MIGRATION_16_17, AppDatabase.MIGRATION_17_18, AppDatabase.MIGRATION_18_19,
|
||||||
AppDatabase.MIGRATION_19_20, AppDatabase.MIGRATION_20_21)
|
AppDatabase.MIGRATION_19_20, AppDatabase.MIGRATION_20_21, AppDatabase.MIGRATION_21_22,
|
||||||
.build()
|
AppDatabase.MIGRATION_22_23)
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun providesHtmlConverter(): HtmlConverter {
|
|
||||||
return HtmlConverterImpl()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -6,17 +6,18 @@ import com.keylesspalace.tusky.db.AppDatabase
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.keylesspalace.tusky.repository.TimelineRepository
|
import com.keylesspalace.tusky.repository.TimelineRepository
|
||||||
import com.keylesspalace.tusky.repository.TimelineRepositoryImpl
|
import com.keylesspalace.tusky.repository.TimelineRepositoryImpl
|
||||||
import com.keylesspalace.tusky.util.HtmlConverter
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
class RepositoryModule {
|
class RepositoryModule {
|
||||||
@Provides
|
@Provides
|
||||||
fun providesTimelineRepository(db: AppDatabase, mastodonApi: MastodonApi,
|
fun providesTimelineRepository(
|
||||||
accountManager: AccountManager, gson: Gson,
|
db: AppDatabase,
|
||||||
htmlConverter: HtmlConverter): TimelineRepository {
|
mastodonApi: MastodonApi,
|
||||||
return TimelineRepositoryImpl(db.timelineDao(), mastodonApi, accountManager, gson,
|
accountManager: AccountManager,
|
||||||
htmlConverter)
|
gson: Gson
|
||||||
|
): TimelineRepository {
|
||||||
|
return TimelineRepositoryImpl(db.timelineDao(), mastodonApi, accountManager, gson)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,24 +15,16 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky.entity
|
package com.keylesspalace.tusky.entity
|
||||||
|
|
||||||
import android.os.Parcel
|
|
||||||
import android.os.Parcelable
|
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import com.keylesspalace.tusky.util.HtmlUtils
|
import java.util.Date
|
||||||
import kotlinx.android.parcel.Parceler
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
|
||||||
import kotlinx.android.parcel.WriteWith
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
data class Account(
|
data class Account(
|
||||||
val id: String,
|
val id: String,
|
||||||
@SerializedName("username") val localUsername: String,
|
@SerializedName("username") val localUsername: String,
|
||||||
@SerializedName("acct", alternate = ["subject"]) val username: String,
|
@SerializedName("acct", alternate = ["subject"]) val username: String,
|
||||||
@SerializedName("display_name") val displayName: String?, // should never be null per Api definition, but some servers break the contract
|
@SerializedName("display_name") val displayName: String?, // should never be null per Api definition, but some servers break the contract
|
||||||
val note: @WriteWith<SpannedParceler>() Spanned,
|
val note: Spanned,
|
||||||
val url: String,
|
val url: String,
|
||||||
val avatar: String,
|
val avatar: String,
|
||||||
val header: String,
|
val header: String,
|
||||||
|
@ -47,7 +39,7 @@ data class Account(
|
||||||
val moved: Account? = null,
|
val moved: Account? = null,
|
||||||
@SerializedName("name") val notestockUsername: String? = null
|
@SerializedName("name") val notestockUsername: String? = null
|
||||||
|
|
||||||
) : Parcelable {
|
) {
|
||||||
|
|
||||||
val name: String
|
val name: String
|
||||||
get() = notestockUsername ?: if (displayName.isNullOrEmpty()) {
|
get() = notestockUsername ?: if (displayName.isNullOrEmpty()) {
|
||||||
|
@ -87,31 +79,20 @@ data class Account(
|
||||||
fun isRemote(): Boolean = this.username != this.localUsername
|
fun isRemote(): Boolean = this.username != this.localUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
data class AccountSource(
|
data class AccountSource(
|
||||||
val privacy: Status.Visibility,
|
val privacy: Status.Visibility,
|
||||||
val sensitive: Boolean,
|
val sensitive: Boolean,
|
||||||
val note: String,
|
val note: String,
|
||||||
val fields: List<StringField>?
|
val fields: List<StringField>?
|
||||||
): Parcelable
|
)
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
data class Field (
|
data class Field (
|
||||||
val name: String,
|
val name: String,
|
||||||
val value: @WriteWith<SpannedParceler>() Spanned,
|
val value: Spanned,
|
||||||
@SerializedName("verified_at") val verifiedAt: Date?
|
@SerializedName("verified_at") val verifiedAt: Date?
|
||||||
): Parcelable
|
)
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
data class StringField (
|
data class StringField (
|
||||||
val name: String,
|
val name: String,
|
||||||
val value: String
|
val value: String
|
||||||
): Parcelable
|
)
|
||||||
|
|
||||||
object SpannedParceler : Parceler<Spanned> {
|
|
||||||
override fun create(parcel: Parcel): Spanned = HtmlUtils.fromHtml(parcel.readString())
|
|
||||||
|
|
||||||
override fun Spanned.write(parcel: Parcel, flags: Int) {
|
|
||||||
parcel.writeString(HtmlUtils.toHtml(this))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,23 +15,19 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky.entity
|
package com.keylesspalace.tusky.entity
|
||||||
|
|
||||||
import android.os.Parcelable
|
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import kotlinx.android.parcel.Parcelize
|
|
||||||
import kotlinx.android.parcel.WriteWith
|
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
data class Card(
|
data class Card(
|
||||||
val url: String,
|
val url: String,
|
||||||
val title: @WriteWith<SpannedParceler>() Spanned,
|
val title: Spanned,
|
||||||
val description: @WriteWith<SpannedParceler>() Spanned,
|
val description: Spanned,
|
||||||
@SerializedName("author_name") val authorName: String,
|
@SerializedName("author_name") val authorName: String,
|
||||||
val image: String,
|
val image: String,
|
||||||
val type: String,
|
val type: String,
|
||||||
val width: Int,
|
val width: Int,
|
||||||
val height: Int
|
val height: Int
|
||||||
) : Parcelable {
|
) {
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return url.hashCode()
|
return url.hashCode()
|
||||||
|
|
|
@ -31,6 +31,7 @@ data class Notification(
|
||||||
REBLOG("reblog"),
|
REBLOG("reblog"),
|
||||||
FAVOURITE("favourite"),
|
FAVOURITE("favourite"),
|
||||||
FOLLOW("follow"),
|
FOLLOW("follow"),
|
||||||
|
FOLLOW_REQUEST("follow_request"),
|
||||||
POLL("poll");
|
POLL("poll");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -43,7 +44,7 @@ data class Notification(
|
||||||
}
|
}
|
||||||
return UNKNOWN
|
return UNKNOWN
|
||||||
}
|
}
|
||||||
val asList = listOf(MENTION, REBLOG, FAVOURITE, FOLLOW, POLL)
|
val asList = listOf(MENTION, REBLOG, FAVOURITE, FOLLOW, FOLLOW_REQUEST, POLL)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
|
|
@ -9,6 +9,7 @@ data class Poll(
|
||||||
val expired: Boolean,
|
val expired: Boolean,
|
||||||
val multiple: Boolean,
|
val multiple: Boolean,
|
||||||
@SerializedName("votes_count") val votesCount: Int,
|
@SerializedName("votes_count") val votesCount: Int,
|
||||||
|
@SerializedName("voters_count") val votersCount: Int?, // nullable for compatibility with Pleroma
|
||||||
val options: List<PollOption>,
|
val options: List<PollOption>,
|
||||||
val voted: Boolean
|
val voted: Boolean
|
||||||
) {
|
) {
|
||||||
|
@ -22,7 +23,12 @@ data class Poll(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy(options = newOptions, votesCount = votesCount + choices.size, voted = true)
|
return copy(
|
||||||
|
options = newOptions,
|
||||||
|
votesCount = votesCount + choices.size,
|
||||||
|
votersCount = votersCount?.plus(1),
|
||||||
|
voted = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toNewPoll(creationDate: Date) = NewPoll(
|
fun toNewPoll(creationDate: Date) = NewPoll(
|
||||||
|
|
|
@ -43,6 +43,7 @@ data class Status(
|
||||||
val mentions: Array<Mention>,
|
val mentions: Array<Mention>,
|
||||||
val application: Application?,
|
val application: Application?,
|
||||||
var pinned: Boolean?,
|
var pinned: Boolean?,
|
||||||
|
var muted: Boolean?,
|
||||||
val poll: Poll?,
|
val poll: Poll?,
|
||||||
val card: Card?,
|
val card: Card?,
|
||||||
val quote: Status?
|
val quote: Status?
|
||||||
|
|
|
@ -199,10 +199,10 @@ class AccountMediaFragment : BaseFragment(), RefreshableFragment, Injectable {
|
||||||
val itemCount = layoutManager.itemCount
|
val itemCount = layoutManager.itemCount
|
||||||
val lastItem = layoutManager.findLastCompletelyVisibleItemPosition()
|
val lastItem = layoutManager.findLastCompletelyVisibleItemPosition()
|
||||||
if (itemCount <= lastItem + 3 && fetchingStatus == FetchingStatus.NOT_FETCHING) {
|
if (itemCount <= lastItem + 3 && fetchingStatus == FetchingStatus.NOT_FETCHING) {
|
||||||
statuses.lastOrNull()?.let { last ->
|
statuses.lastOrNull()?.let { (id) ->
|
||||||
Log.d(TAG, "Requesting statuses with max_id: ${last.id}, (bottom)")
|
Log.d(TAG, "Requesting statuses with max_id: ${id}, (bottom)")
|
||||||
fetchingStatus = FetchingStatus.FETCHING_BOTTOM
|
fetchingStatus = FetchingStatus.FETCHING_BOTTOM
|
||||||
currentCall = api.accountStatuses(accountId, last.id, null, null, null, true, null)
|
currentCall = api.accountStatuses(accountId, id, null, null, null, true, null)
|
||||||
currentCall?.enqueue(bottomCallback)
|
currentCall?.enqueue(bottomCallback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ class AccountMediaFragment : BaseFragment(), RefreshableFragment, Injectable {
|
||||||
if (view != null && activity != null) {
|
if (view != null && activity != null) {
|
||||||
val url = items[currentIndex].attachment.url
|
val url = items[currentIndex].attachment.url
|
||||||
ViewCompat.setTransitionName(view, url)
|
ViewCompat.setTransitionName(view, url)
|
||||||
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity!!, view, url)
|
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), view, url)
|
||||||
startActivity(intent, options.toBundle())
|
startActivity(intent, options.toBundle())
|
||||||
} else {
|
} else {
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
|
|
|
@ -65,10 +65,13 @@ import com.keylesspalace.tusky.db.AccountManager;
|
||||||
import com.keylesspalace.tusky.di.Injectable;
|
import com.keylesspalace.tusky.di.Injectable;
|
||||||
import com.keylesspalace.tusky.entity.Notification;
|
import com.keylesspalace.tusky.entity.Notification;
|
||||||
import com.keylesspalace.tusky.entity.Poll;
|
import com.keylesspalace.tusky.entity.Poll;
|
||||||
|
import com.keylesspalace.tusky.entity.Relationship;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
||||||
import com.keylesspalace.tusky.interfaces.ReselectableFragment;
|
import com.keylesspalace.tusky.interfaces.ReselectableFragment;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
import com.keylesspalace.tusky.util.Either;
|
import com.keylesspalace.tusky.util.Either;
|
||||||
import com.keylesspalace.tusky.util.HttpHeaderLink;
|
import com.keylesspalace.tusky.util.HttpHeaderLink;
|
||||||
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate;
|
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate;
|
||||||
|
@ -97,6 +100,7 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
import at.connyduck.sparkbutton.helpers.Utils;
|
import at.connyduck.sparkbutton.helpers.Utils;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.Single;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
|
@ -114,6 +118,7 @@ public class NotificationsFragment extends SFragment implements
|
||||||
SwipeRefreshLayout.OnRefreshListener,
|
SwipeRefreshLayout.OnRefreshListener,
|
||||||
StatusActionListener,
|
StatusActionListener,
|
||||||
NotificationsAdapter.NotificationActionListener,
|
NotificationsAdapter.NotificationActionListener,
|
||||||
|
AccountActionListener,
|
||||||
Injectable, ReselectableFragment {
|
Injectable, ReselectableFragment {
|
||||||
private static final String TAG = "NotificationF"; // logging tag
|
private static final String TAG = "NotificationF"; // logging tag
|
||||||
|
|
||||||
|
@ -244,11 +249,13 @@ public class NotificationsFragment extends SFragment implements
|
||||||
accountManager.getActiveAccount().getMediaPreviewEnabled(),
|
accountManager.getActiveAccount().getMediaPreviewEnabled(),
|
||||||
preferences.getBoolean("absoluteTimeView", false),
|
preferences.getBoolean("absoluteTimeView", false),
|
||||||
preferences.getBoolean("showBotOverlay", true),
|
preferences.getBoolean("showBotOverlay", true),
|
||||||
preferences.getBoolean("useBlurhash", true)
|
preferences.getBoolean("useBlurhash", true),
|
||||||
|
CardViewMode.NONE,
|
||||||
|
preferences.getBoolean("confirmReblogs", true)
|
||||||
);
|
);
|
||||||
|
|
||||||
adapter = new NotificationsAdapter(accountManager.getActiveAccount().getAccountId(),
|
adapter = new NotificationsAdapter(accountManager.getActiveAccount().getAccountId(),
|
||||||
dataSource, statusDisplayOptions, this, this);
|
dataSource, statusDisplayOptions, this, this, this);
|
||||||
alwaysShowSensitiveMedia = accountManager.getActiveAccount().getAlwaysShowSensitiveMedia();
|
alwaysShowSensitiveMedia = accountManager.getActiveAccount().getAlwaysShowSensitiveMedia();
|
||||||
alwaysOpenSpoiler = accountManager.getActiveAccount().getAlwaysOpenSpoiler();
|
alwaysOpenSpoiler = accountManager.getActiveAccount().getAlwaysOpenSpoiler();
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
@ -767,6 +774,8 @@ public class NotificationsFragment extends SFragment implements
|
||||||
return getString(R.string.notification_boost_name);
|
return getString(R.string.notification_boost_name);
|
||||||
case FOLLOW:
|
case FOLLOW:
|
||||||
return getString(R.string.notification_follow_name);
|
return getString(R.string.notification_follow_name);
|
||||||
|
case FOLLOW_REQUEST:
|
||||||
|
return getString(R.string.notification_follow_request_name);
|
||||||
case POLL:
|
case POLL:
|
||||||
return getString(R.string.notification_poll_name);
|
return getString(R.string.notification_poll_name);
|
||||||
default:
|
default:
|
||||||
|
@ -819,6 +828,29 @@ public class NotificationsFragment extends SFragment implements
|
||||||
super.viewAccount(id);
|
super.viewAccount(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMute(boolean mute, String id, int position) {
|
||||||
|
// No muting from notifications yet
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlock(boolean block, String id, int position) {
|
||||||
|
// No blocking from notifications yet
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRespondToFollowRequest(boolean accept, String id, int position) {
|
||||||
|
Single<Relationship> request = accept ?
|
||||||
|
mastodonApi.authorizeFollowRequestObservable(id) :
|
||||||
|
mastodonApi.rejectFollowRequestObservable(id);
|
||||||
|
request.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))
|
||||||
|
.subscribe(
|
||||||
|
(relationship) -> fullyRefreshWithProgressBar(true),
|
||||||
|
(error) -> Log.e(TAG, String.format("Failed to %s account id %s", accept ? "accept" : "reject", id))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewStatusForNotificationId(String notificationId) {
|
public void onViewStatusForNotificationId(String notificationId) {
|
||||||
for (Either<Placeholder, Notification> either : notifications) {
|
for (Either<Placeholder, Notification> either : notifications) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ import androidx.appcompat.widget.PopupMenu;
|
||||||
import androidx.core.app.ActivityOptionsCompat;
|
import androidx.core.app.ActivityOptionsCompat;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.keylesspalace.tusky.BaseActivity;
|
import com.keylesspalace.tusky.BaseActivity;
|
||||||
import com.keylesspalace.tusky.BottomSheetActivity;
|
import com.keylesspalace.tusky.BottomSheetActivity;
|
||||||
|
@ -215,11 +216,8 @@ public abstract class SFragment extends BaseFragment implements Injectable {
|
||||||
|
|
||||||
PopupMenu popup = new PopupMenu(getContext(), view);
|
PopupMenu popup = new PopupMenu(getContext(), view);
|
||||||
// Give a different menu depending on whether this is the user's own toot or not.
|
// Give a different menu depending on whether this is the user's own toot or not.
|
||||||
if (loggedInAccountId == null || !loggedInAccountId.equals(accountId)) {
|
boolean statusIsByCurrentUser = loggedInAccountId != null && loggedInAccountId.equals(accountId);
|
||||||
popup.inflate(R.menu.status_more);
|
if (statusIsByCurrentUser) {
|
||||||
Menu menu = popup.getMenu();
|
|
||||||
menu.findItem(R.id.status_download_media).setVisible(!status.getAttachments().isEmpty());
|
|
||||||
} else {
|
|
||||||
popup.inflate(R.menu.status_more_for_user);
|
popup.inflate(R.menu.status_more_for_user);
|
||||||
Menu menu = popup.getMenu();
|
Menu menu = popup.getMenu();
|
||||||
switch (status.getVisibility()) {
|
switch (status.getVisibility()) {
|
||||||
|
@ -238,6 +236,10 @@ public abstract class SFragment extends BaseFragment implements Injectable {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
popup.inflate(R.menu.status_more);
|
||||||
|
Menu menu = popup.getMenu();
|
||||||
|
menu.findItem(R.id.status_download_media).setVisible(!status.getAttachments().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu menu = popup.getMenu();
|
Menu menu = popup.getMenu();
|
||||||
|
@ -261,6 +263,15 @@ public abstract class SFragment extends BaseFragment implements Injectable {
|
||||||
}
|
}
|
||||||
openAsItem.setTitle(openAsTitle);
|
openAsItem.setTitle(openAsTitle);
|
||||||
|
|
||||||
|
MenuItem muteConversationItem = menu.findItem(R.id.status_mute_conversation);
|
||||||
|
boolean mutable = statusIsByCurrentUser || accountIsInMentions(activeAccount, status.getMentions());
|
||||||
|
muteConversationItem.setVisible(mutable);
|
||||||
|
if (mutable) {
|
||||||
|
muteConversationItem.setTitle((status.getMuted() == null || !status.getMuted()) ?
|
||||||
|
R.string.action_mute_conversation :
|
||||||
|
R.string.action_unmute_conversation);
|
||||||
|
}
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener(item -> {
|
popup.setOnMenuItemClickListener(item -> {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.status_share_content: {
|
case R.id.status_share_content: {
|
||||||
|
@ -304,11 +315,11 @@ public abstract class SFragment extends BaseFragment implements Injectable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.status_mute: {
|
case R.id.status_mute: {
|
||||||
timelineCases.mute(accountId);
|
onMute(accountId, accountUsername);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.status_block: {
|
case R.id.status_block: {
|
||||||
timelineCases.block(accountId);
|
onBlock(accountId, accountUsername);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.status_report: {
|
case R.id.status_report: {
|
||||||
|
@ -335,12 +346,52 @@ public abstract class SFragment extends BaseFragment implements Injectable {
|
||||||
timelineCases.pin(status, !status.isPinned());
|
timelineCases.pin(status, !status.isPinned());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case R.id.status_mute_conversation: {
|
||||||
|
timelineCases.muteConversation(status, status.getMuted() == null || !status.getMuted())
|
||||||
|
.onErrorReturnItem(status)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))
|
||||||
|
.subscribe();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
popup.show();
|
popup.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onMute(String accountId, String accountUsername) {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setMessage(getString(R.string.dialog_mute_warning, accountUsername))
|
||||||
|
.setPositiveButton(android.R.string.ok, (__, ___) -> timelineCases.mute(accountId))
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onBlock(String accountId, String accountUsername) {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setMessage(getString(R.string.dialog_block_warning, accountUsername))
|
||||||
|
.setPositiveButton(android.R.string.ok, (__, ___) -> timelineCases.block(accountId))
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean accountIsInMentions(AccountEntity account, Status.Mention[] mentions) {
|
||||||
|
if (account == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Status.Mention mention : mentions) {
|
||||||
|
if (account.getUsername().equals(mention.getUsername())) {
|
||||||
|
Uri uri = Uri.parse(mention.getUrl());
|
||||||
|
if (uri != null && account.getDomain().equals(uri.getHost())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected void viewMedia(int urlIndex, Status status, @Nullable View view) {
|
protected void viewMedia(int urlIndex, Status status, @Nullable View view) {
|
||||||
final Status actionable = status.getActionableStatus();
|
final Status actionable = status.getActionableStatus();
|
||||||
final Attachment active = actionable.getAttachments().get(urlIndex);
|
final Attachment active = actionable.getAttachments().get(urlIndex);
|
||||||
|
|
|
@ -56,6 +56,7 @@ import com.keylesspalace.tusky.appstore.BookmarkEvent;
|
||||||
import com.keylesspalace.tusky.appstore.DomainMuteEvent;
|
import com.keylesspalace.tusky.appstore.DomainMuteEvent;
|
||||||
import com.keylesspalace.tusky.appstore.EventHub;
|
import com.keylesspalace.tusky.appstore.EventHub;
|
||||||
import com.keylesspalace.tusky.appstore.FavoriteEvent;
|
import com.keylesspalace.tusky.appstore.FavoriteEvent;
|
||||||
|
import com.keylesspalace.tusky.appstore.MuteConversationEvent;
|
||||||
import com.keylesspalace.tusky.appstore.MuteEvent;
|
import com.keylesspalace.tusky.appstore.MuteEvent;
|
||||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent;
|
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent;
|
||||||
import com.keylesspalace.tusky.appstore.QuickReplyEvent;
|
import com.keylesspalace.tusky.appstore.QuickReplyEvent;
|
||||||
|
@ -78,6 +79,7 @@ import com.keylesspalace.tusky.network.MastodonApi;
|
||||||
import com.keylesspalace.tusky.repository.Placeholder;
|
import com.keylesspalace.tusky.repository.Placeholder;
|
||||||
import com.keylesspalace.tusky.repository.TimelineRepository;
|
import com.keylesspalace.tusky.repository.TimelineRepository;
|
||||||
import com.keylesspalace.tusky.repository.TimelineRequestMode;
|
import com.keylesspalace.tusky.repository.TimelineRequestMode;
|
||||||
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
import com.keylesspalace.tusky.util.Either;
|
import com.keylesspalace.tusky.util.Either;
|
||||||
import com.keylesspalace.tusky.util.LinkHelper;
|
import com.keylesspalace.tusky.util.LinkHelper;
|
||||||
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate;
|
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate;
|
||||||
|
@ -229,7 +231,7 @@ public class TimelineFragment extends SFragment implements
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
Bundle arguments = Objects.requireNonNull(getArguments());
|
Bundle arguments = requireArguments();
|
||||||
kind = Kind.valueOf(arguments.getString(KIND_ARG));
|
kind = Kind.valueOf(arguments.getString(KIND_ARG));
|
||||||
if (kind == Kind.TAG
|
if (kind == Kind.TAG
|
||||||
|| kind == Kind.USER
|
|| kind == Kind.USER
|
||||||
|
@ -245,7 +247,11 @@ public class TimelineFragment extends SFragment implements
|
||||||
accountManager.getActiveAccount().getMediaPreviewEnabled(),
|
accountManager.getActiveAccount().getMediaPreviewEnabled(),
|
||||||
preferences.getBoolean("absoluteTimeView", false),
|
preferences.getBoolean("absoluteTimeView", false),
|
||||||
preferences.getBoolean("showBotOverlay", true),
|
preferences.getBoolean("showBotOverlay", true),
|
||||||
preferences.getBoolean("useBlurhash", true)
|
preferences.getBoolean("useBlurhash", true),
|
||||||
|
preferences.getBoolean("showCardsInTimelines", false) ?
|
||||||
|
CardViewMode.INDENTED :
|
||||||
|
CardViewMode.NONE,
|
||||||
|
preferences.getBoolean("confirmReblogs", true)
|
||||||
);
|
);
|
||||||
adapter = new TimelineAdapter(dataSource, statusDisplayOptions, this);
|
adapter = new TimelineAdapter(dataSource, statusDisplayOptions, this);
|
||||||
|
|
||||||
|
@ -568,6 +574,9 @@ public class TimelineFragment extends SFragment implements
|
||||||
} else if (event instanceof BookmarkEvent) {
|
} else if (event instanceof BookmarkEvent) {
|
||||||
BookmarkEvent bookmarkEvent = (BookmarkEvent) event;
|
BookmarkEvent bookmarkEvent = (BookmarkEvent) event;
|
||||||
handleBookmarkEvent(bookmarkEvent);
|
handleBookmarkEvent(bookmarkEvent);
|
||||||
|
} else if (event instanceof MuteConversationEvent) {
|
||||||
|
MuteConversationEvent muteEvent = (MuteConversationEvent) event;
|
||||||
|
handleMuteConversationEvent(muteEvent);
|
||||||
} else if (event instanceof UnfollowEvent) {
|
} else if (event instanceof UnfollowEvent) {
|
||||||
if (kind == Kind.HOME) {
|
if (kind == Kind.HOME) {
|
||||||
String id = ((UnfollowEvent) event).getAccountId();
|
String id = ((UnfollowEvent) event).getAccountId();
|
||||||
|
@ -1428,6 +1437,10 @@ public class TimelineFragment extends SFragment implements
|
||||||
setBookmarkForStatus(pos, status, bookmarkEvent.getBookmark());
|
setBookmarkForStatus(pos, status, bookmarkEvent.getBookmark());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleMuteConversationEvent(@NonNull MuteConversationEvent event) {
|
||||||
|
fullyRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
private void handleStatusComposeEvent(@NonNull Status status) {
|
private void handleStatusComposeEvent(@NonNull Status status) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case HOME:
|
case HOME:
|
||||||
|
|
|
@ -89,7 +89,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
toolbar = activity!!.toolbar
|
toolbar = requireActivity().toolbar
|
||||||
this.transition = BehaviorSubject.create()
|
this.transition = BehaviorSubject.create()
|
||||||
return inflater.inflate(R.layout.fragment_view_image, container, false)
|
return inflater.inflate(R.layout.fragment_view_image, container, false)
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
val arguments = this.arguments!!
|
val arguments = this.requireArguments()
|
||||||
val attachment = arguments.getParcelable<Attachment>(ARG_ATTACHMENT)
|
val attachment = arguments.getParcelable<Attachment>(ARG_ATTACHMENT)
|
||||||
this.shouldStartTransition = arguments.getBoolean(ARG_START_POSTPONED_TRANSITION)
|
this.shouldStartTransition = arguments.getBoolean(ARG_START_POSTPONED_TRANSITION)
|
||||||
val url: String?
|
val url: String?
|
||||||
|
|
|
@ -58,6 +58,7 @@ import com.keylesspalace.tusky.entity.Status;
|
||||||
import com.keylesspalace.tusky.entity.StatusContext;
|
import com.keylesspalace.tusky.entity.StatusContext;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.network.MastodonApi;
|
import com.keylesspalace.tusky.network.MastodonApi;
|
||||||
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate;
|
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate;
|
||||||
import com.keylesspalace.tusky.util.PairedList;
|
import com.keylesspalace.tusky.util.PairedList;
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||||
|
@ -131,7 +132,11 @@ public final class ViewThreadFragment extends SFragment implements
|
||||||
accountManager.getActiveAccount().getMediaPreviewEnabled(),
|
accountManager.getActiveAccount().getMediaPreviewEnabled(),
|
||||||
preferences.getBoolean("absoluteTimeView", false),
|
preferences.getBoolean("absoluteTimeView", false),
|
||||||
preferences.getBoolean("showBotOverlay", true),
|
preferences.getBoolean("showBotOverlay", true),
|
||||||
preferences.getBoolean("useBlurhash", true)
|
preferences.getBoolean("useBlurhash", true),
|
||||||
|
preferences.getBoolean("showCardsInTimelines", false) ?
|
||||||
|
CardViewMode.INDENTED :
|
||||||
|
CardViewMode.NONE,
|
||||||
|
preferences.getBoolean("confirmReblogs", true)
|
||||||
);
|
);
|
||||||
adapter = new ThreadAdapter(statusDisplayOptions, this);
|
adapter = new ThreadAdapter(statusDisplayOptions, this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,12 +136,12 @@ class ViewVideoFragment : ViewMediaFragment() {
|
||||||
|
|
||||||
progressBar.hide()
|
progressBar.hide()
|
||||||
mp.isLooping = true
|
mp.isLooping = true
|
||||||
if (arguments!!.getBoolean(ARG_START_POSTPONED_TRANSITION)) {
|
if (requireArguments().getBoolean(ARG_START_POSTPONED_TRANSITION)) {
|
||||||
videoView.start()
|
videoView.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments!!.getBoolean(ARG_START_POSTPONED_TRANSITION)) {
|
if (requireArguments().getBoolean(ARG_START_POSTPONED_TRANSITION)) {
|
||||||
mediaActivity.onBringUp()
|
mediaActivity.onBringUp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ class ViewVideoFragment : ViewMediaFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
toolbar = activity!!.toolbar
|
toolbar = requireActivity().toolbar
|
||||||
mediaActivity = activity as ViewMediaActivity
|
mediaActivity = activity as ViewMediaActivity
|
||||||
return inflater.inflate(R.layout.fragment_view_video, container, false)
|
return inflater.inflate(R.layout.fragment_view_video, container, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,42 +41,23 @@ class NotificationPreferencesFragment : PreferenceFragmentCompat(), Preference.O
|
||||||
val activeAccount = accountManager.activeAccount
|
val activeAccount = accountManager.activeAccount
|
||||||
|
|
||||||
if (activeAccount != null) {
|
if (activeAccount != null) {
|
||||||
|
for (pair in mapOf(
|
||||||
val notificationPref = requirePreference("notificationsEnabled") as SwitchPreferenceCompat
|
"notificationsEnabled" to activeAccount.notificationsEnabled,
|
||||||
notificationPref.isChecked = activeAccount.notificationsEnabled
|
"notificationFilterMentions" to activeAccount.notificationsMentioned,
|
||||||
notificationPref.onPreferenceChangeListener = this
|
"notificationFilterFollows" to activeAccount.notificationsFollowed,
|
||||||
|
"notificationFilterFollowRequests" to activeAccount.notificationsFollowRequested,
|
||||||
val mentionedPref = requirePreference("notificationFilterMentions") as SwitchPreferenceCompat
|
"notificationFilterReblogs" to activeAccount.notificationsReblogged,
|
||||||
mentionedPref.isChecked = activeAccount.notificationsMentioned
|
"notificationFilterFavourites" to activeAccount.notificationsFavorited,
|
||||||
mentionedPref.onPreferenceChangeListener = this
|
"notificationFilterPolls" to activeAccount.notificationsPolls,
|
||||||
|
"notificationAlertSound" to activeAccount.notificationSound,
|
||||||
val followedPref = requirePreference("notificationFilterFollows") as SwitchPreferenceCompat
|
"notificationAlertVibrate" to activeAccount.notificationVibration,
|
||||||
followedPref.isChecked = activeAccount.notificationsFollowed
|
"notificationAlertLight" to activeAccount.notificationLight
|
||||||
followedPref.onPreferenceChangeListener = this
|
)) {
|
||||||
|
(requirePreference(pair.key) as SwitchPreferenceCompat).apply {
|
||||||
val boostedPref = requirePreference("notificationFilterReblogs") as SwitchPreferenceCompat
|
isChecked = pair.value
|
||||||
boostedPref.isChecked = activeAccount.notificationsReblogged
|
onPreferenceChangeListener = this@NotificationPreferencesFragment
|
||||||
boostedPref.onPreferenceChangeListener = this
|
}
|
||||||
|
}
|
||||||
val favoritedPref = requirePreference("notificationFilterFavourites") as SwitchPreferenceCompat
|
|
||||||
favoritedPref.isChecked = activeAccount.notificationsFavorited
|
|
||||||
favoritedPref.onPreferenceChangeListener = this
|
|
||||||
|
|
||||||
val pollsPref = requirePreference("notificationFilterPolls") as SwitchPreferenceCompat
|
|
||||||
pollsPref.isChecked = activeAccount.notificationsPolls
|
|
||||||
pollsPref.onPreferenceChangeListener = this
|
|
||||||
|
|
||||||
val soundPref = requirePreference("notificationAlertSound") as SwitchPreferenceCompat
|
|
||||||
soundPref.isChecked = activeAccount.notificationSound
|
|
||||||
soundPref.onPreferenceChangeListener = this
|
|
||||||
|
|
||||||
val vibrationPref = requirePreference("notificationAlertVibrate") as SwitchPreferenceCompat
|
|
||||||
vibrationPref.isChecked = activeAccount.notificationVibration
|
|
||||||
vibrationPref.onPreferenceChangeListener = this
|
|
||||||
|
|
||||||
val lightPref = requirePreference("notificationAlertLight") as SwitchPreferenceCompat
|
|
||||||
lightPref.isChecked = activeAccount.notificationLight
|
|
||||||
lightPref.onPreferenceChangeListener = this
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +77,7 @@ class NotificationPreferencesFragment : PreferenceFragmentCompat(), Preference.O
|
||||||
}
|
}
|
||||||
"notificationFilterMentions" -> activeAccount.notificationsMentioned = newValue as Boolean
|
"notificationFilterMentions" -> activeAccount.notificationsMentioned = newValue as Boolean
|
||||||
"notificationFilterFollows" -> activeAccount.notificationsFollowed = newValue as Boolean
|
"notificationFilterFollows" -> activeAccount.notificationsFollowed = newValue as Boolean
|
||||||
|
"notificationFilterFollowRequests" -> activeAccount.notificationsFollowRequested = newValue as Boolean
|
||||||
"notificationFilterReblogs" -> activeAccount.notificationsReblogged = newValue as Boolean
|
"notificationFilterReblogs" -> activeAccount.notificationsReblogged = newValue as Boolean
|
||||||
"notificationFilterFavourites" -> activeAccount.notificationsFavorited = newValue as Boolean
|
"notificationFilterFavourites" -> activeAccount.notificationsFavorited = newValue as Boolean
|
||||||
"notificationFilterPolls" -> activeAccount.notificationsPolls = newValue as Boolean
|
"notificationFilterPolls" -> activeAccount.notificationsPolls = newValue as Boolean
|
||||||
|
|
|
@ -18,6 +18,8 @@ package com.keylesspalace.tusky.json;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.SpannedString;
|
import android.text.SpannedString;
|
||||||
|
|
||||||
|
import androidx.core.text.HtmlCompat;
|
||||||
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
import com.google.gson.JsonDeserializationContext;
|
||||||
import com.google.gson.JsonDeserializer;
|
import com.google.gson.JsonDeserializer;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
@ -25,7 +27,6 @@ import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.JsonPrimitive;
|
import com.google.gson.JsonPrimitive;
|
||||||
import com.google.gson.JsonSerializationContext;
|
import com.google.gson.JsonSerializationContext;
|
||||||
import com.google.gson.JsonSerializer;
|
import com.google.gson.JsonSerializer;
|
||||||
import com.keylesspalace.tusky.util.HtmlUtils;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
@ -35,7 +36,9 @@ public class SpannedTypeAdapter implements JsonDeserializer<Spanned>, JsonSerial
|
||||||
throws JsonParseException {
|
throws JsonParseException {
|
||||||
String string = json.getAsString();
|
String string = json.getAsString();
|
||||||
if (string != null) {
|
if (string != null) {
|
||||||
return HtmlUtils.fromHtml(string);
|
/* Html.fromHtml returns trailing whitespace if the html ends in a </p> tag, which
|
||||||
|
* all status contents do, so it should be trimmed. */
|
||||||
|
return (Spanned)trimTrailingWhitespace(HtmlCompat.fromHtml(string, HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
} else {
|
} else {
|
||||||
return new SpannedString("");
|
return new SpannedString("");
|
||||||
}
|
}
|
||||||
|
@ -43,6 +46,14 @@ public class SpannedTypeAdapter implements JsonDeserializer<Spanned>, JsonSerial
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JsonElement serialize(Spanned src, Type typeOfSrc, JsonSerializationContext context) {
|
public JsonElement serialize(Spanned src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
return new JsonPrimitive(HtmlUtils.toHtml(src));
|
return new JsonPrimitive(HtmlCompat.toHtml(src, HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CharSequence trimTrailingWhitespace(CharSequence s) {
|
||||||
|
int i = s.length();
|
||||||
|
do {
|
||||||
|
i--;
|
||||||
|
} while (i >= 0 && Character.isWhitespace(s.charAt(i)));
|
||||||
|
return s.subSequence(0, i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,6 +200,16 @@ interface MastodonApi {
|
||||||
@Path("id") statusId: String
|
@Path("id") statusId: String
|
||||||
): Single<Status>
|
): Single<Status>
|
||||||
|
|
||||||
|
@POST("api/v1/statuses/{id}/mute")
|
||||||
|
fun muteConversation(
|
||||||
|
@Path("id") statusId: String
|
||||||
|
): Single<Status>
|
||||||
|
|
||||||
|
@POST("api/v1/statuses/{id}/unmute")
|
||||||
|
fun unmuteConversation(
|
||||||
|
@Path("id") statusId: String
|
||||||
|
): Single<Status>
|
||||||
|
|
||||||
@GET("api/v1/scheduled_statuses")
|
@GET("api/v1/scheduled_statuses")
|
||||||
fun scheduledStatuses(
|
fun scheduledStatuses(
|
||||||
@Query("limit") limit: Int? = null,
|
@Query("limit") limit: Int? = null,
|
||||||
|
@ -383,6 +393,16 @@ interface MastodonApi {
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Call<Relationship>
|
): Call<Relationship>
|
||||||
|
|
||||||
|
@POST("api/v1/follow_requests/{id}/authorize")
|
||||||
|
fun authorizeFollowRequestObservable(
|
||||||
|
@Path("id") accountId: String
|
||||||
|
): Single<Relationship>
|
||||||
|
|
||||||
|
@POST("api/v1/follow_requests/{id}/reject")
|
||||||
|
fun rejectFollowRequestObservable(
|
||||||
|
@Path("id") accountId: String
|
||||||
|
): Single<Relationship>
|
||||||
|
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("api/v1/apps")
|
@POST("api/v1/apps")
|
||||||
fun authenticateApp(
|
fun authenticateApp(
|
||||||
|
|
|
@ -41,7 +41,7 @@ interface TimelineCases {
|
||||||
fun delete(id: String): Single<DeletedStatus>
|
fun delete(id: String): Single<DeletedStatus>
|
||||||
fun pin(status: Status, pin: Boolean)
|
fun pin(status: Status, pin: Boolean)
|
||||||
fun voteInPoll(status: Status, choices: List<Int>): Single<Poll>
|
fun voteInPoll(status: Status, choices: List<Int>): Single<Poll>
|
||||||
|
fun muteConversation(status: Status, mute: Boolean): Single<Status>
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimelineCasesImpl(
|
class TimelineCasesImpl(
|
||||||
|
@ -94,6 +94,19 @@ class TimelineCasesImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun muteConversation(status: Status, mute: Boolean): Single<Status> {
|
||||||
|
val id = status.actionableId
|
||||||
|
|
||||||
|
val call = if (mute) {
|
||||||
|
mastodonApi.muteConversation(id)
|
||||||
|
} else {
|
||||||
|
mastodonApi.unmuteConversation(id)
|
||||||
|
}
|
||||||
|
return call.doAfterSuccess {
|
||||||
|
eventHub.dispatch(MuteConversationEvent(status.id, mute))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun mute(id: String) {
|
override fun mute(id: String) {
|
||||||
val call = mastodonApi.muteAccount(id)
|
val call = mastodonApi.muteAccount(id)
|
||||||
call.enqueue(object : Callback<Relationship> {
|
call.enqueue(object : Callback<Relationship> {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.keylesspalace.tusky.repository
|
package com.keylesspalace.tusky.repository
|
||||||
|
|
||||||
import android.text.SpannedString
|
import android.text.SpannedString
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
|
import androidx.core.text.toHtml
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.keylesspalace.tusky.db.*
|
import com.keylesspalace.tusky.db.*
|
||||||
|
@ -9,7 +11,6 @@ import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.keylesspalace.tusky.repository.TimelineRequestMode.DISK
|
import com.keylesspalace.tusky.repository.TimelineRequestMode.DISK
|
||||||
import com.keylesspalace.tusky.repository.TimelineRequestMode.NETWORK
|
import com.keylesspalace.tusky.repository.TimelineRequestMode.NETWORK
|
||||||
import com.keylesspalace.tusky.util.Either
|
import com.keylesspalace.tusky.util.Either
|
||||||
import com.keylesspalace.tusky.util.HtmlConverter
|
|
||||||
import com.keylesspalace.tusky.util.dec
|
import com.keylesspalace.tusky.util.dec
|
||||||
import com.keylesspalace.tusky.util.inc
|
import com.keylesspalace.tusky.util.inc
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
|
@ -41,8 +42,7 @@ class TimelineRepositoryImpl(
|
||||||
private val timelineDao: TimelineDao,
|
private val timelineDao: TimelineDao,
|
||||||
private val mastodonApi: MastodonApi,
|
private val mastodonApi: MastodonApi,
|
||||||
private val accountManager: AccountManager,
|
private val accountManager: AccountManager,
|
||||||
private val gson: Gson,
|
private val gson: Gson
|
||||||
private val htmlConverter: HtmlConverter
|
|
||||||
) : TimelineRepository {
|
) : TimelineRepository {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -67,7 +67,7 @@ class TimelineRepositoryImpl(
|
||||||
val accountId = acc.id
|
val accountId = acc.id
|
||||||
|
|
||||||
timelineDao.insertInTransaction(
|
timelineDao.insertInTransaction(
|
||||||
status.toEntity(accountId, htmlConverter, gson),
|
status.toEntity(accountId, gson),
|
||||||
status.account.toEntity(accountId, gson),
|
status.account.toEntity(accountId, gson),
|
||||||
status.reblog?.account?.toEntity(accountId, gson)
|
status.reblog?.account?.toEntity(accountId, gson)
|
||||||
)
|
)
|
||||||
|
@ -162,7 +162,7 @@ class TimelineRepositoryImpl(
|
||||||
|
|
||||||
for (status in statuses) {
|
for (status in statuses) {
|
||||||
timelineDao.insertInTransaction(
|
timelineDao.insertInTransaction(
|
||||||
status.toEntity(accountId, htmlConverter, gson),
|
status.toEntity(accountId, gson),
|
||||||
status.account.toEntity(accountId, gson),
|
status.account.toEntity(accountId, gson),
|
||||||
status.reblog?.account?.toEntity(accountId, gson)
|
status.reblog?.account?.toEntity(accountId, gson)
|
||||||
)
|
)
|
||||||
|
@ -226,7 +226,7 @@ class TimelineRepositoryImpl(
|
||||||
inReplyToId = status.inReplyToId,
|
inReplyToId = status.inReplyToId,
|
||||||
inReplyToAccountId = status.inReplyToAccountId,
|
inReplyToAccountId = status.inReplyToAccountId,
|
||||||
reblog = null,
|
reblog = null,
|
||||||
content = status.content?.let(htmlConverter::fromHtml) ?: SpannedString(""),
|
content = status.content?.parseAsHtml() ?: SpannedString(""),
|
||||||
createdAt = Date(status.createdAt),
|
createdAt = Date(status.createdAt),
|
||||||
emojis = emojis,
|
emojis = emojis,
|
||||||
reblogsCount = status.reblogsCount,
|
reblogsCount = status.reblogsCount,
|
||||||
|
@ -241,6 +241,7 @@ class TimelineRepositoryImpl(
|
||||||
mentions = mentions,
|
mentions = mentions,
|
||||||
application = application,
|
application = application,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
|
muted = status.muted,
|
||||||
poll = poll,
|
poll = poll,
|
||||||
card = null,
|
card = null,
|
||||||
quote = null
|
quote = null
|
||||||
|
@ -269,6 +270,7 @@ class TimelineRepositoryImpl(
|
||||||
mentions = arrayOf(),
|
mentions = arrayOf(),
|
||||||
application = null,
|
application = null,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
|
muted = status.muted,
|
||||||
poll = null,
|
poll = null,
|
||||||
card = null,
|
card = null,
|
||||||
quote = null
|
quote = null
|
||||||
|
@ -281,7 +283,7 @@ class TimelineRepositoryImpl(
|
||||||
inReplyToId = status.inReplyToId,
|
inReplyToId = status.inReplyToId,
|
||||||
inReplyToAccountId = status.inReplyToAccountId,
|
inReplyToAccountId = status.inReplyToAccountId,
|
||||||
reblog = null,
|
reblog = null,
|
||||||
content = status.content?.let(htmlConverter::fromHtml) ?: SpannedString(""),
|
content = status.content?.parseAsHtml() ?: SpannedString(""),
|
||||||
createdAt = Date(status.createdAt),
|
createdAt = Date(status.createdAt),
|
||||||
emojis = emojis,
|
emojis = emojis,
|
||||||
reblogsCount = status.reblogsCount,
|
reblogsCount = status.reblogsCount,
|
||||||
|
@ -296,6 +298,7 @@ class TimelineRepositoryImpl(
|
||||||
mentions = mentions,
|
mentions = mentions,
|
||||||
application = application,
|
application = application,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
|
muted = status.muted,
|
||||||
poll = poll,
|
poll = poll,
|
||||||
card = null,
|
card = null,
|
||||||
quote = null
|
quote = null
|
||||||
|
@ -368,12 +371,12 @@ fun Placeholder.toEntity(timelineUserId: Long): TimelineStatusEntity {
|
||||||
application = null,
|
application = null,
|
||||||
reblogServerId = null,
|
reblogServerId = null,
|
||||||
reblogAccountId = null,
|
reblogAccountId = null,
|
||||||
poll = null
|
poll = null,
|
||||||
|
muted = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Status.toEntity(timelineUserId: Long,
|
fun Status.toEntity(timelineUserId: Long,
|
||||||
htmlConverter: HtmlConverter,
|
|
||||||
gson: Gson): TimelineStatusEntity {
|
gson: Gson): TimelineStatusEntity {
|
||||||
val actionable = actionableStatus
|
val actionable = actionableStatus
|
||||||
return TimelineStatusEntity(
|
return TimelineStatusEntity(
|
||||||
|
@ -383,7 +386,7 @@ fun Status.toEntity(timelineUserId: Long,
|
||||||
authorServerId = actionable.account.id,
|
authorServerId = actionable.account.id,
|
||||||
inReplyToId = actionable.inReplyToId,
|
inReplyToId = actionable.inReplyToId,
|
||||||
inReplyToAccountId = actionable.inReplyToAccountId,
|
inReplyToAccountId = actionable.inReplyToAccountId,
|
||||||
content = htmlConverter.toHtml(actionable.content),
|
content = actionable.content.toHtml(),
|
||||||
createdAt = actionable.createdAt.time,
|
createdAt = actionable.createdAt.time,
|
||||||
emojis = actionable.emojis.let(gson::toJson),
|
emojis = actionable.emojis.let(gson::toJson),
|
||||||
reblogsCount = actionable.reblogsCount,
|
reblogsCount = actionable.reblogsCount,
|
||||||
|
@ -396,10 +399,11 @@ fun Status.toEntity(timelineUserId: Long,
|
||||||
visibility = actionable.visibility,
|
visibility = actionable.visibility,
|
||||||
attachments = actionable.attachments.let(gson::toJson),
|
attachments = actionable.attachments.let(gson::toJson),
|
||||||
mentions = actionable.mentions.let(gson::toJson),
|
mentions = actionable.mentions.let(gson::toJson),
|
||||||
application = actionable.let(gson::toJson),
|
application = actionable.application.let(gson::toJson),
|
||||||
reblogServerId = reblog?.id,
|
reblogServerId = reblog?.id,
|
||||||
reblogAccountId = reblog?.let { this.account.id },
|
reblogAccountId = reblog?.let { this.account.id },
|
||||||
poll = actionable.poll.let(gson::toJson)
|
poll = actionable.poll.let(gson::toJson),
|
||||||
|
muted = actionable.muted
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.keylesspalace.tusky.util
|
||||||
|
|
||||||
|
enum class CardViewMode {
|
||||||
|
NONE,
|
||||||
|
FULL_WIDTH,
|
||||||
|
INDENTED
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
package com.keylesspalace.tusky.util
|
|
||||||
|
|
||||||
import android.text.Spanned
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstracting away Android-specific things.
|
|
||||||
*/
|
|
||||||
interface HtmlConverter {
|
|
||||||
fun fromHtml(html: String): Spanned
|
|
||||||
|
|
||||||
fun toHtml(text: Spanned): String
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class HtmlConverterImpl : HtmlConverter {
|
|
||||||
override fun fromHtml(html: String): Spanned {
|
|
||||||
return HtmlUtils.fromHtml(html)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toHtml(text: Spanned): String {
|
|
||||||
return HtmlUtils.toHtml(text)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +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 <http://www.gnu.org/licenses>. */
|
|
||||||
|
|
||||||
package com.keylesspalace.tusky.util;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spanned;
|
|
||||||
|
|
||||||
public class HtmlUtils {
|
|
||||||
private static CharSequence trimTrailingWhitespace(CharSequence s) {
|
|
||||||
int i = s.length();
|
|
||||||
do {
|
|
||||||
i--;
|
|
||||||
} while (i >= 0 && Character.isWhitespace(s.charAt(i)));
|
|
||||||
return s.subSequence(0, i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Spanned fromHtml(String html) {
|
|
||||||
Spanned result;
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
|
|
||||||
} else {
|
|
||||||
result = Html.fromHtml(html);
|
|
||||||
}
|
|
||||||
/* Html.fromHtml returns trailing whitespace if the html ends in a </p> tag, which
|
|
||||||
* all status contents do, so it should be trimmed. */
|
|
||||||
return (Spanned) trimTrailingWhitespace(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String toHtml(Spanned text) {
|
|
||||||
String result;
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
result = Html.toHtml(text, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE);
|
|
||||||
} else {
|
|
||||||
result = Html.toHtml(text);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -82,6 +82,8 @@ class ListStatusAccessibilityDelegate(
|
||||||
}
|
}
|
||||||
if (status.reblogsCount > 0) info.addAction(openRebloggedByAction)
|
if (status.reblogsCount > 0) info.addAction(openRebloggedByAction)
|
||||||
if (status.favouritesCount > 0) info.addAction(openFavsAction)
|
if (status.favouritesCount > 0) info.addAction(openFavsAction)
|
||||||
|
|
||||||
|
info.addAction(moreAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -150,6 +152,9 @@ class ListStatusAccessibilityDelegate(
|
||||||
interrupt()
|
interrupt()
|
||||||
statusActionListener.onShowFavs(pos)
|
statusActionListener.onShowFavs(pos)
|
||||||
}
|
}
|
||||||
|
R.id.action_more -> {
|
||||||
|
statusActionListener.onMore(host, pos)
|
||||||
|
}
|
||||||
else -> return super.performAccessibilityAction(host, action, args)
|
else -> return super.performAccessibilityAction(host, action, args)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -311,5 +316,10 @@ class ListStatusAccessibilityDelegate(
|
||||||
R.id.action_open_faved_by,
|
R.id.action_open_faved_by,
|
||||||
context.getString(R.string.action_open_faved_by))
|
context.getString(R.string.action_open_faved_by))
|
||||||
|
|
||||||
|
private val moreAction = AccessibilityActionCompat(
|
||||||
|
R.id.action_more,
|
||||||
|
context.getString(R.string.action_more)
|
||||||
|
)
|
||||||
|
|
||||||
private data class LinkSpanInfo(val text: String, val link: String)
|
private data class LinkSpanInfo(val text: String, val link: String)
|
||||||
}
|
}
|
|
@ -113,6 +113,7 @@ public class NotificationHelper {
|
||||||
**/
|
**/
|
||||||
public static final String CHANNEL_MENTION = "CHANNEL_MENTION";
|
public static final String CHANNEL_MENTION = "CHANNEL_MENTION";
|
||||||
public static final String CHANNEL_FOLLOW = "CHANNEL_FOLLOW";
|
public static final String CHANNEL_FOLLOW = "CHANNEL_FOLLOW";
|
||||||
|
public static final String CHANNEL_FOLLOW_REQUEST = "CHANNEL_FOLLOW_REQUEST";
|
||||||
public static final String CHANNEL_BOOST = "CHANNEL_BOOST";
|
public static final String CHANNEL_BOOST = "CHANNEL_BOOST";
|
||||||
public static final String CHANNEL_FAVOURITE = "CHANNEL_FAVOURITE";
|
public static final String CHANNEL_FAVOURITE = "CHANNEL_FAVOURITE";
|
||||||
public static final String CHANNEL_POLL = "CHANNEL_POLL";
|
public static final String CHANNEL_POLL = "CHANNEL_POLL";
|
||||||
|
@ -348,6 +349,7 @@ public class NotificationHelper {
|
||||||
String[] channelIds = new String[]{
|
String[] channelIds = new String[]{
|
||||||
CHANNEL_MENTION + account.getIdentifier(),
|
CHANNEL_MENTION + account.getIdentifier(),
|
||||||
CHANNEL_FOLLOW + account.getIdentifier(),
|
CHANNEL_FOLLOW + account.getIdentifier(),
|
||||||
|
CHANNEL_FOLLOW_REQUEST + account.getIdentifier(),
|
||||||
CHANNEL_BOOST + account.getIdentifier(),
|
CHANNEL_BOOST + account.getIdentifier(),
|
||||||
CHANNEL_FAVOURITE + account.getIdentifier(),
|
CHANNEL_FAVOURITE + account.getIdentifier(),
|
||||||
CHANNEL_POLL + account.getIdentifier(),
|
CHANNEL_POLL + account.getIdentifier(),
|
||||||
|
@ -355,6 +357,7 @@ public class NotificationHelper {
|
||||||
int[] channelNames = {
|
int[] channelNames = {
|
||||||
R.string.notification_mention_name,
|
R.string.notification_mention_name,
|
||||||
R.string.notification_follow_name,
|
R.string.notification_follow_name,
|
||||||
|
R.string.notification_follow_request_name,
|
||||||
R.string.notification_boost_name,
|
R.string.notification_boost_name,
|
||||||
R.string.notification_favourite_name,
|
R.string.notification_favourite_name,
|
||||||
R.string.notification_poll_name
|
R.string.notification_poll_name
|
||||||
|
@ -362,12 +365,13 @@ public class NotificationHelper {
|
||||||
int[] channelDescriptions = {
|
int[] channelDescriptions = {
|
||||||
R.string.notification_mention_descriptions,
|
R.string.notification_mention_descriptions,
|
||||||
R.string.notification_follow_description,
|
R.string.notification_follow_description,
|
||||||
|
R.string.notification_follow_request_description,
|
||||||
R.string.notification_boost_description,
|
R.string.notification_boost_description,
|
||||||
R.string.notification_favourite_description,
|
R.string.notification_favourite_description,
|
||||||
R.string.notification_poll_description
|
R.string.notification_poll_description
|
||||||
};
|
};
|
||||||
|
|
||||||
List<NotificationChannel> channels = new ArrayList<>(5);
|
List<NotificationChannel> channels = new ArrayList<>(6);
|
||||||
|
|
||||||
NotificationChannelGroup channelGroup = new NotificationChannelGroup(account.getIdentifier(), account.getFullName());
|
NotificationChannelGroup channelGroup = new NotificationChannelGroup(account.getIdentifier(), account.getFullName());
|
||||||
|
|
||||||
|
@ -508,6 +512,8 @@ public class NotificationHelper {
|
||||||
return account.getNotificationsMentioned();
|
return account.getNotificationsMentioned();
|
||||||
case FOLLOW:
|
case FOLLOW:
|
||||||
return account.getNotificationsFollowed();
|
return account.getNotificationsFollowed();
|
||||||
|
case FOLLOW_REQUEST:
|
||||||
|
return account.getNotificationsFollowRequested();
|
||||||
case REBLOG:
|
case REBLOG:
|
||||||
return account.getNotificationsReblogged();
|
return account.getNotificationsReblogged();
|
||||||
case FAVOURITE:
|
case FAVOURITE:
|
||||||
|
@ -525,6 +531,8 @@ public class NotificationHelper {
|
||||||
return CHANNEL_MENTION + account.getIdentifier();
|
return CHANNEL_MENTION + account.getIdentifier();
|
||||||
case FOLLOW:
|
case FOLLOW:
|
||||||
return CHANNEL_FOLLOW + account.getIdentifier();
|
return CHANNEL_FOLLOW + account.getIdentifier();
|
||||||
|
case FOLLOW_REQUEST:
|
||||||
|
return CHANNEL_FOLLOW_REQUEST + account.getIdentifier();
|
||||||
case REBLOG:
|
case REBLOG:
|
||||||
return CHANNEL_BOOST + account.getIdentifier();
|
return CHANNEL_BOOST + account.getIdentifier();
|
||||||
case FAVOURITE:
|
case FAVOURITE:
|
||||||
|
@ -594,6 +602,9 @@ public class NotificationHelper {
|
||||||
case FOLLOW:
|
case FOLLOW:
|
||||||
return String.format(context.getString(R.string.notification_follow_format),
|
return String.format(context.getString(R.string.notification_follow_format),
|
||||||
accountName);
|
accountName);
|
||||||
|
case FOLLOW_REQUEST:
|
||||||
|
return String.format(context.getString(R.string.notification_follow_request_format),
|
||||||
|
accountName);
|
||||||
case FAVOURITE:
|
case FAVOURITE:
|
||||||
return String.format(context.getString(R.string.notification_favourite_format),
|
return String.format(context.getString(R.string.notification_favourite_format),
|
||||||
accountName);
|
accountName);
|
||||||
|
@ -613,6 +624,7 @@ public class NotificationHelper {
|
||||||
private static String bodyForType(Notification notification, Context context) {
|
private static String bodyForType(Notification notification, Context context) {
|
||||||
switch (notification.getType()) {
|
switch (notification.getType()) {
|
||||||
case FOLLOW:
|
case FOLLOW:
|
||||||
|
case FOLLOW_REQUEST:
|
||||||
return "@" + notification.getAccount().getUsername();
|
return "@" + notification.getAccount().getUsername();
|
||||||
case MENTION:
|
case MENTION:
|
||||||
case FAVOURITE:
|
case FAVOURITE:
|
||||||
|
@ -631,7 +643,7 @@ public class NotificationHelper {
|
||||||
Poll poll = notification.getStatus().getPoll();
|
Poll poll = notification.getStatus().getPoll();
|
||||||
for(PollOption option: poll.getOptions()) {
|
for(PollOption option: poll.getOptions()) {
|
||||||
builder.append(buildDescription(option.getTitle(),
|
builder.append(buildDescription(option.getTitle(),
|
||||||
PollViewDataKt.calculatePercent(option.getVotesCount(), poll.getVotesCount()),
|
PollViewDataKt.calculatePercent(option.getVotesCount(), poll.getVotersCount(), poll.getVotesCount()),
|
||||||
context));
|
context));
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,9 @@ data class StatusDisplayOptions(
|
||||||
@get:JvmName("showBotOverlay")
|
@get:JvmName("showBotOverlay")
|
||||||
val showBotOverlay: Boolean,
|
val showBotOverlay: Boolean,
|
||||||
@get:JvmName("useBlurhash")
|
@get:JvmName("useBlurhash")
|
||||||
val useBlurhash: Boolean
|
val useBlurhash: Boolean,
|
||||||
|
@get:JvmName("cardViewMode")
|
||||||
|
val cardViewMode: CardViewMode,
|
||||||
|
@get:JvmName("confirmReblogs")
|
||||||
|
val confirmReblogs: Boolean
|
||||||
)
|
)
|
|
@ -24,7 +24,6 @@ import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
|
@ -172,15 +171,12 @@ class StatusViewHelper(private val itemView: View) {
|
||||||
sensitiveMediaWarning.visibility = View.GONE
|
sensitiveMediaWarning.visibility = View.GONE
|
||||||
sensitiveMediaShow.visibility = View.GONE
|
sensitiveMediaShow.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
|
sensitiveMediaWarning.text = if (sensitive) {
|
||||||
val hiddenContentText: String = if (sensitive) {
|
|
||||||
context.getString(R.string.status_sensitive_media_title)
|
context.getString(R.string.status_sensitive_media_title)
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.status_media_hidden_title)
|
context.getString(R.string.status_media_hidden_title)
|
||||||
}
|
}
|
||||||
|
|
||||||
sensitiveMediaWarning.text = HtmlUtils.fromHtml(hiddenContentText)
|
|
||||||
|
|
||||||
sensitiveMediaWarning.visibility = if (showingContent) View.GONE else View.VISIBLE
|
sensitiveMediaWarning.visibility = if (showingContent) View.GONE else View.VISIBLE
|
||||||
sensitiveMediaShow.visibility = if (showingContent) View.VISIBLE else View.GONE
|
sensitiveMediaShow.visibility = if (showingContent) View.VISIBLE else View.GONE
|
||||||
sensitiveMediaShow.setOnClickListener { v ->
|
sensitiveMediaShow.setOnClickListener { v ->
|
||||||
|
@ -275,17 +271,22 @@ class StatusViewHelper(private val itemView: View) {
|
||||||
|
|
||||||
private fun getPollInfoText(timestamp: Long, poll: PollViewData, pollDescription: TextView, useAbsoluteTime: Boolean): CharSequence {
|
private fun getPollInfoText(timestamp: Long, poll: PollViewData, pollDescription: TextView, useAbsoluteTime: Boolean): CharSequence {
|
||||||
val context = pollDescription.context
|
val context = pollDescription.context
|
||||||
val votes = NumberFormat.getNumberInstance().format(poll.votesCount.toLong())
|
|
||||||
val votesText = context.resources.getQuantityString(R.plurals.poll_info_votes, poll.votesCount, votes)
|
val votesText = if(poll.votersCount == null) {
|
||||||
val pollDurationInfo: CharSequence
|
val votes = NumberFormat.getNumberInstance().format(poll.votesCount.toLong())
|
||||||
if (poll.expired) {
|
context.resources.getQuantityString(R.plurals.poll_info_votes, poll.votesCount, votes)
|
||||||
pollDurationInfo = context.getString(R.string.poll_info_closed)
|
} else {
|
||||||
|
val votes = NumberFormat.getNumberInstance().format(poll.votersCount.toLong())
|
||||||
|
context.resources.getQuantityString(R.plurals.poll_info_people, poll.votersCount, votes)
|
||||||
|
}
|
||||||
|
val pollDurationInfo = if (poll.expired) {
|
||||||
|
context.getString(R.string.poll_info_closed)
|
||||||
} else {
|
} else {
|
||||||
if (useAbsoluteTime) {
|
if (useAbsoluteTime) {
|
||||||
pollDurationInfo = context.getString(R.string.poll_info_time_absolute, getAbsoluteTime(poll.expiresAt))
|
context.getString(R.string.poll_info_time_absolute, getAbsoluteTime(poll.expiresAt))
|
||||||
} else {
|
} else {
|
||||||
val pollDuration = TimestampUtils.formatPollDuration(context, poll.expiresAt!!.time, timestamp)
|
val pollDuration = TimestampUtils.formatPollDuration(context, poll.expiresAt!!.time, timestamp)
|
||||||
pollDurationInfo = context.getString(R.string.poll_info_time_relative, pollDuration)
|
context.getString(R.string.poll_info_time_relative, pollDuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +299,7 @@ class StatusViewHelper(private val itemView: View) {
|
||||||
|
|
||||||
for (i in 0 until Status.MAX_POLL_OPTIONS) {
|
for (i in 0 until Status.MAX_POLL_OPTIONS) {
|
||||||
if (i < options.size) {
|
if (i < options.size) {
|
||||||
val percent = calculatePercent(options[i].votesCount, poll.votesCount)
|
val percent = calculatePercent(options[i].votesCount, poll.votersCount, poll.votesCount)
|
||||||
|
|
||||||
val pollOptionText = buildDescription(options[i].title, percent, pollResults[i].context)
|
val pollOptionText = buildDescription(options[i].title, percent, pollResults[i].context)
|
||||||
pollResults[i].text = CustomEmojiHelper.emojifyText(pollOptionText, emojis, pollResults[i])
|
pollResults[i].text = CustomEmojiHelper.emojifyText(pollOptionText, emojis, pollResults[i])
|
||||||
|
|
|
@ -18,10 +18,10 @@ package com.keylesspalace.tusky.viewdata
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.entity.Poll
|
import com.keylesspalace.tusky.entity.Poll
|
||||||
import com.keylesspalace.tusky.entity.PollOption
|
import com.keylesspalace.tusky.entity.PollOption
|
||||||
import com.keylesspalace.tusky.util.HtmlUtils
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ data class PollViewData(
|
||||||
val expired: Boolean,
|
val expired: Boolean,
|
||||||
val multiple: Boolean,
|
val multiple: Boolean,
|
||||||
val votesCount: Int,
|
val votesCount: Int,
|
||||||
|
val votersCount: Int?,
|
||||||
val options: List<PollOptionViewData>,
|
val options: List<PollOptionViewData>,
|
||||||
var voted: Boolean
|
var voted: Boolean
|
||||||
)
|
)
|
||||||
|
@ -41,16 +42,17 @@ data class PollOptionViewData(
|
||||||
var selected: Boolean
|
var selected: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
fun calculatePercent(fraction: Int, total: Int): Int {
|
fun calculatePercent(fraction: Int, totalVoters: Int?, totalVotes: Int): Int {
|
||||||
return if (fraction == 0) {
|
return if (fraction == 0) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
|
val total = totalVoters ?: totalVotes
|
||||||
(fraction / total.toDouble() * 100).roundToInt()
|
(fraction / total.toDouble() * 100).roundToInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildDescription(title: String, percent: Int, context: Context): Spanned {
|
fun buildDescription(title: String, percent: Int, context: Context): Spanned {
|
||||||
return SpannableStringBuilder(HtmlUtils.fromHtml(context.getString(R.string.poll_percent_format, percent)))
|
return SpannableStringBuilder(context.getString(R.string.poll_percent_format, percent).parseAsHtml())
|
||||||
.append(" ")
|
.append(" ")
|
||||||
.append(title)
|
.append(title)
|
||||||
}
|
}
|
||||||
|
@ -58,20 +60,21 @@ fun buildDescription(title: String, percent: Int, context: Context): Spanned {
|
||||||
fun Poll?.toViewData(): PollViewData? {
|
fun Poll?.toViewData(): PollViewData? {
|
||||||
if (this == null) return null
|
if (this == null) return null
|
||||||
return PollViewData(
|
return PollViewData(
|
||||||
id,
|
id = id,
|
||||||
expiresAt,
|
expiresAt = expiresAt,
|
||||||
expired,
|
expired = expired,
|
||||||
multiple,
|
multiple = multiple,
|
||||||
votesCount,
|
votesCount = votesCount,
|
||||||
options.map { it.toViewData() },
|
votersCount = votersCount,
|
||||||
voted
|
options = options.map { it.toViewData() },
|
||||||
|
voted = voted
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PollOption.toViewData(): PollOptionViewData {
|
fun PollOption.toViewData(): PollOptionViewData {
|
||||||
return PollOptionViewData(
|
return PollOptionViewData(
|
||||||
title,
|
title = title,
|
||||||
votesCount,
|
votesCount = votesCount,
|
||||||
false
|
selected = false
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -58,6 +58,7 @@ public abstract class StatusViewData {
|
||||||
final boolean reblogged;
|
final boolean reblogged;
|
||||||
final boolean favourited;
|
final boolean favourited;
|
||||||
final boolean bookmarked;
|
final boolean bookmarked;
|
||||||
|
private final boolean muted;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String spoilerText;
|
private final String spoilerText;
|
||||||
private final Status.Visibility visibility;
|
private final Status.Visibility visibility;
|
||||||
|
@ -96,7 +97,7 @@ public abstract class StatusViewData {
|
||||||
private final Status quote;
|
private final Status quote;
|
||||||
private final boolean isNotestock;
|
private final boolean isNotestock;
|
||||||
|
|
||||||
public Concrete(String id, Spanned content, boolean reblogged, boolean favourited, boolean bookmarked,
|
public Concrete(String id, Spanned content, boolean reblogged, boolean favourited, boolean bookmarked, boolean muted,
|
||||||
@Nullable String spoilerText, Status.Visibility visibility, List<Attachment> attachments,
|
@Nullable String spoilerText, Status.Visibility visibility, List<Attachment> attachments,
|
||||||
@Nullable String rebloggedByUsername, @Nullable String rebloggedAvatar, boolean sensitive, boolean isExpanded,
|
@Nullable String rebloggedByUsername, @Nullable String rebloggedAvatar, boolean sensitive, boolean isExpanded,
|
||||||
boolean isShowingContent, String userFullName, String nickname, String avatar,
|
boolean isShowingContent, String userFullName, String nickname, String avatar,
|
||||||
|
@ -119,6 +120,7 @@ public abstract class StatusViewData {
|
||||||
this.reblogged = reblogged;
|
this.reblogged = reblogged;
|
||||||
this.favourited = favourited;
|
this.favourited = favourited;
|
||||||
this.bookmarked = bookmarked;
|
this.bookmarked = bookmarked;
|
||||||
|
this.muted = muted;
|
||||||
this.visibility = visibility;
|
this.visibility = visibility;
|
||||||
this.attachments = attachments;
|
this.attachments = attachments;
|
||||||
this.rebloggedByUsername = rebloggedByUsername;
|
this.rebloggedByUsername = rebloggedByUsername;
|
||||||
|
@ -167,6 +169,10 @@ public abstract class StatusViewData {
|
||||||
return bookmarked;
|
return bookmarked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMuted() {
|
||||||
|
return muted;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getSpoilerText() {
|
public String getSpoilerText() {
|
||||||
return spoilerText;
|
return spoilerText;
|
||||||
|
@ -419,6 +425,7 @@ public abstract class StatusViewData {
|
||||||
private boolean reblogged;
|
private boolean reblogged;
|
||||||
private boolean favourited;
|
private boolean favourited;
|
||||||
private boolean bookmarked;
|
private boolean bookmarked;
|
||||||
|
private boolean muted;
|
||||||
private String spoilerText;
|
private String spoilerText;
|
||||||
private Status.Visibility visibility;
|
private Status.Visibility visibility;
|
||||||
private List<Attachment> attachments;
|
private List<Attachment> attachments;
|
||||||
|
@ -457,6 +464,7 @@ public abstract class StatusViewData {
|
||||||
reblogged = viewData.reblogged;
|
reblogged = viewData.reblogged;
|
||||||
favourited = viewData.favourited;
|
favourited = viewData.favourited;
|
||||||
bookmarked = viewData.bookmarked;
|
bookmarked = viewData.bookmarked;
|
||||||
|
muted = viewData.muted;
|
||||||
spoilerText = viewData.spoilerText;
|
spoilerText = viewData.spoilerText;
|
||||||
visibility = viewData.visibility;
|
visibility = viewData.visibility;
|
||||||
attachments = viewData.attachments == null ? null : new ArrayList<>(viewData.attachments);
|
attachments = viewData.attachments == null ? null : new ArrayList<>(viewData.attachments);
|
||||||
|
@ -512,6 +520,11 @@ public abstract class StatusViewData {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setMuted(boolean muted) {
|
||||||
|
this.muted = muted;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder setSpoilerText(String spoilerText) {
|
public Builder setSpoilerText(String spoilerText) {
|
||||||
this.spoilerText = spoilerText;
|
this.spoilerText = spoilerText;
|
||||||
return this;
|
return this;
|
||||||
|
@ -675,7 +688,7 @@ public abstract class StatusViewData {
|
||||||
if (this.accountEmojis == null) accountEmojis = Collections.emptyList();
|
if (this.accountEmojis == null) accountEmojis = Collections.emptyList();
|
||||||
if (this.createdAt == null) createdAt = new Date();
|
if (this.createdAt == null) createdAt = new Date();
|
||||||
|
|
||||||
return new StatusViewData.Concrete(id, content, reblogged, favourited, bookmarked, spoilerText,
|
return new StatusViewData.Concrete(id, content, reblogged, favourited, bookmarked, muted, spoilerText,
|
||||||
visibility, attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded,
|
visibility, attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded,
|
||||||
isShowingContent, userFullName, nickname, avatar, createdAt, reblogsCount,
|
isShowingContent, userFullName, nickname, avatar, createdAt, reblogsCount,
|
||||||
favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application,
|
favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application,
|
||||||
|
|
|
@ -255,10 +255,10 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/colorSurface"
|
android:background="?attr/colorSurface"
|
||||||
android:elevation="12dp"
|
android:elevation="12dp"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="24dp"
|
||||||
android:paddingTop="8dp"
|
android:paddingTop="12dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="24dp"
|
||||||
android:paddingBottom="52dp"
|
android:paddingBottom="60dp"
|
||||||
app:behavior_hideable="true"
|
app:behavior_hideable="true"
|
||||||
app:behavior_peekHeight="0dp"
|
app:behavior_peekHeight="0dp"
|
||||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
<androidx.emoji.widget.EmojiTextView
|
||||||
|
android:id="@+id/notificationTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:drawableStart="@drawable/ic_person_add_24dp"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:paddingStart="28dp"
|
||||||
|
android:textColor="?android:textColorTertiary"
|
||||||
|
android:textSize="?attr/status_text_medium"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Someone requested to follow you" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:contentDescription="@string/action_view_profile"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/notificationTextView" />
|
||||||
|
|
||||||
|
<androidx.emoji.widget.EmojiTextView
|
||||||
|
android:id="@+id/displayNameTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="14dp"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:textSize="?attr/status_text_large"
|
||||||
|
android:textStyle="normal|bold"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||||
|
tools:text="Display name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/usernameTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="14dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="?attr/status_text_medium"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/displayNameTextView"
|
||||||
|
tools:text="\@username" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/acceptButton"
|
||||||
|
style="@style/TuskyImageButton"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/action_accept"
|
||||||
|
android:padding="4dp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/rejectButton"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||||
|
app:srcCompat="@drawable/ic_check_24dp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/rejectButton"
|
||||||
|
style="@style/TuskyImageButton"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/action_reject"
|
||||||
|
android:padding="4dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||||
|
app:srcCompat="@drawable/ic_reject_24dp" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -158,6 +158,73 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/status_content_warning_button"
|
app:layout_constraintTop_toBottomOf="@id/status_content_warning_button"
|
||||||
tools:text="This is a status" />
|
tools:text="This is a status" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/status_card_view"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/card_frame"
|
||||||
|
android:clipChildren="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:minHeight="80dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/status_display_name"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/status_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/card_image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="300dp"
|
||||||
|
android:layout_margin="1dp"
|
||||||
|
android:background="?attr/colorBackgroundAccent"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="center" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/card_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="6dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingRight="6dp"
|
||||||
|
android:paddingBottom="6dp">
|
||||||
|
|
||||||
|
<androidx.emoji.widget.EmojiTextView
|
||||||
|
android:id="@+id/card_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:lines="1"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="?attr/status_text_medium" />
|
||||||
|
|
||||||
|
<androidx.emoji.widget.EmojiTextView
|
||||||
|
android:id="@+id/card_description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lineSpacingMultiplier="1.1"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="?attr/status_text_medium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/card_link"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lines="1"
|
||||||
|
android:textColor="?android:textColorTertiary"
|
||||||
|
android:textSize="?attr/status_text_medium" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/button_toggle_content"
|
android:id="@+id/button_toggle_content"
|
||||||
style="@style/TuskyButton.Outlined"
|
style="@style/TuskyButton.Outlined"
|
||||||
|
@ -176,7 +243,7 @@
|
||||||
android:textSize="?attr/status_text_medium"
|
android:textSize="?attr/status_text_medium"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintStart_toStartOf="@id/status_display_name"
|
app:layout_constraintStart_toStartOf="@id/status_display_name"
|
||||||
app:layout_constraintTop_toBottomOf="@id/status_content"
|
app:layout_constraintTop_toBottomOf="@id/status_card_view"
|
||||||
tools:text="@string/status_content_show_less"
|
tools:text="@string/status_content_show_less"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/status_content" />
|
app:layout_constraintTop_toBottomOf="@id/status_content" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/card_view"
|
android:id="@+id/status_card_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
@ -216,7 +216,7 @@
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:background="@drawable/media_preview_outline"
|
android:background="@drawable/media_preview_outline"
|
||||||
android:importantForAccessibility="noHideDescendants"
|
android:importantForAccessibility="noHideDescendants"
|
||||||
app:layout_constraintTop_toBottomOf="@id/card_view">
|
app:layout_constraintTop_toBottomOf="@id/status_card_view">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.MediaPreviewImageView
|
<com.keylesspalace.tusky.view.MediaPreviewImageView
|
||||||
android:id="@+id/status_media_preview_0"
|
android:id="@+id/status_media_preview_0"
|
||||||
|
|
|
@ -1,55 +1,50 @@
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:parentTag="android.widget.LinearLayout">
|
tools:layout_height="wrap_content"
|
||||||
|
tools:layout_width="match_parent"
|
||||||
|
tools:parentTag="RadioGroup">
|
||||||
|
|
||||||
<RadioGroup
|
<RadioButton
|
||||||
android:id="@+id/visibilityRadioGroup"
|
android:id="@+id/publicRadioButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:button="@drawable/ic_public_24dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:text="@string/visibility_public"
|
||||||
|
android:textColor="?android:textColorTertiary"
|
||||||
|
app:buttonTint="@color/compound_button_color" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/unlistedRadioButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="@dimen/compose_options_margin"
|
|
||||||
android:layout_marginLeft="@dimen/compose_options_margin"
|
|
||||||
android:layout_marginRight="@dimen/compose_options_margin"
|
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:orientation="vertical">
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:button="@drawable/ic_lock_open_24dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:text="@string/visibility_unlisted"
|
||||||
|
android:textColor="?android:textColorTertiary"
|
||||||
|
app:buttonTint="@color/compound_button_color" />
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/publicRadioButton"
|
android:id="@+id/privateRadioButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_weight="1"
|
android:layout_marginBottom="4dp"
|
||||||
android:paddingEnd="0dp"
|
android:layout_weight="1"
|
||||||
android:paddingStart="10dp"
|
android:button="@drawable/ic_lock_outline_24dp"
|
||||||
android:text="@string/visibility_public"
|
android:paddingStart="10dp"
|
||||||
android:textColor="?android:textColorTertiary"
|
android:paddingEnd="0dp"
|
||||||
app:buttonTint="@color/compound_button_color" />
|
android:text="@string/visibility_private"
|
||||||
|
android:textColor="?android:textColorTertiary"
|
||||||
<RadioButton
|
app:buttonTint="@color/compound_button_color" />
|
||||||
android:id="@+id/unlistedRadioButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:paddingEnd="0dp"
|
|
||||||
android:paddingStart="10dp"
|
|
||||||
android:text="@string/visibility_unlisted"
|
|
||||||
android:textColor="?android:textColorTertiary"
|
|
||||||
app:buttonTint="@color/compound_button_color" />
|
|
||||||
|
|
||||||
<RadioButton
|
|
||||||
android:id="@+id/privateRadioButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:paddingEnd="0dp"
|
|
||||||
android:paddingStart="10dp"
|
|
||||||
android:text="@string/visibility_private"
|
|
||||||
android:textColor="?android:textColorTertiary"
|
|
||||||
app:buttonTint="@color/compound_button_color" />
|
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/unleakableRadioButton"
|
android:id="@+id/unleakableRadioButton"
|
||||||
|
@ -58,8 +53,9 @@
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:paddingEnd="0dp"
|
android:button="@drawable/ic_reblog_unleakable_24dp"
|
||||||
android:paddingStart="10dp"
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
android:text="@string/visibility_unleakable"
|
android:text="@string/visibility_unleakable"
|
||||||
android:textColor="?android:textColorTertiary"
|
android:textColor="?android:textColorTertiary"
|
||||||
app:buttonTint="@color/compound_button_color"
|
app:buttonTint="@color/compound_button_color"
|
||||||
|
@ -71,12 +67,11 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:paddingEnd="0dp"
|
android:button="@drawable/ic_email_24dp"
|
||||||
android:paddingStart="10dp"
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
android:text="@string/visibility_direct"
|
android:text="@string/visibility_direct"
|
||||||
android:textColor="?android:textColorTertiary"
|
android:textColor="?android:textColorTertiary"
|
||||||
app:buttonTint="@color/compound_button_color" />
|
app:buttonTint="@color/compound_button_color" />
|
||||||
|
|
||||||
</RadioGroup>
|
|
||||||
|
|
||||||
</merge>
|
</merge>
|
|
@ -21,6 +21,9 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/status_download_media"
|
android:id="@+id/status_download_media"
|
||||||
android:title="@string/download_media" />
|
android:title="@string/download_media" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/status_mute_conversation"
|
||||||
|
android:title="@string/action_mute_conversation" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/status_mute"
|
android:id="@+id/status_mute"
|
||||||
android:title="@string/action_mute" />
|
android:title="@string/action_mute" />
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
android:id="@+id/status_unreblog_private"
|
android:id="@+id/status_unreblog_private"
|
||||||
android:title="@string/unreblog_private"
|
android:title="@string/unreblog_private"
|
||||||
android:visible="false" />
|
android:visible="false" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/status_mute_conversation"
|
||||||
|
android:title="@string/action_mute_conversation" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/status_delete"
|
android:id="@+id/status_delete"
|
||||||
android:title="@string/action_delete" />
|
android:title="@string/action_delete" />
|
||||||
|
|
|
@ -2,82 +2,82 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_generic">وقع هناك خطأ.</string>
|
<string name="error_generic">وقع هناك خطأ.</string>
|
||||||
<string name="error_network">حدث خطأ في الشبكة! يرجى التحقق من اتصالك ثم أعد المحاولة!</string>
|
<string name="error_network">حدث خطأ في الشبكة! يرجى التحقق من اتصالك ثم أعد المحاولة!</string>
|
||||||
<string name="error_empty">لا يجب أن يترك فارغا.</string>
|
<string name="error_empty">لا يجب أن يترك هذا الحقل فارغا.</string>
|
||||||
<string name="error_invalid_domain">اسم النطاق غير صالح</string>
|
<string name="error_invalid_domain">اسم النطاق الذي قمتَ بإدخاله غير صالح</string>
|
||||||
<string name="error_failed_app_registration">اخفقت المصادقة مع مثيل الخادم هذا.</string>
|
<string name="error_failed_app_registration">اخفقت المصادقة مع مثيل الخادم هذا.</string>
|
||||||
<string name="error_no_web_browser_found">تعذر العثور على متصفح ويب قابل للإستعمال.</string>
|
<string name="error_no_web_browser_found">تعذر العثور على متصفح ويب صالح للإستعمال.</string>
|
||||||
<string name="error_authorization_unknown">لقد وقع هناك خطأ مجهول في التصريح.</string>
|
<string name="error_authorization_unknown">لقد وقع هناك خطأ مجهول في التصريح.</string>
|
||||||
<string name="error_authorization_denied">تم رفض التصريح.</string>
|
<string name="error_authorization_denied">تم رفض التصريح.</string>
|
||||||
<string name="error_retrieving_oauth_token">فشل الحصول على رمز الدخول.</string>
|
<string name="error_retrieving_oauth_token">فشل الحصول على رمز الولوج.</string>
|
||||||
<string name="error_compose_character_limit">المنشور طويل جدا !</string>
|
<string name="error_compose_character_limit">إنّ المنشور طويل جدا!</string>
|
||||||
<string name="error_image_upload_size">يجب أن يكون حجم الملف أقل من 4 ميغابايت.</string>
|
<string name="error_image_upload_size">يجب أن يكون حجم الملف أقل من 8 ميغابايت.</string>
|
||||||
<string name="error_video_upload_size">يجب أن يكون حجم ملفات الفيديو أقل من 40 ميغا بايت.</string>
|
<string name="error_video_upload_size">يجب أن يكون حجم ملفات الفيديو أقل من 40 ميغا بايت.</string>
|
||||||
<string name="error_media_upload_type">لا يمكن رفع هذا النوع من الملفات.</string>
|
<string name="error_media_upload_type">لا يمكن تحميل هذا النوع من الملفات.</string>
|
||||||
<string name="error_media_upload_opening">تعذر فتح ذاك الملف.</string>
|
<string name="error_media_upload_opening">تعذر فتح ذاك الملف.</string>
|
||||||
<string name="error_media_upload_permission">التصريح لازم لقراءة الوسائط.</string>
|
<string name="error_media_upload_permission">التصريح لازم لقراءة الوسائط.</string>
|
||||||
<string name="error_media_download_permission">التصريح لازم للإحتفاظ بالوسائط.</string>
|
<string name="error_media_download_permission">التصريح لازم للإحتفاظ بالوسائط.</string>
|
||||||
<string name="error_media_upload_image_or_video">لا يمكنك إرفاق كلا من الصور و الفيديوهات في نفس المنشور.</string>
|
<string name="error_media_upload_image_or_video">لا يمكنك إرفاق كلا من الصور والفيديوهات في نفس المنشور في آن واحد.</string>
|
||||||
<string name="error_media_upload_sending">اخفقت عملية الرفع.</string>
|
<string name="error_media_upload_sending">اخفقت عملية الرفع.</string>
|
||||||
<string name="error_sender_account_gone">خطأ عند إرسال التبويق.</string>
|
<string name="error_sender_account_gone">خطأ عند إرسال التبويق.</string>
|
||||||
<string name="title_home">الرئيسية</string>
|
<string name="title_home">الرئيسي</string>
|
||||||
<string name="title_notifications">الاشعارات</string>
|
<string name="title_notifications">الاشعارات</string>
|
||||||
<string name="title_public_local">المحلية</string>
|
<string name="title_public_local">المحلي</string>
|
||||||
<string name="title_public_federated">الفدرالية</string>
|
<string name="title_public_federated">الفدرالي</string>
|
||||||
<string name="title_direct_messages">الرسائل المباشرة</string>
|
<string name="title_direct_messages">الرسائل المباشرة</string>
|
||||||
<string name="title_tab_preferences">الألسنة</string>
|
<string name="title_tab_preferences">الألسنة</string>
|
||||||
<string name="title_view_thread">تبويق</string>
|
<string name="title_view_thread">تبويق</string>
|
||||||
<string name="title_statuses">المشاركات</string>
|
<string name="title_statuses">المنشورات</string>
|
||||||
<string name="title_statuses_with_replies">يحتوي على ردود</string>
|
<string name="title_statuses_with_replies">التبويقات والردود</string>
|
||||||
<string name="title_statuses_pinned">مدبّس</string>
|
<string name="title_statuses_pinned">المدبّسة</string>
|
||||||
<string name="title_follows">المتابَعون</string>
|
<string name="title_follows">المتابَعون</string>
|
||||||
<string name="title_followers">المتابِعون</string>
|
<string name="title_followers">المتابِعون</string>
|
||||||
<string name="title_favourites">المفضلة</string>
|
<string name="title_favourites">المفضلة</string>
|
||||||
<string name="title_mutes">الحسابات المكتومة</string>
|
<string name="title_mutes">الحسابات المكتومة</string>
|
||||||
<string name="title_blocks">الحسابات المحظورة</string>
|
<string name="title_blocks">الحسابات المحظورة</string>
|
||||||
<string name="title_follow_requests">طلبات المتابعة</string>
|
<string name="title_follow_requests">طلبات المتابعة</string>
|
||||||
<string name="title_edit_profile">عدل ملفك الشخصي</string>
|
<string name="title_edit_profile">عدل ملفك التعريفي</string>
|
||||||
<string name="title_saved_toot">المسودات</string>
|
<string name="title_saved_toot">المسودات</string>
|
||||||
<string name="title_licenses">الرّخص</string>
|
<string name="title_licenses">الرّخص</string>
|
||||||
<string name="status_username_format">\@%s</string>
|
<string name="status_username_format">\@%s</string>
|
||||||
<string name="status_boosted_format">%s رقّي</string>
|
<string name="status_boosted_format">شارَكَه %s</string>
|
||||||
<string name="status_sensitive_media_title">محتوى حساس</string>
|
<string name="status_sensitive_media_title">محتوى حساس</string>
|
||||||
<string name="status_media_hidden_title">وسائط مخفية</string>
|
<string name="status_media_hidden_title">وسائط مخفية</string>
|
||||||
<string name="status_sensitive_media_directions">اضغط للعرض</string>
|
<string name="status_sensitive_media_directions">اضغط للعرض</string>
|
||||||
<string name="status_content_warning_show_more">اعرض أكثر</string>
|
<string name="status_content_warning_show_more">اعرض المزيد</string>
|
||||||
<string name="status_content_warning_show_less">اعرض أقل</string>
|
<string name="status_content_warning_show_less">اعرض أقل</string>
|
||||||
<string name="status_content_show_more">توسيع</string>
|
<string name="status_content_show_more">توسيع</string>
|
||||||
<string name="status_content_show_less">تصغير</string>
|
<string name="status_content_show_less">تصغير</string>
|
||||||
<string name="message_empty">لا شيء هنا.</string>
|
<string name="message_empty">لا شيء هنا.</string>
|
||||||
<string name="footer_empty">لا يوجد شيئ هنا. إسحب إلى أسفل للتحديث !</string>
|
<string name="footer_empty">لا يوجد شيء هنا. إسحب إلى أسفل للإنعاش!</string>
|
||||||
<string name="notification_reblog_format">رقّى %s تبويقك</string>
|
<string name="notification_reblog_format">شارَك %s تبويقك</string>
|
||||||
<string name="notification_favourite_format">أعجِب %s بتبويقك</string>
|
<string name="notification_favourite_format">أعجِب %s بتبويقك</string>
|
||||||
<string name="notification_follow_format">%s يتبعك</string>
|
<string name="notification_follow_format">%s يتبعك</string>
|
||||||
<string name="report_username_format">أبلغ عن @%s</string>
|
<string name="report_username_format">أبلغ عن @%s</string>
|
||||||
<string name="report_comment_hint">تعليقات إضافية ؟</string>
|
<string name="report_comment_hint">تعليقات إضافية؟</string>
|
||||||
<string name="action_quick_reply">إجابة سريعة</string>
|
<string name="action_quick_reply">رد سريع</string>
|
||||||
<string name="action_reply">أجب</string>
|
<string name="action_reply">رد</string>
|
||||||
<string name="action_reblog">رقّي</string>
|
<string name="action_reblog">رقّي</string>
|
||||||
<string name="action_unreblog">إزالة الترقية</string>
|
<string name="action_unreblog">إزالة الترقية</string>
|
||||||
<string name="action_favourite">تفضيل</string>
|
<string name="action_favourite">تفضيل</string>
|
||||||
<string name="action_unfavourite">إزالة المفضلة</string>
|
<string name="action_unfavourite">إزالة المفضلة</string>
|
||||||
<string name="action_more">المزيد</string>
|
<string name="action_more">المزيد</string>
|
||||||
<string name="action_compose">حرر</string>
|
<string name="action_compose">حرر</string>
|
||||||
<string name="action_login">التسجيل بواسطة ماستدون</string>
|
<string name="action_login">الولوج إلى ماستدون</string>
|
||||||
<string name="action_logout">خروج</string>
|
<string name="action_logout">خروج</string>
|
||||||
<string name="action_logout_confirm">متأكد مِن أنك تود الخروج من الحساب %1$s ؟</string>
|
<string name="action_logout_confirm">متأكد مِن أنك تود الخروج من الحساب %1$s؟</string>
|
||||||
<string name="action_follow">إتبع</string>
|
<string name="action_follow">إتبع</string>
|
||||||
<string name="action_unfollow">إلغاء التتبع</string>
|
<string name="action_unfollow">إلغاء المتابعة</string>
|
||||||
<string name="action_block">قم بحظره</string>
|
<string name="action_block">قم بحظره</string>
|
||||||
<string name="action_unblock">إلغاء الحظر</string>
|
<string name="action_unblock">إلغاء الحظر</string>
|
||||||
<string name="action_hide_reblogs">إخفاء الترقيات</string>
|
<string name="action_hide_reblogs">إخفاء الترقيات</string>
|
||||||
<string name="action_show_reblogs">إظهار الترقيات</string>
|
<string name="action_show_reblogs">إظهار الترقيات</string>
|
||||||
<string name="action_report">أبلغ</string>
|
<string name="action_report">أبلغ عنه</string>
|
||||||
<string name="action_delete">إحذف</string>
|
<string name="action_delete">إحذف</string>
|
||||||
<string name="action_send">بَوّق</string>
|
<string name="action_send">بَوّق</string>
|
||||||
<string name="action_send_public">بوّق!</string>
|
<string name="action_send_public">بوّق!</string>
|
||||||
<string name="action_retry">إعادة المحاولة</string>
|
<string name="action_retry">أعد المحاولة</string>
|
||||||
<string name="action_close">إغلاق</string>
|
<string name="action_close">إغلاق</string>
|
||||||
<string name="action_view_profile">الملف الشخصي</string>
|
<string name="action_view_profile">الملف التعريفي</string>
|
||||||
<string name="action_view_preferences">التفضيلات</string>
|
<string name="action_view_preferences">التفضيلات</string>
|
||||||
<string name="action_view_account_preferences">تفضيلات الحساب</string>
|
<string name="action_view_account_preferences">تفضيلات الحساب</string>
|
||||||
<string name="action_view_favourites">المفضلة</string>
|
<string name="action_view_favourites">المفضلة</string>
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
<string name="action_hide_media">إخفاء الوسائط</string>
|
<string name="action_hide_media">إخفاء الوسائط</string>
|
||||||
<string name="action_open_drawer">إفتح الدرج</string>
|
<string name="action_open_drawer">إفتح الدرج</string>
|
||||||
<string name="action_save">إحفظ</string>
|
<string name="action_save">إحفظ</string>
|
||||||
<string name="action_edit_profile">تعديل الملف الشخصي</string>
|
<string name="action_edit_profile">تعديل الملف التعريفي</string>
|
||||||
<string name="action_edit_own_profile">تعديل</string>
|
<string name="action_edit_own_profile">تعديل</string>
|
||||||
<string name="action_undo">إلغاء</string>
|
<string name="action_undo">إلغاء</string>
|
||||||
<string name="action_accept">موافقة</string>
|
<string name="action_accept">موافقة</string>
|
||||||
|
@ -109,8 +109,8 @@
|
||||||
<string name="action_links">الروابط</string>
|
<string name="action_links">الروابط</string>
|
||||||
<string name="action_mentions">الإشارات</string>
|
<string name="action_mentions">الإشارات</string>
|
||||||
<string name="action_hashtags">الوسوم</string>
|
<string name="action_hashtags">الوسوم</string>
|
||||||
<string name="action_open_reblogged_by">عرض الترقيات</string>
|
<string name="action_open_reblogged_by">اعرض الترقيات</string>
|
||||||
<string name="action_open_faved_by">عرض المفضلات</string>
|
<string name="action_open_faved_by">اعرض المفضلات</string>
|
||||||
<string name="title_hashtags_dialog">الوسوم</string>
|
<string name="title_hashtags_dialog">الوسوم</string>
|
||||||
<string name="title_mentions_dialog">الإشارات</string>
|
<string name="title_mentions_dialog">الإشارات</string>
|
||||||
<string name="title_links_dialog">الروابط</string>
|
<string name="title_links_dialog">الروابط</string>
|
||||||
|
@ -120,23 +120,23 @@
|
||||||
<string name="action_share_as">شاركه كـ…</string>
|
<string name="action_share_as">شاركه كـ…</string>
|
||||||
<string name="send_status_link_to">شارك رابط التبويق مع…</string>
|
<string name="send_status_link_to">شارك رابط التبويق مع…</string>
|
||||||
<string name="send_status_content_to">شارك التبويق على…</string>
|
<string name="send_status_content_to">شارك التبويق على…</string>
|
||||||
<string name="send_media_to">شارك رابط التبويق مع…</string>
|
<string name="send_media_to">شارك الوسيط مع…</string>
|
||||||
<string name="confirmation_reported">تم الإرسال !</string>
|
<string name="confirmation_reported">تم إرساله!</string>
|
||||||
<string name="confirmation_unblocked">تم فك الحجب عن الحساب</string>
|
<string name="confirmation_unblocked">تم فك الحجب عن الحساب</string>
|
||||||
<string name="confirmation_unmuted">تم فك الكتم عن الحساب</string>
|
<string name="confirmation_unmuted">لم يعد الحساب مكتومًا</string>
|
||||||
<string name="status_sent">تم إرساله !</string>
|
<string name="status_sent">تم إرساله!</string>
|
||||||
<string name="status_sent_long">تم إرسال الرد بنجاح.</string>
|
<string name="status_sent_long">تم إرسال الرد بنجاح.</string>
|
||||||
<string name="hint_domain">أي سيرفر ؟</string>
|
<string name="hint_domain">أي مثيل خادم؟</string>
|
||||||
<string name="hint_compose">ما الجديد ؟</string>
|
<string name="hint_compose">ما الجديد؟</string>
|
||||||
<string name="hint_content_warning">تحذير عن المحتوى</string>
|
<string name="hint_content_warning">تحذير عن المحتوى</string>
|
||||||
<string name="hint_display_name">الإسم العلني</string>
|
<string name="hint_display_name">الإسم العلني</string>
|
||||||
<string name="hint_note">السيرة</string>
|
<string name="hint_note">السيرة</string>
|
||||||
<string name="hint_search">البحث عن…</string>
|
<string name="hint_search">البحث عن…</string>
|
||||||
<string name="search_no_results">لم يتم العثور على نتائج</string>
|
<string name="search_no_results">لم يتم العثور على أية نتائج</string>
|
||||||
<string name="label_quick_reply">إجابة …</string>
|
<string name="label_quick_reply">رد…</string>
|
||||||
<string name="label_avatar">الصورة الرمزية</string>
|
<string name="label_avatar">صورة الملف التعريفي</string>
|
||||||
<string name="label_header">رأس الصفحة</string>
|
<string name="label_header">صورة رأس الصفحة</string>
|
||||||
<string name="link_whats_an_instance">ماذا نعني بمثيل الخادم ؟</string>
|
<string name="link_whats_an_instance">ماذا نعني بمثيل الخادم؟</string>
|
||||||
<string name="login_connection">الإتصال جارٍ…</string>
|
<string name="login_connection">الإتصال جارٍ…</string>
|
||||||
<string name="dialog_whats_an_instance">بإمكانك إدخال عنوان أي مثيل خادوم ماستدون هنا. على سبيل المثال mastodon.social أو icosahedron.website أو social.tchncs.de أوالإطلاع على <a href="https://instances.social">لاكتشاف المزيد !</a>
|
<string name="dialog_whats_an_instance">بإمكانك إدخال عنوان أي مثيل خادوم ماستدون هنا. على سبيل المثال mastodon.social أو icosahedron.website أو social.tchncs.de أوالإطلاع على <a href="https://instances.social">لاكتشاف المزيد !</a>
|
||||||
\n
|
\n
|
||||||
|
@ -148,13 +148,13 @@
|
||||||
<string name="dialog_title_finishing_media_upload">تتمة رفع الوسائط</string>
|
<string name="dialog_title_finishing_media_upload">تتمة رفع الوسائط</string>
|
||||||
<string name="dialog_message_uploading_media">الإرسال جارٍ…</string>
|
<string name="dialog_message_uploading_media">الإرسال جارٍ…</string>
|
||||||
<string name="dialog_download_image">تنزيل</string>
|
<string name="dialog_download_image">تنزيل</string>
|
||||||
<string name="dialog_message_cancel_follow_request">هل تريد رفض طلب المتابعة ؟</string>
|
<string name="dialog_message_cancel_follow_request">هل تريد رفض طلب المتابعة؟</string>
|
||||||
<string name="dialog_unfollow_warning">هل تود إلغاء متابعة هذا الحساب ؟</string>
|
<string name="dialog_unfollow_warning">هل تود إلغاء متابعة هذا الحساب؟</string>
|
||||||
<string name="dialog_delete_toot_warning">هل تريد حذف هذا التبويق؟</string>
|
<string name="dialog_delete_toot_warning">هل تريد حذف هذا التبويق؟</string>
|
||||||
<string name="visibility_public">عمومي : ينشر على الخيوط العمومية</string>
|
<string name="visibility_public">للعامة: ينشر على الخيوط العمومية</string>
|
||||||
<string name="visibility_unlisted">غير مدرج : لا يُعرَض على الخيوط العمومية</string>
|
<string name="visibility_unlisted">غير مدرج: لا يُعرَض على الخيوط العمومية</string>
|
||||||
<string name="visibility_private">لمتابعيك فقط : يُنشر إلى متابعيك فقط</string>
|
<string name="visibility_private">لمتابعيك فقط: يُنشر إلى متابعيك فقط</string>
|
||||||
<string name="visibility_direct">مباشر : يُنشر إلى المستخدمين المشار إليهم فقط</string>
|
<string name="visibility_direct">مباشر: يُنشر إلى المستخدمين المشار إليهم فقط</string>
|
||||||
<string name="pref_title_edit_notification_settings">تعديل الاشعارات</string>
|
<string name="pref_title_edit_notification_settings">تعديل الاشعارات</string>
|
||||||
<string name="pref_title_notifications_enabled">الإخطارات</string>
|
<string name="pref_title_notifications_enabled">الإخطارات</string>
|
||||||
<string name="pref_title_notification_alerts">التنبيهات</string>
|
<string name="pref_title_notification_alerts">التنبيهات</string>
|
||||||
|
@ -163,12 +163,12 @@
|
||||||
<string name="pref_title_notification_alert_light">إعلام بالضوء</string>
|
<string name="pref_title_notification_alert_light">إعلام بالضوء</string>
|
||||||
<string name="pref_title_notification_filters">أخطرني عندما</string>
|
<string name="pref_title_notification_filters">أخطرني عندما</string>
|
||||||
<string name="pref_title_notification_filter_mentions">يشار إلي</string>
|
<string name="pref_title_notification_filter_mentions">يشار إلي</string>
|
||||||
<string name="pref_title_notification_filter_follows">يتبعني أحد</string>
|
<string name="pref_title_notification_filter_follows">يتبعني أحدهم</string>
|
||||||
<string name="pref_title_notification_filter_reblogs">تُرقّى منشوراتي</string>
|
<string name="pref_title_notification_filter_reblogs">تُرقّى منشوراتي</string>
|
||||||
<string name="pref_title_notification_filter_favourites">أعجب أحد ما بمنشوراتي</string>
|
<string name="pref_title_notification_filter_favourites">يُعجَب أحد ما بمنشوراتي</string>
|
||||||
<string name="pref_title_appearance_settings">المظهر</string>
|
<string name="pref_title_appearance_settings">المظهر</string>
|
||||||
<string name="pref_title_app_theme">سمة التطبيق</string>
|
<string name="pref_title_app_theme">حُلّة التطبيق</string>
|
||||||
<string name="pref_title_timelines">الخيوط</string>
|
<string name="pref_title_timelines">الخيوط الزمنية</string>
|
||||||
<string name="pref_title_timeline_filters">عوامل التصفية</string>
|
<string name="pref_title_timeline_filters">عوامل التصفية</string>
|
||||||
<string name="app_them_dark">داكنة</string>
|
<string name="app_them_dark">داكنة</string>
|
||||||
<string name="app_theme_light">فاتحة</string>
|
<string name="app_theme_light">فاتحة</string>
|
||||||
|
@ -339,7 +339,7 @@
|
||||||
<string name="action_open_reblogger">إظهار صاحب الترقية</string>
|
<string name="action_open_reblogger">إظهار صاحب الترقية</string>
|
||||||
<string name="action_open_media_n">افتح الوسيط #%d</string>
|
<string name="action_open_media_n">افتح الوسيط #%d</string>
|
||||||
|
|
||||||
<string name="download_media">تنزيل الوسائط</string>
|
<string name="download_media">نزّل الوسائط</string>
|
||||||
<string name="downloading_media">جارٍ تنزيل الوسائط</string>
|
<string name="downloading_media">جارٍ تنزيل الوسائط</string>
|
||||||
|
|
||||||
<string name="dialog_redraft_toot_warning">هل تريد حذف وإعادة صياغة هذا التبويق؟</string>
|
<string name="dialog_redraft_toot_warning">هل تريد حذف وإعادة صياغة هذا التبويق؟</string>
|
||||||
|
@ -378,7 +378,7 @@
|
||||||
<string name="poll_ended_created">لقد انتهى استطلاع رأي قمتَ بإنشائه</string>
|
<string name="poll_ended_created">لقد انتهى استطلاع رأي قمتَ بإنشائه</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="pref_title_notification_filter_poll">انتهت استطلاعات الرأي</string>
|
<string name="pref_title_notification_filter_poll">تنتهي استطلاعات الرأي</string>
|
||||||
<plurals name="favs">
|
<plurals name="favs">
|
||||||
<item quantity="zero"><b>%1$s</b>" مفضلة"</item>
|
<item quantity="zero"><b>%1$s</b>" مفضلة"</item>
|
||||||
<item quantity="one"><b>%1$s</b> مفضلة</item>
|
<item quantity="one"><b>%1$s</b> مفضلة</item>
|
||||||
|
@ -457,7 +457,7 @@
|
||||||
<string name="filter_dialog_whole_word">الكلمة كاملة</string>
|
<string name="filter_dialog_whole_word">الكلمة كاملة</string>
|
||||||
<string name="description_poll">استطلاع رأي بالخيارات: %1$s, %2$s, %3$s, %4$s; %5$s</string>
|
<string name="description_poll">استطلاع رأي بالخيارات: %1$s, %2$s, %3$s, %4$s; %5$s</string>
|
||||||
|
|
||||||
<string name="mute_domain_warning">هل أنت متأكد من أنك تريد حجب كافة %s ؟ سوف لن يكون باستطاعتك رؤية أي محتوى قادم من هذا النطاق بعد الآن ، لا في الخيوط الزمنية العامة ولا في إخطاراتك. سيتم إزالة متابِعيك الذين هم على هذا النطاق.</string>
|
<string name="mute_domain_warning">هل أنت متأكد من أنك تريد حجب كافة %s؟ سوف لن يكون باستطاعتك رؤية أي محتوى قادم من هذا النطاق بعد الآن ، لا في الخيوط الزمنية العامة ولا في إخطاراتك. سيتم إزالة متابِعيك الذين هم على هذا النطاق.</string>
|
||||||
<string name="report_description_1">سيتم إرسال التقرير إلى مشرفي خادمك. يمكنك تقديم تفسير عن سبب الإبلاغ عن الحساب أدناه:</string>
|
<string name="report_description_1">سيتم إرسال التقرير إلى مشرفي خادمك. يمكنك تقديم تفسير عن سبب الإبلاغ عن الحساب أدناه:</string>
|
||||||
<string name="report_description_remote_instance">هذا الحساب ينتسب إلى خادم آخر. هل تريد إرسال نسخة مجهولة من التقرير إلى هناك أيضا؟</string>
|
<string name="report_description_remote_instance">هذا الحساب ينتسب إلى خادم آخر. هل تريد إرسال نسخة مجهولة من التقرير إلى هناك أيضا؟</string>
|
||||||
|
|
||||||
|
@ -501,4 +501,6 @@
|
||||||
<string name="no_scheduled_status">ليس لديك أية منشورات مُبرمَجة للنشر.</string>
|
<string name="no_scheduled_status">ليس لديك أية منشورات مُبرمَجة للنشر.</string>
|
||||||
|
|
||||||
<string name="error_audio_upload_size">يجب أن يكون حجم الملفات الصوتية أقل مِن 40 ميغابايت.</string>
|
<string name="error_audio_upload_size">يجب أن يكون حجم الملفات الصوتية أقل مِن 40 ميغابايت.</string>
|
||||||
</resources>
|
<string name="warning_scheduling_interval">تُقدّر أدنى فترة لبرمجة النشر في ماستدون بـ 5 دقائق.</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|
|
@ -534,4 +534,7 @@
|
||||||
|
|
||||||
<string name="no_scheduled_status">No tens cap estat planificat.</string>
|
<string name="no_scheduled_status">No tens cap estat planificat.</string>
|
||||||
|
|
||||||
</resources>
|
<string name="error_audio_upload_size">Els fitxers d\'àudio han de ser més petits de 40MB.</string>
|
||||||
|
<string name="no_saved_status">No tens cap esborrany.</string>
|
||||||
|
<string name="warning_scheduling_interval">L\'interval mínim de planificació a Mastodon és de 5 minuts.</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources></resources>
|
|
@ -469,4 +469,9 @@
|
||||||
<string name="list">Listo</string>
|
<string name="list">Listo</string>
|
||||||
<string name="post_lookup_error_format">Eraro dum elserĉo de la mesaĝo %s</string>
|
<string name="post_lookup_error_format">Eraro dum elserĉo de la mesaĝo %s</string>
|
||||||
|
|
||||||
</resources>
|
<string name="error_audio_upload_size">Aŭdia dosiero devas esti malpli ol 40MB.</string>
|
||||||
|
<string name="gradient_for_media">Montri buntajn transirojn por kaŝitaj aŭdovidaĵoj</string>
|
||||||
|
|
||||||
|
<string name="no_saved_status">Vi ne havas iun ajn malneton.</string>
|
||||||
|
<string name="no_scheduled_status">Vi ne havas iun ajn planitan mesaĝon.</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<string name="error_network">¡Se ha producido un error de red! ¡Por favor, comprueba tu conexión e inténtalo de nuevo!</string>
|
<string name="error_network">¡Se ha producido un error de red! ¡Por favor, comprueba tu conexión e inténtalo de nuevo!</string>
|
||||||
<string name="error_empty">Este campo no puede estar vacío.</string>
|
<string name="error_empty">Este campo no puede estar vacío.</string>
|
||||||
<string name="error_invalid_domain">Nombre de dominio incorrecto</string>
|
<string name="error_invalid_domain">Nombre de dominio incorrecto</string>
|
||||||
<string name="error_failed_app_registration">Inicio de sesión fallido.</string>
|
<string name="error_failed_app_registration">Fallo de autenticación con esta instancia.</string>
|
||||||
<string name="error_no_web_browser_found">No se ha encontrado ningún navegador web.</string>
|
<string name="error_no_web_browser_found">No se ha encontrado ningún navegador web.</string>
|
||||||
<string name="error_authorization_unknown">Ocurrió un error de autorización no identificado.</string>
|
<string name="error_authorization_unknown">Ocurrió un error de autorización no identificado.</string>
|
||||||
<string name="error_authorization_denied">La autorización falló.</string>
|
<string name="error_authorization_denied">La autorización falló.</string>
|
||||||
|
@ -474,9 +474,10 @@
|
||||||
<string name="select_list_title">Seleccionar lista</string>
|
<string name="select_list_title">Seleccionar lista</string>
|
||||||
<string name="list">Lista</string>
|
<string name="list">Lista</string>
|
||||||
<string name="error_audio_upload_size">Los ficheros de audio deben ser menores de 40MB.</string>
|
<string name="error_audio_upload_size">Los ficheros de audio deben ser menores de 40MB.</string>
|
||||||
<string name="gradient_for_media">Mostrar degradados coloridos para el contenido multimedia oculto.</string>
|
<string name="gradient_for_media">Mostrar degradados coloridos para el contenido multimedia oculto</string>
|
||||||
|
|
||||||
<string name="no_saved_status">No tienes ningún borrador.</string>
|
<string name="no_saved_status">No tienes ningún borrador.</string>
|
||||||
<string name="no_scheduled_status">No tienes ningún estado programado.</string>
|
<string name="no_scheduled_status">No tienes ningún estado programado.</string>
|
||||||
|
|
||||||
</resources>
|
<string name="warning_scheduling_interval">Mastodon tiene un intervalo de programación mínimo de 5 minutos.</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<string name="title_saved_toot">Brouillons</string>
|
<string name="title_saved_toot">Brouillons</string>
|
||||||
<string name="title_licenses">Licences</string>
|
<string name="title_licenses">Licences</string>
|
||||||
<string name="status_username_format">\@%s</string>
|
<string name="status_username_format">\@%s</string>
|
||||||
<string name="status_boosted_format">%s a boosté</string>
|
<string name="status_boosted_format">%s a partagé</string>
|
||||||
<string name="status_sensitive_media_title">Contenu sensible</string>
|
<string name="status_sensitive_media_title">Contenu sensible</string>
|
||||||
<string name="status_media_hidden_title">Média caché</string>
|
<string name="status_media_hidden_title">Média caché</string>
|
||||||
<string name="status_sensitive_media_directions">Cliquer pour voir</string>
|
<string name="status_sensitive_media_directions">Cliquer pour voir</string>
|
||||||
|
@ -49,15 +49,15 @@
|
||||||
<string name="status_content_show_less">Replier</string>
|
<string name="status_content_show_less">Replier</string>
|
||||||
<string name="message_empty">Rien ici.</string>
|
<string name="message_empty">Rien ici.</string>
|
||||||
<string name="footer_empty">Il n’y a aucun pouet pour le moment.\nGlissez vers le bas pour actualiser !</string>
|
<string name="footer_empty">Il n’y a aucun pouet pour le moment.\nGlissez vers le bas pour actualiser !</string>
|
||||||
<string name="notification_reblog_format">%s a boosté votre pouet</string>
|
<string name="notification_reblog_format">%s a partagé votre pouet</string>
|
||||||
<string name="notification_favourite_format">%s a ajouté votre pouet à ses favoris</string>
|
<string name="notification_favourite_format">%s a ajouté votre pouet à ses favoris</string>
|
||||||
<string name="notification_follow_format">%s vous suit</string>
|
<string name="notification_follow_format">%s vous suit</string>
|
||||||
<string name="report_username_format">Signaler @%s</string>
|
<string name="report_username_format">Signaler @%s</string>
|
||||||
<string name="report_comment_hint">Commentaires additonnels ?</string>
|
<string name="report_comment_hint">Commentaires additonnels ?</string>
|
||||||
<string name="action_quick_reply">Réponse rapide</string>
|
<string name="action_quick_reply">Réponse rapide</string>
|
||||||
<string name="action_reply">Répondre</string>
|
<string name="action_reply">Répondre</string>
|
||||||
<string name="action_reblog">Booster</string>
|
<string name="action_reblog">Partager</string>
|
||||||
<string name="action_unreblog">Supprimer le boost</string>
|
<string name="action_unreblog">Annuler le partage</string>
|
||||||
<string name="action_favourite">Favori</string>
|
<string name="action_favourite">Favori</string>
|
||||||
<string name="action_unfavourite">Supprimer le favori</string>
|
<string name="action_unfavourite">Supprimer le favori</string>
|
||||||
<string name="action_more">Plus</string>
|
<string name="action_more">Plus</string>
|
||||||
|
@ -69,8 +69,8 @@
|
||||||
<string name="action_unfollow">Ne plus suivre</string>
|
<string name="action_unfollow">Ne plus suivre</string>
|
||||||
<string name="action_block">Bloquer</string>
|
<string name="action_block">Bloquer</string>
|
||||||
<string name="action_unblock">Débloquer</string>
|
<string name="action_unblock">Débloquer</string>
|
||||||
<string name="action_hide_reblogs">Cacher les boosts</string>
|
<string name="action_hide_reblogs">Cacher les partages</string>
|
||||||
<string name="action_show_reblogs">Montrer les boosts</string>
|
<string name="action_show_reblogs">Montrer les partages</string>
|
||||||
<string name="action_report">Signaler</string>
|
<string name="action_report">Signaler</string>
|
||||||
<string name="action_delete">Supprimer</string>
|
<string name="action_delete">Supprimer</string>
|
||||||
<string name="action_send">POUET</string>
|
<string name="action_send">POUET</string>
|
||||||
|
@ -109,8 +109,8 @@
|
||||||
<string name="action_links">Liens</string>
|
<string name="action_links">Liens</string>
|
||||||
<string name="action_mentions">Mentions</string>
|
<string name="action_mentions">Mentions</string>
|
||||||
<string name="action_hashtags">Hashtags</string>
|
<string name="action_hashtags">Hashtags</string>
|
||||||
<string name="action_open_reblogger">Afficher l’auteur·rice du boost</string>
|
<string name="action_open_reblogger">Afficher l’auteur·rice du partage</string>
|
||||||
<string name="action_open_reblogged_by">Afficher les boosts</string>
|
<string name="action_open_reblogged_by">Montrer les partages</string>
|
||||||
<string name="action_open_faved_by">Montrer les favoris</string>
|
<string name="action_open_faved_by">Montrer les favoris</string>
|
||||||
<string name="title_hashtags_dialog">Hashtags</string>
|
<string name="title_hashtags_dialog">Hashtags</string>
|
||||||
<string name="title_mentions_dialog">Mentions</string>
|
<string name="title_mentions_dialog">Mentions</string>
|
||||||
|
@ -170,7 +170,7 @@
|
||||||
<string name="pref_title_notification_filters">Me notifier lorsque</string>
|
<string name="pref_title_notification_filters">Me notifier lorsque</string>
|
||||||
<string name="pref_title_notification_filter_mentions">on me mentionne</string>
|
<string name="pref_title_notification_filter_mentions">on me mentionne</string>
|
||||||
<string name="pref_title_notification_filter_follows">on me suit</string>
|
<string name="pref_title_notification_filter_follows">on me suit</string>
|
||||||
<string name="pref_title_notification_filter_reblogs">mes messages sont boostés</string>
|
<string name="pref_title_notification_filter_reblogs">mes pouets sont partagés</string>
|
||||||
<string name="pref_title_notification_filter_favourites">mes messages sont mis en favoris</string>
|
<string name="pref_title_notification_filter_favourites">mes messages sont mis en favoris</string>
|
||||||
<string name="pref_title_appearance_settings">Apparence</string>
|
<string name="pref_title_appearance_settings">Apparence</string>
|
||||||
<string name="pref_title_app_theme">Thème de l’application</string>
|
<string name="pref_title_app_theme">Thème de l’application</string>
|
||||||
|
@ -187,7 +187,7 @@
|
||||||
<string name="pref_title_language">Langue</string>
|
<string name="pref_title_language">Langue</string>
|
||||||
<string name="pref_title_status_filter">Filtrage des fils</string>
|
<string name="pref_title_status_filter">Filtrage des fils</string>
|
||||||
<string name="pref_title_status_tabs">Onglets</string>
|
<string name="pref_title_status_tabs">Onglets</string>
|
||||||
<string name="pref_title_show_boosts">Afficher les boosts</string>
|
<string name="pref_title_show_boosts">Montrer les partages</string>
|
||||||
<string name="pref_title_show_replies">Afficher les réponses</string>
|
<string name="pref_title_show_replies">Afficher les réponses</string>
|
||||||
<string name="pref_title_show_media_preview">Montrer les miniatures des médias</string>
|
<string name="pref_title_show_media_preview">Montrer les miniatures des médias</string>
|
||||||
<string name="pref_title_proxy_settings">Proxy</string>
|
<string name="pref_title_proxy_settings">Proxy</string>
|
||||||
|
@ -213,7 +213,7 @@
|
||||||
<string name="notification_follow_name">Nouveaux abonnés</string>
|
<string name="notification_follow_name">Nouveaux abonnés</string>
|
||||||
<string name="notification_follow_description">Notifications pour les nouveaux abonnés</string>
|
<string name="notification_follow_description">Notifications pour les nouveaux abonnés</string>
|
||||||
<string name="notification_boost_name">Partages</string>
|
<string name="notification_boost_name">Partages</string>
|
||||||
<string name="notification_boost_description">Notifications quand vos pouets sont boostés</string>
|
<string name="notification_boost_description">Notifications quand vos pouets sont partagés</string>
|
||||||
<string name="notification_favourite_name">Favoris</string>
|
<string name="notification_favourite_name">Favoris</string>
|
||||||
<string name="notification_favourite_description">Notifications quand vos pouets sont mis en favoris</string>
|
<string name="notification_favourite_description">Notifications quand vos pouets sont mis en favoris</string>
|
||||||
<string name="notification_mention_format">%s vous a mentionné</string>
|
<string name="notification_mention_format">%s vous a mentionné</string>
|
||||||
|
@ -316,8 +316,8 @@
|
||||||
<string name="download_failed">Échec du téléchargement</string>
|
<string name="download_failed">Échec du téléchargement</string>
|
||||||
<string name="profile_badge_bot_text">Robot</string>
|
<string name="profile_badge_bot_text">Robot</string>
|
||||||
<string name="account_moved_description">%1$s a déménagé vers :</string>
|
<string name="account_moved_description">%1$s a déménagé vers :</string>
|
||||||
<string name="reblog_private">Booster vers l’audience originale</string>
|
<string name="reblog_private">Partager à l’audience originale</string>
|
||||||
<string name="unreblog_private">Ne plus booster</string>
|
<string name="unreblog_private">Annuler le partage</string>
|
||||||
<string name="license_description">Yuito contient du code et des ressources issus des projets open source suivants :</string>
|
<string name="license_description">Yuito contient du code et des ressources issus des projets open source suivants :</string>
|
||||||
<string name="license_apache_2">Sous licence Apache (copie ci-dessous)</string>
|
<string name="license_apache_2">Sous licence Apache (copie ci-dessous)</string>
|
||||||
<string name="license_cc_by_4">CC-BY 4.0</string>
|
<string name="license_cc_by_4">CC-BY 4.0</string>
|
||||||
|
@ -335,10 +335,10 @@
|
||||||
<item quantity="other"><b>%1$s</b> Favoris</item>
|
<item quantity="other"><b>%1$s</b> Favoris</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="reblogs">
|
<plurals name="reblogs">
|
||||||
<item quantity="one"><b>%s</b> Boost</item>
|
<item quantity="one"><b>%s</b> Partage</item>
|
||||||
<item quantity="other"><b>%s</b> Boosts</item>
|
<item quantity="other"><b>%s</b> Partages</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="title_reblogged_by">Boosté par</string>
|
<string name="title_reblogged_by">Partagé par</string>
|
||||||
<string name="title_favourited_by">Mis en favoris par</string>
|
<string name="title_favourited_by">Mis en favoris par</string>
|
||||||
<string name="conversation_1_recipients">%1$s</string>
|
<string name="conversation_1_recipients">%1$s</string>
|
||||||
<string name="conversation_2_recipients">%1$s et %2$s</string>
|
<string name="conversation_2_recipients">%1$s et %2$s</string>
|
||||||
|
@ -371,7 +371,7 @@
|
||||||
<string name="notifications_apply_filter">Filtrer</string>
|
<string name="notifications_apply_filter">Filtrer</string>
|
||||||
<string name="filter_apply">Appliquer</string>
|
<string name="filter_apply">Appliquer</string>
|
||||||
|
|
||||||
<string name="compose_shortcut_long_label">Écrire un pouet</string>
|
<string name="compose_shortcut_long_label">Rédiger un pouet</string>
|
||||||
<string name="compose_shortcut_short_label">Écrire</string>
|
<string name="compose_shortcut_short_label">Écrire</string>
|
||||||
<string name="pref_title_bot_overlay">Afficher l\'indicateur de robots</string>
|
<string name="pref_title_bot_overlay">Afficher l\'indicateur de robots</string>
|
||||||
|
|
||||||
|
@ -486,4 +486,6 @@
|
||||||
<string name="no_saved_status">Vous n’avez aucun brouillon.</string>
|
<string name="no_saved_status">Vous n’avez aucun brouillon.</string>
|
||||||
<string name="no_scheduled_status">Vous n’avez aucun pouet planifié.</string>
|
<string name="no_scheduled_status">Vous n’avez aucun pouet planifié.</string>
|
||||||
|
|
||||||
|
<string name="warning_scheduling_interval">L’intervalle minimum de planification sur Mastodon est de 5 minutes.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -508,4 +508,6 @@
|
||||||
<string name="no_scheduled_status">Þú ert ekki með neinar áætlaðar stöðufærslur.</string>
|
<string name="no_scheduled_status">Þú ert ekki með neinar áætlaðar stöðufærslur.</string>
|
||||||
|
|
||||||
<string name="error_audio_upload_size">Hljóðskrár verða að vera minni en 40MB.</string>
|
<string name="error_audio_upload_size">Hljóðskrár verða að vera minni en 40MB.</string>
|
||||||
</resources>
|
<string name="warning_scheduling_interval">Mastodon er með 5 mínútna lágmarksbil fyrir áætlaðar aðgerðir.</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|
|
@ -420,4 +420,10 @@
|
||||||
<string name="pref_title_show_notifications_filter">通知フィルターを表示</string>
|
<string name="pref_title_show_notifications_filter">通知フィルターを表示</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="action_reset_schedule">リセット</string>
|
||||||
|
<string name="error_audio_upload_size">音声ファイルは40MB未満にしてください。</string>
|
||||||
|
<string name="title_bookmarks">ブックマーク</string>
|
||||||
|
<string name="action_bookmark">ブックマーク</string>
|
||||||
|
<string name="action_edit">編集</string>
|
||||||
|
<string name="action_view_bookmarks">ブックマーク</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<resources><string name="action_login">Qqen γer Maṣṭudun</string>
|
<resources><string name="action_login">Qqen ɣer Maṣṭudun</string>
|
||||||
<string name="title_favourites">Ismenyifen</string>
|
<string name="title_favourites">Ismenyifen</string>
|
||||||
<string name="title_saved_toot">Irewwayen</string>
|
<string name="title_saved_toot">Irewwayen</string>
|
||||||
<string name="action_logout">Ffeγ</string>
|
<string name="action_logout">Ffeɣ</string>
|
||||||
<string name="action_view_preferences">Iγewwaṛen</string>
|
<string name="action_view_preferences">Iɣewwaṛen</string>
|
||||||
<string name="action_view_account_preferences">Iγewwaṛen n umiḍan</string>
|
<string name="action_view_account_preferences">Iɣewwaṛen n umiḍan</string>
|
||||||
<string name="action_edit_profile">Ẓreg amaγnu</string>
|
<string name="action_edit_profile">Ẓreg amaɣnu</string>
|
||||||
<string name="action_search">Nadi</string>
|
<string name="action_search">Nadi</string>
|
||||||
<string name="about_title_activity">Γef</string>
|
<string name="about_title_activity">Ɣef</string>
|
||||||
<string name="action_lists">Umuγen</string>
|
<string name="action_lists">Umuɣen</string>
|
||||||
<string name="title_lists">Umuγen</string>
|
<string name="title_lists">Umuɣen</string>
|
||||||
<string name="error_compose_character_limit">Tijewwiqt-ik aṭas i γuzzifet!</string>
|
<string name="error_compose_character_limit">Tijewwiqt-ik aṭas i ɣuzzifet!</string>
|
||||||
<string name="title_home">Agejdan</string>
|
<string name="title_home">Agejdan</string>
|
||||||
<string name="title_tab_preferences">Iccaren</string>
|
<string name="title_tab_preferences">Iccaren</string>
|
||||||
<string name="title_view_thread">Tijewwiqt</string>
|
<string name="title_view_thread">Tijewwiqt</string>
|
||||||
<string name="title_statuses">Iznan</string>
|
<string name="title_statuses">Iznan</string>
|
||||||
<string name="title_statuses_with_replies">S tririyin</string>
|
<string name="title_statuses_with_replies">S tririyin</string>
|
||||||
<string name="title_edit_profile">Ẓreg amaγnu-ik</string>
|
<string name="title_edit_profile">Ẓreg amaɣnu-ik</string>
|
||||||
<string name="status_username_format">\@%s</string>
|
<string name="status_username_format">\@%s</string>
|
||||||
<string name="status_content_warning_show_more">Zeṛ ugar</string>
|
<string name="status_content_warning_show_more">Zeṛ ugar</string>
|
||||||
<string name="status_content_warning_show_less">Zeṛ kra kan</string>
|
<string name="status_content_warning_show_less">Zeṛ kra kan</string>
|
||||||
|
@ -35,13 +35,13 @@
|
||||||
<string name="action_send_public">JEWWEQ!</string>
|
<string name="action_send_public">JEWWEQ!</string>
|
||||||
<string name="action_retry">Ɛreḍ tikkelt-nniḍen</string>
|
<string name="action_retry">Ɛreḍ tikkelt-nniḍen</string>
|
||||||
<string name="action_close">Derreɛ</string>
|
<string name="action_close">Derreɛ</string>
|
||||||
<string name="action_view_profile">Amaγnu</string>
|
<string name="action_view_profile">Amaɣnu</string>
|
||||||
<string name="action_view_favourites">Ismenyifen</string>
|
<string name="action_view_favourites">Ismenyifen</string>
|
||||||
<string name="action_open_in_web">Ldi deg uminig</string>
|
<string name="action_open_in_web">Ldi deg uminig</string>
|
||||||
<string name="action_share">Bḍu</string>
|
<string name="action_share">Bḍu</string>
|
||||||
<string name="action_mute">Sgugem</string>
|
<string name="action_mute">Sgugem</string>
|
||||||
<string name="action_access_saved_toot">Irewwayen</string>
|
<string name="action_access_saved_toot">Irewwayen</string>
|
||||||
<string name="action_open_faved_by">Sken-ed ismenyifen</string>
|
<string name="action_open_faved_by">Sken-d ismenyifen</string>
|
||||||
|
|
||||||
<string name="notification_favourite_name">Ismenyifen</string>
|
<string name="notification_favourite_name">Ismenyifen</string>
|
||||||
<plurals name="favs">
|
<plurals name="favs">
|
||||||
|
@ -51,11 +51,11 @@
|
||||||
|
|
||||||
<string name="no_saved_status">Ur tesɛiḍ ara irewwayen.</string>
|
<string name="no_saved_status">Ur tesɛiḍ ara irewwayen.</string>
|
||||||
<string name="error_generic">Tella-d tucḍa.</string>
|
<string name="error_generic">Tella-d tucḍa.</string>
|
||||||
<string name="title_notifications">Tilγa</string>
|
<string name="title_notifications">Tilɣa</string>
|
||||||
<string name="link_whats_an_instance">D acu i ttummant\?</string>
|
<string name="link_whats_an_instance">D acu i ttummant\?</string>
|
||||||
|
|
||||||
<string name="title_bookmarks">Ticraḍ</string>
|
<string name="title_bookmarks">Ticraḍ</string>
|
||||||
<string name="action_bookmark">Rnu γer ticraḍ</string>
|
<string name="action_bookmark">Rnu ɣer ticraḍ</string>
|
||||||
<string name="action_view_bookmarks">Ticraḍ</string>
|
<string name="action_view_bookmarks">Ticraḍ</string>
|
||||||
<string name="action_mute_domain">Sgugem %s</string>
|
<string name="action_mute_domain">Sgugem %s</string>
|
||||||
<string name="action_mention">Bder</string>
|
<string name="action_mention">Bder</string>
|
||||||
|
@ -64,20 +64,20 @@
|
||||||
<string name="action_undo">Sefsex</string>
|
<string name="action_undo">Sefsex</string>
|
||||||
<string name="action_emoji_keyboard">Anasiw n imujiyen</string>
|
<string name="action_emoji_keyboard">Anasiw n imujiyen</string>
|
||||||
<string name="action_add_tab">Rnu iccer</string>
|
<string name="action_add_tab">Rnu iccer</string>
|
||||||
<string name="action_copy_link">Nγel aseγwen</string>
|
<string name="action_copy_link">Nɣel aseɣwen</string>
|
||||||
<string name="action_open_as">Ldi amzun d %s</string>
|
<string name="action_open_as">Ldi amzun d %s</string>
|
||||||
<string name="action_share_as">Bḍu amzun d…</string>
|
<string name="action_share_as">Bḍu amzun d…</string>
|
||||||
<string name="send_status_link_to">Bḍu aseγwen n tijewwiq s…</string>
|
<string name="send_status_link_to">Bḍu aseɣwen n tijewwiq s…</string>
|
||||||
<string name="send_status_content_to">Bḍu tijewwiqt d…</string>
|
<string name="send_status_content_to">Bḍu tijewwiqt d…</string>
|
||||||
<string name="hint_domain">Anta tummant\?</string>
|
<string name="hint_domain">Anta tummant\?</string>
|
||||||
<string name="hint_compose">d-acu i gellan d amaynut\?</string>
|
<string name="hint_compose">d-acu i gellan d amaynut\?</string>
|
||||||
<string name="hint_search">Nadi…</string>
|
<string name="hint_search">Nadi…</string>
|
||||||
|
|
||||||
<string name="label_quick_reply">Tiririn…</string>
|
<string name="label_quick_reply">Tiririn…</string>
|
||||||
<string name="label_avatar">Tugna n umaγnu</string>
|
<string name="label_avatar">Tugna n umaɣnu</string>
|
||||||
<string name="dialog_download_image">Sider</string>
|
<string name="dialog_download_image">Sider</string>
|
||||||
<string name="dialog_delete_toot_warning">Kkes tijewwiqt-a\?</string>
|
<string name="dialog_delete_toot_warning">Kkes tijewwiqt-a\?</string>
|
||||||
<string name="pref_title_edit_notification_settings">Ẓreg tilγa</string>
|
<string name="pref_title_edit_notification_settings">Ẓreg tilɣa</string>
|
||||||
<string name="pref_title_appearance_settings">Agrudem</string>
|
<string name="pref_title_appearance_settings">Agrudem</string>
|
||||||
<string name="app_theme_light">Aceɛlal</string>
|
<string name="app_theme_light">Aceɛlal</string>
|
||||||
<string name="app_theme_black">Aberkan</string>
|
<string name="app_theme_black">Aberkan</string>
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
<string name="notification_summary_medium">%1$s, %2$s, akked %3$s</string>
|
<string name="notification_summary_medium">%1$s, %2$s, akked %3$s</string>
|
||||||
<string name="notification_summary_small">%1$s akked %2$s</string>
|
<string name="notification_summary_small">%1$s akked %2$s</string>
|
||||||
<string name="about_tusky_version">Tusky %s</string>
|
<string name="about_tusky_version">Tusky %s</string>
|
||||||
<string name="about_tusky_account">Amaγnu n Tusky</string>
|
<string name="about_tusky_account">Amaɣnu n Tusky</string>
|
||||||
|
|
||||||
<string name="status_media_images">Tugniwin</string>
|
<string name="status_media_images">Tugniwin</string>
|
||||||
<string name="status_media_video">Tibidyutin</string>
|
<string name="status_media_video">Tibidyutin</string>
|
||||||
|
@ -109,17 +109,17 @@
|
||||||
<string name="pin_action">Senṭeḍ</string>
|
<string name="pin_action">Senṭeḍ</string>
|
||||||
|
|
||||||
<string name="action_view_mutes">Imiḍanen yettwasgugmen</string>
|
<string name="action_view_mutes">Imiḍanen yettwasgugmen</string>
|
||||||
<string name="action_view_blocks">Imiḍanen yettusḥebsen</string>
|
<string name="action_view_blocks">Imiḍan yettwacekklen</string>
|
||||||
<string name="action_view_domain_mutes">Tiγula yettwaffren</string>
|
<string name="action_view_domain_mutes">Tiɣula yettwaffren</string>
|
||||||
<string name="action_view_follow_requests">Isuturen n teḍfeṛt</string>
|
<string name="action_view_follow_requests">Isuturen n teḍfeṛt</string>
|
||||||
<string name="action_view_media">Taγwalt</string>
|
<string name="action_view_media">Taɣwalt</string>
|
||||||
<string name="notifications_clear">Sfeḍ</string>
|
<string name="notifications_clear">Sfeḍ</string>
|
||||||
<string name="title_mutes">Imiḍanen yettwasgugmen</string>
|
<string name="title_mutes">Imiḍanen yettwasgugmen</string>
|
||||||
<string name="title_blocks">Imiḍanen yettusḥebsen</string>
|
<string name="title_blocks">Imiḍanen yettwacekklen</string>
|
||||||
<string name="title_domain_mutes">Tiγula yettwaffren</string>
|
<string name="title_domain_mutes">Tiɣula yettwaffren</string>
|
||||||
<string name="title_follow_requests">Isuturen n teḍfeṛt</string>
|
<string name="title_follow_requests">Isuturen n teḍfeṛt</string>
|
||||||
<string name="pref_title_notifications_enabled">Ẓreg tilγa</string>
|
<string name="pref_title_notifications_enabled">Tilɣa</string>
|
||||||
<string name="title_media">Taγwalt</string>
|
<string name="title_media">Taywalt</string>
|
||||||
<string name="action_remove">Kkes</string>
|
<string name="action_remove">Kkes</string>
|
||||||
<string name="compose_shortcut_short_label">Azen</string>
|
<string name="compose_shortcut_short_label">Azen</string>
|
||||||
|
|
||||||
|
@ -129,28 +129,28 @@
|
||||||
<string name="action_add_poll">Rnu assenqed</string>
|
<string name="action_add_poll">Rnu assenqed</string>
|
||||||
<string name="action_photo_take">Ṭef tugna</string>
|
<string name="action_photo_take">Ṭef tugna</string>
|
||||||
<string name="action_toggle_visibility">Timeẓriwt n tijewwaqt</string>
|
<string name="action_toggle_visibility">Timeẓriwt n tijewwaqt</string>
|
||||||
<string name="action_schedule_toot">Sγiwes tijewwaqt-a</string>
|
<string name="action_schedule_toot">Sɣiwes tijewwaqt-a</string>
|
||||||
<string name="status_share_content">Bḍu agbur n tijewwiqt-a</string>
|
<string name="status_share_content">Bḍu agbur n tijewwiqt-a</string>
|
||||||
<string name="status_share_link">Bḍu aseγwen γer tijewwiqt</string>
|
<string name="status_share_link">Bḍu aseɣwen ɣer tijewwiqt</string>
|
||||||
<string name="filter_addition_dialog_title">Rnu amsizdeg</string>
|
<string name="filter_addition_dialog_title">Rnu amsizdeg</string>
|
||||||
<string name="filter_edit_dialog_title">Ẓreg amsizdeg</string>
|
<string name="filter_edit_dialog_title">Ẓreg amsizdeg</string>
|
||||||
<string name="action_create_list">Snulfu-d umuγ</string>
|
<string name="action_create_list">Snulfu-d umuɣ</string>
|
||||||
<string name="action_rename_list">Snifel isem n wumuγ</string>
|
<string name="action_rename_list">Snifel isem n wumuɣ</string>
|
||||||
<string name="action_delete_list">Kkes umuγ-a</string>
|
<string name="action_delete_list">Kkes umuɣ-a</string>
|
||||||
<string name="action_edit_list">Ẓreg umuγ-a</string>
|
<string name="action_edit_list">Ẓreg umuɣ-a</string>
|
||||||
<string name="action_add_to_list">Rnu yiwen umiḍan γer tabdert</string>
|
<string name="action_add_to_list">Rnu yiwen umiḍan ɣer wummuɣ</string>
|
||||||
<string name="action_remove_from_list">Kkes amiḍan seg wumuγ</string>
|
<string name="action_remove_from_list">Kkes amiḍan seg wumuɣ</string>
|
||||||
|
|
||||||
<string name="profile_metadata_add">Rnu isefka</string>
|
<string name="profile_metadata_add">Rnu isefka</string>
|
||||||
<string name="hint_list_name">Isem n wumuγ</string>
|
<string name="hint_list_name">Isem n wumuɣ</string>
|
||||||
|
|
||||||
<string name="select_list_title">Fren tabdart</string>
|
<string name="select_list_title">Fren tabdart</string>
|
||||||
<string name="list">Umuγ</string>
|
<string name="list">Umuɣ</string>
|
||||||
<string name="notifications_apply_filter">Sizdeg</string>
|
<string name="notifications_apply_filter">Sizdeg</string>
|
||||||
<string name="title_accounts">Imiḍanen</string>
|
<string name="title_accounts">Imiḍanen</string>
|
||||||
<string name="add_poll_choice">Rnu yiwen wefran</string>
|
<string name="add_poll_choice">Rnu yiwen wefran</string>
|
||||||
<string name="report_username_format">Ccetki γef @%s</string>
|
<string name="report_username_format">Ccetki ɣef @%s</string>
|
||||||
<string name="action_report">Ccetki</string>
|
<string name="action_report">Ccetki fell-as</string>
|
||||||
<string name="action_reject">Ggami</string>
|
<string name="action_reject">Ggami</string>
|
||||||
<string name="download_image">Yessidired %1$s</string>
|
<string name="download_image">Yessidired %1$s</string>
|
||||||
|
|
||||||
|
@ -159,16 +159,16 @@
|
||||||
<string name="login_connection">itteqqen…</string>
|
<string name="login_connection">itteqqen…</string>
|
||||||
|
|
||||||
<string name="dialog_message_uploading_media">Issalay…</string>
|
<string name="dialog_message_uploading_media">Issalay…</string>
|
||||||
<string name="pref_title_notification_filter_poll">fukken kran n wadγaren</string>
|
<string name="pref_title_notification_filter_poll">fukken kran n wadɣaren</string>
|
||||||
<string name="pref_title_timeline_filters">Imzizdigen</string>
|
<string name="pref_title_timeline_filters">Imzizdigen</string>
|
||||||
|
|
||||||
<string name="app_theme_auto">Akken yella yiṭij</string>
|
<string name="app_theme_auto">Akken yella yiṭij</string>
|
||||||
<string name="pref_title_browser_settings">Iminig</string>
|
<string name="pref_title_browser_settings">Iminig</string>
|
||||||
<string name="pref_title_show_replies">Sken-ed tiririyin</string>
|
<string name="pref_title_show_replies">Sken-d tiririyin</string>
|
||||||
<string name="pref_title_http_proxy_settings">Apṛuksi HTTP</string>
|
<string name="pref_title_http_proxy_settings">Apṛuksi HTTP</string>
|
||||||
<string name="pref_title_http_proxy_server">Tansa n upṛuksi HTTP</string>
|
<string name="pref_title_http_proxy_server">Tansa n upṛuksi HTTP</string>
|
||||||
<string name="notification_follow_name">Imeḍfaṛen imaynuten</string>
|
<string name="notification_follow_name">Imeḍfaṛen imaynuten</string>
|
||||||
<string name="notification_poll_name">Adγaren</string>
|
<string name="notification_poll_name">Adɣaren</string>
|
||||||
<string name="notification_mention_format">Yuder-ik-id %s</string>
|
<string name="notification_mention_format">Yuder-ik-id %s</string>
|
||||||
<string name="description_account_locked">Yettwargel umiḍan</string>
|
<string name="description_account_locked">Yettwargel umiḍan</string>
|
||||||
|
|
||||||
|
@ -183,26 +183,26 @@
|
||||||
<string name="restart">Ales tanekra</string>
|
<string name="restart">Ales tanekra</string>
|
||||||
<string name="download_failed">Tuccḍa n usider</string>
|
<string name="download_failed">Tuccḍa n usider</string>
|
||||||
|
|
||||||
<string name="account_moved_description">Igujj %1$s γer:</string>
|
<string name="account_moved_description">Igujj %1$s ɣer:</string>
|
||||||
|
|
||||||
<string name="unpin_action">Kkes asenṭeḍ</string>
|
<string name="unpin_action">Kkes asenṭeḍ</string>
|
||||||
<string name="conversation_1_recipients">%1$s</string>
|
<string name="conversation_1_recipients">%1$s</string>
|
||||||
<string name="conversation_2_recipients">%1$s akked %2$s</string>
|
<string name="conversation_2_recipients">%1$s akked %2$s</string>
|
||||||
<string name="conversation_more_recipients">%1$s, %2$s akked %3$d nniḍen</string>
|
<string name="conversation_more_recipients">%1$s, %2$s akked %3$d nniḍen</string>
|
||||||
<string name="compose_shortcut_long_label">Aru tijewwiqt</string>
|
<string name="compose_shortcut_long_label">Aru tijewwiqt</string>
|
||||||
<string name="poll_info_format"> <!-- 15 n wadγaren • 1 n wesrag id yeqqimen --> %1$s • %2$s</string>
|
<string name="poll_info_format"> <!-- 15 n wadɣaren • 1 n wesrag id yeqqimen --> %1$s • %2$s</string>
|
||||||
<plurals name="poll_info_votes">
|
<plurals name="poll_info_votes">
|
||||||
<item quantity="one">%s wedγar</item>
|
<item quantity="one">%s n wedɣar</item>
|
||||||
<item quantity="other">%s n yedγaren</item>
|
<item quantity="other">%s n yedɣaren</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="poll_info_time_relative">%s id yugran</string>
|
<string name="poll_info_time_relative">%s id yugran</string>
|
||||||
<string name="poll_info_time_absolute">ad ifak deg %s</string>
|
<string name="poll_info_time_absolute">ad ifak deg %s</string>
|
||||||
<string name="poll_info_closed">ifuk</string>
|
<string name="poll_info_closed">ifuk</string>
|
||||||
|
|
||||||
<string name="poll_vote">Dγer</string>
|
<string name="poll_vote">Dɣer</string>
|
||||||
|
|
||||||
<string name="poll_ended_voted">Ifuk, tura kan, yiwen wedγar t tteki-iḍ degs</string>
|
<string name="poll_ended_voted">Ifuk, tura kan, yiwen wedɣar t tteki-iḍ degs</string>
|
||||||
<string name="poll_ended_created">Ifukk yiwen wedγar id snulfaḍ</string>
|
<string name="poll_ended_created">Ifukk yiwen wedɣar id snulfaḍ</string>
|
||||||
|
|
||||||
<plurals name="poll_timespan_days">
|
<plurals name="poll_timespan_days">
|
||||||
<item quantity="one">%d n wass</item>
|
<item quantity="one">%d n wass</item>
|
||||||
|
@ -214,18 +214,18 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="poll_timespan_minutes">
|
<plurals name="poll_timespan_minutes">
|
||||||
<item quantity="one">%d n tasdidt</item>
|
<item quantity="one">%d n tasdidt</item>
|
||||||
<item quantity="other">%d n tesdidin</item>
|
<item quantity="other">%d n tisdidin</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="button_continue">Kemmel</string>
|
<string name="button_continue">Kemmel</string>
|
||||||
<string name="button_back">Uγal</string>
|
<string name="button_back">Uɣal</string>
|
||||||
<string name="failed_report">Tella-d tuccḍa deg ccetki</string>
|
<string name="failed_report">Tella-d tuccḍa deg ccetki</string>
|
||||||
<string name="failed_search">Tucḍa n unadi</string>
|
<string name="failed_search">Tucḍa n unadi</string>
|
||||||
|
|
||||||
<string name="create_poll_title">Assenqed</string>
|
<string name="create_poll_title">Assenqed</string>
|
||||||
<string name="poll_duration_5_min">5 n tasditin</string>
|
<string name="poll_duration_5_min">5 n tisdidin</string>
|
||||||
<string name="poll_duration_30_min">30 n tasditin</string>
|
<string name="poll_duration_30_min">30 n tisdidin</string>
|
||||||
<string name="poll_duration_1_hour">1 n wesrag</string>
|
<string name="poll_duration_1_hour">1 n usrag</string>
|
||||||
<string name="poll_duration_6_hours">6 n wesragen</string>
|
<string name="poll_duration_6_hours">6 n isragen</string>
|
||||||
<string name="poll_duration_1_day">1 n wass</string>
|
<string name="poll_duration_1_day">1 n wass</string>
|
||||||
<string name="poll_duration_3_days">3 n wussan</string>
|
<string name="poll_duration_3_days">3 n wussan</string>
|
||||||
<string name="poll_duration_7_days">7 n wussan</string>
|
<string name="poll_duration_7_days">7 n wussan</string>
|
||||||
|
@ -233,30 +233,70 @@
|
||||||
|
|
||||||
<string name="title_follows">Ig ṭafaṛ</string>
|
<string name="title_follows">Ig ṭafaṛ</string>
|
||||||
<string name="title_followers">Imeḍfaṛen</string>
|
<string name="title_followers">Imeḍfaṛen</string>
|
||||||
<string name="hint_search_people_list">Nadi γef medden i teṭafareḍ</string>
|
<string name="hint_search_people_list">Nadi ɣef medden i teṭafareḍ</string>
|
||||||
<string name="description_visiblity_private">Imeḍfaṛen</string>
|
<string name="description_visiblity_private">Imeḍfaṛen</string>
|
||||||
|
|
||||||
<string name="action_links">Iseγwan</string>
|
<string name="action_links">Iseɣwan</string>
|
||||||
<string name="action_mentions">Tibdarin</string>
|
<string name="action_mentions">Tibdarin</string>
|
||||||
<string name="title_mentions_dialog">Tibdarin</string>
|
<string name="title_mentions_dialog">Tibdarin</string>
|
||||||
<string name="title_links_dialog">Iseγwan</string>
|
<string name="title_links_dialog">Iseɣwan</string>
|
||||||
<string name="confirmation_reported">Yettwaceyyaɛ!</string>
|
<string name="confirmation_reported">Yettwaceyyaɛ!</string>
|
||||||
<string name="status_sent">Yettwaceyyaɛ!</string>
|
<string name="status_sent">Yettwaceyyaɛ!</string>
|
||||||
<string name="search_no_results">Ula d yiwen n ugmuḍ</string>
|
<string name="search_no_results">Ula d yiwen n ugmuḍ</string>
|
||||||
|
|
||||||
<string name="post_privacy_followers_only">I yimeḍfaṛen kan</string>
|
<string name="post_privacy_followers_only">I yimeḍfaṛen kan</string>
|
||||||
|
|
||||||
<string name="pref_status_text_size">Teγzi n weḍṛis</string>
|
<string name="pref_status_text_size">Teɣzi n weḍṛis</string>
|
||||||
|
|
||||||
<string name="about_powered_by_tusky">Yettwamdemmar s Tusky</string>
|
<string name="about_powered_by_tusky">Yettwamdemmar s Tusky</string>
|
||||||
<string name="about_project_site">Asmel Web n usenfaṛ:
|
<string name="about_project_site">Asmel Web n usenfaṛ:
|
||||||
\n https://tusky.app</string>
|
\n https://tusky.app</string>
|
||||||
<string name="abbreviated_hours_ago">%dasr</string>
|
<string name="abbreviated_hours_ago">%dsr</string>
|
||||||
<string name="abbreviated_minutes_ago">%dtas</string>
|
<string name="abbreviated_minutes_ago">%dtsd</string>
|
||||||
<string name="abbreviated_seconds_ago">%dtasn</string>
|
<string name="abbreviated_seconds_ago">%dtsn</string>
|
||||||
|
|
||||||
<string name="compose_save_draft">Sekles amzun d arewway\?</string>
|
<string name="compose_save_draft">Sekles amzun d arewway\?</string>
|
||||||
<string name="later">Ticki</string>
|
<string name="later">Ticki</string>
|
||||||
<string name="profile_badge_bot_text">Aṛubut</string>
|
<string name="profile_badge_bot_text">Aṛubut</string>
|
||||||
<string name="description_status_bookmarked">Yettwarna γer ticṛad</string>
|
<string name="description_status_bookmarked">Yettwarna ɣer ticṛad</string>
|
||||||
|
<string name="abbreviated_in_hours">deg %dsr</string>
|
||||||
|
<string name="abbreviated_in_minutes">deg %dtsd</string>
|
||||||
|
<string name="abbreviated_in_seconds">deg %dtsn</string>
|
||||||
|
<plurals name="poll_timespan_seconds">
|
||||||
|
<item quantity="one">%d n tasint</item>
|
||||||
|
<item quantity="other">%d n tasinin</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
<string name="status_sensitive_media_title">Agbur amḥulfu</string>
|
||||||
|
<string name="pref_default_media_sensitivity">Creḍ allal n teywalt amzun d amḥulfu</string>
|
||||||
|
<string name="action_reset_schedule">Wennez tikkelt-nniḍen</string>
|
||||||
|
<string name="error_media_upload_sending">Asali ur yeddi ara.</string>
|
||||||
|
<string name="error_sender_account_gone">Tuccḍa deg tuzna n tijewwiqt.</string>
|
||||||
|
|
||||||
|
<string name="title_public_local">Adigan</string>
|
||||||
|
<string name="title_licenses">Turagin</string>
|
||||||
|
|
||||||
|
<string name="status_boosted_format">Yebḍa-t %s</string>
|
||||||
|
<string name="notification_reblog_format">%s Y·Tebḍa tijewwiqt-ik·im</string>
|
||||||
|
<string name="notification_favourite_format">%s Y·Terna tijewwiqt-ik·im ɣer imenyafen-is</string>
|
||||||
|
<string name="action_quick_reply">Tiririt taruradt</string>
|
||||||
|
<string name="action_reblog">Bḍu</string>
|
||||||
|
<string name="action_unreblog">Kkes beṭu</string>
|
||||||
|
<string name="action_hide_reblogs">Ffer beṭuyat</string>
|
||||||
|
<string name="action_show_reblogs">Sken-d beṭuyat</string>
|
||||||
|
<string name="action_unmute">Ur sgugum ara</string>
|
||||||
|
<string name="action_accept">Ddeg</string>
|
||||||
|
<string name="action_hashtags">Ihacṭagen</string>
|
||||||
|
<string name="action_open_reblogged_by">Sken-d beṭuyat</string>
|
||||||
|
<string name="title_hashtags_dialog">Ihacṭagen</string>
|
||||||
|
<string name="confirmation_unmuted">Aseqdac nni ur yettwasgugem ara tura</string>
|
||||||
|
<string name="confirmation_domain_unmuted">%s ur yettwaffer ara</string>
|
||||||
|
|
||||||
|
<string name="hint_note">Assisen</string>
|
||||||
|
<string name="label_header">Tugna n yiɣef n umaɣnu</string>
|
||||||
|
|
||||||
|
<string name="error_empty">Ur ilaq ara ad yili d ilem.</string>
|
||||||
|
<string name="action_block">Cekkel</string>
|
||||||
|
<string name="action_unblock">Kkes tacekkalt</string>
|
||||||
|
<string name="confirmation_unblocked">Tettwakkes tacekkalt ɣef umiḍan-nni</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -520,4 +520,6 @@
|
||||||
|
|
||||||
<string name="no_saved_status">Du har ikke lagret noen kladder.</string>
|
<string name="no_saved_status">Du har ikke lagret noen kladder.</string>
|
||||||
<string name="error_audio_upload_size">Lydfiler må være mindre enn 40MB.</string>
|
<string name="error_audio_upload_size">Lydfiler må være mindre enn 40MB.</string>
|
||||||
</resources>
|
<string name="warning_scheduling_interval">Mastodon har et minimums planleggingsinterval på 5 minutter.</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|
|
@ -491,4 +491,5 @@
|
||||||
<string name="no_saved_status">Avètz pas cap de borrolhon.</string>
|
<string name="no_saved_status">Avètz pas cap de borrolhon.</string>
|
||||||
<string name="no_scheduled_status">Avètz pas cap de tut planificat.</string>
|
<string name="no_scheduled_status">Avètz pas cap de tut planificat.</string>
|
||||||
|
|
||||||
</resources>
|
<string name="warning_scheduling_interval">L’interval minimum de planificacion sus Mastodon e de 5 minutas.</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -498,4 +498,6 @@
|
||||||
<string name="no_saved_status">Nie masz żadnych szkiców.</string>
|
<string name="no_saved_status">Nie masz żadnych szkiców.</string>
|
||||||
<string name="no_scheduled_status">Nie masz żadnych zaplanowanych wpisów.</string>
|
<string name="no_scheduled_status">Nie masz żadnych zaplanowanych wpisów.</string>
|
||||||
|
|
||||||
|
<string name="warning_scheduling_interval">Mastodon umożliwia wysłanie minimalnie 5 minut od zaplanowania.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -486,4 +486,5 @@
|
||||||
|
|
||||||
<string name="error_audio_upload_size">Áudios devem ser menores que 40MB.</string>
|
<string name="error_audio_upload_size">Áudios devem ser menores que 40MB.</string>
|
||||||
<string name="no_saved_status">Sem rascunhos.</string>
|
<string name="no_saved_status">Sem rascunhos.</string>
|
||||||
|
<string name="warning_scheduling_interval">Mastodon possui um intervalo mínimo de 5 minutos para agendar.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -546,4 +546,13 @@
|
||||||
<string name="description_status_bookmarked">Добавлено в закладки</string>
|
<string name="description_status_bookmarked">Добавлено в закладки</string>
|
||||||
<string name="select_list_title">Выбрать список</string>
|
<string name="select_list_title">Выбрать список</string>
|
||||||
<string name="list">Список</string>
|
<string name="list">Список</string>
|
||||||
</resources>
|
<string name="error_audio_upload_size">Аудиофайлы должны быть меньше 40МБ.</string>
|
||||||
|
<string name="gradient_for_media">Показывать цветные градиенты для скрытых медиа</string>
|
||||||
|
|
||||||
|
<string name="post_lookup_error_format">Ошибка поиска поста %s</string>
|
||||||
|
|
||||||
|
<string name="no_saved_status">У вас нет черновиков.</string>
|
||||||
|
<string name="no_scheduled_status">У вас нет запланированных постов.</string>
|
||||||
|
<string name="warning_scheduling_interval">Минимальный интервал планирования в Mastodon составляет 5 минут.</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<string name="error_media_upload_sending">Uppladdningen misslyckades.</string>
|
<string name="error_media_upload_sending">Uppladdningen misslyckades.</string>
|
||||||
<string name="error_sender_account_gone">Kunde inte skicka toot.</string>
|
<string name="error_sender_account_gone">Kunde inte skicka toot.</string>
|
||||||
<string name="title_home">Hem</string>
|
<string name="title_home">Hem</string>
|
||||||
<string name="title_notifications">Notifikationer</string>
|
<string name="title_notifications">Aviseringar</string>
|
||||||
<string name="title_public_local">Lokalt</string>
|
<string name="title_public_local">Lokalt</string>
|
||||||
<string name="title_public_federated">Federerat</string>
|
<string name="title_public_federated">Federerat</string>
|
||||||
<string name="title_direct_messages">Direkta meddelanden</string>
|
<string name="title_direct_messages">Direkta meddelanden</string>
|
||||||
|
@ -158,15 +158,15 @@
|
||||||
<string name="visibility_unlisted">Olistad: Visa inte i offentliga tidslinjer</string>
|
<string name="visibility_unlisted">Olistad: Visa inte i offentliga tidslinjer</string>
|
||||||
<string name="visibility_private">Enbart-följare: Ses enbart av följare</string>
|
<string name="visibility_private">Enbart-följare: Ses enbart av följare</string>
|
||||||
<string name="visibility_direct">Direkt: Skicka endast till nämnda användare</string>
|
<string name="visibility_direct">Direkt: Skicka endast till nämnda användare</string>
|
||||||
<string name="pref_title_edit_notification_settings">Notifikationer</string>
|
<string name="pref_title_edit_notification_settings">Aviseringar</string>
|
||||||
<string name="pref_title_notifications_enabled">Notifikationer</string>
|
<string name="pref_title_notifications_enabled">Aviseringar</string>
|
||||||
<string name="pref_title_notification_alerts">Alarm</string>
|
<string name="pref_title_notification_alerts">Alarm</string>
|
||||||
<string name="pref_title_notification_alert_sound">Meddela med ljud</string>
|
<string name="pref_title_notification_alert_sound">Meddela med ljud</string>
|
||||||
<string name="pref_title_notification_alert_vibrate">Meddela med vibration</string>
|
<string name="pref_title_notification_alert_vibrate">Meddela med vibration</string>
|
||||||
<string name="pref_title_notification_alert_light">Notifieringar med LED</string>
|
<string name="pref_title_notification_alert_light">Notifieringar med LED</string>
|
||||||
<string name="pref_title_notification_filters">Meddela mig när</string>
|
<string name="pref_title_notification_filters">Meddela mig när</string>
|
||||||
<string name="pref_title_notification_filter_mentions">omnämnd</string>
|
<string name="pref_title_notification_filter_mentions">omnämnd</string>
|
||||||
<string name="pref_title_notification_filter_follows">följande</string>
|
<string name="pref_title_notification_filter_follows">nya följare</string>
|
||||||
<string name="pref_title_notification_filter_reblogs">mina inlägg är knuffade</string>
|
<string name="pref_title_notification_filter_reblogs">mina inlägg är knuffade</string>
|
||||||
<string name="pref_title_notification_filter_favourites">mina inlägg är favoriserade</string>
|
<string name="pref_title_notification_filter_favourites">mina inlägg är favoriserade</string>
|
||||||
<string name="pref_title_appearance_settings">Utseende</string>
|
<string name="pref_title_appearance_settings">Utseende</string>
|
||||||
|
@ -177,7 +177,7 @@
|
||||||
<string name="app_theme_light">Ljust</string>
|
<string name="app_theme_light">Ljust</string>
|
||||||
<string name="app_theme_black">Svart</string>
|
<string name="app_theme_black">Svart</string>
|
||||||
<string name="app_theme_auto">Automatiskt vid solnedgång</string>
|
<string name="app_theme_auto">Automatiskt vid solnedgång</string>
|
||||||
<string name="app_theme_system">Använd systemdesign</string>
|
<string name="app_theme_system">Använd system-tema</string>
|
||||||
<string name="pref_title_browser_settings">Webbläsare</string>
|
<string name="pref_title_browser_settings">Webbläsare</string>
|
||||||
<string name="pref_title_custom_tabs">Använd Chrome-anpassade flikar</string>
|
<string name="pref_title_custom_tabs">Använd Chrome-anpassade flikar</string>
|
||||||
<string name="pref_title_hide_follow_button">Dölj skriv-knappen vid skrollning</string>
|
<string name="pref_title_hide_follow_button">Dölj skriv-knappen vid skrollning</string>
|
||||||
|
@ -206,13 +206,13 @@
|
||||||
<string name="status_text_size_large">Stor</string>
|
<string name="status_text_size_large">Stor</string>
|
||||||
<string name="status_text_size_largest">Största</string>
|
<string name="status_text_size_largest">Största</string>
|
||||||
<string name="notification_mention_name">Nya omnämnanden</string>
|
<string name="notification_mention_name">Nya omnämnanden</string>
|
||||||
<string name="notification_mention_descriptions">Notifieringar om nya omnämnanden</string>
|
<string name="notification_mention_descriptions">Aviseringar om nya omnämnanden</string>
|
||||||
<string name="notification_follow_name">Nya följare</string>
|
<string name="notification_follow_name">Nya följare</string>
|
||||||
<string name="notification_follow_description">Notifieringar om nya följare</string>
|
<string name="notification_follow_description">Aviseringar på nya följare</string>
|
||||||
<string name="notification_boost_name">Knuffar</string>
|
<string name="notification_boost_name">Knuffar</string>
|
||||||
<string name="notification_boost_description">Notifieringar när dina toots blir knuffade</string>
|
<string name="notification_boost_description">Aviseringar när dina toots blir knuffade</string>
|
||||||
<string name="notification_favourite_name">Favoriter</string>
|
<string name="notification_favourite_name">Favoriter</string>
|
||||||
<string name="notification_favourite_description">Notifieringar när dina toots blir markerade som favoriter</string>
|
<string name="notification_favourite_description">Aviseringar när dina toots blir markerade som favoriter</string>
|
||||||
<string name="notification_mention_format">%s omnämnde dig</string>
|
<string name="notification_mention_format">%s omnämnde dig</string>
|
||||||
<string name="notification_summary_large">%1$s, %2$s, %3$s och %4$d andra</string>
|
<string name="notification_summary_large">%1$s, %2$s, %3$s och %4$d andra</string>
|
||||||
<string name="notification_summary_medium">%1$s, %2$s, och %3$s</string>
|
<string name="notification_summary_medium">%1$s, %2$s, och %3$s</string>
|
||||||
|
@ -239,7 +239,7 @@
|
||||||
<string name="status_share_link">Dela länk till toot</string>
|
<string name="status_share_link">Dela länk till toot</string>
|
||||||
<string name="status_media_images">Bilder</string>
|
<string name="status_media_images">Bilder</string>
|
||||||
<string name="status_media_video">Video</string>
|
<string name="status_media_video">Video</string>
|
||||||
<string name="state_follow_requested">Följarförfrågad</string>
|
<string name="state_follow_requested">Följarförfrågan</string>
|
||||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||||
<string name="abbreviated_in_years">om %dy</string>
|
<string name="abbreviated_in_years">om %dy</string>
|
||||||
<string name="abbreviated_in_days">om %dd</string>
|
<string name="abbreviated_in_days">om %dd</string>
|
||||||
|
@ -272,9 +272,9 @@
|
||||||
<string name="error_rename_list">Kunde inte byta namn på lista</string>
|
<string name="error_rename_list">Kunde inte byta namn på lista</string>
|
||||||
<string name="error_delete_list">Kunde inte radera lista</string>
|
<string name="error_delete_list">Kunde inte radera lista</string>
|
||||||
<string name="action_create_list">Skapa en lista</string>
|
<string name="action_create_list">Skapa en lista</string>
|
||||||
<string name="action_rename_list">Byt namn</string>
|
<string name="action_rename_list">Byt namn på listan</string>
|
||||||
<string name="action_delete_list">Ta bort</string>
|
<string name="action_delete_list">Ta bort listan</string>
|
||||||
<string name="action_edit_list">Ändra</string>
|
<string name="action_edit_list">Redigera lista</string>
|
||||||
<string name="hint_search_people_list">Sök efter personer du följer</string>
|
<string name="hint_search_people_list">Sök efter personer du följer</string>
|
||||||
<string name="action_add_to_list">Lägg till konto i listan</string>
|
<string name="action_add_to_list">Lägg till konto i listan</string>
|
||||||
<string name="action_remove_from_list">Ta bort kontot från listan</string>
|
<string name="action_remove_from_list">Ta bort kontot från listan</string>
|
||||||
|
@ -287,7 +287,7 @@
|
||||||
<string name="lock_account_label_description">Kräver att du manuellt godkänner följare</string>
|
<string name="lock_account_label_description">Kräver att du manuellt godkänner följare</string>
|
||||||
<string name="compose_save_draft">Spara utkast?</string>
|
<string name="compose_save_draft">Spara utkast?</string>
|
||||||
<string name="send_toot_notification_title">Skickar toot…</string>
|
<string name="send_toot_notification_title">Skickar toot…</string>
|
||||||
<string name="send_toot_notification_error_title">Fel vid sändning av toot</string>
|
<string name="send_toot_notification_error_title">Kunde inte skicka toot</string>
|
||||||
<string name="send_toot_notification_channel_name">Skickar toot</string>
|
<string name="send_toot_notification_channel_name">Skickar toot</string>
|
||||||
<string name="send_toot_notification_cancel_title">Sändning avbruten</string>
|
<string name="send_toot_notification_cancel_title">Sändning avbruten</string>
|
||||||
<string name="send_toot_notification_saved_content">En kopia av tooten har sparats i dina utkast</string>
|
<string name="send_toot_notification_saved_content">En kopia av tooten har sparats i dina utkast</string>
|
||||||
|
@ -298,14 +298,14 @@
|
||||||
<string name="system_default">Systemstandard</string>
|
<string name="system_default">Systemstandard</string>
|
||||||
<string name="download_fonts">Du behöver ladda ned dessa emojis först</string>
|
<string name="download_fonts">Du behöver ladda ned dessa emojis först</string>
|
||||||
<string name="performing_lookup_title">Utför sökning…</string>
|
<string name="performing_lookup_title">Utför sökning…</string>
|
||||||
<string name="expand_collapse_all_statuses">Expandera/Dölj alla status</string>
|
<string name="expand_collapse_all_statuses">Expandera/Dölj alla statusar</string>
|
||||||
<string name="action_open_toot">Öppna toot</string>
|
<string name="action_open_toot">Öppna toot</string>
|
||||||
<string name="restart_required">Omstart av appen krävs</string>
|
<string name="restart_required">Omstart av appen krävs</string>
|
||||||
<string name="restart_emoji">Du måste starta om Yuito för att tillämpa ändringarna</string>
|
<string name="restart_emoji">Du måste starta om Yuito för att tillämpa ändringarna</string>
|
||||||
<string name="later">Senare</string>
|
<string name="later">Senare</string>
|
||||||
<string name="restart">Starta om</string>
|
<string name="restart">Starta om</string>
|
||||||
<string name="caption_systememoji">Standard-emojis för din enhet</string>
|
<string name="caption_systememoji">Standard-emojis för din enhet</string>
|
||||||
<string name="caption_blobmoji">Emojis baserade på The Blob emojis kända från Android 4.4–7.1</string>
|
<string name="caption_blobmoji">Emojis baserade på The Blob emojis från Android 4.4–7.1</string>
|
||||||
<string name="caption_twemoji">Mastodon\'s standard emojis</string>
|
<string name="caption_twemoji">Mastodon\'s standard emojis</string>
|
||||||
<string name="download_failed">Nedladdning misslyckad</string>
|
<string name="download_failed">Nedladdning misslyckad</string>
|
||||||
<string name="profile_badge_bot_text">Robot</string>
|
<string name="profile_badge_bot_text">Robot</string>
|
||||||
|
@ -373,9 +373,9 @@
|
||||||
|
|
||||||
<string name="pref_title_bot_overlay">Visa robotindikator</string>
|
<string name="pref_title_bot_overlay">Visa robotindikator</string>
|
||||||
|
|
||||||
<string name="notification_clear_text">Är du säker på att du vill rensa dina notifieringar permanent\?</string>
|
<string name="notification_clear_text">Är du säker på att du vill rensa dina aviseringar permanent\?</string>
|
||||||
|
|
||||||
<string name="action_delete_and_redraft">Radera och skriv nytt</string>
|
<string name="action_delete_and_redraft">Radera och skriv på nytt</string>
|
||||||
<string name="dialog_redraft_toot_warning">Radera och skriv ny toot\?</string>
|
<string name="dialog_redraft_toot_warning">Radera och skriv ny toot\?</string>
|
||||||
|
|
||||||
<string name="poll_info_format"> <!-- 15 röster • 1 timme kvar --> %1$s • %2$s</string>
|
<string name="poll_info_format"> <!-- 15 röster • 1 timme kvar --> %1$s • %2$s</string>
|
||||||
|
@ -384,15 +384,15 @@
|
||||||
<item quantity="other">%s röster</item>
|
<item quantity="other">%s röster</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="poll_info_time_relative">%s kvar</string>
|
<string name="poll_info_time_relative">%s kvar</string>
|
||||||
<string name="poll_info_time_absolute">avslutas %s</string>
|
<string name="poll_info_time_absolute">avslutas vid %s</string>
|
||||||
<string name="poll_info_closed">stängd</string>
|
<string name="poll_info_closed">stängd</string>
|
||||||
|
|
||||||
<string name="poll_vote">Rösta</string>
|
<string name="poll_vote">Rösta</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="pref_title_notification_filter_poll">omröstning är avslutad</string>
|
<string name="pref_title_notification_filter_poll">omröstningar har avslutats</string>
|
||||||
<string name="notification_poll_name">Omröstningar</string>
|
<string name="notification_poll_name">Omröstningar</string>
|
||||||
<string name="notification_poll_description">Notifieringar när omröstningar har avslutats</string>
|
<string name="notification_poll_description">Aviseringar när omröstningar har avslutats</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="poll_ended_voted">En omröstning där du har röstat är avslutad</string>
|
<string name="poll_ended_voted">En omröstning där du har röstat är avslutad</string>
|
||||||
|
@ -424,9 +424,9 @@
|
||||||
<string name="title_domain_mutes">Dolda domäner</string>
|
<string name="title_domain_mutes">Dolda domäner</string>
|
||||||
<string name="action_view_domain_mutes">Dolda domäner</string>
|
<string name="action_view_domain_mutes">Dolda domäner</string>
|
||||||
<string name="action_mute_domain">Tysta %s</string>
|
<string name="action_mute_domain">Tysta %s</string>
|
||||||
<string name="confirmation_domain_unmuted">%s inte tystnad längre</string>
|
<string name="confirmation_domain_unmuted">%s inte tystad längre</string>
|
||||||
|
|
||||||
<string name="mute_domain_warning">Är du säker på att du vill blockera allt från %s\? Du kommer inte kunna se något innehåll från denna domän i publika tidslinje eller i dina notifieringar. Dina följare på domänen kommer inte att bli borttagna.</string>
|
<string name="mute_domain_warning">Är du säker på att du vill blockera allt från %s\? Du kommer inte kunna se något innehåll från denna domän i publika tidslinjer eller i dina notifieringar. Dina följare på domänen kommer inte att bli borttagna.</string>
|
||||||
<string name="mute_domain_warning_dialog_ok">Dölj hela domänen</string>
|
<string name="mute_domain_warning_dialog_ok">Dölj hela domänen</string>
|
||||||
|
|
||||||
<string name="caption_notoemoji">Google\'s nuvarande emojis</string>
|
<string name="caption_notoemoji">Google\'s nuvarande emojis</string>
|
||||||
|
@ -443,7 +443,7 @@
|
||||||
|
|
||||||
<string name="pref_title_show_notifications_filter">Visa notifikationsfilter</string>
|
<string name="pref_title_show_notifications_filter">Visa notifikationsfilter</string>
|
||||||
<string name="filter_dialog_whole_word">Helt ord</string>
|
<string name="filter_dialog_whole_word">Helt ord</string>
|
||||||
<string name="filter_dialog_whole_word_description">När nyckelordet eller frasen är alfanumerisk enbart, blir den enbart appliceras om den matchar hela ordet</string>
|
<string name="filter_dialog_whole_word_description">När nyckelordet eller frasen enbart är alfanumerisk, appliceras den om den matchar hela ordet</string>
|
||||||
<string name="pref_title_alway_open_spoiler">Expandera alltid toots med innehållsvarningar</string>
|
<string name="pref_title_alway_open_spoiler">Expandera alltid toots med innehållsvarningar</string>
|
||||||
<string name="title_accounts">Konton</string>
|
<string name="title_accounts">Konton</string>
|
||||||
<string name="failed_search">Sökning misslyckades</string>
|
<string name="failed_search">Sökning misslyckades</string>
|
||||||
|
@ -482,4 +482,5 @@
|
||||||
|
|
||||||
<string name="error_audio_upload_size">Ljudfiler måste vara mindre än 40MB.</string>
|
<string name="error_audio_upload_size">Ljudfiler måste vara mindre än 40MB.</string>
|
||||||
<string name="no_saved_status">Du har inga utkast.</string>
|
<string name="no_saved_status">Du har inga utkast.</string>
|
||||||
|
<string name="warning_scheduling_interval">Mastodon har ett minimalt schemaläggningsintervall på 5 minuter.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
|
|
||||||
<string name="login_connection">正在連線…</string>
|
<string name="login_connection">正在連線…</string>
|
||||||
|
|
||||||
<string name="dialog_whats_an_instance">請輸入你帳號所在的 Mastodon 站點的域名或地址</string>
|
<string name="dialog_whats_an_instance">"請輸入你帳號所在的 Mastodon 站點的域名或地址 "</string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
|
|
||||||
<string name="login_connection">正在連線…</string>
|
<string name="login_connection">正在連線…</string>
|
||||||
|
|
||||||
<string name="dialog_whats_an_instance">請輸入你帳號所在的 Mastodon 站點的域名或地址</string>
|
<string name="dialog_whats_an_instance">"請輸入你帳號所在的 Mastodon 站點的域名或地址 "</string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
|
|
||||||
<string name="login_connection">正在連線…</string>
|
<string name="login_connection">正在連線…</string>
|
||||||
|
|
||||||
<string name="dialog_whats_an_instance">請輸入你帳號所在的 Mastodon 站點的域名或地址</string>
|
<string name="dialog_whats_an_instance">"請輸入你帳號所在的 Mastodon 站點的域名或地址 "</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="dialog_title_finishing_media_upload">正在完成上傳…</string>
|
<string name="dialog_title_finishing_media_upload">正在完成上傳…</string>
|
||||||
|
|
|
@ -22,4 +22,5 @@
|
||||||
<item name="action_open_reblogger" type="id" />
|
<item name="action_open_reblogger" type="id" />
|
||||||
<item name="action_open_reblogged_by" type="id" />
|
<item name="action_open_reblogged_by" type="id" />
|
||||||
<item name="action_open_faved_by" type="id" />
|
<item name="action_open_faved_by" type="id" />
|
||||||
|
<item name="action_more" type="id" />
|
||||||
</resources>
|
</resources>
|
|
@ -7,7 +7,6 @@
|
||||||
<dimen name="compose_media_preview_margin">8dp</dimen>
|
<dimen name="compose_media_preview_margin">8dp</dimen>
|
||||||
<dimen name="compose_media_preview_margin_bottom">0dp</dimen>
|
<dimen name="compose_media_preview_margin_bottom">0dp</dimen>
|
||||||
<dimen name="compose_media_preview_size">120dp</dimen>
|
<dimen name="compose_media_preview_size">120dp</dimen>
|
||||||
<dimen name="compose_options_margin">8dp</dimen>
|
|
||||||
<dimen name="account_avatar_margin">14dp</dimen>
|
<dimen name="account_avatar_margin">14dp</dimen>
|
||||||
<dimen name="tab_page_margin">16dp</dimen>
|
<dimen name="tab_page_margin">16dp</dimen>
|
||||||
<dimen name="status_line_margin_start">36dp</dimen>
|
<dimen name="status_line_margin_start">36dp</dimen>
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
<string name="notification_reblog_format">%s boosted your toot</string>
|
<string name="notification_reblog_format">%s boosted your toot</string>
|
||||||
<string name="notification_favourite_format">%s favorited your toot</string>
|
<string name="notification_favourite_format">%s favorited your toot</string>
|
||||||
<string name="notification_follow_format">%s followed you</string>
|
<string name="notification_follow_format">%s followed you</string>
|
||||||
|
<string name="notification_follow_request_format">%s requested to follow you</string>
|
||||||
|
|
||||||
<string name="report_username_format">Report @%s</string>
|
<string name="report_username_format">Report @%s</string>
|
||||||
<string name="report_comment_hint">Additional comments?</string>
|
<string name="report_comment_hint">Additional comments?</string>
|
||||||
|
@ -113,6 +114,8 @@
|
||||||
<string name="action_mute">Mute</string>
|
<string name="action_mute">Mute</string>
|
||||||
<string name="action_unmute">Unmute</string>
|
<string name="action_unmute">Unmute</string>
|
||||||
<string name="action_mute_domain">Mute %s</string>
|
<string name="action_mute_domain">Mute %s</string>
|
||||||
|
<string name="action_mute_conversation">Mute conversation</string>
|
||||||
|
<string name="action_unmute_conversation">Unmute conversation</string>
|
||||||
<string name="action_mention">Mention</string>
|
<string name="action_mention">Mention</string>
|
||||||
<string name="action_hide_media">Hide media</string>
|
<string name="action_hide_media">Hide media</string>
|
||||||
<string name="action_open_drawer">Open drawer</string>
|
<string name="action_open_drawer">Open drawer</string>
|
||||||
|
@ -205,6 +208,8 @@
|
||||||
<string name="dialog_redraft_toot_warning">Delete and re-draft this toot?</string>
|
<string name="dialog_redraft_toot_warning">Delete and re-draft this toot?</string>
|
||||||
<string name="mute_domain_warning">Are you sure you want to block all of %s? You will not see content from that domain in any public timelines or in your notifications. Your followers from that domain will be removed.</string>
|
<string name="mute_domain_warning">Are you sure you want to block all of %s? You will not see content from that domain in any public timelines or in your notifications. Your followers from that domain will be removed.</string>
|
||||||
<string name="mute_domain_warning_dialog_ok">Hide entire domain</string>
|
<string name="mute_domain_warning_dialog_ok">Hide entire domain</string>
|
||||||
|
<string name="dialog_block_warning">Block @%s?</string>
|
||||||
|
<string name="dialog_mute_warning">Mute @%s?</string>
|
||||||
|
|
||||||
<string name="visibility_public">Public: Post to public timelines</string>
|
<string name="visibility_public">Public: Post to public timelines</string>
|
||||||
<string name="visibility_unlisted">Unlisted: Do not show in public timelines</string>
|
<string name="visibility_unlisted">Unlisted: Do not show in public timelines</string>
|
||||||
|
@ -221,6 +226,7 @@
|
||||||
<string name="pref_title_notification_filters">Notify me when</string>
|
<string name="pref_title_notification_filters">Notify me when</string>
|
||||||
<string name="pref_title_notification_filter_mentions">mentioned</string>
|
<string name="pref_title_notification_filter_mentions">mentioned</string>
|
||||||
<string name="pref_title_notification_filter_follows">followed</string>
|
<string name="pref_title_notification_filter_follows">followed</string>
|
||||||
|
<string name="pref_title_notification_filter_follow_requests">follow requested</string>
|
||||||
<string name="pref_title_notification_filter_reblogs">my posts are boosted</string>
|
<string name="pref_title_notification_filter_reblogs">my posts are boosted</string>
|
||||||
<string name="pref_title_notification_filter_favourites">my posts are favorited</string>
|
<string name="pref_title_notification_filter_favourites">my posts are favorited</string>
|
||||||
<string name="pref_title_notification_filter_poll">polls have ended</string>
|
<string name="pref_title_notification_filter_poll">polls have ended</string>
|
||||||
|
@ -284,6 +290,8 @@
|
||||||
<string name="notification_mention_descriptions">Notifications about new mentions</string>
|
<string name="notification_mention_descriptions">Notifications about new mentions</string>
|
||||||
<string name="notification_follow_name">New Followers</string>
|
<string name="notification_follow_name">New Followers</string>
|
||||||
<string name="notification_follow_description">Notifications about new followers</string>
|
<string name="notification_follow_description">Notifications about new followers</string>
|
||||||
|
<string name="notification_follow_request_name">Follow Requests</string>
|
||||||
|
<string name="notification_follow_request_description">Notifications about follow requests</string>
|
||||||
<string name="notification_boost_name">Boosts</string>
|
<string name="notification_boost_name">Boosts</string>
|
||||||
<string name="notification_boost_description">Notifications when your toots get boosted</string>
|
<string name="notification_boost_description">Notifications when your toots get boosted</string>
|
||||||
<string name="notification_favourite_name">Favorites</string>
|
<string name="notification_favourite_name">Favorites</string>
|
||||||
|
@ -516,6 +524,10 @@
|
||||||
<item quantity="one">%s vote</item>
|
<item quantity="one">%s vote</item>
|
||||||
<item quantity="other">%s votes</item>
|
<item quantity="other">%s votes</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="poll_info_people">
|
||||||
|
<item quantity="one">%s person</item>
|
||||||
|
<item quantity="other">%s people</item>
|
||||||
|
</plurals>
|
||||||
<string name="poll_info_time_relative">%s left</string>
|
<string name="poll_info_time_relative">%s left</string>
|
||||||
<string name="poll_info_time_absolute">ends at %s</string>
|
<string name="poll_info_time_absolute">ends at %s</string>
|
||||||
<string name="poll_info_closed">closed</string>
|
<string name="poll_info_closed">closed</string>
|
||||||
|
@ -576,5 +588,7 @@
|
||||||
<string name="no_saved_status">You don\'t have any drafts.</string>
|
<string name="no_saved_status">You don\'t have any drafts.</string>
|
||||||
<string name="no_scheduled_status">You don\'t have any scheduled statuses.</string>
|
<string name="no_scheduled_status">You don\'t have any scheduled statuses.</string>
|
||||||
<string name="warning_scheduling_interval">Mastodon has a minimum scheduling interval of 5 minutes.</string>
|
<string name="warning_scheduling_interval">Mastodon has a minimum scheduling interval of 5 minutes.</string>
|
||||||
|
<string name="pref_title_show_cards_in_timelines">Show link previews in timelines</string>
|
||||||
|
<string name="pref_title_confirm_reblogs">Show confirmation dialog before boosting</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -27,6 +27,12 @@
|
||||||
android:title="@string/pref_title_notification_filter_follows"
|
android:title="@string/pref_title_notification_filter_follows"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="notificationFilterFollowRequests"
|
||||||
|
android:title="@string/pref_title_notification_filter_follow_requests"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="notificationFilterReblogs"
|
android:key="notificationFilterReblogs"
|
||||||
|
|
|
@ -72,6 +72,18 @@
|
||||||
android:title="@string/pref_title_show_notifications_filter"
|
android:title="@string/pref_title_show_notifications_filter"
|
||||||
app:singleLineTitle="false" />
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="showCardsInTimelines"
|
||||||
|
android:title="@string/pref_title_show_cards_in_timelines"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="confirmReblogs"
|
||||||
|
android:title="@string/pref_title_confirm_reblogs"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/pref_title_limited_bandwidth_settings">
|
<PreferenceCategory android:title="@string/pref_title_limited_bandwidth_settings">
|
||||||
|
|
|
@ -88,6 +88,7 @@ class BottomSheetActivityTest {
|
||||||
arrayOf(),
|
arrayOf(),
|
||||||
null,
|
null,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
|
muted = false,
|
||||||
poll = null,
|
poll = null,
|
||||||
card = null
|
card = null
|
||||||
)
|
)
|
||||||
|
|
|
@ -68,6 +68,7 @@ class ComposeActivityTest {
|
||||||
notificationsEnabled = true,
|
notificationsEnabled = true,
|
||||||
notificationsMentioned = true,
|
notificationsMentioned = true,
|
||||||
notificationsFollowed = true,
|
notificationsFollowed = true,
|
||||||
|
notificationsFollowRequested = false,
|
||||||
notificationsReblogged = true,
|
notificationsReblogged = true,
|
||||||
notificationsFavorited = true,
|
notificationsFavorited = true,
|
||||||
notificationSound = true,
|
notificationSound = true,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.keylesspalace.tusky.fragment.SFragment
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.nhaarman.mockitokotlin2.mock
|
import com.nhaarman.mockitokotlin2.mock
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import okio.Timeout
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
@ -99,6 +100,10 @@ class FilterTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun timeout(): Timeout {
|
||||||
|
throw Error("not implemented")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
activity.mastodonApi = apiMock
|
activity.mastodonApi = apiMock
|
||||||
|
@ -214,6 +219,7 @@ class FilterTest {
|
||||||
mentions = emptyArray(),
|
mentions = emptyArray(),
|
||||||
application = null,
|
application = null,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
|
muted = false,
|
||||||
poll = if (pollOptions != null) {
|
poll = if (pollOptions != null) {
|
||||||
Poll(
|
Poll(
|
||||||
id = "1234",
|
id = "1234",
|
||||||
|
@ -221,6 +227,7 @@ class FilterTest {
|
||||||
expired = false,
|
expired = false,
|
||||||
multiple = false,
|
multiple = false,
|
||||||
votesCount = 0,
|
votesCount = 0,
|
||||||
|
votersCount = 0,
|
||||||
options = pollOptions.map {
|
options = pollOptions.map {
|
||||||
PollOption(it, 0)
|
PollOption(it, 0)
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,13 +18,9 @@ package com.keylesspalace.tusky
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.util.Log
|
|
||||||
import androidx.emoji.text.EmojiCompat
|
import androidx.emoji.text.EmojiCompat
|
||||||
import com.keylesspalace.tusky.util.LocaleManager
|
import com.keylesspalace.tusky.util.LocaleManager
|
||||||
import dagger.android.DispatchingAndroidInjector
|
|
||||||
import dagger.android.HasAndroidInjector
|
|
||||||
import de.c1710.filemojicompat.FileEmojiCompatConfig
|
import de.c1710.filemojicompat.FileEmojiCompatConfig
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
// override TuskyApplication for Robolectric tests, only initialize the necessary stuff
|
// override TuskyApplication for Robolectric tests, only initialize the necessary stuff
|
||||||
class TuskyApplication : Application() {
|
class TuskyApplication : Application() {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.keylesspalace.tusky.fragment
|
package com.keylesspalace.tusky.fragment
|
||||||
|
|
||||||
import android.text.Spanned
|
import android.text.SpannableString
|
||||||
|
import android.text.SpannedString
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.keylesspalace.tusky.SpanUtilsTest
|
import com.keylesspalace.tusky.SpanUtilsTest
|
||||||
import com.keylesspalace.tusky.db.AccountEntity
|
import com.keylesspalace.tusky.db.AccountEntity
|
||||||
|
@ -12,7 +14,6 @@ import com.keylesspalace.tusky.entity.Status
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.keylesspalace.tusky.repository.*
|
import com.keylesspalace.tusky.repository.*
|
||||||
import com.keylesspalace.tusky.util.Either
|
import com.keylesspalace.tusky.util.Either
|
||||||
import com.keylesspalace.tusky.util.HtmlConverter
|
|
||||||
import com.nhaarman.mockitokotlin2.isNull
|
import com.nhaarman.mockitokotlin2.isNull
|
||||||
import com.nhaarman.mockitokotlin2.verify
|
import com.nhaarman.mockitokotlin2.verify
|
||||||
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
||||||
|
@ -24,14 +25,18 @@ import io.reactivex.schedulers.TestScheduler
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentMatchers.any
|
import org.mockito.ArgumentMatchers.any
|
||||||
import org.mockito.ArgumentMatchers.anyInt
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
@Config(sdk = [28])
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
class TimelineRepositoryTest {
|
class TimelineRepositoryTest {
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var timelineDao: TimelineDao
|
lateinit var timelineDao: TimelineDao
|
||||||
|
@ -56,15 +61,6 @@ class TimelineRepositoryTest {
|
||||||
domain = "domain.com",
|
domain = "domain.com",
|
||||||
isActive = true
|
isActive = true
|
||||||
)
|
)
|
||||||
private val htmlConverter = object : HtmlConverter {
|
|
||||||
override fun fromHtml(html: String): Spanned {
|
|
||||||
return SpanUtilsTest.FakeSpannable(html)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toHtml(text: Spanned): String {
|
|
||||||
return text.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
@ -74,8 +70,7 @@ class TimelineRepositoryTest {
|
||||||
gson = Gson()
|
gson = Gson()
|
||||||
testScheduler = TestScheduler()
|
testScheduler = TestScheduler()
|
||||||
RxJavaPlugins.setIoSchedulerHandler { testScheduler }
|
RxJavaPlugins.setIoSchedulerHandler { testScheduler }
|
||||||
subject = TimelineRepositoryImpl(timelineDao, mastodonApi, accountManager, gson,
|
subject = TimelineRepositoryImpl(timelineDao, mastodonApi, accountManager, gson)
|
||||||
htmlConverter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -97,7 +92,7 @@ class TimelineRepositoryTest {
|
||||||
verify(timelineDao).insertStatusIfNotThere(Placeholder("1").toEntity(account.id))
|
verify(timelineDao).insertStatusIfNotThere(Placeholder("1").toEntity(account.id))
|
||||||
for (status in statuses) {
|
for (status in statuses) {
|
||||||
verify(timelineDao).insertInTransaction(
|
verify(timelineDao).insertInTransaction(
|
||||||
status.toEntity(account.id, htmlConverter, gson),
|
status.toEntity(account.id, gson),
|
||||||
status.account.toEntity(account.id, gson),
|
status.account.toEntity(account.id, gson),
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
@ -129,7 +124,7 @@ class TimelineRepositoryTest {
|
||||||
// We assume for now that overlapped one is inserted but it's not that important
|
// We assume for now that overlapped one is inserted but it's not that important
|
||||||
for (status in response) {
|
for (status in response) {
|
||||||
verify(timelineDao).insertInTransaction(
|
verify(timelineDao).insertInTransaction(
|
||||||
status.toEntity(account.id, htmlConverter, gson),
|
status.toEntity(account.id, gson),
|
||||||
status.account.toEntity(account.id, gson),
|
status.account.toEntity(account.id, gson),
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
@ -159,7 +154,7 @@ class TimelineRepositoryTest {
|
||||||
verify(timelineDao).deleteRange(account.id, response.last().id, response.first().id)
|
verify(timelineDao).deleteRange(account.id, response.last().id, response.first().id)
|
||||||
for (status in response) {
|
for (status in response) {
|
||||||
verify(timelineDao).insertInTransaction(
|
verify(timelineDao).insertInTransaction(
|
||||||
status.toEntity(account.id, htmlConverter, gson),
|
status.toEntity(account.id, gson),
|
||||||
status.account.toEntity(account.id, gson),
|
status.account.toEntity(account.id, gson),
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
@ -201,7 +196,7 @@ class TimelineRepositoryTest {
|
||||||
// We assume for now that overlapped one is inserted but it's not that important
|
// We assume for now that overlapped one is inserted but it's not that important
|
||||||
for (status in response) {
|
for (status in response) {
|
||||||
verify(timelineDao).insertInTransaction(
|
verify(timelineDao).insertInTransaction(
|
||||||
status.toEntity(account.id, htmlConverter, gson),
|
status.toEntity(account.id, gson),
|
||||||
status.account.toEntity(account.id, gson),
|
status.account.toEntity(account.id, gson),
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
@ -246,7 +241,7 @@ class TimelineRepositoryTest {
|
||||||
|
|
||||||
for (status in response) {
|
for (status in response) {
|
||||||
verify(timelineDao).insertInTransaction(
|
verify(timelineDao).insertInTransaction(
|
||||||
status.toEntity(account.id, htmlConverter, gson),
|
status.toEntity(account.id, gson),
|
||||||
status.account.toEntity(account.id, gson),
|
status.account.toEntity(account.id, gson),
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
@ -263,7 +258,7 @@ class TimelineRepositoryTest {
|
||||||
val status = makeStatus("2")
|
val status = makeStatus("2")
|
||||||
val dbStatus = makeStatus("1")
|
val dbStatus = makeStatus("1")
|
||||||
val dbResult = TimelineStatusWithAccount()
|
val dbResult = TimelineStatusWithAccount()
|
||||||
dbResult.status = dbStatus.toEntity(account.id, htmlConverter, gson)
|
dbResult.status = dbStatus.toEntity(account.id, gson)
|
||||||
dbResult.account = status.account.toEntity(account.id, gson)
|
dbResult.account = status.account.toEntity(account.id, gson)
|
||||||
|
|
||||||
whenever(mastodonApi.homeTimelineSingle(any(), any(), any()))
|
whenever(mastodonApi.homeTimelineSingle(any(), any(), any()))
|
||||||
|
@ -297,7 +292,7 @@ class TimelineRepositoryTest {
|
||||||
return Status(
|
return Status(
|
||||||
id = id,
|
id = id,
|
||||||
account = account,
|
account = account,
|
||||||
content = SpanUtilsTest.FakeSpannable("hello$id"),
|
content = SpannableString("hello$id"),
|
||||||
createdAt = Date(),
|
createdAt = Date(),
|
||||||
emojis = listOf(),
|
emojis = listOf(),
|
||||||
reblogsCount = 3,
|
reblogsCount = 3,
|
||||||
|
@ -314,6 +309,7 @@ class TimelineRepositoryTest {
|
||||||
inReplyToAccountId = null,
|
inReplyToAccountId = null,
|
||||||
inReplyToId = null,
|
inReplyToId = null,
|
||||||
pinned = false,
|
pinned = false,
|
||||||
|
muted = false,
|
||||||
reblog = null,
|
reblog = null,
|
||||||
url = "http://example.com/statuses/$id",
|
url = "http://example.com/statuses/$id",
|
||||||
poll = null,
|
poll = null,
|
||||||
|
@ -328,7 +324,7 @@ class TimelineRepositoryTest {
|
||||||
localUsername = "test$id",
|
localUsername = "test$id",
|
||||||
username = "test$id@example.com",
|
username = "test$id@example.com",
|
||||||
displayName = "Example Account $id",
|
displayName = "Example Account $id",
|
||||||
note = SpanUtilsTest.FakeSpannable("Note! $id"),
|
note = SpannableString("Note! $id"),
|
||||||
url = "https://example.com/@test$id",
|
url = "https://example.com/@test$id",
|
||||||
avatar = "avatar$id",
|
avatar = "avatar$id",
|
||||||
header = "Header$id",
|
header = "Header$id",
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.61'
|
ext.kotlin_version = '1.3.71'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
classpath 'com.android.tools.build:gradle:3.6.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Un client per a diversos comptes per a la xarxa social Mastodont
|
Un client multicomptes per a la xarxa social Mastodont
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue