forked from mirrors/Fedilab
Merge branch 'develop' into main
This commit is contained in:
commit
92a9479c95
85 changed files with 2866 additions and 2098 deletions
|
@ -1,7 +1,7 @@
|
|||
[![Translation status](https://hosted.weblate.org/widgets/fedilab/-/strings/svg-badge.svg)](https://hosted.weblate.org/engage/fedilab/)
|
||||
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
|
||||
# Fedilab is a multi-accounts client for Mastodon, Pleroma, Peertube, GNU Social, Friendica and Pixelfed
|
||||
# Fedilab is a multi-accounts client for Mastodon, Pleroma, Friendica and Pixelfed
|
||||
|
||||
## Donate
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
[WIKI](https://fedilab.app/wiki/home/)
|
||||
|
||||
[Release notes](https://framagit.org/tom79/fedilab/tags)
|
||||
[Release notes](https://codeberg.org/tom79/Fedilab/tags)
|
||||
|
||||
Lead developer: [toot.fedilab.app/@apps](https://toot.fedilab.app/@apps)
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ android {
|
|||
defaultConfig {
|
||||
minSdk 21
|
||||
targetSdk 31
|
||||
versionCode 396
|
||||
versionName "3.0.6"
|
||||
versionCode 399
|
||||
versionName "3.0.9"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
flavorDimensions "default"
|
||||
|
@ -85,11 +85,9 @@ dependencies {
|
|||
implementation 'com.github.GrenderG:Toasty:1.5.2'
|
||||
implementation 'org.framagit.tom79:SparkButton:1.0.13'
|
||||
implementation "com.github.bumptech.glide:glide:4.12.0"
|
||||
implementation "com.github.bumptech.glide:okhttp3-integration:4.12.0"
|
||||
|
||||
implementation 'com.github.mergehez:ArgPlayer:v3.1'
|
||||
implementation ("com.github.bumptech.glide:recyclerview-integration:4.12.0") {
|
||||
// Excludes the support library because it's already included by Glide.
|
||||
transitive = false
|
||||
}
|
||||
implementation project(path: ':mytransl')
|
||||
implementation project(path: ':ratethisapp')
|
||||
|
||||
|
@ -99,8 +97,7 @@ dependencies {
|
|||
implementation project(path: ':cropper')
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:4.12.0"
|
||||
implementation 'jp.wasabeef:glide-transformations:4.3.0'
|
||||
implementation 'com.github.penfeizhou.android.animation:apng:2.22.0'
|
||||
implementation 'com.github.penfeizhou.android.animation:gif:2.22.0'
|
||||
implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.22.0'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
|
||||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||
implementation 'com.github.piasy:rxandroidaudio:1.7.0'
|
||||
|
|
730
app/src/main/assets/languages/iso_639_1.json
Normal file
730
app/src/main/assets/languages/iso_639_1.json
Normal file
|
@ -0,0 +1,730 @@
|
|||
[
|
||||
{
|
||||
"code": "aa",
|
||||
"language": "Afaraf"
|
||||
},
|
||||
{
|
||||
"code": "ab",
|
||||
"language": "аҧсуа бызшәа"
|
||||
},
|
||||
{
|
||||
"code": "ae",
|
||||
"language": "avesta"
|
||||
},
|
||||
{
|
||||
"code": "af",
|
||||
"language": "Afrikaans"
|
||||
},
|
||||
{
|
||||
"code": "ak",
|
||||
"language": "Akan"
|
||||
},
|
||||
{
|
||||
"code": "am",
|
||||
"language": "አማርኛ"
|
||||
},
|
||||
{
|
||||
"code": "an",
|
||||
"language": "aragonés"
|
||||
},
|
||||
{
|
||||
"code": "ar",
|
||||
"language": "اللغة العربية"
|
||||
},
|
||||
{
|
||||
"code": "as",
|
||||
"language": "অসমীয়া"
|
||||
},
|
||||
{
|
||||
"code": "av",
|
||||
"language": "авар мацӀ"
|
||||
},
|
||||
{
|
||||
"code": "ay",
|
||||
"language": "aymar aru"
|
||||
},
|
||||
{
|
||||
"code": "az",
|
||||
"language": "azərbaycan dili"
|
||||
},
|
||||
{
|
||||
"code": "ba",
|
||||
"language": "башҡорт теле"
|
||||
},
|
||||
{
|
||||
"code": "be",
|
||||
"language": "беларуская мова"
|
||||
},
|
||||
{
|
||||
"code": "bg",
|
||||
"language": "български език"
|
||||
},
|
||||
{
|
||||
"code": "bh",
|
||||
"language": "भोजपुरी"
|
||||
},
|
||||
{
|
||||
"code": "bi",
|
||||
"language": "Bislama"
|
||||
},
|
||||
{
|
||||
"code": "bm",
|
||||
"language": "bamanankan"
|
||||
},
|
||||
{
|
||||
"code": "bn",
|
||||
"language": "বাংলা"
|
||||
},
|
||||
{
|
||||
"code": "bo",
|
||||
"language": "བོད་ཡིག"
|
||||
},
|
||||
{
|
||||
"code": "br",
|
||||
"language": "brezhoneg"
|
||||
},
|
||||
{
|
||||
"code": "bs",
|
||||
"language": "bosanski jezik"
|
||||
},
|
||||
{
|
||||
"code": "ca",
|
||||
"language": "Català"
|
||||
},
|
||||
{
|
||||
"code": "ce",
|
||||
"language": "нохчийн мотт"
|
||||
},
|
||||
{
|
||||
"code": "ch",
|
||||
"language": "Chamoru"
|
||||
},
|
||||
{
|
||||
"code": "co",
|
||||
"language": "corsu"
|
||||
},
|
||||
{
|
||||
"code": "cr",
|
||||
"language": "ᓀᐦᐃᔭᐍᐏᐣ"
|
||||
},
|
||||
{
|
||||
"code": "cs",
|
||||
"language": "čeština"
|
||||
},
|
||||
{
|
||||
"code": "cu",
|
||||
"language": "ѩзыкъ словѣньскъ"
|
||||
},
|
||||
{
|
||||
"code": "cv",
|
||||
"language": "чӑваш чӗлхи"
|
||||
},
|
||||
{
|
||||
"code": "cy",
|
||||
"language": "Cymraeg"
|
||||
},
|
||||
{
|
||||
"code": "da",
|
||||
"language": "dansk"
|
||||
},
|
||||
{
|
||||
"code": "de",
|
||||
"language": "Deutsch"
|
||||
},
|
||||
{
|
||||
"code": "dv",
|
||||
"language": "Dhivehi"
|
||||
},
|
||||
{
|
||||
"code": "dz",
|
||||
"language": "རྫོང་ཁ"
|
||||
},
|
||||
{
|
||||
"code": "ee",
|
||||
"language": "Eʋegbe"
|
||||
},
|
||||
{
|
||||
"code": "el",
|
||||
"language": "Ελληνικά"
|
||||
},
|
||||
{
|
||||
"code": "en",
|
||||
"language": "English"
|
||||
},
|
||||
{
|
||||
"code": "eo",
|
||||
"language": "Esperanto"
|
||||
},
|
||||
{
|
||||
"code": "es",
|
||||
"language": "Español"
|
||||
},
|
||||
{
|
||||
"code": "et",
|
||||
"language": "eesti"
|
||||
},
|
||||
{
|
||||
"code": "eu",
|
||||
"language": "euskara"
|
||||
},
|
||||
{
|
||||
"code": "fa",
|
||||
"language": "فارسی"
|
||||
},
|
||||
{
|
||||
"code": "ff",
|
||||
"language": "Fulfulde"
|
||||
},
|
||||
{
|
||||
"code": "fi",
|
||||
"language": "suomi"
|
||||
},
|
||||
{
|
||||
"code": "fj",
|
||||
"language": "Vakaviti"
|
||||
},
|
||||
{
|
||||
"code": "fo",
|
||||
"language": "føroyskt"
|
||||
},
|
||||
{
|
||||
"code": "fr",
|
||||
"language": "Français"
|
||||
},
|
||||
{
|
||||
"code": "fy",
|
||||
"language": "Frysk"
|
||||
},
|
||||
{
|
||||
"code": "ga",
|
||||
"language": "Gaeilge"
|
||||
},
|
||||
{
|
||||
"code": "gd",
|
||||
"language": "Gàidhlig"
|
||||
},
|
||||
{
|
||||
"code": "gl",
|
||||
"language": "galego"
|
||||
},
|
||||
{
|
||||
"code": "gu",
|
||||
"language": "ગુજરાતી"
|
||||
},
|
||||
{
|
||||
"code": "gv",
|
||||
"language": "Gaelg"
|
||||
},
|
||||
{
|
||||
"code": "ha",
|
||||
"language": "هَوُسَ"
|
||||
},
|
||||
{
|
||||
"code": "he",
|
||||
"language": "עברית"
|
||||
},
|
||||
{
|
||||
"code": "hi",
|
||||
"language": "हिन्दी"
|
||||
},
|
||||
{
|
||||
"code": "ho",
|
||||
"language": "Hiri Motu"
|
||||
},
|
||||
{
|
||||
"code": "hr",
|
||||
"language": "Hrvatski"
|
||||
},
|
||||
{
|
||||
"code": "ht",
|
||||
"language": "Kreyòl ayisyen"
|
||||
},
|
||||
{
|
||||
"code": "hu",
|
||||
"language": "magyar"
|
||||
},
|
||||
{
|
||||
"code": "hy",
|
||||
"language": "Հայերեն"
|
||||
},
|
||||
{
|
||||
"code": "hz",
|
||||
"language": "Otjiherero"
|
||||
},
|
||||
{
|
||||
"code": "ia",
|
||||
"language": "Interlingua"
|
||||
},
|
||||
{
|
||||
"code": "id",
|
||||
"language": "Bahasa Indonesia"
|
||||
},
|
||||
{
|
||||
"code": "ie",
|
||||
"language": "Interlingue"
|
||||
},
|
||||
{
|
||||
"code": "ig",
|
||||
"language": "Asụsụ Igbo"
|
||||
},
|
||||
{
|
||||
"code": "ii",
|
||||
"language": "ꆈꌠ꒿ Nuosuhxop"
|
||||
},
|
||||
{
|
||||
"code": "ik",
|
||||
"language": "Iñupiaq"
|
||||
},
|
||||
{
|
||||
"code": "io",
|
||||
"language": "Ido"
|
||||
},
|
||||
{
|
||||
"code": "is",
|
||||
"language": "Íslenska"
|
||||
},
|
||||
{
|
||||
"code": "it",
|
||||
"language": "Italiano"
|
||||
},
|
||||
{
|
||||
"code": "iu",
|
||||
"language": "ᐃᓄᒃᑎᑐᑦ"
|
||||
},
|
||||
{
|
||||
"code": "ja",
|
||||
"language": "日本語"
|
||||
},
|
||||
{
|
||||
"code": "jv",
|
||||
"language": "basa Jawa"
|
||||
},
|
||||
{
|
||||
"code": "ka",
|
||||
"language": "ქართული"
|
||||
},
|
||||
{
|
||||
"code": "kg",
|
||||
"language": "Kikongo"
|
||||
},
|
||||
{
|
||||
"code": "ki",
|
||||
"language": "Gĩkũyũ"
|
||||
},
|
||||
{
|
||||
"code": "kj",
|
||||
"language": "Kuanyama"
|
||||
},
|
||||
{
|
||||
"code": "kk",
|
||||
"language": "қазақ тілі"
|
||||
},
|
||||
{
|
||||
"code": "kl",
|
||||
"language": "kalaallisut"
|
||||
},
|
||||
{
|
||||
"code": "km",
|
||||
"language": "ខេមរភាសា"
|
||||
},
|
||||
{
|
||||
"code": "kn",
|
||||
"language": "ಕನ್ನಡ"
|
||||
},
|
||||
{
|
||||
"code": "ko",
|
||||
"language": "한국어"
|
||||
},
|
||||
{
|
||||
"code": "kr",
|
||||
"language": "Kanuri"
|
||||
},
|
||||
{
|
||||
"code": "ks",
|
||||
"language": "कश्मीरी"
|
||||
},
|
||||
{
|
||||
"code": "ku",
|
||||
"language": "Kurmancî"
|
||||
},
|
||||
{
|
||||
"code": "kv",
|
||||
"language": "коми кыв"
|
||||
},
|
||||
{
|
||||
"code": "kw",
|
||||
"language": "Kernewek"
|
||||
},
|
||||
{
|
||||
"code": "ky",
|
||||
"language": "Кыргызча"
|
||||
},
|
||||
{
|
||||
"code": "la",
|
||||
"language": "latine"
|
||||
},
|
||||
{
|
||||
"code": "lb",
|
||||
"language": "Lëtzebuergesch"
|
||||
},
|
||||
{
|
||||
"code": "lg",
|
||||
"language": "Luganda"
|
||||
},
|
||||
{
|
||||
"code": "li",
|
||||
"language": "Limburgs"
|
||||
},
|
||||
{
|
||||
"code": "ln",
|
||||
"language": "Lingála"
|
||||
},
|
||||
{
|
||||
"code": "lo",
|
||||
"language": "ພາສາ"
|
||||
},
|
||||
{
|
||||
"code": "lt",
|
||||
"language": "lietuvių kalba"
|
||||
},
|
||||
{
|
||||
"code": "lu",
|
||||
"language": "Tshiluba"
|
||||
},
|
||||
{
|
||||
"code": "lv",
|
||||
"language": "latviešu valoda"
|
||||
},
|
||||
{
|
||||
"code": "mg",
|
||||
"language": "fiteny malagasy"
|
||||
},
|
||||
{
|
||||
"code": "mh",
|
||||
"language": "Kajin M̧ajeļ"
|
||||
},
|
||||
{
|
||||
"code": "mi",
|
||||
"language": "te reo Māori"
|
||||
},
|
||||
{
|
||||
"code": "mk",
|
||||
"language": "македонски јазик"
|
||||
},
|
||||
{
|
||||
"code": "ml",
|
||||
"language": "മലയാളം"
|
||||
},
|
||||
{
|
||||
"code": "mn",
|
||||
"language": "Монгол хэл"
|
||||
},
|
||||
{
|
||||
"code": "mr",
|
||||
"language": "मराठी"
|
||||
},
|
||||
{
|
||||
"code": "ms",
|
||||
"language": "Bahasa Melayu"
|
||||
},
|
||||
{
|
||||
"code": "mt",
|
||||
"language": "Malti"
|
||||
},
|
||||
{
|
||||
"code": "my",
|
||||
"language": "ဗမာစာ"
|
||||
},
|
||||
{
|
||||
"code": "na",
|
||||
"language": "Ekakairũ Naoero"
|
||||
},
|
||||
{
|
||||
"code": "nb",
|
||||
"language": "Norsk bokmål"
|
||||
},
|
||||
{
|
||||
"code": "nd",
|
||||
"language": "isiNdebele"
|
||||
},
|
||||
{
|
||||
"code": "ne",
|
||||
"language": "नेपाली"
|
||||
},
|
||||
{
|
||||
"code": "ng",
|
||||
"language": "Owambo"
|
||||
},
|
||||
{
|
||||
"code": "nl",
|
||||
"language": "Nederlands"
|
||||
},
|
||||
{
|
||||
"code": "nn",
|
||||
"language": "Norsk Nynorsk"
|
||||
},
|
||||
{
|
||||
"code": "no",
|
||||
"language": "Norsk"
|
||||
},
|
||||
{
|
||||
"code": "nr",
|
||||
"language": "isiNdebele"
|
||||
},
|
||||
{
|
||||
"code": "nv",
|
||||
"language": "Diné bizaad"
|
||||
},
|
||||
{
|
||||
"code": "ny",
|
||||
"language": "chiCheŵa"
|
||||
},
|
||||
{
|
||||
"code": "oc",
|
||||
"language": "occitan"
|
||||
},
|
||||
{
|
||||
"code": "oj",
|
||||
"language": "ᐊᓂᔑᓈᐯᒧᐎᓐ"
|
||||
},
|
||||
{
|
||||
"code": "om",
|
||||
"language": "Afaan Oromoo"
|
||||
},
|
||||
{
|
||||
"code": "or",
|
||||
"language": "ଓଡ଼ିଆ"
|
||||
},
|
||||
{
|
||||
"code": "os",
|
||||
"language": "ирон æвзаг"
|
||||
},
|
||||
{
|
||||
"code": "pa",
|
||||
"language": "ਪੰਜਾਬੀ"
|
||||
},
|
||||
{
|
||||
"code": "pi",
|
||||
"language": "पाऴि"
|
||||
},
|
||||
{
|
||||
"code": "pl",
|
||||
"language": "Polski"
|
||||
},
|
||||
{
|
||||
"code": "ps",
|
||||
"language": "پښتو"
|
||||
},
|
||||
{
|
||||
"code": "pt",
|
||||
"language": "Português"
|
||||
},
|
||||
{
|
||||
"code": "qu",
|
||||
"language": "Runa Simi"
|
||||
},
|
||||
{
|
||||
"code": "rm",
|
||||
"language": "rumantsch grischun"
|
||||
},
|
||||
{
|
||||
"code": "rn",
|
||||
"language": "Ikirundi"
|
||||
},
|
||||
{
|
||||
"code": "ro",
|
||||
"language": "Română"
|
||||
},
|
||||
{
|
||||
"code": "ru",
|
||||
"language": "Русский"
|
||||
},
|
||||
{
|
||||
"code": "rw",
|
||||
"language": "Ikinyarwanda"
|
||||
},
|
||||
{
|
||||
"code": "sa",
|
||||
"language": "संस्कृतम्"
|
||||
},
|
||||
{
|
||||
"code": "sc",
|
||||
"language": "sardu"
|
||||
},
|
||||
{
|
||||
"code": "sd",
|
||||
"language": "सिन्धी"
|
||||
},
|
||||
{
|
||||
"code": "se",
|
||||
"language": "Davvisámegiella"
|
||||
},
|
||||
{
|
||||
"code": "sg",
|
||||
"language": "yângâ tî sängö"
|
||||
},
|
||||
{
|
||||
"code": "si",
|
||||
"language": "සිංහල"
|
||||
},
|
||||
{
|
||||
"code": "sk",
|
||||
"language": "slovenčina"
|
||||
},
|
||||
{
|
||||
"code": "sl",
|
||||
"language": "slovenščina"
|
||||
},
|
||||
{
|
||||
"code": "sn",
|
||||
"language": "chiShona"
|
||||
},
|
||||
{
|
||||
"code": "so",
|
||||
"language": "Soomaaliga"
|
||||
},
|
||||
{
|
||||
"code": "sq",
|
||||
"language": "Shqip"
|
||||
},
|
||||
{
|
||||
"code": "sr",
|
||||
"language": "српски језик"
|
||||
},
|
||||
{
|
||||
"code": "ss",
|
||||
"language": "SiSwati"
|
||||
},
|
||||
{
|
||||
"code": "st",
|
||||
"language": "Sesotho"
|
||||
},
|
||||
{
|
||||
"code": "su",
|
||||
"language": "Basa Sunda"
|
||||
},
|
||||
{
|
||||
"code": "sv",
|
||||
"language": "Svenska"
|
||||
},
|
||||
{
|
||||
"code": "sw",
|
||||
"language": "Kiswahili"
|
||||
},
|
||||
{
|
||||
"code": "ta",
|
||||
"language": "தமிழ்"
|
||||
},
|
||||
{
|
||||
"code": "te",
|
||||
"language": "తెలుగు"
|
||||
},
|
||||
{
|
||||
"code": "tg",
|
||||
"language": "тоҷикӣ"
|
||||
},
|
||||
{
|
||||
"code": "th",
|
||||
"language": "ไทย"
|
||||
},
|
||||
{
|
||||
"code": "ti",
|
||||
"language": "ትግርኛ"
|
||||
},
|
||||
{
|
||||
"code": "tk",
|
||||
"language": "Türkmen"
|
||||
},
|
||||
{
|
||||
"code": "tl",
|
||||
"language": "Wikang Tagalog"
|
||||
},
|
||||
{
|
||||
"code": "tn",
|
||||
"language": "Setswana"
|
||||
},
|
||||
{
|
||||
"code": "to",
|
||||
"language": "faka Tonga"
|
||||
},
|
||||
{
|
||||
"code": "tr",
|
||||
"language": "Türkçe"
|
||||
},
|
||||
{
|
||||
"code": "ts",
|
||||
"language": "Xitsonga"
|
||||
},
|
||||
{
|
||||
"code": "tt",
|
||||
"language": "татар теле"
|
||||
},
|
||||
{
|
||||
"code": "tw",
|
||||
"language": "Twi"
|
||||
},
|
||||
{
|
||||
"code": "ty",
|
||||
"language": "Reo Tahiti"
|
||||
},
|
||||
{
|
||||
"code": "ug",
|
||||
"language": "ئۇيغۇرچە"
|
||||
},
|
||||
{
|
||||
"code": "uk",
|
||||
"language": "Українська"
|
||||
},
|
||||
{
|
||||
"code": "ur",
|
||||
"language": "اردو"
|
||||
},
|
||||
{
|
||||
"code": "uz",
|
||||
"language": "Ўзбек"
|
||||
},
|
||||
{
|
||||
"code": "ve",
|
||||
"language": "Tshivenḓa"
|
||||
},
|
||||
{
|
||||
"code": "vi",
|
||||
"language": "Tiếng Việt"
|
||||
},
|
||||
{
|
||||
"code": "vo",
|
||||
"language": "Volapük"
|
||||
},
|
||||
{
|
||||
"code": "wa",
|
||||
"language": "walon"
|
||||
},
|
||||
{
|
||||
"code": "wo",
|
||||
"language": "Wollof"
|
||||
},
|
||||
{
|
||||
"code": "xh",
|
||||
"language": "isiXhosa"
|
||||
},
|
||||
{
|
||||
"code": "yi",
|
||||
"language": "ייִדיש"
|
||||
},
|
||||
{
|
||||
"code": "yo",
|
||||
"language": "Yorùbá"
|
||||
},
|
||||
{
|
||||
"code": "za",
|
||||
"language": "Saɯ cueŋƅ"
|
||||
},
|
||||
{
|
||||
"code": "zh",
|
||||
"language": "中文"
|
||||
},
|
||||
{
|
||||
"code": "zu",
|
||||
"language": "isiZulu"
|
||||
}
|
||||
]
|
|
@ -8,7 +8,7 @@
|
|||
"accent": "#FF2b90d9",
|
||||
"accent_dark": "#FF1b80c9",
|
||||
"accent_light": "#FF772b90d9",
|
||||
"background": "#FF121212",
|
||||
"background": "#FF272727",
|
||||
"background_dark": "#FF282c37",
|
||||
"background_light": "#FF282c37",
|
||||
"should_tint_statusbar": true,
|
||||
|
|
|
@ -537,7 +537,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
|||
headerMainBinding.ownerAccounts.setImageResource(R.drawable.ic_baseline_arrow_drop_up_24);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<BaseAccount> accounts = new Account(BaseMainActivity.this).getAll();
|
||||
List<BaseAccount> accounts = new Account(BaseMainActivity.this).getCrossAccounts();
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
binding.navView.getMenu().clear();
|
||||
|
@ -772,7 +772,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
|||
currentAccount.mastodon_account.display_name = currentAccount.mastodon_account.acct;
|
||||
}
|
||||
headerMainBinding.accountName.setText(currentAccount.mastodon_account.display_name);
|
||||
Helper.loadPP(headerMainBinding.accountProfilePicture, currentAccount);
|
||||
Helper.loadPP(headerMainBinding.accountProfilePicture, currentAccount, false);
|
||||
MastodonHelper.loadProfileMediaMastodon(headerMainBinding.backgroundImage, currentAccount.mastodon_account, MastodonHelper.MediaAccountType.HEADER);
|
||||
/*
|
||||
* Some general data are loaded when the app starts such;
|
||||
|
@ -786,7 +786,12 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
|||
new ViewModelProvider(BaseMainActivity.this).get(InstancesVM.class).getEmoji(currentInstance);
|
||||
//Retrieve instance info
|
||||
new ViewModelProvider(BaseMainActivity.this).get(InstancesVM.class).getInstance(currentInstance)
|
||||
.observe(BaseMainActivity.this, instance -> instanceInfo = instance.info);
|
||||
.observe(BaseMainActivity.this, instance -> {
|
||||
instanceInfo = instance.info;
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
editor.putString(getString(R.string.INSTANCE_INFO) + MainActivity.currentInstance, Instance.serialize(instanceInfo));
|
||||
editor.apply();
|
||||
});
|
||||
//Retrieve filters
|
||||
new ViewModelProvider(BaseMainActivity.this).get(AccountsVM.class).getFilters(currentInstance, currentToken)
|
||||
.observe(BaseMainActivity.this, filters -> mainFilters = filters);
|
||||
|
@ -850,7 +855,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
|||
binding.toolbarSearch.setOnSearchClickListener(v -> binding.tabLayout.setVisibility(View.VISIBLE));
|
||||
//For receiving data from other activities
|
||||
LocalBroadcastManager.getInstance(BaseMainActivity.this).registerReceiver(broadcast_data, new IntentFilter(Helper.BROADCAST_DATA));
|
||||
if (emojis == null || !emojis.containsKey(BaseMainActivity.currentInstance)) {
|
||||
if (emojis == null || !emojis.containsKey(BaseMainActivity.currentInstance) || emojis.get(BaseMainActivity.currentInstance) == null) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
emojis.put(currentInstance, new EmojiInstance(BaseMainActivity.this).getEmojiList(BaseMainActivity.currentInstance));
|
||||
|
@ -1059,11 +1064,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
public void redrawPinned(List<MastodonList> mastodonLists) {
|
||||
int currentItem = binding.viewPager.getCurrentItem();
|
||||
new ViewModelProvider(BaseMainActivity.this).get(TopBarVM.class).getDBPinned()
|
||||
|
|
|
@ -22,8 +22,6 @@ import android.content.SharedPreferences;
|
|||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
|
@ -46,6 +44,7 @@ import com.bumptech.glide.Glide;
|
|||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -105,14 +104,7 @@ public class AdminAccountActivity extends BaseActivity {
|
|||
}
|
||||
binding.toolbar.setPopupTheme(Helper.popupStyle());
|
||||
if (account != null) {
|
||||
new Thread(() -> {
|
||||
account = SpannableHelper.convertAccount(AdminAccountActivity.this, account);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> initializeView(account);
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
}).start();
|
||||
|
||||
initializeView(account);
|
||||
} else {
|
||||
Toasty.error(AdminAccountActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
|
@ -314,7 +306,10 @@ public class AdminAccountActivity extends BaseActivity {
|
|||
}
|
||||
|
||||
|
||||
binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE);
|
||||
binding.accountDn.setText(
|
||||
account.getSpanDisplayName(AdminAccountActivity.this,
|
||||
new WeakReference<>(binding.accountDn)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
binding.accountUn.setText(String.format("@%s", account.acct));
|
||||
binding.accountUn.setOnLongClickListener(v -> {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
|
|
|
@ -22,8 +22,6 @@ import android.content.SharedPreferences;
|
|||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
|
@ -46,6 +44,7 @@ import com.bumptech.glide.Glide;
|
|||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -105,14 +104,7 @@ public class AdminReportActivity extends BaseActivity {
|
|||
}
|
||||
binding.toolbar.setPopupTheme(Helper.popupStyle());
|
||||
if (account != null) {
|
||||
new Thread(() -> {
|
||||
account = SpannableHelper.convertAccount(AdminReportActivity.this, account);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> initializeView(account);
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
}).start();
|
||||
|
||||
initializeView(account);
|
||||
} else {
|
||||
Toasty.error(AdminReportActivity.this, getString(R.string.toast_error_loading_account), Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
|
@ -331,8 +323,10 @@ public class AdminReportActivity extends BaseActivity {
|
|||
binding.accountMoved.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
|
||||
binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE);
|
||||
binding.accountDn.setText(
|
||||
account.getSpanDisplayName(AdminReportActivity.this,
|
||||
new WeakReference<>(binding.accountDn)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
binding.accountUn.setText(String.format("@%s", account.acct));
|
||||
binding.accountUn.setOnLongClickListener(v -> {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.content.BroadcastReceiver;
|
|||
import android.content.ClipData;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.net.Uri;
|
||||
|
@ -48,6 +49,7 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.work.Data;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
|
@ -69,10 +71,12 @@ import app.fedilab.android.R;
|
|||
import app.fedilab.android.client.entities.api.Attachment;
|
||||
import app.fedilab.android.client.entities.api.Context;
|
||||
import app.fedilab.android.client.entities.api.EmojiInstance;
|
||||
import app.fedilab.android.client.entities.api.Instance;
|
||||
import app.fedilab.android.client.entities.api.Mention;
|
||||
import app.fedilab.android.client.entities.api.ScheduledStatus;
|
||||
import app.fedilab.android.client.entities.api.Status;
|
||||
import app.fedilab.android.client.entities.app.BaseAccount;
|
||||
import app.fedilab.android.client.entities.app.Languages;
|
||||
import app.fedilab.android.client.entities.app.StatusDraft;
|
||||
import app.fedilab.android.databinding.ActivityPaginationBinding;
|
||||
import app.fedilab.android.databinding.PopupContactBinding;
|
||||
|
@ -81,7 +85,6 @@ import app.fedilab.android.helper.DividerDecorationSimple;
|
|||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.MediaHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.helper.ThemeHelper;
|
||||
import app.fedilab.android.interfaces.OnDownloadInterface;
|
||||
import app.fedilab.android.jobs.ScheduleThreadWorker;
|
||||
|
@ -100,7 +103,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
public static final int REQUEST_AUDIO_PERMISSION_RESULT = 1653;
|
||||
public static final int PICK_MEDIA = 5700;
|
||||
public static final int TAKE_PHOTO = 5600;
|
||||
|
||||
private final Timer timer = new Timer();
|
||||
private List<Status> statusList;
|
||||
private Status statusReply, statusMention;
|
||||
private StatusDraft statusDraft;
|
||||
|
@ -234,6 +237,14 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
}
|
||||
}).start();
|
||||
}
|
||||
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ComposeActivity.this);
|
||||
if (MainActivity.instanceInfo == null) {
|
||||
String instanceInfo = sharedpreferences.getString(getString(R.string.INSTANCE_INFO) + instance, null);
|
||||
if (instanceInfo != null) {
|
||||
MainActivity.instanceInfo = Instance.restore(instanceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
StatusesVM statusesVM = new ViewModelProvider(ComposeActivity.this).get(StatusesVM.class);
|
||||
//Empty compose
|
||||
List<Status> statusDraftList = new ArrayList<>();
|
||||
|
@ -257,86 +268,70 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
}
|
||||
});
|
||||
} else if (statusDraft != null) {//Restore a draft with all messages
|
||||
new Thread(() -> {
|
||||
if (statusDraft.statusReplyList != null) {
|
||||
statusDraft.statusReplyList = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusDraft.statusReplyList);
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
if (statusDraft.statusReplyList != null) {
|
||||
statusList.addAll(statusDraft.statusReplyList);
|
||||
binding.recyclerView.addItemDecoration(new DividerDecorationSimple(ComposeActivity.this, statusList));
|
||||
}
|
||||
int statusCount = statusList.size();
|
||||
statusList.addAll(statusDraft.statusDraftList);
|
||||
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility);
|
||||
composeAdapter.manageDrafts = this;
|
||||
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
|
||||
binding.recyclerView.setLayoutManager(mLayoutManager);
|
||||
binding.recyclerView.setAdapter(composeAdapter);
|
||||
binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1);
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
if (statusDraft.statusReplyList != null) {
|
||||
statusList.addAll(statusDraft.statusReplyList);
|
||||
binding.recyclerView.addItemDecoration(new DividerDecorationSimple(ComposeActivity.this, statusList));
|
||||
}
|
||||
int statusCount = statusList.size();
|
||||
statusList.addAll(statusDraft.statusDraftList);
|
||||
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility);
|
||||
composeAdapter.manageDrafts = this;
|
||||
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
|
||||
binding.recyclerView.setLayoutManager(mLayoutManager);
|
||||
binding.recyclerView.setAdapter(composeAdapter);
|
||||
binding.recyclerView.scrollToPosition(composeAdapter.getItemCount() - 1);
|
||||
|
||||
} else if (statusReply != null) {
|
||||
new Thread(() -> {
|
||||
statusReply = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusReply);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
statusList.add(statusReply);
|
||||
int statusCount = statusList.size();
|
||||
statusDraftList.get(0).in_reply_to_id = statusReply.id;
|
||||
//We change order for mentions
|
||||
//At first place the account that has been mentioned if it's not our
|
||||
statusDraftList.get(0).mentions = new ArrayList<>();
|
||||
if (!statusReply.account.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
|
||||
Mention mention = new Mention();
|
||||
mention.acct = "@" + statusReply.account.acct;
|
||||
mention.url = statusReply.account.url;
|
||||
mention.username = statusReply.account.username;
|
||||
statusDraftList.get(0).mentions.add(mention);
|
||||
}
|
||||
statusList.add(statusReply);
|
||||
int statusCount = statusList.size();
|
||||
statusDraftList.get(0).in_reply_to_id = statusReply.id;
|
||||
//We change order for mentions
|
||||
//At first place the account that has been mentioned if it's not our
|
||||
statusDraftList.get(0).mentions = new ArrayList<>();
|
||||
if (statusReply.account.acct != null && !statusReply.account.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
|
||||
Mention mention = new Mention();
|
||||
mention.acct = "@" + statusReply.account.acct;
|
||||
mention.url = statusReply.account.url;
|
||||
mention.username = statusReply.account.username;
|
||||
statusDraftList.get(0).mentions.add(mention);
|
||||
}
|
||||
|
||||
//There are other mentions to
|
||||
if (statusReply.mentions != null && statusReply.mentions.size() > 0) {
|
||||
for (Mention mentionTmp : statusReply.mentions) {
|
||||
if (!mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && !mentionTmp.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
|
||||
statusDraftList.get(0).mentions.add(mentionTmp);
|
||||
}
|
||||
}
|
||||
//There are other mentions to
|
||||
if (statusReply.mentions != null && statusReply.mentions.size() > 0) {
|
||||
for (Mention mentionTmp : statusReply.mentions) {
|
||||
if (statusReply.account.acct != null && !mentionTmp.acct.equalsIgnoreCase(statusReply.account.acct) && !mentionTmp.acct.equalsIgnoreCase(currentAccount.mastodon_account.acct)) {
|
||||
statusDraftList.get(0).mentions.add(mentionTmp);
|
||||
}
|
||||
if (mentionBooster != null) {
|
||||
Mention mention = new Mention();
|
||||
mention.acct = mentionBooster.acct;
|
||||
mention.url = mentionBooster.url;
|
||||
mention.username = mentionBooster.username;
|
||||
boolean present = false;
|
||||
for (Mention mentionTmp : statusDraftList.get(0).mentions) {
|
||||
if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) {
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!present) {
|
||||
statusDraftList.get(0).mentions.add(mention);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mentionBooster != null) {
|
||||
Mention mention = new Mention();
|
||||
mention.acct = mentionBooster.acct;
|
||||
mention.url = mentionBooster.url;
|
||||
mention.username = mentionBooster.username;
|
||||
boolean present = false;
|
||||
for (Mention mentionTmp : statusDraftList.get(0).mentions) {
|
||||
if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) {
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
if (statusReply.spoiler_text != null) {
|
||||
statusDraftList.get(0).spoiler_text = statusReply.spoiler_text;
|
||||
}
|
||||
//StatusDraftList at this point should only have one element
|
||||
statusList.addAll(statusDraftList);
|
||||
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility);
|
||||
composeAdapter.manageDrafts = this;
|
||||
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
|
||||
binding.recyclerView.setLayoutManager(mLayoutManager);
|
||||
binding.recyclerView.setAdapter(composeAdapter);
|
||||
statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReply.id)
|
||||
.observe(ComposeActivity.this, this::initializeContextView);
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
}
|
||||
if (!present) {
|
||||
statusDraftList.get(0).mentions.add(mention);
|
||||
}
|
||||
}
|
||||
if (statusReply.spoiler_text != null) {
|
||||
statusDraftList.get(0).spoiler_text = statusReply.spoiler_text;
|
||||
}
|
||||
//StatusDraftList at this point should only have one element
|
||||
statusList.addAll(statusDraftList);
|
||||
composeAdapter = new ComposeAdapter(statusList, statusCount, account, accountMention, visibility);
|
||||
composeAdapter.manageDrafts = this;
|
||||
LinearLayoutManager mLayoutManager = new LinearLayoutManager(ComposeActivity.this);
|
||||
binding.recyclerView.setLayoutManager(mLayoutManager);
|
||||
binding.recyclerView.setAdapter(composeAdapter);
|
||||
statusesVM.getContext(currentInstance, BaseMainActivity.currentToken, statusReply.id)
|
||||
.observe(ComposeActivity.this, this::initializeContextView);
|
||||
} else {
|
||||
//Compose without replying
|
||||
statusList.addAll(statusDraftList);
|
||||
|
@ -348,19 +343,20 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
if (statusMention != null) {
|
||||
composeAdapter.loadMentions(statusMention);
|
||||
}
|
||||
|
||||
}
|
||||
MastodonHelper.loadPPMastodon(binding.profilePicture, account.mastodon_account);
|
||||
LocalBroadcastManager.getInstance(this)
|
||||
.registerReceiver(imageReceiver,
|
||||
new IntentFilter(Helper.INTENT_SEND_MODIFIED_IMAGE));
|
||||
|
||||
new Timer().scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
storeDraft(false);
|
||||
}
|
||||
}, 0, 10000);
|
||||
if (timer != null) {
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
storeDraft(false);
|
||||
}
|
||||
}, 0, 10000);
|
||||
}
|
||||
|
||||
if (sharedUriList != null && sharedUriList.size() > 0) {
|
||||
|
||||
|
@ -395,6 +391,9 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
}
|
||||
LocalBroadcastManager.getInstance(this)
|
||||
.unregisterReceiver(imageReceiver);
|
||||
}
|
||||
|
@ -579,6 +578,46 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
} else {
|
||||
Toasty.info(ComposeActivity.this, getString(R.string.toot_error_no_content), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
} else if (item.getItemId() == R.id.action_language) {
|
||||
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ComposeActivity.this);
|
||||
List<Languages.Language> languages = Languages.get(ComposeActivity.this);
|
||||
String[] codesArr = new String[0];
|
||||
String[] languagesArr = new String[0];
|
||||
|
||||
String currentCode = sharedpreferences.getString(getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, null);
|
||||
int selection = 0;
|
||||
|
||||
if (languages != null) {
|
||||
codesArr = new String[languages.size()];
|
||||
languagesArr = new String[languages.size()];
|
||||
int i = 0;
|
||||
for (Languages.Language language : languages) {
|
||||
codesArr[i] = language.code;
|
||||
languagesArr[i] = language.language;
|
||||
if (currentCode != null && currentCode.equalsIgnoreCase(language.code)) {
|
||||
selection = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ComposeActivity.this, Helper.dialogStyle());
|
||||
builder.setTitle(getString(R.string.message_language));
|
||||
|
||||
builder.setSingleChoiceItems(languagesArr, selection, null);
|
||||
String[] finalCodesArr = codesArr;
|
||||
builder.setPositiveButton(R.string.validate, (dialog, which) -> {
|
||||
int selectedPosition = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
editor.putString(getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, finalCodesArr[selectedPosition]);
|
||||
editor.apply();
|
||||
dialog.dismiss();
|
||||
});
|
||||
builder.setNegativeButton(R.string.reset, (dialog, which) -> {
|
||||
editor.putString(getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, null);
|
||||
editor.apply();
|
||||
dialog.dismiss();
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -667,6 +706,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
} else {
|
||||
statusReplies.add(status);
|
||||
}
|
||||
|
||||
}
|
||||
if (statusDraft == null) {
|
||||
statusDraft = new StatusDraft(ComposeActivity.this);
|
||||
|
@ -677,10 +717,12 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
}
|
||||
}
|
||||
if (statusReplies.size() > 0) {
|
||||
statusDraft.statusReplyList = statusReplies;
|
||||
statusDraft.statusReplyList = new ArrayList<>();
|
||||
statusDraft.statusReplyList.addAll(statusReplies);
|
||||
}
|
||||
if (statusDrafts.size() > 0) {
|
||||
statusDraft.statusDraftList = statusDrafts;
|
||||
statusDraft.statusDraftList = new ArrayList<>();
|
||||
statusDraft.statusDraftList.addAll(statusDrafts);
|
||||
}
|
||||
if (statusDraft.instance == null) {
|
||||
statusDraft.instance = account.instance;
|
||||
|
@ -750,6 +792,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft);
|
||||
intent.putExtra(Helper.ARG_INSTANCE, instance);
|
||||
intent.putExtra(Helper.ARG_TOKEN, token);
|
||||
intent.putExtra(Helper.ARG_USER_ID, account.user_id);
|
||||
intent.putExtra(Helper.ARG_SCHEDULED_DATE, scheduledDate);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(intent);
|
||||
|
@ -757,7 +800,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
|||
startService(intent);
|
||||
}
|
||||
} else {
|
||||
new ThreadMessageService(ComposeActivity.this, instance, token, statusDraft, scheduledDate);
|
||||
new ThreadMessageService(ComposeActivity.this, instance, account.user_id, token, statusDraft, scheduledDate);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ import app.fedilab.android.databinding.ActivityConversationBinding;
|
|||
import app.fedilab.android.exception.DBException;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.helper.ThemeHelper;
|
||||
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonContext;
|
||||
import app.fedilab.android.viewmodel.mastodon.StatusesVM;
|
||||
|
@ -82,21 +81,14 @@ public class ContextActivity extends BaseActivity {
|
|||
focusedStatus = null; // or other values
|
||||
if (b != null)
|
||||
focusedStatus = (Status) b.getSerializable(Helper.ARG_STATUS);
|
||||
if (focusedStatus == null && currentAccount == null || currentAccount.mastodon_account == null) {
|
||||
if (focusedStatus == null || currentAccount == null || currentAccount.mastodon_account == null) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account);
|
||||
Bundle bundle = new Bundle();
|
||||
new Thread(() -> {
|
||||
focusedStatus = SpannableHelper.convertStatus(getApplication().getApplicationContext(), focusedStatus);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
bundle.putSerializable(Helper.ARG_STATUS, focusedStatus);
|
||||
currentFragment = Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_content_main, new FragmentMastodonContext(), bundle, null, null);
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
bundle.putSerializable(Helper.ARG_STATUS, focusedStatus);
|
||||
currentFragment = Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_content_main, new FragmentMastodonContext(), bundle, null, null);
|
||||
StatusesVM timelinesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class);
|
||||
timelinesVM.getStatus(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, focusedStatus.id).observe(ContextActivity.this, status -> {
|
||||
if (status != null) {
|
||||
|
@ -168,10 +160,4 @@ public class ContextActivity extends BaseActivity {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
currentFragment = null;
|
||||
}
|
||||
}
|
|
@ -205,12 +205,6 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding.lvStatus.setAdapter(null);
|
||||
binding = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllDeleted() {
|
||||
|
|
|
@ -294,7 +294,6 @@ public class MediaActivity extends BaseActivity implements OnDownloadInterface {
|
|||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
binding = null;
|
||||
unregisterReceiver(onDownloadComplete);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
|
|
@ -27,11 +27,7 @@ import android.content.SharedPreferences;
|
|||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
|
@ -64,6 +60,7 @@ import com.bumptech.glide.request.target.CustomTarget;
|
|||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -148,8 +145,6 @@ public class ProfileActivity extends BaseActivity {
|
|||
account_id = b.getString(Helper.ARG_USER_ID, null);
|
||||
mention_str = b.getString(Helper.ARG_MENTION, null);
|
||||
}
|
||||
|
||||
|
||||
postponeEnterTransition();
|
||||
|
||||
//Remove title
|
||||
|
@ -165,14 +160,7 @@ public class ProfileActivity extends BaseActivity {
|
|||
binding.toolbar.setPopupTheme(Helper.popupStyle());
|
||||
accountsVM = new ViewModelProvider(ProfileActivity.this).get(AccountsVM.class);
|
||||
if (account != null) {
|
||||
new Thread(() -> {
|
||||
account = SpannableHelper.convertAccount(ProfileActivity.this, account);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> initializeView(account);
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
}).start();
|
||||
|
||||
initializeView(account);
|
||||
} else if (account_id != null) {
|
||||
accountsVM.getAccount(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account_id).observe(ProfileActivity.this, fetchedAccount -> {
|
||||
account = fetchedAccount;
|
||||
|
@ -359,11 +347,11 @@ public class ProfileActivity extends BaseActivity {
|
|||
binding.fieldsContainer.setAdapter(fieldAdapter);
|
||||
binding.fieldsContainer.setLayoutManager(new LinearLayoutManager(ProfileActivity.this));
|
||||
}
|
||||
if (account.span_display_name == null && account.display_name == null) {
|
||||
binding.accountDn.setText(account.username);
|
||||
} else {
|
||||
binding.accountDn.setText(account.span_display_name != null ? account.span_display_name : account.display_name, TextView.BufferType.SPANNABLE);
|
||||
}
|
||||
|
||||
binding.accountDn.setText(
|
||||
account.getSpanDisplayName(ProfileActivity.this,
|
||||
new WeakReference<>(binding.accountDn)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
|
||||
binding.accountUn.setText(String.format("@%s", account.acct));
|
||||
binding.accountUn.setOnLongClickListener(v -> {
|
||||
|
@ -377,12 +365,10 @@ public class ProfileActivity extends BaseActivity {
|
|||
clipboard.setPrimaryClip(clip);
|
||||
return false;
|
||||
});
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
binding.accountNote.setText(account.span_note != null ? account.span_note : new SpannableString(Html.fromHtml(account.note, Html.FROM_HTML_MODE_COMPACT)), TextView.BufferType.SPANNABLE);
|
||||
else
|
||||
binding.accountNote.setText(account.span_note != null ? account.span_note : new SpannableString(Html.fromHtml(account.note)), TextView.BufferType.SPANNABLE);
|
||||
|
||||
binding.accountNote.setText(
|
||||
account.getSpanNote(ProfileActivity.this,
|
||||
new WeakReference<>(binding.accountNote)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
binding.accountNote.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
MastodonHelper.loadPPMastodon(binding.accountPp, account);
|
||||
|
|
|
@ -53,6 +53,7 @@ public class SearchResultTabActivity extends BaseActivity {
|
|||
|
||||
private String search;
|
||||
private ActivitySearchResultTabsBinding binding;
|
||||
private TabLayout.Tab initial;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -77,7 +78,8 @@ public class SearchResultTabActivity extends BaseActivity {
|
|||
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary)));
|
||||
}
|
||||
setTitle(search);
|
||||
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.tags)));
|
||||
initial = binding.searchTabLayout.newTab();
|
||||
binding.searchTabLayout.addTab(initial.setText(getString(R.string.tags)));
|
||||
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.accounts)));
|
||||
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.toots)));
|
||||
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.action_cache)));
|
||||
|
@ -125,7 +127,6 @@ public class SearchResultTabActivity extends BaseActivity {
|
|||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(binding.searchTabLayout.getWindowToken(), 0);
|
||||
query = query.replaceAll("^#+", "");
|
||||
search = query.trim();
|
||||
|
@ -134,6 +135,7 @@ public class SearchResultTabActivity extends BaseActivity {
|
|||
searchView.clearFocus();
|
||||
setTitle(search);
|
||||
searchView.setIconified(true);
|
||||
binding.searchTabLayout.selectTab(initial);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ package app.fedilab.android.activities;
|
|||
|
||||
import static app.fedilab.android.BaseMainActivity.currentAccount;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
@ -62,6 +63,7 @@ public class SettingsActivity extends BaseActivity {
|
|||
}
|
||||
canGoBack = false;
|
||||
|
||||
binding.setAccount.setOnClickListener(v -> displaySettings(SettingsEnum.ACCOUNT));
|
||||
binding.setTimelines.setOnClickListener(v -> displaySettings(SettingsEnum.TIMELINES));
|
||||
binding.setNotifications.setOnClickListener(v -> displaySettings(SettingsEnum.NOTIFICATIONS));
|
||||
binding.setInterface.setOnClickListener(v -> displaySettings(SettingsEnum.INTERFACE));
|
||||
|
@ -79,61 +81,66 @@ public class SettingsActivity extends BaseActivity {
|
|||
|
||||
public void displaySettings(SettingsEnum settingsEnum) {
|
||||
|
||||
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fragmentTransaction =
|
||||
fragmentManager.beginTransaction();
|
||||
String category = "";
|
||||
switch (settingsEnum) {
|
||||
case TIMELINES:
|
||||
FragmentTimelinesSettings fragmentTimelinesSettings = new FragmentTimelinesSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentTimelinesSettings);
|
||||
currentFragment = fragmentTimelinesSettings;
|
||||
category = getString(R.string.settings_category_label_timelines);
|
||||
break;
|
||||
case NOTIFICATIONS:
|
||||
FragmentNotificationsSettings fragmentNotificationsSettings = new FragmentNotificationsSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentNotificationsSettings);
|
||||
currentFragment = fragmentNotificationsSettings;
|
||||
category = getString(R.string.notifications);
|
||||
break;
|
||||
case INTERFACE:
|
||||
FragmentInterfaceSettings fragmentInterfaceSettings = new FragmentInterfaceSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentInterfaceSettings);
|
||||
currentFragment = fragmentInterfaceSettings;
|
||||
category = getString(R.string.settings_category_label_interface);
|
||||
break;
|
||||
case COMPOSE:
|
||||
FragmentComposeSettings fragmentComposeSettings = new FragmentComposeSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentComposeSettings);
|
||||
currentFragment = fragmentComposeSettings;
|
||||
category = getString(R.string.compose);
|
||||
break;
|
||||
case PRIVACY:
|
||||
FragmentPrivacySettings fragmentPrivacySettings = new FragmentPrivacySettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentPrivacySettings);
|
||||
currentFragment = fragmentPrivacySettings;
|
||||
category = getString(R.string.action_privacy);
|
||||
break;
|
||||
case THEMING:
|
||||
FragmentThemingSettings fragmentThemingSettings = new FragmentThemingSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentThemingSettings);
|
||||
currentFragment = fragmentThemingSettings;
|
||||
category = getString(R.string.theming);
|
||||
break;
|
||||
case LANGUAGE:
|
||||
FragmentLanguageSettings fragmentLanguageSettings = new FragmentLanguageSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentLanguageSettings);
|
||||
currentFragment = fragmentLanguageSettings;
|
||||
category = getString(R.string.languages);
|
||||
break;
|
||||
if (settingsEnum == SettingsEnum.ACCOUNT) {
|
||||
Intent intent = new Intent(SettingsActivity.this, EditProfileActivity.class);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fragmentTransaction =
|
||||
fragmentManager.beginTransaction();
|
||||
String category = "";
|
||||
switch (settingsEnum) {
|
||||
case TIMELINES:
|
||||
FragmentTimelinesSettings fragmentTimelinesSettings = new FragmentTimelinesSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentTimelinesSettings);
|
||||
currentFragment = fragmentTimelinesSettings;
|
||||
category = getString(R.string.settings_category_label_timelines);
|
||||
break;
|
||||
case NOTIFICATIONS:
|
||||
FragmentNotificationsSettings fragmentNotificationsSettings = new FragmentNotificationsSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentNotificationsSettings);
|
||||
currentFragment = fragmentNotificationsSettings;
|
||||
category = getString(R.string.notifications);
|
||||
break;
|
||||
case INTERFACE:
|
||||
FragmentInterfaceSettings fragmentInterfaceSettings = new FragmentInterfaceSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentInterfaceSettings);
|
||||
currentFragment = fragmentInterfaceSettings;
|
||||
category = getString(R.string.settings_category_label_interface);
|
||||
break;
|
||||
case COMPOSE:
|
||||
FragmentComposeSettings fragmentComposeSettings = new FragmentComposeSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentComposeSettings);
|
||||
currentFragment = fragmentComposeSettings;
|
||||
category = getString(R.string.compose);
|
||||
break;
|
||||
case PRIVACY:
|
||||
FragmentPrivacySettings fragmentPrivacySettings = new FragmentPrivacySettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentPrivacySettings);
|
||||
currentFragment = fragmentPrivacySettings;
|
||||
category = getString(R.string.action_privacy);
|
||||
break;
|
||||
case THEMING:
|
||||
FragmentThemingSettings fragmentThemingSettings = new FragmentThemingSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentThemingSettings);
|
||||
currentFragment = fragmentThemingSettings;
|
||||
category = getString(R.string.theming);
|
||||
break;
|
||||
case LANGUAGE:
|
||||
FragmentLanguageSettings fragmentLanguageSettings = new FragmentLanguageSettings();
|
||||
fragmentTransaction.replace(R.id.fragment_container, fragmentLanguageSettings);
|
||||
currentFragment = fragmentLanguageSettings;
|
||||
category = getString(R.string.languages);
|
||||
break;
|
||||
|
||||
}
|
||||
String title = String.format(Locale.getDefault(), "%s - %s", getString(R.string.settings), category);
|
||||
setTitle(title);
|
||||
canGoBack = true;
|
||||
fragmentTransaction.commit();
|
||||
});
|
||||
}
|
||||
String title = String.format(Locale.getDefault(), "%s - %s", getString(R.string.settings), category);
|
||||
setTitle(title);
|
||||
canGoBack = true;
|
||||
fragmentTransaction.commit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,15 +163,6 @@ public class SettingsActivity extends BaseActivity {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (currentFragment != null) {
|
||||
currentFragment.onDestroy();
|
||||
}
|
||||
binding = null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
@ -177,6 +175,8 @@ public class SettingsActivity extends BaseActivity {
|
|||
|
||||
|
||||
public enum SettingsEnum {
|
||||
@SerializedName("ACCOUNT")
|
||||
ACCOUNT("ACCOUNT"),
|
||||
@SerializedName("TIMELINES")
|
||||
TIMELINES("TIMELINES"),
|
||||
@SerializedName("NOTIFICATIONS")
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package app.fedilab.android.client.endpoints;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.DELETE;
|
||||
import retrofit2.http.Header;
|
||||
import retrofit2.http.PUT;
|
||||
import retrofit2.http.Path;
|
||||
|
||||
public interface PleromaAPI {
|
||||
|
||||
|
||||
@PUT("pleroma/statuses/{id}/reactions/{name}")
|
||||
Call<Void> addReaction(
|
||||
@Header("Authorization") String app_token,
|
||||
@Path("id") String id,
|
||||
@Path("name") String name
|
||||
);
|
||||
|
||||
@DELETE("pleroma/statuses/{id}/reactions/{name}")
|
||||
Call<Void> removeReaction(
|
||||
@Header("Authorization") String app_token,
|
||||
@Path("id") String id,
|
||||
@Path("name") String name
|
||||
);
|
||||
|
||||
}
|
|
@ -14,15 +14,20 @@ package app.fedilab.android.client.entities.api;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
|
||||
public class Account implements Serializable {
|
||||
|
||||
@SerializedName("id")
|
||||
|
@ -74,11 +79,21 @@ public class Account implements Serializable {
|
|||
@SerializedName("moved")
|
||||
public Account moved;
|
||||
|
||||
//Some extra spannable element - They will be filled automatically when fetching the account
|
||||
public transient Spannable span_display_name;
|
||||
public transient Spannable span_note;
|
||||
public synchronized Spannable getSpanDisplayName(Context context, WeakReference<View> viewWeakReference) {
|
||||
if (display_name == null || display_name.isEmpty()) {
|
||||
display_name = username;
|
||||
}
|
||||
return SpannableHelper.convert(context, display_name, null, this, null, true, viewWeakReference);
|
||||
}
|
||||
|
||||
|
||||
public synchronized Spannable getSpanNote(Context context, WeakReference<View> viewWeakReference) {
|
||||
return SpannableHelper.convert(context, note, null, this, null, true, viewWeakReference);
|
||||
}
|
||||
|
||||
public transient RelationShip relationShip;
|
||||
|
||||
|
||||
public static class AccountParams implements Serializable {
|
||||
@SerializedName("discoverable")
|
||||
public boolean discoverable;
|
||||
|
|
|
@ -14,13 +14,18 @@ package app.fedilab.android.client.entities.api;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
|
||||
public class Announcement {
|
||||
@SerializedName("id")
|
||||
public String id;
|
||||
|
@ -49,6 +54,9 @@ public class Announcement {
|
|||
@SerializedName("reactions")
|
||||
public List<Reaction> reactions;
|
||||
|
||||
//Some extra spannable element - They will be filled automatically when fetching the status
|
||||
public transient Spannable span_content;
|
||||
|
||||
public synchronized Spannable getSpanContent(Context context, WeakReference<View> viewWeakReference) {
|
||||
return SpannableHelper.convert(context, content, null, null, this, true, viewWeakReference);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,13 +14,22 @@ package app.fedilab.android.client.entities.api;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
|
||||
public class Field implements Serializable {
|
||||
@SerializedName("name")
|
||||
public String name;
|
||||
|
@ -30,7 +39,19 @@ public class Field implements Serializable {
|
|||
public Date verified_at;
|
||||
|
||||
//Some extra spannable element - They will be filled automatically when fetching the account
|
||||
public transient Spannable value_span;
|
||||
private transient ForegroundColorSpan value_span;
|
||||
|
||||
public synchronized Spannable getValueSpan(Context context, Account account, WeakReference<View> viewWeakReference) {
|
||||
|
||||
if (verified_at != null && value != null) {
|
||||
value_span = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.verified_text));
|
||||
}
|
||||
Spannable spannable = SpannableHelper.convert(context, value, null, account, null, true, viewWeakReference);
|
||||
if (value_span != null && spannable != null) {
|
||||
spannable.setSpan(value_span, 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
return spannable;
|
||||
}
|
||||
|
||||
public static class FieldParams implements Serializable {
|
||||
@SerializedName("name")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package app.fedilab.android.client.entities.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -113,6 +114,25 @@ public class Instance implements Serializable {
|
|||
return mimeTypes;
|
||||
}
|
||||
|
||||
|
||||
public static String serialize(Instance instance) {
|
||||
Gson gson = new Gson();
|
||||
try {
|
||||
return gson.toJson(instance);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Instance restore(String serialized) {
|
||||
Gson gson = new Gson();
|
||||
try {
|
||||
return gson.fromJson(serialized, Instance.class);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Configuration implements Serializable {
|
||||
@SerializedName("statuses")
|
||||
public StatusesConf statusesConf;
|
||||
|
|
|
@ -29,6 +29,8 @@ public class Notification {
|
|||
public String type;
|
||||
@SerializedName("created_at")
|
||||
public Date created_at;
|
||||
@SerializedName("emoji")
|
||||
public String emoji;
|
||||
@SerializedName("account")
|
||||
public Account account;
|
||||
@SerializedName("status")
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package app.fedilab.android.client.entities.api;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public class Pleroma implements Serializable {
|
||||
@SerializedName("emoji_reactions")
|
||||
public List<Reaction> emoji_reactions;
|
||||
}
|
|
@ -14,14 +14,19 @@ package app.fedilab.android.client.entities.api;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
|
||||
public class Poll implements Serializable {
|
||||
|
||||
@SerializedName("id")
|
||||
|
@ -53,7 +58,11 @@ public class Poll implements Serializable {
|
|||
@SerializedName("votes_count")
|
||||
public int votes_count;
|
||||
|
||||
//Some extra spannable element - They will be filled automatically when fetching the poll
|
||||
public transient Spannable span_title;
|
||||
|
||||
public Spannable getSpanTitle(Context context, Status status, WeakReference<View> viewWeakReference) {
|
||||
span_title = SpannableHelper.convert(context, title, status, null, null, true, viewWeakReference);
|
||||
return span_title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@ package app.fedilab.android.client.entities.api;
|
|||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Reaction {
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Reaction implements Serializable {
|
||||
@SerializedName("name")
|
||||
public String name;
|
||||
@SerializedName("count")
|
||||
|
|
|
@ -14,16 +14,21 @@ package app.fedilab.android.client.entities.api;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
|
||||
public class Status implements Serializable, Cloneable {
|
||||
|
||||
@SerializedName("id")
|
||||
|
@ -84,14 +89,12 @@ public class Status implements Serializable, Cloneable {
|
|||
public Card card;
|
||||
@SerializedName("poll")
|
||||
public Poll poll;
|
||||
@SerializedName("pleroma")
|
||||
public Pleroma pleroma;
|
||||
|
||||
|
||||
public Attachment art_attachment;
|
||||
|
||||
//Some extra spannable element - They will be filled automatically when fetching the status
|
||||
public transient Spannable span_content;
|
||||
public transient Spannable span_spoiler_text;
|
||||
public transient Spannable span_translate;
|
||||
public boolean isExpended = false;
|
||||
public boolean isTruncated = true;
|
||||
public boolean isFetchMore = false;
|
||||
|
@ -105,6 +108,24 @@ public class Status implements Serializable, Cloneable {
|
|||
public transient boolean setCursorToEnd = false;
|
||||
public transient int cursorPosition = 0;
|
||||
public transient boolean submitted = false;
|
||||
//Some extra spannable element - They will be filled automatically when fetching the status
|
||||
|
||||
public synchronized Spannable getSpanContent(Context context, WeakReference<View> viewWeakReference) {
|
||||
return SpannableHelper.convert(context, content, this, null, null, true, viewWeakReference);
|
||||
}
|
||||
|
||||
|
||||
public Spannable getSpanContentNitter() {
|
||||
return SpannableHelper.convertNitter(content);
|
||||
}
|
||||
|
||||
public synchronized Spannable getSpanSpoiler(Context context, WeakReference<View> viewWeakReference) {
|
||||
return SpannableHelper.convert(context, spoiler_text, this, null, null, true, viewWeakReference);
|
||||
}
|
||||
|
||||
public synchronized Spannable getSpanTranslate(Context context, WeakReference<View> viewWeakReference) {
|
||||
return SpannableHelper.convert(context, translationContent, this, null, null, true, viewWeakReference);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
|
|
|
@ -295,7 +295,7 @@ public class Account extends BaseAccount implements Serializable {
|
|||
}
|
||||
try {
|
||||
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, null, null, null, null, null, null);
|
||||
return cursorToListUser(c);
|
||||
return cursorToListUserWithOwner(c);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package app.fedilab.android.client.entities.app;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class Languages implements Serializable {
|
||||
|
||||
@SerializedName("languages")
|
||||
public List<Language> languages;
|
||||
|
||||
public static List<Language> get(AppCompatActivity activity) {
|
||||
try {
|
||||
InputStream is = activity.getAssets().open("languages/iso_639_1.json");
|
||||
int size = is.available();
|
||||
byte[] buffer = new byte[size];
|
||||
is.read(buffer);
|
||||
is.close();
|
||||
String json = new String(buffer, StandardCharsets.UTF_8);
|
||||
Gson gson = new Gson();
|
||||
try {
|
||||
return gson.fromJson(json, new TypeToken<List<Language>>() {
|
||||
}.getType());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Language implements Serializable {
|
||||
@SerializedName("code")
|
||||
public String code;
|
||||
@SerializedName("language")
|
||||
public String language;
|
||||
}
|
||||
}
|
|
@ -29,7 +29,6 @@ import app.fedilab.android.client.entities.api.Notification;
|
|||
import app.fedilab.android.client.entities.api.Status;
|
||||
import app.fedilab.android.exception.DBException;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.sqlite.Sqlite;
|
||||
import app.fedilab.android.ui.fragment.timeline.FragmentMastodonNotification;
|
||||
|
||||
|
@ -576,7 +575,6 @@ public class QuickLoad {
|
|||
}
|
||||
quickLoad.position = c.getInt(c.getColumnIndexOrThrow(Sqlite.COL_POSITION));
|
||||
//TimelineHelper.filterStatus(_mContext, quickLoad.statuses, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
quickLoad.statuses = SpannableHelper.convertStatus(_mContext, quickLoad.statuses);
|
||||
return quickLoad;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public class MisskeyNote implements Serializable {
|
|||
@SerializedName("emojis")
|
||||
public List<MisskeyEmoji> emojis;
|
||||
|
||||
public static Status convert(MisskeyNote misskeyNote) {
|
||||
public static Status convert(MisskeyNote misskeyNote, String instance) {
|
||||
Status status = new Status();
|
||||
status.id = misskeyNote.id;
|
||||
status.in_reply_to_id = misskeyNote.replyId;
|
||||
|
@ -64,7 +64,10 @@ public class MisskeyNote implements Serializable {
|
|||
status.spoiler_text = misskeyNote.cw;
|
||||
status.visibility = misskeyNote.visibility;
|
||||
status.created_at = misskeyNote.createdAt;
|
||||
status.uri = misskeyNote.uri;
|
||||
if (misskeyNote.url == null) {
|
||||
misskeyNote.url = "https://" + instance + "/notes/" + misskeyNote.id;
|
||||
}
|
||||
status.uri = misskeyNote.uri != null ? misskeyNote.uri : misskeyNote.url;
|
||||
status.url = misskeyNote.url;
|
||||
|
||||
Account account = new Account();
|
||||
|
|
|
@ -105,8 +105,8 @@ public class Nitter implements Serializable {
|
|||
}
|
||||
}
|
||||
Nitter nitterAccount = accounts.get(feedItem.creator);
|
||||
app.fedilab.android.client.entities.api.Account account = new app.fedilab.android.client.entities.api.Account();
|
||||
if (nitterAccount != null) {
|
||||
app.fedilab.android.client.entities.api.Account account = new app.fedilab.android.client.entities.api.Account();
|
||||
String[] names = nitterAccount.image.title.split("/");
|
||||
account.id = feedItem.guid;
|
||||
account.acct = names[1].replace("@", "");
|
||||
|
@ -116,6 +116,15 @@ public class Nitter implements Serializable {
|
|||
account.avatar_static = nitterAccount.image.url;
|
||||
account.url = nitterAccount.image.link;
|
||||
status.account = account;
|
||||
} else {
|
||||
account.id = feedItem.guid;
|
||||
account.acct = feedItem.creator.replace("@", "");
|
||||
account.username = feedItem.creator.replace("@", "");
|
||||
account.display_name = feedItem.creator.replace("@", "");
|
||||
account.avatar = "";
|
||||
account.avatar_static = "";
|
||||
account.url = feedItem.link;
|
||||
status.account = account;
|
||||
}
|
||||
|
||||
if (feedItem.description != null) {
|
||||
|
|
|
@ -149,7 +149,7 @@ public class CrossActionHelper {
|
|||
}
|
||||
});
|
||||
} else if (targetedStatus != null) {
|
||||
searchVM.search(ownerAccount.instance, ownerAccount.token, targetedStatus.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(ownerAccount.instance, ownerAccount.token, targetedStatus.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status status = results.statuses.get(0);
|
||||
|
@ -278,8 +278,6 @@ public class CrossActionHelper {
|
|||
if (results != null) {
|
||||
if (results.statuses == null) {
|
||||
results.statuses = new ArrayList<>();
|
||||
} else {
|
||||
results.statuses = SpannableHelper.convertStatus(context, results.statuses);
|
||||
}
|
||||
if (results.accounts == null) {
|
||||
results.accounts = new ArrayList<>();
|
||||
|
@ -308,15 +306,15 @@ public class CrossActionHelper {
|
|||
/**
|
||||
* Fetch and federate the remote status
|
||||
*/
|
||||
public static void fetchRemoteAccount(@NonNull Context context, @NonNull BaseAccount ownerAccount, app.fedilab.android.client.entities.api.Account targetedAccount, Callback callback) {
|
||||
public static void fetchRemoteAccount(@NonNull Context context, @NonNull BaseAccount ownerAccount, String targetedAcct, Callback callback) {
|
||||
|
||||
|
||||
MastodonSearchService mastodonSearchService = init(context, BaseMainActivity.currentInstance);
|
||||
String search;
|
||||
if (targetedAccount.acct.contains("@")) { //Not from same instance
|
||||
search = targetedAccount.acct;
|
||||
if (targetedAcct.contains("@")) { //Not from same instance
|
||||
search = targetedAcct;
|
||||
} else {
|
||||
search = targetedAccount.acct + "@" + BaseMainActivity.currentInstance;
|
||||
search = targetedAcct + "@" + BaseMainActivity.currentInstance;
|
||||
}
|
||||
new Thread(() -> {
|
||||
Call<Results> resultsCall = mastodonSearchService.search(ownerAccount.token, search, null, "accounts", false, true, false, 0, null, null, 1);
|
||||
|
@ -329,8 +327,6 @@ public class CrossActionHelper {
|
|||
if (results != null) {
|
||||
if (results.statuses == null) {
|
||||
results.statuses = new ArrayList<>();
|
||||
} else {
|
||||
results.statuses = SpannableHelper.convertStatus(context, results.statuses);
|
||||
}
|
||||
if (results.accounts == null) {
|
||||
results.accounts = new ArrayList<>();
|
||||
|
@ -374,8 +370,6 @@ public class CrossActionHelper {
|
|||
if (results != null) {
|
||||
if (results.statuses == null) {
|
||||
results.statuses = new ArrayList<>();
|
||||
} else {
|
||||
results.statuses = SpannableHelper.convertStatus(context, results.statuses);
|
||||
}
|
||||
if (results.accounts == null) {
|
||||
results.accounts = new ArrayList<>();
|
||||
|
|
106
app/src/main/java/app/fedilab/android/helper/CustomEmoji.java
Normal file
106
app/src/main/java/app/fedilab/android/helper/CustomEmoji.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package app.fedilab.android.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.style.ReplacementSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
|
||||
|
||||
public class CustomEmoji extends ReplacementSpan {
|
||||
private final float scale;
|
||||
private final WeakReference<View> viewWeakReference;
|
||||
private Drawable imageDrawable;
|
||||
|
||||
|
||||
CustomEmoji(WeakReference<View> viewWeakReference) {
|
||||
Context mContext = viewWeakReference.get().getContext();
|
||||
this.viewWeakReference = viewWeakReference;
|
||||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
scale = sharedpreferences.getFloat(mContext.getString(R.string.SET_FONT_SCALE), 1.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(@NonNull Paint paint, CharSequence charSequence, int i, int i1, @Nullable Paint.FontMetricsInt fontMetricsInt) {
|
||||
if (fontMetricsInt != null) {
|
||||
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
|
||||
fontMetricsInt.top = (int) fontMetrics.top;
|
||||
fontMetricsInt.ascent = (int) fontMetrics.ascent;
|
||||
fontMetricsInt.descent = (int) fontMetrics.descent;
|
||||
fontMetricsInt.bottom = (int) fontMetrics.bottom;
|
||||
}
|
||||
return (int) (paint.getTextSize() * scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
|
||||
if (imageDrawable != null) {
|
||||
canvas.save();
|
||||
int emojiSize = (int) (paint.getTextSize() * scale);
|
||||
Drawable drawable = imageDrawable;
|
||||
drawable.setBounds(0, 0, emojiSize, emojiSize);
|
||||
int transY = bottom - drawable.getBounds().bottom;
|
||||
transY -= paint.getFontMetrics().descent / 2;
|
||||
canvas.translate(x, (float) transY);
|
||||
drawable.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
public Target<Drawable> getTarget(boolean animate) {
|
||||
return new CustomTarget<Drawable>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
|
||||
View view = viewWeakReference.get();
|
||||
if (animate && resource instanceof Animatable) {
|
||||
Drawable.Callback callback = resource.getCallback();
|
||||
resource.setCallback(new Drawable.Callback() {
|
||||
@Override
|
||||
public void invalidateDrawable(@NonNull Drawable drawable) {
|
||||
if (callback != null) {
|
||||
callback.invalidateDrawable(drawable);
|
||||
}
|
||||
view.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long l) {
|
||||
if (callback != null) {
|
||||
callback.scheduleDrawable(drawable, runnable, l);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {
|
||||
if (callback != null) {
|
||||
callback.unscheduleDrawable(drawable, runnable);
|
||||
}
|
||||
}
|
||||
});
|
||||
((Animatable) resource).start();
|
||||
}
|
||||
imageDrawable = resource;
|
||||
view.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCleared(@Nullable Drawable placeholder) {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -87,8 +87,10 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
@ -119,7 +121,7 @@ import java.text.ParseException;
|
|||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
@ -352,9 +354,9 @@ public class Helper {
|
|||
public static int counter = 1;
|
||||
|
||||
static {
|
||||
Map<PatternType, Pattern> aMap = new HashMap<>();
|
||||
aMap.put(PatternType.MENTION, mentionPattern);
|
||||
LinkedHashMap<PatternType, Pattern> aMap = new LinkedHashMap<>();
|
||||
aMap.put(PatternType.MENTION_LONG, mentionLongPattern);
|
||||
aMap.put(PatternType.MENTION, mentionPattern);
|
||||
aMap.put(PatternType.TAG, hashtagPattern);
|
||||
aMap.put(PatternType.GROUP, groupPattern);
|
||||
patternHashMap = Collections.unmodifiableMap(aMap);
|
||||
|
@ -1043,6 +1045,7 @@ public class Helper {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a profile picture for the account
|
||||
*
|
||||
|
@ -1050,25 +1053,39 @@ public class Helper {
|
|||
* @param account - {@link Account}
|
||||
*/
|
||||
public static void loadPP(ImageView view, BaseAccount account) {
|
||||
loadPP(view, account, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a profile picture for the account
|
||||
*
|
||||
* @param view ImageView - the view where the image will be loaded
|
||||
* @param account - {@link Account}
|
||||
*/
|
||||
public static void loadPP(ImageView view, BaseAccount account, boolean crop) {
|
||||
Context context = view.getContext();
|
||||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean disableGif = sharedpreferences.getBoolean(context.getString(R.string.SET_DISABLE_GIF), false);
|
||||
String targetedUrl = disableGif ? account.mastodon_account.avatar_static : account.mastodon_account.avatar;
|
||||
if (targetedUrl != null) {
|
||||
if (disableGif || (!targetedUrl.endsWith(".gif"))) {
|
||||
Glide.with(view.getContext())
|
||||
RequestBuilder<Drawable> requestBuilder = Glide.with(view.getContext())
|
||||
.asDrawable()
|
||||
.load(targetedUrl)
|
||||
.thumbnail(0.1f)
|
||||
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)))
|
||||
.into(view);
|
||||
.thumbnail(0.1f);
|
||||
if (crop) {
|
||||
requestBuilder = requestBuilder.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)));
|
||||
}
|
||||
requestBuilder.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))).into(view);
|
||||
} else {
|
||||
Glide.with(view.getContext())
|
||||
RequestBuilder<GifDrawable> requestBuilder = Glide.with(view.getContext())
|
||||
.asGif()
|
||||
.load(targetedUrl)
|
||||
.thumbnail(0.1f)
|
||||
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)))
|
||||
.into(view);
|
||||
.thumbnail(0.1f);
|
||||
if (crop) {
|
||||
requestBuilder = requestBuilder.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)));
|
||||
}
|
||||
requestBuilder.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))).into(view);
|
||||
}
|
||||
} else {
|
||||
Glide.with(view.getContext())
|
||||
|
@ -1722,4 +1739,13 @@ public class Helper {
|
|||
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static <T, E> T getKeyByValue(Map<T, E> map, E value) {
|
||||
for (Map.Entry<T, E> entry : map.entrySet()) {
|
||||
if (Objects.equals(value, entry.getValue())) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package app.fedilab.android.helper;
|
||||
|
||||
import com.bumptech.glide.annotation.GlideModule;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
|
||||
@GlideModule
|
||||
public final class MyAppGlideModule extends AppGlideModule {
|
||||
@Override
|
||||
public boolean isManifestParsingEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -115,11 +115,6 @@ public class NotificationsHelper {
|
|||
if (notifications.notifications.size() > 0) {
|
||||
since_ids.put(slug, notifications.notifications.get(0).id);
|
||||
}
|
||||
for (Notification notification : notifications.notifications) {
|
||||
if (notification != null && notification.status != null) {
|
||||
notification.status = SpannableHelper.convertStatus(context.getApplicationContext(), notification.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
notifications.pagination = MastodonHelper.getPagination(notificationsResponse.headers());
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -107,6 +107,18 @@ public class TimelineHelper {
|
|||
Matcher m = p.matcher(content);
|
||||
if (m.find()) {
|
||||
statusesToRemove.add(status);
|
||||
continue;
|
||||
}
|
||||
if (status.spoiler_text != null) {
|
||||
String spoilerText;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
spoilerText = Html.fromHtml(status.spoiler_text, Html.FROM_HTML_MODE_LEGACY).toString();
|
||||
else
|
||||
spoilerText = Html.fromHtml(status.spoiler_text).toString();
|
||||
Matcher ms = p.matcher(spoilerText);
|
||||
if (ms.find()) {
|
||||
statusesToRemove.add(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -118,6 +130,18 @@ public class TimelineHelper {
|
|||
content = Html.fromHtml(status.content).toString();
|
||||
if (content.contains(filter.phrase)) {
|
||||
statusesToRemove.add(status);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status.spoiler_text != null) {
|
||||
String spoilerText;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
spoilerText = Html.fromHtml(status.spoiler_text, Html.FROM_HTML_MODE_LEGACY).toString();
|
||||
else
|
||||
spoilerText = Html.fromHtml(status.spoiler_text).toString();
|
||||
if (spoilerText.contains(filter.phrase)) {
|
||||
statusesToRemove.add(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ public class NotificationsWorker extends Worker {
|
|||
String instance = getInputData().getString(Helper.ARG_INSTANCE);
|
||||
String token = getInputData().getString(Helper.ARG_TOKEN);
|
||||
String statusDraftId = getInputData().getString(Helper.ARG_STATUS_DRAFT_ID);
|
||||
String userId = getInputData().getString(Helper.ARG_USER_ID);
|
||||
StatusDraft statusDraft;
|
||||
try {
|
||||
statusDraft = new StatusDraft(getApplicationContext()).geStatusDraft(statusDraftId);
|
||||
|
@ -82,6 +83,7 @@ public class NotificationsWorker extends Worker {
|
|||
intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft);
|
||||
intent.putExtra(Helper.ARG_INSTANCE, instance);
|
||||
intent.putExtra(Helper.ARG_TOKEN, token);
|
||||
intent.putExtra(Helper.ARG_USER_ID, userId);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
getApplicationContext().startForegroundService(intent);
|
||||
} else {
|
||||
|
|
|
@ -74,6 +74,7 @@ public class ScheduleThreadWorker extends Worker {
|
|||
Data outputData;
|
||||
String instance = getInputData().getString(Helper.ARG_INSTANCE);
|
||||
String token = getInputData().getString(Helper.ARG_TOKEN);
|
||||
String userId = getInputData().getString(Helper.ARG_USER_ID);
|
||||
String statusDraftId = getInputData().getString(Helper.ARG_STATUS_DRAFT_ID);
|
||||
StatusDraft statusDraft;
|
||||
try {
|
||||
|
@ -82,6 +83,7 @@ public class ScheduleThreadWorker extends Worker {
|
|||
intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft);
|
||||
intent.putExtra(Helper.ARG_INSTANCE, instance);
|
||||
intent.putExtra(Helper.ARG_TOKEN, token);
|
||||
intent.putExtra(Helper.ARG_USER_ID, userId);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
getApplicationContext().startForegroundService(intent);
|
||||
} else {
|
||||
|
|
|
@ -202,9 +202,10 @@ public class PostMessageService extends IntentService {
|
|||
if (error) {
|
||||
return;
|
||||
}
|
||||
String language = sharedPreferences.getString(context.getString(R.string.SET_COMPOSE_LANGUAGE) + dataPost.userId + dataPost.instance, null);
|
||||
if (dataPost.scheduledDate == null) {
|
||||
statusCall = mastodonStatusesService.createStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in,
|
||||
poll_multiple, poll_hide_totals, in_reply_to_status, statuses.get(i).sensitive, statuses.get(i).spoiler_text, statuses.get(i).visibility.toLowerCase(), statuses.get(i).language);
|
||||
poll_multiple, poll_hide_totals, in_reply_to_status, statuses.get(i).sensitive, statuses.get(i).spoiler_text, statuses.get(i).visibility.toLowerCase(), language);
|
||||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
|
@ -339,11 +340,13 @@ public class PostMessageService extends IntentService {
|
|||
StatusDraft statusDraft = null;
|
||||
String token = null, instance = null;
|
||||
String scheduledDate = null;
|
||||
String userId = null;
|
||||
if (intent != null && intent.getExtras() != null) {
|
||||
Bundle b = intent.getExtras();
|
||||
statusDraft = (StatusDraft) b.getSerializable(Helper.ARG_STATUS_DRAFT);
|
||||
token = b.getString(Helper.ARG_TOKEN);
|
||||
instance = b.getString(Helper.ARG_INSTANCE);
|
||||
userId = b.getString(Helper.ARG_USER_ID);
|
||||
scheduledDate = b.getString(Helper.ARG_SCHEDULED_DATE);
|
||||
}
|
||||
//Should not be null, but a simple security
|
||||
|
@ -356,6 +359,7 @@ public class PostMessageService extends IntentService {
|
|||
DataPost dataPost = new DataPost();
|
||||
dataPost.instance = instance;
|
||||
dataPost.token = token;
|
||||
dataPost.userId = userId;
|
||||
dataPost.statusDraft = statusDraft;
|
||||
dataPost.scheduledDate = scheduledDate;
|
||||
dataPost.notificationBuilder = notificationBuilder;
|
||||
|
@ -367,6 +371,7 @@ public class PostMessageService extends IntentService {
|
|||
static class DataPost {
|
||||
String instance;
|
||||
String token;
|
||||
String userId;
|
||||
StatusDraft statusDraft;
|
||||
int messageToSend;
|
||||
int messageSent;
|
||||
|
|
|
@ -22,9 +22,10 @@ import app.fedilab.android.client.entities.app.StatusDraft;
|
|||
|
||||
public class ThreadMessageService {
|
||||
|
||||
public ThreadMessageService(Context context, String instance, String token, StatusDraft statusDraft, String scheduledDate) {
|
||||
public ThreadMessageService(Context context, String instance, String userId, String token, StatusDraft statusDraft, String scheduledDate) {
|
||||
PostMessageService.DataPost dataPost = new PostMessageService.DataPost();
|
||||
dataPost.instance = instance;
|
||||
dataPost.userId = userId;
|
||||
dataPost.token = token;
|
||||
dataPost.scheduledDate = scheduledDate;
|
||||
dataPost.statusDraft = statusDraft;
|
||||
|
|
|
@ -37,6 +37,7 @@ import androidx.lifecycle.ViewModelStoreOwner;
|
|||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -224,9 +225,15 @@ public class AccountAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
}
|
||||
});
|
||||
}
|
||||
accountViewHolder.binding.displayName.setText(account.span_display_name, TextView.BufferType.SPANNABLE);
|
||||
accountViewHolder.binding.displayName.setText(
|
||||
account.getSpanDisplayName(context,
|
||||
new WeakReference<>(accountViewHolder.binding.displayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
accountViewHolder.binding.username.setText(String.format("@%s", account.acct));
|
||||
accountViewHolder.binding.bio.setText(account.span_note, TextView.BufferType.SPANNABLE);
|
||||
accountViewHolder.binding.bio.setText(
|
||||
account.getSpanNote(context,
|
||||
new WeakReference<>(accountViewHolder.binding.bio)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
|
|
|
@ -27,6 +27,7 @@ import androidx.lifecycle.ViewModelProvider;
|
|||
import androidx.lifecycle.ViewModelStoreOwner;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -78,7 +79,10 @@ public class AccountListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
|
|||
account = getItem(position);
|
||||
AccountListViewHolder holder = (AccountListViewHolder) viewHolder;
|
||||
MastodonHelper.loadPPMastodon(holder.binding.avatar, account);
|
||||
holder.binding.displayName.setText(account.span_display_name, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.displayName.setText(
|
||||
account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holder.binding.displayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holder.binding.username.setText(String.format("@%s", account.acct));
|
||||
|
||||
if (searchList != null) {
|
||||
|
|
|
@ -37,6 +37,7 @@ import com.vanniktech.emoji.EmojiManager;
|
|||
import com.vanniktech.emoji.EmojiPopup;
|
||||
import com.vanniktech.emoji.one.EmojiOneProvider;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.BaseMainActivity;
|
||||
|
@ -75,19 +76,23 @@ public class AnnouncementAdapter extends RecyclerView.Adapter<AnnouncementAdapte
|
|||
return new AnnouncementHolder(itemBinding);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull AnnouncementHolder holder, int position) {
|
||||
Announcement announcement = announcements.get(position);
|
||||
if (announcement.reactions != null && announcement.reactions.size() > 0) {
|
||||
ReactionAdapter reactionAdapter = new ReactionAdapter(announcement.id, announcement.reactions);
|
||||
holder.binding.reactionsView.setAdapter(reactionAdapter);
|
||||
holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter);
|
||||
LinearLayoutManager layoutManager
|
||||
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
|
||||
holder.binding.reactionsView.setLayoutManager(layoutManager);
|
||||
holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
|
||||
} else {
|
||||
holder.binding.reactionsView.setAdapter(null);
|
||||
holder.binding.layoutReactions.reactionsView.setAdapter(null);
|
||||
}
|
||||
holder.binding.content.setText(announcement.span_content, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.content.setText(
|
||||
announcement.getSpanContent(context,
|
||||
new WeakReference<>(holder.binding.content)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
if (announcement.starts_at != null) {
|
||||
String dateIni;
|
||||
String dateEnd;
|
||||
|
@ -104,11 +109,11 @@ public class AnnouncementAdapter extends RecyclerView.Adapter<AnnouncementAdapte
|
|||
} else {
|
||||
holder.binding.dates.setVisibility(View.GONE);
|
||||
}
|
||||
holder.binding.statusEmoji.setOnClickListener(v -> {
|
||||
holder.binding.layoutReactions.statusEmoji.setOnClickListener(v -> {
|
||||
EmojiManager.install(new EmojiOneProvider());
|
||||
final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(holder.binding.statusEmoji).setOnEmojiPopupDismissListener(() -> {
|
||||
final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(holder.binding.layoutReactions.statusEmoji).setOnEmojiPopupDismissListener(() -> {
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(holder.binding.statusEmoji.getWindowToken(), 0);
|
||||
imm.hideSoftInputFromWindow(holder.binding.layoutReactions.statusEmoji.getWindowToken(), 0);
|
||||
}).setOnEmojiClickListener((emoji, imageView) -> {
|
||||
String emojiStr = imageView.getUnicode();
|
||||
boolean alreadyAdded = false;
|
||||
|
@ -138,10 +143,10 @@ public class AnnouncementAdapter extends RecyclerView.Adapter<AnnouncementAdapte
|
|||
announcementsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcement.id, emojiStr);
|
||||
}
|
||||
})
|
||||
.build(holder.binding.fakeEdittext);
|
||||
.build(holder.binding.layoutReactions.fakeEdittext);
|
||||
emojiPopup.toggle();
|
||||
});
|
||||
holder.binding.statusAddCustomEmoji.setOnClickListener(v -> {
|
||||
holder.binding.layoutReactions.statusAddCustomEmoji.setOnClickListener(v -> {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle());
|
||||
int paddingPixel = 15;
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
|
|
|
@ -73,6 +73,7 @@ import com.bumptech.glide.request.target.CustomTarget;
|
|||
import com.bumptech.glide.request.transition.Transition;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.Normalizer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -455,13 +456,18 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
List<Attachment> attachmentList = statusList.get(position).media_attachments;
|
||||
if (attachmentList != null && attachmentList.size() > 0) {
|
||||
holder.binding.sensitiveMedia.setVisibility(View.VISIBLE);
|
||||
if (currentAccount.mastodon_account.source != null) {
|
||||
holder.binding.sensitiveMedia.setChecked(currentAccount.mastodon_account.source.sensitive);
|
||||
statusList.get(position).sensitive = currentAccount.mastodon_account.source.sensitive;
|
||||
} else {
|
||||
statusList.get(position).sensitive = false;
|
||||
if (!statusList.get(position).sensitive) {
|
||||
if (currentAccount.mastodon_account.source != null) {
|
||||
holder.binding.sensitiveMedia.setChecked(currentAccount.mastodon_account.source.sensitive);
|
||||
statusList.get(position).sensitive = currentAccount.mastodon_account.source.sensitive;
|
||||
} else {
|
||||
statusList.get(position).sensitive = false;
|
||||
}
|
||||
}
|
||||
holder.binding.sensitiveMedia.setOnCheckedChangeListener((buttonView, isChecked) -> statusList.get(position).sensitive = isChecked);
|
||||
|
||||
holder.binding.sensitiveMedia.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
statusList.get(position).sensitive = isChecked;
|
||||
});
|
||||
int mediaPosition = 0;
|
||||
for (Attachment attachment : attachmentList) {
|
||||
ComposeAttachmentItemBinding composeAttachmentItemBinding = ComposeAttachmentItemBinding.inflate(LayoutInflater.from(context), holder.binding.attachmentsList, false);
|
||||
|
@ -664,6 +670,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
return statusList.size();
|
||||
}
|
||||
|
||||
private List<Emoji> emojisList = new ArrayList<>();
|
||||
/**
|
||||
* Initialize text watcher for content writing
|
||||
* It will allow to complete autocomplete edit text while starting words with @, #, : etc.
|
||||
|
@ -672,7 +679,6 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
* @return {@link TextWatcher}
|
||||
*/
|
||||
public TextWatcher initializeTextWatcher(ComposeAdapter.ComposeViewHolder holder) {
|
||||
final List<Emoji>[] emojis = new List[]{null};
|
||||
String pattern = "(.|\\s)*(@[\\w_-]+@[a-z0-9.\\-]+|@[\\w_-]+)";
|
||||
final Pattern mentionPattern = Pattern.compile(pattern);
|
||||
|
||||
|
@ -958,13 +964,13 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
new Thread(() -> {
|
||||
List<Emoji> emojisToDisplay = new ArrayList<>();
|
||||
try {
|
||||
if (emojis[0] == null) {
|
||||
emojis[0] = new EmojiInstance(context).getEmojiList(BaseMainActivity.currentInstance);
|
||||
if (emojisList == null || emojisList.size() == 0) {
|
||||
emojisList = new EmojiInstance(context).getEmojiList(BaseMainActivity.currentInstance);
|
||||
}
|
||||
if (emojis[0] == null) {
|
||||
if (emojis == null) {
|
||||
return;
|
||||
}
|
||||
for (Emoji emoji : emojis[0]) {
|
||||
for (Emoji emoji : emojisList) {
|
||||
if (shortcode != null && emoji.shortcode.contains(shortcode)) {
|
||||
emojisToDisplay.add(emoji);
|
||||
if (emojisToDisplay.size() >= 10) {
|
||||
|
@ -983,7 +989,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
if (searchA.length > 0) {
|
||||
final String search = searchA[searchA.length - 1];
|
||||
holder.binding.content.setOnItemClickListener((parent, view, position, id) -> {
|
||||
String shortcodeSelected = emojis[0].get(position).shortcode;
|
||||
String shortcodeSelected = emojisToDisplay.get(position).shortcode;
|
||||
String deltaSearch = "";
|
||||
int searchLength = searchDeep;
|
||||
if (currentCursorPosition < searchDeep) { //Less than 15 characters are written before the cursor position
|
||||
|
@ -1032,21 +1038,40 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
|
||||
int theme_statuses_color = -1;
|
||||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (sharedpreferences.getBoolean("use_custom_theme", false)) {
|
||||
theme_statuses_color = sharedpreferences.getInt("theme_statuses_color", -1);
|
||||
}
|
||||
if (getItemViewType(position) == TYPE_NORMAL) {
|
||||
Status status = statusList.get(position);
|
||||
StatusSimpleViewHolder holder = (StatusSimpleViewHolder) viewHolder;
|
||||
holder.binding.statusContent.setText(status.span_content, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.statusContent.setText(
|
||||
status.getSpanContent(context,
|
||||
new WeakReference<>(holder.binding.statusContent)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
MastodonHelper.loadPPMastodon(holder.binding.avatar, status.account);
|
||||
holder.binding.displayName.setText(status.account.span_display_name, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.displayName.setText(
|
||||
status.account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holder.binding.displayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holder.binding.username.setText(String.format("@%s", status.account.acct));
|
||||
if (status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) {
|
||||
|
||||
holder.binding.spoiler.setVisibility(View.VISIBLE);
|
||||
holder.binding.spoiler.setText(status.span_spoiler_text, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.spoiler.setText(
|
||||
status.getSpanSpoiler(context,
|
||||
new WeakReference<>(holder.binding.spoiler)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
} else {
|
||||
holder.binding.spoiler.setVisibility(View.GONE);
|
||||
holder.binding.spoiler.setText(null);
|
||||
}
|
||||
if (theme_statuses_color != -1) {
|
||||
holder.binding.cardviewContainer.setBackgroundColor(theme_statuses_color);
|
||||
} else {
|
||||
holder.binding.cardviewContainer.setBackgroundColor(ContextCompat.getColor(context, R.color.cyanea_primary_dark_reference));
|
||||
}
|
||||
} else if (getItemViewType(position) == TYPE_COMPOSE) {
|
||||
Status statusDraft = statusList.get(position);
|
||||
|
||||
|
@ -1058,7 +1083,11 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
|
||||
int newInputTypeSpoiler = holder.binding.contentSpoiler.getInputType() & (holder.binding.contentSpoiler.getInputType() ^ InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE);
|
||||
holder.binding.contentSpoiler.setInputType(newInputTypeSpoiler);
|
||||
|
||||
if (theme_statuses_color != -1) {
|
||||
holder.binding.cardviewContainer.setBackgroundColor(theme_statuses_color);
|
||||
} else {
|
||||
holder.binding.cardviewContainer.setBackgroundColor(ContextCompat.getColor(context, R.color.cyanea_primary_dark_reference));
|
||||
}
|
||||
holder.binding.buttonAttach.setOnClickListener(v -> {
|
||||
if (instanceInfo.configuration.media_attachments.supported_mime_types != null) {
|
||||
if (instanceInfo.getMimeTypeAudio().size() == 0) {
|
||||
|
|
|
@ -36,6 +36,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
|
@ -137,14 +138,20 @@ public class ConversationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
notifyItemChanged(position);
|
||||
});
|
||||
holder.binding.spoiler.setVisibility(View.VISIBLE);
|
||||
holder.binding.spoiler.setText(conversation.last_status.span_spoiler_text, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.spoiler.setText(
|
||||
conversation.last_status.getSpanSpoiler(context,
|
||||
new WeakReference<>(holder.binding.spoiler)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
} else {
|
||||
holder.binding.spoiler.setVisibility(View.GONE);
|
||||
holder.binding.spoilerExpand.setVisibility(View.GONE);
|
||||
holder.binding.spoiler.setText(null);
|
||||
}
|
||||
//--- MAIN CONTENT ---
|
||||
holder.binding.statusContent.setText(conversation.last_status.span_content, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.statusContent.setText(
|
||||
conversation.last_status.getSpanContent(context,
|
||||
new WeakReference<>(holder.binding.statusContent)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
//--- DATE ---
|
||||
holder.binding.lastMessageDate.setText(Helper.dateDiff(context, conversation.last_status.created_at));
|
||||
|
||||
|
|
|
@ -16,26 +16,16 @@ package app.fedilab.android.ui.drawer;
|
|||
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.github.penfeizhou.animation.apng.APNGDrawable;
|
||||
import com.github.penfeizhou.animation.apng.decode.APNGParser;
|
||||
import com.github.penfeizhou.animation.gif.GifDrawable;
|
||||
import com.github.penfeizhou.animation.gif.decode.GifParser;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
|
@ -52,7 +42,7 @@ public class EmojiAdapter extends BaseAdapter {
|
|||
}
|
||||
|
||||
public int getCount() {
|
||||
return emojiList.size();
|
||||
return emojiList == null ? 0 : emojiList.size();
|
||||
}
|
||||
|
||||
public Emoji getItem(int position) {
|
||||
|
@ -76,28 +66,8 @@ public class EmojiAdapter extends BaseAdapter {
|
|||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(holder.view.getContext());
|
||||
boolean disableAnimatedEmoji = sharedpreferences.getBoolean(parent.getContext().getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false);
|
||||
Glide.with(holder.binding.imgCustomEmoji.getContext())
|
||||
.asFile()
|
||||
.load(!disableAnimatedEmoji ? emoji.url : emoji.static_url)
|
||||
.into(new CustomTarget<File>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull File resource, @Nullable Transition<? super File> transition) {
|
||||
if (APNGParser.isAPNG(resource.getAbsolutePath())) {
|
||||
APNGDrawable apngDrawable = APNGDrawable.fromFile(resource.getAbsolutePath());
|
||||
holder.binding.imgCustomEmoji.setImageDrawable(apngDrawable);
|
||||
} else if (GifParser.isGif(resource.getAbsolutePath())) {
|
||||
GifDrawable gifDrawable = GifDrawable.fromFile(resource.getAbsolutePath());
|
||||
holder.binding.imgCustomEmoji.setImageDrawable(gifDrawable);
|
||||
} else {
|
||||
Drawable drawable = Drawable.createFromPath(resource.getAbsolutePath());
|
||||
holder.binding.imgCustomEmoji.setImageDrawable(drawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCleared(@Nullable Drawable placeholder) {
|
||||
|
||||
}
|
||||
});
|
||||
.into(holder.binding.imgCustomEmoji);
|
||||
|
||||
return holder.view;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,7 @@ package app.fedilab.android.ui.drawer;
|
|||
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
@ -27,9 +25,11 @@ import androidx.annotation.NonNull;
|
|||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.client.entities.api.Account;
|
||||
import app.fedilab.android.client.entities.api.Field;
|
||||
import app.fedilab.android.databinding.DrawerFieldBinding;
|
||||
|
||||
|
@ -38,6 +38,7 @@ public class FieldAdapter extends RecyclerView.Adapter<FieldAdapter.FieldViewHol
|
|||
|
||||
private final List<Field> fields;
|
||||
private Context context;
|
||||
private Account account;
|
||||
|
||||
public FieldAdapter(List<Field> fields) {
|
||||
this.fields = fields;
|
||||
|
@ -66,9 +67,11 @@ public class FieldAdapter extends RecyclerView.Adapter<FieldAdapter.FieldViewHol
|
|||
Field field = fields.get(position);
|
||||
if (field.verified_at != null) {
|
||||
holder.binding.value.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(context, R.drawable.ic_baseline_verified_24), null);
|
||||
field.value_span.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.verified_text)), 0, field.value_span.toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
holder.binding.value.setText(field.value_span != null ? field.value_span : field.value, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.value.setText(
|
||||
field.getValueSpan(context, account,
|
||||
new WeakReference<>(holder.binding.value)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holder.binding.value.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
holder.binding.label.setText(field.name);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityOptionsCompat;
|
||||
|
@ -31,6 +32,7 @@ import androidx.lifecycle.ViewModelProvider;
|
|||
import androidx.lifecycle.ViewModelStoreOwner;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -58,6 +60,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
private final int TYPE_POLL = 5;
|
||||
private final int TYPE_STATUS = 6;
|
||||
private final int NOTIFICATION_FETCH_MORE = 7;
|
||||
private final int TYPE_REACTION = 8;
|
||||
public FetchMoreCallBack fetchMoreCallBack;
|
||||
private Context context;
|
||||
|
||||
|
@ -94,6 +97,8 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
return TYPE_POLL;
|
||||
case "status":
|
||||
return TYPE_STATUS;
|
||||
case "pleroma:emoji_reaction":
|
||||
return TYPE_REACTION;
|
||||
}
|
||||
return super.getItemViewType(position);
|
||||
}
|
||||
|
@ -114,13 +119,36 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will manage the current position of the element in the adapter. Action is async, and position might have changed
|
||||
*
|
||||
* @param notificationList List<Notification> - Not null when calling from notification adapter
|
||||
* @param id String - Current status
|
||||
* @return int - position in real time
|
||||
*/
|
||||
public static int getPositionAsync(List<Notification> notificationList, String id) {
|
||||
int position = 0;
|
||||
if (notificationList != null) {
|
||||
for (Notification notification : notificationList) {
|
||||
if (notification.status != null && notification.status.id.compareTo(id) == 0) {
|
||||
break;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
Notification notification = notificationList.get(position);
|
||||
if (getItemViewType(position) == TYPE_FOLLOW || getItemViewType(position) == TYPE_FOLLOW_REQUEST) {
|
||||
ViewHolderFollow holderFollow = (ViewHolderFollow) viewHolder;
|
||||
MastodonHelper.loadPPMastodon(holderFollow.binding.avatar, notification.account);
|
||||
holderFollow.binding.displayName.setText(notification.account.display_name);
|
||||
holderFollow.binding.displayName.setText(
|
||||
notification.account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holderFollow.binding.displayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holderFollow.binding.username.setText(String.format("@%s", notification.account.acct));
|
||||
if (getItemViewType(position) == TYPE_FOLLOW_REQUEST) {
|
||||
holderFollow.binding.rejectButton.setVisibility(View.VISIBLE);
|
||||
|
@ -172,6 +200,8 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
holderStatus.bindingNotification.status.typeOfNotification.setImageResource(R.drawable.ic_baseline_star_24);
|
||||
} else if (getItemViewType(position) == TYPE_REBLOG) {
|
||||
holderStatus.bindingNotification.status.typeOfNotification.setImageResource(R.drawable.ic_baseline_repeat_24);
|
||||
} else if (getItemViewType(position) == TYPE_REACTION) {
|
||||
holderStatus.bindingNotification.status.typeOfNotification.setImageResource(R.drawable.ic_baseline_insert_emoticon_24);
|
||||
} else if (getItemViewType(position) == TYPE_POLL) {
|
||||
holderStatus.bindingNotification.status.typeOfNotification.setImageResource(R.drawable.ic_baseline_poll_24);
|
||||
}
|
||||
|
@ -180,15 +210,25 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
statusManagement(context, statusesVM, searchVM, holderStatus, this, null, notificationList, notification.status, Timeline.TimeLineEnum.NOTIFICATION, false, true);
|
||||
holderStatus.bindingNotification.status.dateShort.setText(Helper.dateDiff(context, notification.created_at));
|
||||
holderStatus.bindingNotification.containerTransparent.setAlpha(.3f);
|
||||
if (getItemViewType(position) == TYPE_MENTION || getItemViewType(position) == TYPE_STATUS) {
|
||||
if (getItemViewType(position) == TYPE_MENTION || getItemViewType(position) == TYPE_STATUS || getItemViewType(position) == TYPE_REACTION) {
|
||||
holderStatus.bindingNotification.status.actionButtons.setVisibility(View.VISIBLE);
|
||||
String title = "";
|
||||
if (getItemViewType(position) == TYPE_MENTION) {
|
||||
title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_mention));
|
||||
} else if (getItemViewType(position) == TYPE_STATUS) {
|
||||
title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_status));
|
||||
} else if (getItemViewType(position) == TYPE_REACTION) {
|
||||
if (notification.emoji == null) {
|
||||
notification.emoji = "";
|
||||
}
|
||||
title = String.format(Locale.getDefault(), "%s reacted with %s", notification.account.username, notification.emoji);
|
||||
MastodonHelper.loadPPMastodon(holderStatus.bindingNotification.status.avatar, notification.account);
|
||||
}
|
||||
holderStatus.bindingNotification.status.displayName.setText(title);
|
||||
notification.account.display_name = title;
|
||||
holderStatus.bindingNotification.status.displayName.setText(
|
||||
notification.account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holderStatus.bindingNotification.status.displayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holderStatus.bindingNotification.status.username.setText(String.format("@%s", notification.account.acct));
|
||||
holderStatus.bindingNotification.containerTransparent.setAlpha(.1f);
|
||||
if (notification.status != null && notification.status.visibility.equalsIgnoreCase("direct")) {
|
||||
|
@ -255,13 +295,19 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
|||
// start the new activity
|
||||
context.startActivity(intent, options.toBundle());
|
||||
});
|
||||
holderStatus.bindingNotification.status.displayName.setText(title);
|
||||
notification.account.display_name = title;
|
||||
holderStatus.bindingNotification.status.displayName.setText(
|
||||
notification.account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holderStatus.bindingNotification.status.displayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holderStatus.bindingNotification.status.displayName.setText(title, TextView.BufferType.SPANNABLE);
|
||||
holderStatus.bindingNotification.status.username.setText(String.format("@%s", notification.account.acct));
|
||||
holderStatus.bindingNotification.status.actionButtons.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ package app.fedilab.android.ui.drawer;
|
|||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
|
||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
||||
import static app.fedilab.android.BaseMainActivity.emojis;
|
||||
import static app.fedilab.android.BaseMainActivity.regex_home;
|
||||
import static app.fedilab.android.BaseMainActivity.regex_local;
|
||||
import static app.fedilab.android.BaseMainActivity.regex_public;
|
||||
|
@ -35,10 +37,7 @@ import android.graphics.drawable.Drawable;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.Html;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
|
@ -49,7 +48,9 @@ import android.view.LayoutInflater;
|
|||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RelativeLayout;
|
||||
|
@ -69,9 +70,11 @@ import androidx.lifecycle.ViewModelProvider;
|
|||
import androidx.lifecycle.ViewModelStoreOwner;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
@ -80,14 +83,16 @@ import com.github.stom79.mytransl.client.HttpsConnectionException;
|
|||
import com.github.stom79.mytransl.client.Results;
|
||||
import com.github.stom79.mytransl.translate.Params;
|
||||
import com.github.stom79.mytransl.translate.Translate;
|
||||
import com.vanniktech.emoji.EmojiManager;
|
||||
import com.vanniktech.emoji.EmojiPopup;
|
||||
import com.vanniktech.emoji.one.EmojiOneProvider;
|
||||
import com.varunest.sparkbutton.SparkButton;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -96,6 +101,7 @@ import app.fedilab.android.R;
|
|||
import app.fedilab.android.activities.ComposeActivity;
|
||||
import app.fedilab.android.activities.ContextActivity;
|
||||
import app.fedilab.android.activities.CustomSharingActivity;
|
||||
import app.fedilab.android.activities.MainActivity;
|
||||
import app.fedilab.android.activities.MediaActivity;
|
||||
import app.fedilab.android.activities.ProfileActivity;
|
||||
import app.fedilab.android.activities.ReportActivity;
|
||||
|
@ -103,7 +109,9 @@ import app.fedilab.android.activities.StatusInfoActivity;
|
|||
import app.fedilab.android.client.entities.api.Attachment;
|
||||
import app.fedilab.android.client.entities.api.Notification;
|
||||
import app.fedilab.android.client.entities.api.Poll;
|
||||
import app.fedilab.android.client.entities.api.Reaction;
|
||||
import app.fedilab.android.client.entities.api.Status;
|
||||
import app.fedilab.android.client.entities.app.Account;
|
||||
import app.fedilab.android.client.entities.app.StatusCache;
|
||||
import app.fedilab.android.client.entities.app.StatusDraft;
|
||||
import app.fedilab.android.client.entities.app.Timeline;
|
||||
|
@ -127,6 +135,7 @@ import app.fedilab.android.ui.fragment.timeline.FragmentMastodonContext;
|
|||
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
|
||||
import app.fedilab.android.viewmodel.mastodon.SearchVM;
|
||||
import app.fedilab.android.viewmodel.mastodon.StatusesVM;
|
||||
import app.fedilab.android.viewmodel.pleroma.ActionsVM;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
import jp.wasabeef.glide.transformations.BlurTransformation;
|
||||
|
||||
|
@ -253,6 +262,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
statusToDeal.bookmarked = statusReturned.bookmarked;
|
||||
statusToDeal.reblogs_count = statusReturned.reblogs_count;
|
||||
statusToDeal.favourites_count = statusReturned.favourites_count;
|
||||
|
||||
//Update status in cache if not a remote instance
|
||||
if (!remote) {
|
||||
new Thread(() -> {
|
||||
|
@ -315,10 +325,120 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
boolean fullAttachement = sharedpreferences.getBoolean(context.getString(R.string.SET_FULL_PREVIEW), false);
|
||||
boolean displayBookmark = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_BOOKMARK), false);
|
||||
|
||||
if (MainActivity.currentAccount != null && MainActivity.currentAccount.api == Account.API.PLEROMA) {
|
||||
holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE);
|
||||
if (status.pleroma != null && status.pleroma.emoji_reactions != null && status.pleroma.emoji_reactions.size() > 0) {
|
||||
ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.pleroma.emoji_reactions);
|
||||
holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter);
|
||||
LinearLayoutManager layoutManager
|
||||
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
|
||||
holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
|
||||
} else {
|
||||
holder.binding.layoutReactions.reactionsView.setAdapter(null);
|
||||
}
|
||||
holder.binding.layoutReactions.statusEmoji.setOnClickListener(v -> {
|
||||
EmojiManager.install(new EmojiOneProvider());
|
||||
final EmojiPopup emojiPopup = EmojiPopup.Builder.fromRootView(holder.binding.layoutReactions.statusEmoji).setOnEmojiPopupDismissListener(() -> {
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(holder.binding.layoutReactions.statusEmoji.getWindowToken(), 0);
|
||||
}).setOnEmojiClickListener((emoji, imageView) -> {
|
||||
String emojiStr = imageView.getUnicode();
|
||||
boolean alreadyAdded = false;
|
||||
for (Reaction reaction : status.pleroma.emoji_reactions) {
|
||||
if (reaction.name.compareTo(emojiStr) == 0) {
|
||||
alreadyAdded = true;
|
||||
reaction.count = (reaction.count - 1);
|
||||
if (reaction.count == 0) {
|
||||
status.pleroma.emoji_reactions.remove(reaction);
|
||||
}
|
||||
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!alreadyAdded) {
|
||||
Reaction reaction = new Reaction();
|
||||
reaction.me = true;
|
||||
reaction.count = 1;
|
||||
reaction.name = emojiStr;
|
||||
status.pleroma.emoji_reactions.add(0, reaction);
|
||||
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
|
||||
}
|
||||
ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
||||
if (alreadyAdded) {
|
||||
actionVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||
} else {
|
||||
actionVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||
}
|
||||
})
|
||||
.build(holder.binding.layoutReactions.fakeEdittext);
|
||||
emojiPopup.toggle();
|
||||
});
|
||||
holder.binding.layoutReactions.statusAddCustomEmoji.setOnClickListener(v -> {
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle());
|
||||
int paddingPixel = 15;
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
int paddingDp = (int) (paddingPixel * density);
|
||||
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||
builder.setTitle(R.string.insert_emoji);
|
||||
AlertDialog alertDialogEmoji = null;
|
||||
if (emojis != null && emojis.size() > 0 && emojis.get(BaseMainActivity.currentInstance) != null) {
|
||||
GridView gridView = new GridView(context);
|
||||
gridView.setAdapter(new EmojiAdapter(emojis.get(BaseMainActivity.currentInstance)));
|
||||
gridView.setNumColumns(5);
|
||||
AlertDialog finalAlertDialogEmoji = alertDialogEmoji;
|
||||
gridView.setOnItemClickListener((parent, view, index, id) -> {
|
||||
String emojiStr = emojis.get(BaseMainActivity.currentInstance).get(index).shortcode;
|
||||
String url = emojis.get(BaseMainActivity.currentInstance).get(index).url;
|
||||
String static_url = emojis.get(BaseMainActivity.currentInstance).get(index).static_url;
|
||||
boolean alreadyAdded = false;
|
||||
for (Reaction reaction : status.pleroma.emoji_reactions) {
|
||||
if (reaction.name.compareTo(emojiStr) == 0) {
|
||||
alreadyAdded = true;
|
||||
reaction.count = (reaction.count - 1);
|
||||
if (reaction.count == 0) {
|
||||
status.pleroma.emoji_reactions.remove(reaction);
|
||||
}
|
||||
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!alreadyAdded) {
|
||||
Reaction reaction = new Reaction();
|
||||
reaction.me = true;
|
||||
reaction.count = 1;
|
||||
reaction.name = emojiStr;
|
||||
reaction.url = url;
|
||||
reaction.static_url = static_url;
|
||||
status.pleroma.emoji_reactions.add(0, reaction);
|
||||
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
|
||||
}
|
||||
ActionsVM actionsVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
||||
if (alreadyAdded) {
|
||||
actionsVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||
} else {
|
||||
actionsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||
}
|
||||
if (finalAlertDialogEmoji != null) {
|
||||
finalAlertDialogEmoji.dismiss();
|
||||
}
|
||||
});
|
||||
gridView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp);
|
||||
builder.setView(gridView);
|
||||
} else {
|
||||
TextView textView = new TextView(context);
|
||||
textView.setText(context.getString(R.string.no_emoji));
|
||||
textView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp);
|
||||
builder.setView(textView);
|
||||
}
|
||||
alertDialogEmoji = builder.show();
|
||||
});
|
||||
}
|
||||
|
||||
int truncate_toots_size = sharedpreferences.getInt(context.getString(R.string.SET_TRUNCATE_TOOTS_SIZE), 0);
|
||||
boolean display_video_preview = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_VIDEO_PREVIEWS), true);
|
||||
boolean isModerator = sharedpreferences.getBoolean(Helper.PREF_IS_MODERATOR, false);
|
||||
boolean isAdmin = sharedpreferences.getBoolean(Helper.PREF_IS_ADMINISTRATOR, false);
|
||||
// boolean display_video_preview = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_VIDEO_PREVIEWS), true);
|
||||
// boolean isModerator = sharedpreferences.getBoolean(Helper.PREF_IS_MODERATOR, false);
|
||||
// boolean isAdmin = sharedpreferences.getBoolean(Helper.PREF_IS_ADMINISTRATOR, false);
|
||||
int theme_icons_color = -1;
|
||||
int theme_statuses_color = -1;
|
||||
int theme_boost_header_color = -1;
|
||||
|
@ -400,6 +520,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
if (theme_statuses_color != -1) {
|
||||
holder.binding.cardviewContainer.setBackgroundColor(theme_statuses_color);
|
||||
holder.binding.translationLabel.setBackgroundColor(theme_statuses_color);
|
||||
} else {
|
||||
holder.binding.cardviewContainer.setBackgroundColor(ContextCompat.getColor(context, R.color.cyanea_primary_dark_reference));
|
||||
holder.binding.translationLabel.setBackgroundColor(ContextCompat.getColor(context, R.color.cyanea_primary_dark_reference));
|
||||
}
|
||||
if (theme_boost_header_color != -1 && status.reblog != null) {
|
||||
holder.binding.statusBoosterInfo.setBackgroundColor(theme_boost_header_color);
|
||||
|
@ -471,6 +594,35 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
holder.binding.card.setVisibility(View.GONE);
|
||||
}
|
||||
if (!canBeFederated) {
|
||||
holder.binding.actionShareContainer.setVisibility(View.VISIBLE);
|
||||
holder.binding.actionShare.setOnClickListener(v -> {
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via));
|
||||
String url;
|
||||
if (statusToDeal.uri.startsWith("http"))
|
||||
url = status.uri;
|
||||
else
|
||||
url = status.url;
|
||||
String extra_text;
|
||||
if (share_details) {
|
||||
extra_text = statusToDeal.account.acct;
|
||||
if (extra_text.split("@").length == 1)
|
||||
extra_text = "@" + extra_text + "@" + BaseMainActivity.currentInstance;
|
||||
else
|
||||
extra_text = "@" + extra_text;
|
||||
extra_text += " \uD83D\uDD17 " + url + "\r\n-\n";
|
||||
extra_text += statusToDeal.text;
|
||||
} else {
|
||||
extra_text = url;
|
||||
}
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, extra_text);
|
||||
sendIntent.setType("text/plain");
|
||||
context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with)));
|
||||
});
|
||||
} else {
|
||||
holder.binding.actionShareContainer.setVisibility(View.GONE);
|
||||
}
|
||||
if (minified || !canBeFederated) {
|
||||
holder.binding.actionButtons.setVisibility(View.GONE);
|
||||
} else {
|
||||
|
@ -491,14 +643,12 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.binding.actionButtonBookmark.setOnClickListener(v -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = statusList.get(0);
|
||||
statusesVM.bookmark(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchedStatus.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.BOOKMARK_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.BOOKMARK_ACTION, statusToDeal, _status, true));
|
||||
} else {
|
||||
Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
|
@ -506,16 +656,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (statusToDeal.bookmarked) {
|
||||
statusesVM.unBookmark(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNBOOKMARK_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNBOOKMARK_ACTION, statusToDeal, _status, false));
|
||||
} else {
|
||||
((SparkButton) v).playAnimation();
|
||||
statusesVM.bookmark(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.BOOKMARK_ACTION, statusToDeal, _status, remote);
|
||||
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.BOOKMARK_ACTION, statusToDeal, _status, false));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -523,7 +668,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.binding.statusUserInfo.setOnClickListener(v -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
|
@ -550,10 +695,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
context.startActivity(intent, options.toBundle());
|
||||
}
|
||||
});
|
||||
holder.binding.statusBoosterAvatar.setOnClickListener(v -> {
|
||||
holder.binding.statusBoosterInfo.setOnClickListener(v -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
|
@ -599,14 +744,12 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
alt_bld.setPositiveButton(R.string.yes, (dialog, id) -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
statusesVM.reblog(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchedStatus.id, null)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, true));
|
||||
} else {
|
||||
Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
|
@ -614,15 +757,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (statusToDeal.reblogged) {
|
||||
statusesVM.unReblog(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNREBLOG_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNREBLOG_ACTION, statusToDeal, _status, false));
|
||||
} else {
|
||||
((SparkButton) v).playAnimation();
|
||||
statusesVM.reblog(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, null)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, false));
|
||||
}
|
||||
}
|
||||
dialog.dismiss();
|
||||
|
@ -633,14 +772,12 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
statusesVM.reblog(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchedStatus.id, null)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, true));
|
||||
} else {
|
||||
Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
|
@ -648,15 +785,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (statusToDeal.reblogged) {
|
||||
statusesVM.unReblog(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNREBLOG_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNREBLOG_ACTION, statusToDeal, _status, false));
|
||||
} else {
|
||||
((SparkButton) v).playAnimation();
|
||||
statusesVM.reblog(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, null)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.REBLOG_ACTION, statusToDeal, _status, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -681,14 +814,12 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
alt_bld.setPositiveButton(R.string.yes, (dialog, id) -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchedStatus.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, true));
|
||||
} else {
|
||||
Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
|
@ -696,15 +827,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (status.favourited) {
|
||||
statusesVM.unFavourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNFAVOURITE_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNFAVOURITE_ACTION, statusToDeal, _status, false));
|
||||
} else {
|
||||
((SparkButton) v).playAnimation();
|
||||
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, false));
|
||||
}
|
||||
}
|
||||
dialog.dismiss();
|
||||
|
@ -715,14 +842,12 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchedStatus.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, true));
|
||||
} else {
|
||||
Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
|
@ -730,15 +855,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (statusToDeal.favourited) {
|
||||
statusesVM.unFavourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNFAVOURITE_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.UNFAVOURITE_ACTION, statusToDeal, _status, false));
|
||||
} else {
|
||||
((SparkButton) v).playAnimation();
|
||||
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
|
||||
.observe((LifecycleOwner) context, _status -> {
|
||||
manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, remote);
|
||||
});
|
||||
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, statusList, notificationList, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -748,11 +869,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
|
||||
//--- ACCOUNT INFO ---
|
||||
MastodonHelper.loadPPMastodon(holder.binding.avatar, statusToDeal.account);
|
||||
Spannable span_display_name = statusToDeal.account.span_display_name;
|
||||
if (span_display_name == null || span_display_name.toString().trim().length() == 0) {
|
||||
span_display_name = new SpannableString(statusToDeal.account.username);
|
||||
}
|
||||
holder.binding.displayName.setText(span_display_name, TextView.BufferType.SPANNABLE);
|
||||
|
||||
holder.binding.displayName.setText(
|
||||
statusToDeal.account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holder.binding.displayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
if (theme_text_header_1_line != -1) {
|
||||
holder.binding.displayName.setTextColor(theme_text_header_1_line);
|
||||
}
|
||||
|
@ -772,16 +893,27 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
}
|
||||
|
||||
if (statusToDeal.account.bot) {
|
||||
holder.binding.botIcon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.binding.botIcon.setVisibility(View.GONE);
|
||||
}
|
||||
if (statusToDeal.in_reply_to_id != null) {
|
||||
if (statusToDeal.in_reply_to_id != null && timelineType != Timeline.TimeLineEnum.UNKNOWN) {
|
||||
holder.binding.replyIcon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.binding.replyIcon.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
int ressource = R.drawable.ic_baseline_public_24;
|
||||
switch (status.visibility) {
|
||||
case "unlisted":
|
||||
ressource = R.drawable.ic_baseline_lock_open_24;
|
||||
break;
|
||||
case "private":
|
||||
ressource = R.drawable.ic_baseline_lock_24;
|
||||
break;
|
||||
case "direct":
|
||||
ressource = R.drawable.ic_baseline_mail_24;
|
||||
break;
|
||||
}
|
||||
if (status.isFocused) {
|
||||
holder.binding.statusInfo.setVisibility(View.VISIBLE);
|
||||
holder.binding.reblogsCount.setText(String.valueOf(status.reblogs_count));
|
||||
|
@ -789,23 +921,14 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.binding.time.setText(Helper.longDateToString(status.created_at));
|
||||
holder.binding.time.setVisibility(View.VISIBLE);
|
||||
holder.binding.dateShort.setVisibility(View.GONE);
|
||||
int ressource = R.drawable.ic_baseline_public_24;
|
||||
switch (status.visibility) {
|
||||
case "unlisted":
|
||||
ressource = R.drawable.ic_baseline_lock_open_24;
|
||||
break;
|
||||
case "private":
|
||||
ressource = R.drawable.ic_baseline_lock_24;
|
||||
break;
|
||||
case "direct":
|
||||
ressource = R.drawable.ic_baseline_mail_24;
|
||||
break;
|
||||
}
|
||||
holder.binding.visibility.setImageResource(ressource);
|
||||
holder.binding.dateShort.setVisibility(View.GONE);
|
||||
holder.binding.visibilitySmall.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.binding.visibilitySmall.setImageResource(ressource);
|
||||
holder.binding.statusInfo.setVisibility(View.GONE);
|
||||
holder.binding.dateShort.setVisibility(View.VISIBLE);
|
||||
holder.binding.visibilitySmall.setVisibility(View.VISIBLE);
|
||||
holder.binding.dateShort.setText(Helper.dateDiff(context, status.created_at));
|
||||
holder.binding.time.setVisibility(View.GONE);
|
||||
Helper.absoluteDateTimeReveal(context, holder.binding.dateShort, status.created_at);
|
||||
|
@ -817,7 +940,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
if (expand_cw || expand) {
|
||||
holder.binding.spoilerExpand.setVisibility(View.VISIBLE);
|
||||
holder.binding.spoiler.setVisibility(View.VISIBLE);
|
||||
holder.binding.spoiler.setText(statusToDeal.span_spoiler_text, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.spoiler.setText(
|
||||
statusToDeal.getSpanSpoiler(context,
|
||||
new WeakReference<>(holder.binding.spoiler)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
statusToDeal.isExpended = true;
|
||||
statusToDeal.isMediaDisplayed = true;
|
||||
} else {
|
||||
|
@ -828,7 +954,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
});
|
||||
holder.binding.spoilerExpand.setVisibility(View.VISIBLE);
|
||||
holder.binding.spoiler.setVisibility(View.VISIBLE);
|
||||
holder.binding.spoiler.setText(statusToDeal.span_spoiler_text, TextView.BufferType.SPANNABLE);
|
||||
|
||||
holder.binding.spoiler.setText(
|
||||
statusToDeal.getSpanSpoiler(context,
|
||||
new WeakReference<>(holder.binding.spoiler)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
}
|
||||
if (statusToDeal.isExpended) {
|
||||
holder.binding.spoilerExpand.setText(context.getString(R.string.hide_content));
|
||||
|
@ -844,13 +974,13 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
//--- BOOSTER INFO ---
|
||||
if (status.reblog != null) {
|
||||
MastodonHelper.loadPPMastodon(holder.binding.statusBoosterAvatar, status.account);
|
||||
Spannable span_display_name_boost = status.account.span_display_name;
|
||||
if (span_display_name_boost == null || span_display_name_boost.toString().trim().length() == 0) {
|
||||
span_display_name_boost = new SpannableString(status.account.username);
|
||||
}
|
||||
holder.binding.statusBoosterDisplayName.setText(span_display_name_boost, TextView.BufferType.SPANNABLE);
|
||||
|
||||
holder.binding.statusBoosterDisplayName.setText(
|
||||
status.account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holder.binding.statusBoosterDisplayName)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
|
||||
holder.binding.statusBoosterInfo.setVisibility(View.VISIBLE);
|
||||
holder.binding.boosterDivider.setVisibility(View.VISIBLE);
|
||||
if (theme_text_header_1_line != -1) {
|
||||
holder.binding.statusBoosterDisplayName.setTextColor(theme_text_header_1_line);
|
||||
}
|
||||
|
@ -860,7 +990,6 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
}
|
||||
} else {
|
||||
holder.binding.statusBoosterInfo.setVisibility(View.GONE);
|
||||
holder.binding.boosterDivider.setVisibility(View.GONE);
|
||||
}
|
||||
//--- BOOST VISIBILITY ---
|
||||
switch (statusToDeal.visibility) {
|
||||
|
@ -880,7 +1009,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
break;
|
||||
}
|
||||
//--- MAIN CONTENT ---
|
||||
holder.binding.statusContent.setText(statusToDeal.span_content, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.statusContent.setText(
|
||||
statusToDeal.getSpanContent(context,
|
||||
new WeakReference<>(holder.binding.statusContent)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
if (truncate_toots_size > 0) {
|
||||
holder.binding.statusContent.setMaxLines(truncate_toots_size);
|
||||
holder.binding.statusContent.setEllipsize(TextUtils.TruncateAt.END);
|
||||
|
@ -911,7 +1043,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
}
|
||||
if (statusToDeal.translationContent != null) {
|
||||
holder.binding.containerTrans.setVisibility(View.VISIBLE);
|
||||
holder.binding.statusContentTranslated.setText(statusToDeal.span_translate, TextView.BufferType.SPANNABLE);
|
||||
holder.binding.statusContentTranslated.setText(
|
||||
statusToDeal.getSpanTranslate(context,
|
||||
new WeakReference<>(holder.binding.statusContentTranslated)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
} else {
|
||||
holder.binding.containerTrans.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -925,6 +1060,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.binding.statusContent.setVisibility(View.GONE);
|
||||
holder.binding.mediaContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
|
||||
//--- MEDIA ATTACHMENT ---
|
||||
if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) {
|
||||
|
@ -994,17 +1130,19 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
|
||||
if (!mediaObfuscated(statusToDeal) || expand_media) {
|
||||
layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_24);
|
||||
Glide.with(layoutMediaBinding.media.getContext())
|
||||
RequestBuilder<Drawable> requestBuilder = Glide.with(layoutMediaBinding.media.getContext())
|
||||
.load(statusToDeal.media_attachments.get(0).preview_url)
|
||||
.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY)))
|
||||
.into(layoutMediaBinding.media);
|
||||
.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY)));
|
||||
if (!fullAttachement) {
|
||||
requestBuilder = requestBuilder.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY)));
|
||||
}
|
||||
requestBuilder.into(layoutMediaBinding.media);
|
||||
} else {
|
||||
layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_off_24);
|
||||
Glide.with(layoutMediaBinding.media.getContext())
|
||||
.load(statusToDeal.media_attachments.get(0).preview_url)
|
||||
.apply(new RequestOptions().transform(new BlurTransformation(50, 3)))
|
||||
// .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners((int) Helper.convertDpToPixel(3, context))))
|
||||
.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY)))
|
||||
.into(layoutMediaBinding.media);
|
||||
}
|
||||
layoutMediaBinding.viewHide.setOnClickListener(v -> {
|
||||
|
@ -1046,17 +1184,18 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
lp.setMargins(0, 0, (int) Helper.convertDpToPixel(5, context), 0);
|
||||
if (!mediaObfuscated(statusToDeal) || expand_media) {
|
||||
layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_24);
|
||||
Glide.with(layoutMediaBinding.media.getContext())
|
||||
RequestBuilder<Drawable> requestBuilder = Glide.with(layoutMediaBinding.media.getContext())
|
||||
.load(attachment.preview_url)
|
||||
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners((int) Helper.convertDpToPixel(3, context))))
|
||||
.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY)))
|
||||
.into(layoutMediaBinding.media);
|
||||
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners((int) Helper.convertDpToPixel(3, context))));
|
||||
if (!fullAttachement) {
|
||||
requestBuilder = requestBuilder.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY)));
|
||||
}
|
||||
requestBuilder.into(layoutMediaBinding.media);
|
||||
} else {
|
||||
layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_off_24);
|
||||
Glide.with(layoutMediaBinding.media.getContext())
|
||||
.load(attachment.preview_url)
|
||||
.apply(new RequestOptions().transform(new BlurTransformation(50, 3)))
|
||||
.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY)))
|
||||
// .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners((int) Helper.convertDpToPixel(3, context))))
|
||||
.into(layoutMediaBinding.media);
|
||||
}
|
||||
|
@ -1096,7 +1235,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.binding.reblogInfo.setOnClickListener(v -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
|
@ -1123,7 +1262,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.binding.favouriteInfo.setOnClickListener(v -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
|
@ -1174,7 +1313,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
pollItemBinding.pollItemPercent.setTextColor(theme_text_color);
|
||||
pollItemBinding.pollItemText.setTextColor(theme_text_color);
|
||||
}
|
||||
pollItemBinding.pollItemText.setText(pollItem.span_title, TextView.BufferType.SPANNABLE);
|
||||
pollItemBinding.pollItemText.setText(
|
||||
pollItem.getSpanTitle(context, statusToDeal,
|
||||
new WeakReference<>(pollItemBinding.pollItemText)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
pollItemBinding.pollItemValue.setProgress((int) value);
|
||||
if (pollItem.votes_count == greaterValue) {
|
||||
pollItemBinding.pollItemPercent.setTypeface(null, Typeface.BOLD);
|
||||
|
@ -1202,7 +1344,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
for (Poll.PollItem pollOption : statusToDeal.poll.options) {
|
||||
CheckBox cb = new CheckBox(context);
|
||||
cb.setButtonTintList(ThemeHelper.getButtonColorStateList(context));
|
||||
cb.setText(pollOption.span_title, TextView.BufferType.SPANNABLE);
|
||||
cb.setText(
|
||||
pollOption.getSpanTitle(context, statusToDeal,
|
||||
new WeakReference<>(cb)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holder.binding.poll.multipleChoice.addView(cb);
|
||||
}
|
||||
holder.binding.poll.multipleChoice.setVisibility(View.VISIBLE);
|
||||
|
@ -1213,7 +1358,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
for (Poll.PollItem pollOption : statusToDeal.poll.options) {
|
||||
RadioButton rb = new RadioButton(context);
|
||||
rb.setButtonTintList(ThemeHelper.getButtonColorStateList(context));
|
||||
rb.setText(pollOption.span_title, TextView.BufferType.SPANNABLE);
|
||||
rb.setText(
|
||||
pollOption.getSpanTitle(context, statusToDeal,
|
||||
new WeakReference<>(rb)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
|
||||
holder.binding.poll.singleChoiceRadioGroup.addView(rb);
|
||||
}
|
||||
holder.binding.poll.singleChoiceRadioGroup.setVisibility(View.VISIBLE);
|
||||
|
@ -1256,7 +1405,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
//Vote on the poll
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
|
@ -1322,9 +1471,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
return false;
|
||||
});
|
||||
if (!minified && canBeFederated) {
|
||||
holder.binding.mainContainer.setOnClickListener(v -> {
|
||||
holder.binding.statusContent.callOnClick();
|
||||
});
|
||||
holder.binding.mainContainer.setOnClickListener(v -> holder.binding.statusContent.callOnClick());
|
||||
holder.binding.statusContent.setOnClickListener(v -> {
|
||||
if (status.isFocused || v.getTag() == SpannableHelper.CLICKABLE_SPAN) {
|
||||
if (v.getTag() == SpannableHelper.CLICKABLE_SPAN) {
|
||||
|
@ -1340,7 +1487,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
} else {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = results.statuses.get(0);
|
||||
|
@ -1446,11 +1593,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
builderInner.show();
|
||||
} else if (itemId == R.id.action_schedule_boost) {
|
||||
MastodonHelper.scheduleBoost(context, MastodonHelper.ScheduleType.BOOST, statusToDeal, null, null);
|
||||
} else if (itemId == R.id.action_admin) {
|
||||
/* Intent intent = new Intent(context, AccountReportActivity.class);
|
||||
} /*else if (itemId == R.id.action_admin) {
|
||||
Intent intent = new Intent(context, AccountReportActivity.class);
|
||||
intent.putExtra(Helper.ARG_ACCOUNT, statusToDeal.account);
|
||||
context.startActivity(intent);*/
|
||||
} else if (itemId == R.id.action_open_browser) {
|
||||
context.startActivity(intent);
|
||||
} */ else if (itemId == R.id.action_open_browser) {
|
||||
Helper.openBrowser(context, statusToDeal.url);
|
||||
} else if (itemId == R.id.action_remove) {
|
||||
AlertDialog.Builder builderInner = new AlertDialog.Builder(context, Helper.dialogStyle());
|
||||
|
@ -1540,12 +1687,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
if (translate.getTranslatedContent() != null) {
|
||||
statusToDeal.translationShown = true;
|
||||
statusToDeal.translationContent = translate.getTranslatedContent();
|
||||
new Thread(() -> {
|
||||
SpannableHelper.convertStatus(context.getApplicationContext(), statusToDeal);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
adapter.notifyItemChanged(getPositionAsync(notificationList, statusList, statusToDeal));
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
@ -1631,7 +1773,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.binding.actionButtonReply.setOnClickListener(v -> {
|
||||
if (remote) {
|
||||
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.url, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
|
||||
.observe((LifecycleOwner) context, results -> {
|
||||
if (results.statuses != null && results.statuses.size() > 0) {
|
||||
Status fetchedStatus = statusList.get(0);
|
||||
|
@ -1657,6 +1799,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
holder.bindingReport.checkbox.setChecked(status.isChecked);
|
||||
holder.bindingReport.checkbox.setOnClickListener(v -> status.isChecked = !status.isChecked);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean mediaObfuscated(Status status) {
|
||||
|
@ -1723,6 +1866,34 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will manage the current position of the element in the adapter. Action is async, and position might have changed
|
||||
*
|
||||
* @param notificationList List<Notification> - Not null when calling from notification adapter
|
||||
* @param statusList ist<Status> statusList - Not null when calling from status adapter
|
||||
* @param id String - Current status
|
||||
* @return int - position in real time
|
||||
*/
|
||||
public static int getPositionAsync(List<Notification> notificationList, List<Status> statusList, String id) {
|
||||
int position = 0;
|
||||
if (statusList != null) {
|
||||
for (Status _status : statusList) {
|
||||
if (id != null && ((_status.id != null && _status.id.compareTo(id) == 0) || (_status.reblog != null && _status.reblog.id != null && _status.reblog.id.compareTo(id) == 0))) {
|
||||
break;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
} else if (notificationList != null) {
|
||||
for (Notification notification : notificationList) {
|
||||
if (notification.status != null && notification.status.id.compareTo(id) == 0) {
|
||||
break;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (timelineType == Timeline.TimeLineEnum.ART) {
|
||||
|
@ -1783,36 +1954,6 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class);
|
||||
SearchVM searchVM = new ViewModelProvider((ViewModelStoreOwner) context).get(SearchVM.class);
|
||||
statusManagement(context, statusesVM, searchVM, holder, this, statusList, null, status, timelineType, minified, canBeFederated);
|
||||
if (holder.timer != null) {
|
||||
holder.timer.cancel();
|
||||
holder.timer = null;
|
||||
}
|
||||
if (holder.dateTimer != null) {
|
||||
holder.dateTimer.cancel();
|
||||
holder.dateTimer = null;
|
||||
}
|
||||
if (status.emojis != null && status.emojis.size() > 0) {
|
||||
holder.timer = new Timer();
|
||||
holder.timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> holder.binding.statusContent.invalidate();
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
}
|
||||
}, 100, 100);
|
||||
}
|
||||
holder.dateTimer = new Timer();
|
||||
holder.dateTimer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> holder.binding.dateShort.setText(Helper.dateDiff(context, status.created_at));
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
}
|
||||
}, 100, 10000);
|
||||
} else if (viewHolder.getItemViewType() == STATUS_ART) {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
MastodonHelper.loadPPMastodon(holder.bindingArt.artPp, status.account);
|
||||
|
@ -1820,7 +1961,10 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
.load(status.art_attachment.preview_url)
|
||||
.apply(new RequestOptions().transform(new RoundedCorners((int) Helper.convertDpToPixel(3, context))))
|
||||
.into(holder.bindingArt.artMedia);
|
||||
holder.bindingArt.artAcct.setText(status.account.span_display_name, TextView.BufferType.SPANNABLE);
|
||||
holder.bindingArt.artAcct.setText(
|
||||
status.account.getSpanDisplayName(context,
|
||||
new WeakReference<>(holder.bindingArt.artAcct)),
|
||||
TextView.BufferType.SPANNABLE);
|
||||
holder.bindingArt.artUsername.setText(String.format(Locale.getDefault(), "@%s", status.account.acct));
|
||||
holder.bindingArt.artPp.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(context, ProfileActivity.class);
|
||||
|
@ -1878,12 +2022,6 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
@Override
|
||||
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
|
||||
super.onViewRecycled(holder);
|
||||
if (holder instanceof StatusViewHolder && ((StatusViewHolder) holder).timer != null) {
|
||||
((StatusViewHolder) holder).timer.cancel();
|
||||
}
|
||||
if (holder instanceof StatusViewHolder && ((StatusViewHolder) holder).dateTimer != null) {
|
||||
((StatusViewHolder) holder).dateTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public interface FetchMoreCallBack {
|
||||
|
@ -1899,8 +2037,6 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
DrawerFetchMoreBinding bindingFetchMore;
|
||||
DrawerStatusNotificationBinding bindingNotification;
|
||||
DrawerStatusArtBinding bindingArt;
|
||||
Timer timer;
|
||||
Timer dateTimer;
|
||||
|
||||
StatusViewHolder(DrawerStatusBinding itemView) {
|
||||
super(itemView.getRoot());
|
||||
|
|
|
@ -122,7 +122,7 @@ public class FragmentMedia extends Fragment {
|
|||
|
||||
binding.mediaPicture.setVisibility(View.VISIBLE);
|
||||
binding.mediaPicture.setTransitionName(attachment.url);
|
||||
if (Helper.isValidContextForGlide(requireActivity())) {
|
||||
if (Helper.isValidContextForGlide(requireActivity()) && isAdded()) {
|
||||
Glide.with(requireActivity())
|
||||
.asBitmap()
|
||||
.dontTransform()
|
||||
|
@ -142,7 +142,7 @@ public class FragmentMedia extends Fragment {
|
|||
binding.mediaPicture.setVisibility(View.VISIBLE);
|
||||
binding.pbarInf.setIndeterminate(true);
|
||||
binding.loader.setVisibility(View.VISIBLE);
|
||||
if (Helper.isValidContextForGlide(requireActivity())) {
|
||||
if (Helper.isValidContextForGlide(requireActivity()) && isAdded()) {
|
||||
Glide.with(requireActivity())
|
||||
.asBitmap()
|
||||
.dontTransform()
|
||||
|
@ -312,7 +312,6 @@ public class FragmentMedia extends Fragment {
|
|||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
binding = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,11 +14,14 @@ package app.fedilab.android.ui.fragment.settings;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
|
@ -31,16 +34,28 @@ public class FragmentLanguageSettings extends PreferenceFragmentCompat implement
|
|||
createPref();
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private void createPref() {
|
||||
ListPreference SET_DEFAULT_LOCALE_NEW = findPreference(getString(R.string.SET_DEFAULT_LOCALE_NEW));
|
||||
if (SET_DEFAULT_LOCALE_NEW != null) {
|
||||
SET_DEFAULT_LOCALE_NEW.getContext().setTheme(Helper.dialogStyle());
|
||||
}
|
||||
|
||||
Preference SET_TRANSLATE_VALUES_RESET = findPreference(getString(R.string.SET_TRANSLATE_VALUES_RESET));
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
||||
if (SET_TRANSLATE_VALUES_RESET != null) {
|
||||
SET_TRANSLATE_VALUES_RESET.setOnPreferenceClickListener(preference -> {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(getString(R.string.SET_DEFAULT_LOCALE_NEW), null);
|
||||
editor.commit();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.compareToIgnoreCase(getString(R.string.SET_DEFAULT_LOCALE_NEW)) == 0) {
|
||||
if (key.compareToIgnoreCase(getString(R.string.SET_DEFAULT_LOCALE_NEW)) == 0 || key.compareToIgnoreCase(getString(R.string.SET_TRANSLATE_VALUES_RESET)) == 0) {
|
||||
requireActivity().recreate();
|
||||
Helper.recreateMainActivity(requireActivity());
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ import android.content.BroadcastReceiver;
|
|||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -45,7 +43,6 @@ import app.fedilab.android.client.entities.app.Timeline;
|
|||
import app.fedilab.android.databinding.FragmentPaginationBinding;
|
||||
import app.fedilab.android.helper.DividerDecoration;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.helper.ThemeHelper;
|
||||
import app.fedilab.android.ui.drawer.StatusAdapter;
|
||||
import app.fedilab.android.viewmodel.mastodon.StatusesVM;
|
||||
|
@ -98,26 +95,19 @@ public class FragmentMastodonContext extends Fragment {
|
|||
}
|
||||
} else if (statusPosted != null && statusAdapter != null) {
|
||||
if (requireActivity() instanceof ContextActivity) {
|
||||
new Thread(() -> {
|
||||
Status convertStatus = SpannableHelper.convertStatus(context, statusPosted);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
int i = 0;
|
||||
for (Status status : statuses) {
|
||||
if (status.id.equals(convertStatus.in_reply_to_id)) {
|
||||
statuses.add((i + 1), convertStatus);
|
||||
statusAdapter.notifyItemInserted((i + 1));
|
||||
if (requireActivity() instanceof ContextActivity) {
|
||||
//Redraw decorations
|
||||
statusAdapter.notifyItemRangeChanged(0, statuses.size());
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
int i = 0;
|
||||
for (Status status : statuses) {
|
||||
if (status.id.equals(statusPosted.in_reply_to_id)) {
|
||||
statuses.add((i + 1), statusPosted);
|
||||
statusAdapter.notifyItemInserted((i + 1));
|
||||
if (requireActivity() instanceof ContextActivity) {
|
||||
//Redraw decorations
|
||||
statusAdapter.notifyItemRangeChanged(0, statuses.size());
|
||||
}
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,17 +14,14 @@ package app.fedilab.android.ui.fragment.timeline;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -178,22 +175,6 @@ public class FragmentMastodonNotification extends Fragment implements Notificati
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
NotificationManager mNotificationManager = (NotificationManager) requireActivity().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && BaseMainActivity.currentAccount != null && BaseMainActivity.currentAccount.mastodon_account != null) {
|
||||
for (StatusBarNotification statusBarNotification : mNotificationManager.getActiveNotifications()) {
|
||||
if ((BaseMainActivity.currentAccount.mastodon_account.acct + "@" + BaseMainActivity.currentAccount.instance).equals(statusBarNotification.getGroupKey())) {
|
||||
mNotificationManager.cancel(statusBarNotification.getId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mNotificationManager.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Intialize the view for notifications
|
||||
*
|
||||
|
@ -456,25 +437,28 @@ public class FragmentMastodonNotification extends Fragment implements Notificati
|
|||
}
|
||||
int position = 0;
|
||||
//We loop through messages already in the timeline
|
||||
for (Notification notificationsAlreadyPresent : this.notificationList) {
|
||||
//We compare the date of each status and we only add status having a date greater than the another, it is inserted at this position
|
||||
//Pinned messages are ignored because their date can be older
|
||||
if (notificationReceived.id.compareTo(notificationsAlreadyPresent.id) > 0) {
|
||||
if (this.notificationList != null) {
|
||||
notificationAdapter.notifyItemRangeChanged(0, this.notificationList.size());
|
||||
for (Notification notificationsAlreadyPresent : this.notificationList) {
|
||||
//We compare the date of each status and we only add status having a date greater than the another, it is inserted at this position
|
||||
//Pinned messages are ignored because their date can be older
|
||||
if (notificationReceived.id.compareTo(notificationsAlreadyPresent.id) > 0) {
|
||||
//We add the status to a list of id - thus we know it is already in the timeline
|
||||
idOfAddedNotifications.add(notificationReceived.id);
|
||||
this.notificationList.add(position, notificationReceived);
|
||||
notificationAdapter.notifyItemInserted(position);
|
||||
break;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
//Statuses added at the bottom, we flag them by position = -2 for not dealing with them and fetch more
|
||||
if (position == this.notificationList.size()) {
|
||||
//We add the status to a list of id - thus we know it is already in the timeline
|
||||
idOfAddedNotifications.add(notificationReceived.id);
|
||||
this.notificationList.add(position, notificationReceived);
|
||||
notificationAdapter.notifyItemInserted(position);
|
||||
break;
|
||||
return NOTIFICATION__AT_THE_BOTTOM;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
//Statuses added at the bottom, we flag them by position = -2 for not dealing with them and fetch more
|
||||
if (position == this.notificationList.size()) {
|
||||
//We add the status to a list of id - thus we know it is already in the timeline
|
||||
idOfAddedNotifications.add(notificationReceived.id);
|
||||
this.notificationList.add(position, notificationReceived);
|
||||
notificationAdapter.notifyItemInserted(position);
|
||||
return NOTIFICATION__AT_THE_BOTTOM;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
@ -491,8 +475,8 @@ public class FragmentMastodonNotification extends Fragment implements Notificati
|
|||
}
|
||||
}).start();
|
||||
}
|
||||
super.onDestroyView();
|
||||
LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(receive_action);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,7 +30,6 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
@ -57,7 +56,6 @@ import app.fedilab.android.client.entities.app.Timeline;
|
|||
import app.fedilab.android.databinding.FragmentPaginationBinding;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.helper.ThemeHelper;
|
||||
import app.fedilab.android.ui.drawer.StatusAdapter;
|
||||
import app.fedilab.android.viewmodel.mastodon.AccountsVM;
|
||||
|
@ -119,15 +117,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
statusAdapter.notifyItemRemoved(position);
|
||||
}
|
||||
} else if (statusPosted != null && statusAdapter != null && timelineType == Timeline.TimeLineEnum.HOME) {
|
||||
new Thread(() -> {
|
||||
Status convertStatus = SpannableHelper.convertStatus(context, statusPosted);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
statuses.add(0, convertStatus);
|
||||
statusAdapter.notifyItemInserted(0);
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
statuses.add(0, statusPosted);
|
||||
statusAdapter.notifyItemInserted(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,15 +175,12 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
|
||||
public void scrollToTop() {
|
||||
if (binding != null) {
|
||||
binding.recyclerView.scrollToPosition(0);
|
||||
binding.swipeContainer.setRefreshing(true);
|
||||
flagLoading = false;
|
||||
route(DIRECTION.SCROLL_TOP, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
}
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
|
||||
|
@ -437,6 +425,9 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
} else if (direction == DIRECTION.BOTTOM) {
|
||||
flagLoading = true;
|
||||
}
|
||||
if (direction == DIRECTION.SCROLL_TOP) {
|
||||
binding.recyclerView.scrollToPosition(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -473,7 +464,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
statusFetchMore.isFetchMore = true;
|
||||
statusFetchMore.id = Helper.generateString();
|
||||
int insertAt;
|
||||
if (direction == DIRECTION.REFRESH || direction == DIRECTION.BOTTOM) {
|
||||
if (direction == DIRECTION.REFRESH || direction == DIRECTION.BOTTOM || direction == DIRECTION.SCROLL_TOP) {
|
||||
insertAt = lastInsertedPosition;
|
||||
} else {
|
||||
insertAt = initialInsertedPosition;
|
||||
|
@ -499,27 +490,31 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
return STATUS_PRESENT;
|
||||
}
|
||||
int position = 0;
|
||||
//We loop through messages already in the timeline
|
||||
for (Status statusAlreadyPresent : this.statuses) {
|
||||
//We compare the date of each status and we only add status having a date greater than the another, it is inserted at this position
|
||||
//Pinned messages are ignored because their date can be older
|
||||
if (statusReceived.id.compareTo(statusAlreadyPresent.id) > 0 && !statusAlreadyPresent.pinned) {
|
||||
if (this.statuses != null) {
|
||||
statusAdapter.notifyItemRangeChanged(0, this.statuses.size());
|
||||
//We loop through messages already in the timeline
|
||||
for (Status statusAlreadyPresent : this.statuses) {
|
||||
//We compare the date of each status and we only add status having a date greater than the another, it is inserted at this position
|
||||
//Pinned messages are ignored because their date can be older
|
||||
if (statusReceived.id.compareTo(statusAlreadyPresent.id) > 0 && !statusAlreadyPresent.pinned) {
|
||||
//We add the status to a list of id - thus we know it is already in the timeline
|
||||
idOfAddedStatuses.add(statusReceived.id);
|
||||
this.statuses.add(position, statusReceived);
|
||||
statusAdapter.notifyItemInserted(position);
|
||||
break;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
//Statuses added at the bottom, we flag them by position = -2 for not dealing with them and fetch more
|
||||
if (position == this.statuses.size()) {
|
||||
//We add the status to a list of id - thus we know it is already in the timeline
|
||||
idOfAddedStatuses.add(statusReceived.id);
|
||||
this.statuses.add(position, statusReceived);
|
||||
statusAdapter.notifyItemInserted(position);
|
||||
break;
|
||||
return STATUS_AT_THE_BOTTOM;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
//Statuses added at the bottom, we flag them by position = -2 for not dealing with them and fetch more
|
||||
if (position == this.statuses.size()) {
|
||||
//We add the status to a list of id - thus we know it is already in the timeline
|
||||
idOfAddedStatuses.add(statusReceived.id);
|
||||
this.statuses.add(position, statusReceived);
|
||||
statusAdapter.notifyItemInserted(position);
|
||||
return STATUS_AT_THE_BOTTOM;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
|
@ -627,11 +622,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
} else if (direction == DIRECTION.TOP) {
|
||||
timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, true, false, false, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing));
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, true, false, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -647,11 +642,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
} else if (direction == DIRECTION.TOP) {
|
||||
timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, false, true, false, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing));
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getPublic(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, false, true, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -669,11 +664,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false));
|
||||
} else if (direction == DIRECTION.TOP) {
|
||||
flagLoading = false;
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getNitter(remoteInstance, pinnedTimeline.remoteInstance.host, null)
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -692,11 +687,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false));
|
||||
} else if (direction == DIRECTION.TOP) {
|
||||
flagLoading = false;
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getMisskey(remoteInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -713,11 +708,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false));
|
||||
} else if (direction == DIRECTION.TOP) {
|
||||
flagLoading = false;
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getPeertube(remoteInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -733,11 +728,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
} else if (direction == DIRECTION.TOP) {
|
||||
timelinesVM.getPublic(null, remoteInstance, true, false, false, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing));
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getPublic(null, remoteInstance, true, false, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -754,11 +749,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
} else if (direction == DIRECTION.TOP) {
|
||||
timelinesVM.getList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, list_id, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing));
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, list_id, null, null, null, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -778,11 +773,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
} else if (direction == DIRECTION.TOP) {
|
||||
timelinesVM.getHashTag(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, tagTimeline.name, false, tagTimeline.isART, tagTimeline.all, tagTimeline.any, tagTimeline.none, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing));
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getHashTag(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, tagTimeline.name, false, tagTimeline.isART, tagTimeline.all, tagTimeline.any, tagTimeline.none, null, null, null, MastodonHelper.statusesPerCall(requireActivity()))
|
||||
.observe(getViewLifecycleOwner(), statusesRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusesRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusesRefresh);
|
||||
}
|
||||
|
@ -964,11 +959,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
.observe(getViewLifecycleOwner(), statusesTop -> dealWithPagination(statusesTop, DIRECTION.TOP, true));
|
||||
}
|
||||
|
||||
} else if (direction == DIRECTION.REFRESH) {
|
||||
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
|
||||
timelinesVM.getHome(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, true, null, null, null, MastodonHelper.statusesPerCall(requireActivity()), false)
|
||||
.observe(getViewLifecycleOwner(), statusRefresh -> {
|
||||
if (statusAdapter != null) {
|
||||
dealWithPagination(statusRefresh, DIRECTION.REFRESH, true);
|
||||
dealWithPagination(statusRefresh, direction, true);
|
||||
} else {
|
||||
initializeStatusesCommonView(statusRefresh);
|
||||
}
|
||||
|
@ -1029,6 +1024,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
|||
public enum DIRECTION {
|
||||
TOP,
|
||||
BOTTOM,
|
||||
REFRESH
|
||||
REFRESH,
|
||||
SCROLL_TOP
|
||||
}
|
||||
}
|
|
@ -14,15 +14,17 @@ package app.fedilab.android.ui.fragment.timeline;
|
|||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
@ -238,6 +240,20 @@ public class FragmentNotificationContainer extends Fragment {
|
|||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
NotificationManager mNotificationManager = (NotificationManager) requireActivity().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && BaseMainActivity.currentAccount != null && BaseMainActivity.currentAccount.mastodon_account != null) {
|
||||
for (StatusBarNotification statusBarNotification : mNotificationManager.getActiveNotifications()) {
|
||||
if (statusBarNotification.getGroupKey().contains(BaseMainActivity.currentAccount.mastodon_account.acct + "@" + BaseMainActivity.currentAccount.instance)) {
|
||||
mNotificationManager.cancel(statusBarNotification.getId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mNotificationManager.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void scrollToTop() {
|
||||
if (binding != null) {
|
||||
|
@ -251,11 +267,5 @@ public class FragmentNotificationContainer extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ import app.fedilab.android.client.entities.api.Tag;
|
|||
import app.fedilab.android.client.entities.api.Token;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Call;
|
||||
|
@ -306,9 +305,6 @@ public class AccountsVM extends AndroidViewModel {
|
|||
}
|
||||
}
|
||||
Account finalAccount = account;
|
||||
if (finalAccount != null) {
|
||||
SpannableHelper.convertAccount(getApplication().getApplicationContext(), finalAccount);
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> accountMutableLiveData.setValue(finalAccount);
|
||||
mainHandler.post(myRunnable);
|
||||
|
@ -342,7 +338,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<List<Status>> accountStatusesResponse = accountStatusesCall.execute();
|
||||
if (accountStatusesResponse.isSuccessful()) {
|
||||
statusList = SpannableHelper.convertStatus(getApplication().getApplicationContext(), accountStatusesResponse.body());
|
||||
statusList = accountStatusesResponse.body();
|
||||
pagination = MastodonHelper.getPagination(accountStatusesResponse.headers());
|
||||
|
||||
}
|
||||
|
@ -378,7 +374,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<List<Account>> followersResponse = followersCall.execute();
|
||||
if (followersResponse.isSuccessful()) {
|
||||
accountList = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), followersResponse.body());
|
||||
accountList = followersResponse.body();
|
||||
pagination = MastodonHelper.getPagination(followersResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -414,7 +410,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<List<Account>> followingResponse = followingCall.execute();
|
||||
if (followingResponse.isSuccessful()) {
|
||||
accountList = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), followingResponse.body());
|
||||
accountList = followingResponse.body();
|
||||
pagination = MastodonHelper.getPagination(followingResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -883,11 +879,6 @@ public class AccountsVM extends AndroidViewModel {
|
|||
}
|
||||
}
|
||||
List<Account> finalAccountList = accountList;
|
||||
if (finalAccountList != null) {
|
||||
for (Account account : finalAccountList) {
|
||||
SpannableHelper.convertAccount(getApplication().getApplicationContext(), account);
|
||||
}
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> accountListMutableLiveData.setValue(finalAccountList);
|
||||
mainHandler.post(myRunnable);
|
||||
|
@ -912,7 +903,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
Response<List<Status>> bookmarksResponse = bookmarksCall.execute();
|
||||
if (bookmarksResponse.isSuccessful()) {
|
||||
statusList = bookmarksResponse.body();
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusList);
|
||||
statuses.statuses = statusList;
|
||||
statuses.pagination = MastodonHelper.getPagination(bookmarksResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -943,7 +934,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
Response<List<Status>> favouritesResponse = favouritesCall.execute();
|
||||
if (favouritesResponse.isSuccessful()) {
|
||||
statusList = favouritesResponse.body();
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusList);
|
||||
statuses.statuses = statusList;
|
||||
statuses.pagination = MastodonHelper.getPagination(favouritesResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -975,7 +966,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
Response<List<Account>> mutesResponse = mutesCall.execute();
|
||||
if (mutesResponse.isSuccessful()) {
|
||||
accountList = mutesResponse.body();
|
||||
accounts.accounts = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), accountList);
|
||||
accounts.accounts = accountList;
|
||||
accounts.pagination = MastodonHelper.getPagination(mutesResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -1007,7 +998,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
Response<List<Account>> blocksResponse = blocksCall.execute();
|
||||
if (blocksResponse.isSuccessful()) {
|
||||
accountList = blocksResponse.body();
|
||||
accounts.accounts = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), accountList);
|
||||
accounts.accounts = accountList;
|
||||
accounts.pagination = MastodonHelper.getPagination(blocksResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -1303,7 +1294,7 @@ public class AccountsVM extends AndroidViewModel {
|
|||
Response<List<Account>> followRequestsResponse = followRequestsCall.execute();
|
||||
if (followRequestsResponse.isSuccessful()) {
|
||||
accountList = followRequestsResponse.body();
|
||||
accounts.accounts = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), accountList);
|
||||
accounts.accounts = accountList;
|
||||
accounts.pagination = MastodonHelper.getPagination(followRequestsResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -23,16 +23,12 @@ import androidx.lifecycle.AndroidViewModel;
|
|||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import app.fedilab.android.client.endpoints.MastodonAnnouncementsService;
|
||||
import app.fedilab.android.client.entities.api.Announcement;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Response;
|
||||
|
@ -55,7 +51,6 @@ public class AnnouncementsVM extends AndroidViewModel {
|
|||
}
|
||||
|
||||
private MastodonAnnouncementsService init(@NonNull String instance) {
|
||||
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
|
||||
Retrofit retrofit = new Retrofit.Builder()
|
||||
.baseUrl("https://" + instance + "/api/v1/")
|
||||
.addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder()))
|
||||
|
@ -83,7 +78,6 @@ public class AnnouncementsVM extends AndroidViewModel {
|
|||
Response<List<Announcement>> getAnnouncementsResponse = getAnnouncementsCall.execute();
|
||||
if (getAnnouncementsResponse.isSuccessful()) {
|
||||
announcementList = getAnnouncementsResponse.body();
|
||||
SpannableHelper.convertAnnouncement(getApplication(), announcementList);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -35,7 +35,6 @@ import app.fedilab.android.client.entities.api.Notifications;
|
|||
import app.fedilab.android.client.entities.api.PushSubscription;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.helper.TimelineHelper;
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Call;
|
||||
|
@ -103,15 +102,6 @@ public class NotificationsVM extends AndroidViewModel {
|
|||
if (notificationsResponse.isSuccessful()) {
|
||||
List<Notification> notFilteredNotifications = notificationsResponse.body();
|
||||
notifications.notifications = TimelineHelper.filterNotification(getApplication().getApplicationContext(), notFilteredNotifications);
|
||||
if (notifications.notifications != null) {
|
||||
for (Notification notification : notifications.notifications) {
|
||||
if (notification != null) {
|
||||
if (notification.status != null) {
|
||||
notification.status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), notification.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
notifications.pagination = MastodonHelper.getPagination(notificationsResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -147,9 +137,6 @@ public class NotificationsVM extends AndroidViewModel {
|
|||
Response<Notification> notificationResponse = notificationCall.execute();
|
||||
if (notificationResponse.isSuccessful()) {
|
||||
notification = notificationResponse.body();
|
||||
if (notification != null) {
|
||||
notification.status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), notification.status);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -36,7 +36,6 @@ import app.fedilab.android.client.entities.api.Status;
|
|||
import app.fedilab.android.client.entities.app.StatusCache;
|
||||
import app.fedilab.android.exception.DBException;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Response;
|
||||
|
@ -112,13 +111,9 @@ public class SearchVM extends AndroidViewModel {
|
|||
if (results != null) {
|
||||
if (results.statuses == null) {
|
||||
results.statuses = new ArrayList<>();
|
||||
} else {
|
||||
results.statuses = SpannableHelper.convertStatus(getApplication(), results.statuses);
|
||||
}
|
||||
if (results.accounts == null) {
|
||||
results.accounts = new ArrayList<>();
|
||||
} else {
|
||||
results.accounts = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), results.accounts);
|
||||
}
|
||||
if (results.hashtags == null) {
|
||||
results.hashtags = new ArrayList<>();
|
||||
|
@ -144,7 +139,6 @@ public class SearchVM extends AndroidViewModel {
|
|||
try {
|
||||
results.statuses = new ArrayList<>();
|
||||
List<Status> statuses = new StatusCache(getApplication()).searchStatus(StatusCache.CacheEnum.HOME, instance, userId, q);
|
||||
statuses = SpannableHelper.convertStatus(getApplication(), statuses);
|
||||
results.statuses.addAll(statuses);
|
||||
} catch (DBException e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -47,7 +47,6 @@ import app.fedilab.android.client.entities.app.StatusCache;
|
|||
import app.fedilab.android.exception.DBException;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.helper.TimelineHelper;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.MultipartBody;
|
||||
|
@ -279,7 +278,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -356,13 +355,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
context = contextResponse.body();
|
||||
if (context != null) {
|
||||
TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.descendants, TimelineHelper.FilterTimeLineType.CONTEXT);
|
||||
for (Status status : context.descendants) {
|
||||
SpannableHelper.convertStatus(getApplication().getApplicationContext(), status);
|
||||
}
|
||||
TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.ancestors, TimelineHelper.FilterTimeLineType.CONTEXT);
|
||||
for (Status status : context.ancestors) {
|
||||
SpannableHelper.convertStatus(getApplication().getApplicationContext(), status);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -406,7 +399,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<List<Account>> accountsResponse = accountsCall.execute();
|
||||
if (accountsResponse.isSuccessful()) {
|
||||
accounts = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), accountsResponse.body());
|
||||
accounts = accountsResponse.body();
|
||||
}
|
||||
headers = accountsResponse.headers();
|
||||
} catch (Exception e) {
|
||||
|
@ -451,7 +444,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<List<Account>> accountsResponse = accountsCall.execute();
|
||||
if (accountsResponse.isSuccessful()) {
|
||||
accounts = SpannableHelper.convertAccounts(getApplication().getApplicationContext(), accountsResponse.body());
|
||||
accounts = accountsResponse.body();
|
||||
}
|
||||
headers = accountsResponse.headers();
|
||||
} catch (Exception e) {
|
||||
|
@ -461,7 +454,9 @@ public class StatusesVM extends AndroidViewModel {
|
|||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Accounts accountsPagination = new Accounts();
|
||||
accountsPagination.accounts = accounts;
|
||||
accountsPagination.pagination = MastodonHelper.getPagination(headers);
|
||||
if (headers != null) {
|
||||
accountsPagination.pagination = MastodonHelper.getPagination(headers);
|
||||
}
|
||||
Runnable myRunnable = () -> accountsMutableLiveData.setValue(accountsPagination);
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
|
@ -487,7 +482,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -531,7 +526,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -577,7 +572,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -621,7 +616,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -665,7 +660,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -709,7 +704,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -753,7 +748,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -797,7 +792,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -841,7 +836,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
@ -885,7 +880,7 @@ public class StatusesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<Status> statusResponse = statusCall.execute();
|
||||
if (statusResponse.isSuccessful()) {
|
||||
status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusResponse.body());
|
||||
status = statusResponse.body();
|
||||
} else {
|
||||
if (statusResponse.errorBody() != null) {
|
||||
errorMessage = statusResponse.errorBody().string();
|
||||
|
|
|
@ -48,7 +48,6 @@ import app.fedilab.android.client.entities.peertube.PeertubeVideo;
|
|||
import app.fedilab.android.exception.DBException;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.SpannableHelper;
|
||||
import app.fedilab.android.helper.TimelineHelper;
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Call;
|
||||
|
@ -121,7 +120,7 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
Response<List<Status>> publicTlResponse = publicTlCall.execute();
|
||||
if (publicTlResponse.isSuccessful()) {
|
||||
statusList = publicTlResponse.body();
|
||||
statusList = SpannableHelper.convertStatus(getApplication().getApplicationContext(), statusList);
|
||||
statusList = statusList;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -190,8 +189,7 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
Response<List<Status>> publicTlResponse = publicTlCall.execute();
|
||||
if (publicTlResponse.isSuccessful()) {
|
||||
List<Status> notFilteredStatuses = publicTlResponse.body();
|
||||
List<Status> filteredStatuses = TimelineHelper.filterStatus(getApplication(), notFilteredStatuses, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), filteredStatuses);
|
||||
statuses.statuses = TimelineHelper.filterStatus(getApplication(), notFilteredStatuses, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.pagination = MastodonHelper.getPagination(publicTlResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -219,7 +217,6 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
statusesMutableLiveData = new MutableLiveData<>();
|
||||
new Thread(() -> {
|
||||
Call<Nitter> publicTlCall = mastodonTimelinesService.getNitter(accountsStr, max_position);
|
||||
|
||||
Statuses statuses = new Statuses();
|
||||
if (publicTlCall != null) {
|
||||
try {
|
||||
|
@ -233,8 +230,10 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
statusList.add(status);
|
||||
}
|
||||
}
|
||||
statuses.statuses = SpannableHelper.convertNitterStatus(getApplication().getApplicationContext(), statusList);
|
||||
statuses.pagination = MastodonHelper.getPagination(publicTlResponse.headers());
|
||||
statuses.statuses = statusList;
|
||||
String max_id = publicTlResponse.headers().get("min-id");
|
||||
statuses.pagination = new Pagination();
|
||||
statuses.pagination.max_id = max_id;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -273,12 +272,11 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
List<Status> statusList = new ArrayList<>();
|
||||
if (misskeyNoteList != null) {
|
||||
for (MisskeyNote misskeyNote : misskeyNoteList) {
|
||||
Status status = MisskeyNote.convert(misskeyNote);
|
||||
Status status = MisskeyNote.convert(misskeyNote, instance);
|
||||
statusList.add(status);
|
||||
}
|
||||
}
|
||||
List<Status> filteredStatuses = TimelineHelper.filterStatus(getApplication(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), filteredStatuses);
|
||||
statuses.statuses = TimelineHelper.filterStatus(getApplication(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.pagination = new Pagination();
|
||||
if (statusList.size() > 0) {
|
||||
statuses.pagination.min_id = statusList.get(0).id;
|
||||
|
@ -324,8 +322,7 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
statusList.add(status);
|
||||
}
|
||||
}
|
||||
List<Status> filteredStatuses = TimelineHelper.filterStatus(getApplication(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), filteredStatuses);
|
||||
statuses.statuses = TimelineHelper.filterStatus(getApplication(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.pagination = new Pagination();
|
||||
if (statusList.size() > 0) {
|
||||
//These values are not used.
|
||||
|
@ -400,14 +397,14 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
MastodonTimelinesService mastodonTimelinesService = init(instance);
|
||||
new Thread(() -> {
|
||||
Statuses statuses = new Statuses();
|
||||
Call<List<Status>> hashTagTlCall = mastodonTimelinesService.getHashTag(token, hashtag, local, onlyMedia, all, any, none, maxId, sinceId, minId, limit);
|
||||
String hashtagTrim = hashtag.replaceAll("\\#", "");
|
||||
Call<List<Status>> hashTagTlCall = mastodonTimelinesService.getHashTag(token, hashtagTrim, local, onlyMedia, all, any, none, maxId, sinceId, minId, limit);
|
||||
if (hashTagTlCall != null) {
|
||||
try {
|
||||
Response<List<Status>> hashTagTlResponse = hashTagTlCall.execute();
|
||||
if (hashTagTlResponse.isSuccessful()) {
|
||||
List<Status> notFilteredStatuses = hashTagTlResponse.body();
|
||||
List<Status> filteredStatuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), notFilteredStatuses, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), filteredStatuses);
|
||||
statuses.statuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), notFilteredStatuses, TimelineHelper.FilterTimeLineType.PUBLIC);
|
||||
statuses.pagination = MastodonHelper.getPagination(hashTagTlResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -449,8 +446,7 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
Response<List<Status>> homeTlResponse = homeTlCall.execute();
|
||||
if (homeTlResponse.isSuccessful()) {
|
||||
List<Status> notFilteredStatuses = homeTlResponse.body();
|
||||
List<Status> filteredStatuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), notFilteredStatuses, TimelineHelper.FilterTimeLineType.HOME);
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), filteredStatuses);
|
||||
statuses.statuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), notFilteredStatuses, TimelineHelper.FilterTimeLineType.HOME);
|
||||
statuses.pagination = MastodonHelper.getPagination(homeTlResponse.headers());
|
||||
if (!fetchingMissing) {
|
||||
for (Status status : statuses.statuses) {
|
||||
|
@ -502,8 +498,7 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
statuses = statusCacheDAO.geStatuses(StatusCache.CacheEnum.HOME, instance, user_id, maxId, minId, sinceId);
|
||||
|
||||
if (statuses != null) {
|
||||
List<Status> filteredStatuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), statuses.statuses, TimelineHelper.FilterTimeLineType.HOME);
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), filteredStatuses);
|
||||
statuses.statuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), statuses.statuses, TimelineHelper.FilterTimeLineType.HOME);
|
||||
if (statuses.statuses != null && statuses.statuses.size() > 0) {
|
||||
statuses.pagination = new Pagination();
|
||||
statuses.pagination.min_id = statuses.statuses.get(0).id;
|
||||
|
@ -570,7 +565,7 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
try {
|
||||
Response<List<Status>> listTlResponse = listTlCall.execute();
|
||||
if (listTlResponse.isSuccessful()) {
|
||||
statuses.statuses = SpannableHelper.convertStatus(getApplication().getApplicationContext(), listTlResponse.body());
|
||||
statuses.statuses = listTlResponse.body();
|
||||
statuses.pagination = MastodonHelper.getPagination(listTlResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -606,11 +601,6 @@ public class TimelinesVM extends AndroidViewModel {
|
|||
Response<List<Conversation>> conversationsResponse = conversationsCall.execute();
|
||||
if (conversationsResponse.isSuccessful()) {
|
||||
conversations.conversations = conversationsResponse.body();
|
||||
if (conversations.conversations != null) {
|
||||
for (Conversation conversation : conversations.conversations) {
|
||||
conversation.last_status = SpannableHelper.convertStatus(getApplication().getApplicationContext(), conversation.last_status);
|
||||
}
|
||||
}
|
||||
conversations.pagination = MastodonHelper.getPagination(conversationsResponse.headers());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package app.fedilab.android.viewmodel.pleroma;
|
||||
/* Copyright 2022 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Fedilab 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 Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import app.fedilab.android.client.endpoints.PleromaAPI;
|
||||
import app.fedilab.android.client.entities.api.Announcement;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class ActionsVM extends AndroidViewModel {
|
||||
|
||||
final OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.connectTimeout(60, TimeUnit.SECONDS)
|
||||
.callTimeout(60, TimeUnit.SECONDS)
|
||||
.proxy(Helper.getProxy(getApplication().getApplicationContext()))
|
||||
.build();
|
||||
private MutableLiveData<Announcement> announcementMutableLiveData;
|
||||
private MutableLiveData<List<Announcement>> announcementListMutableLiveData;
|
||||
|
||||
public ActionsVM(@NonNull Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
private PleromaAPI init(@NonNull String instance) {
|
||||
Retrofit retrofit = new Retrofit.Builder()
|
||||
.baseUrl("https://" + instance + "/api/v1/")
|
||||
.addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder()))
|
||||
.client(okHttpClient)
|
||||
.build();
|
||||
return retrofit.create(PleromaAPI.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* React to an announcement with an emoji.
|
||||
*
|
||||
* @param instance Instance domain of the active account
|
||||
* @param token Access token of the active account
|
||||
* @param id Local ID of an announcement
|
||||
* @param name Unicode emoji, or shortcode of custom emoji
|
||||
*/
|
||||
public void addReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) {
|
||||
PleromaAPI pleromaAPI = init(instance);
|
||||
new Thread(() -> {
|
||||
Call<Void> addReactionCall = pleromaAPI.addReaction(token, id, name);
|
||||
if (addReactionCall != null) {
|
||||
try {
|
||||
addReactionCall.execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo a react emoji to an announcement.
|
||||
*
|
||||
* @param instance Instance domain of the active account
|
||||
* @param token Access token of the active account
|
||||
* @param id Local ID of an announcement
|
||||
* @param name Unicode emoji, or shortcode of custom emoji
|
||||
*/
|
||||
public void removeReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) {
|
||||
PleromaAPI pleromaAPI = init(instance);
|
||||
new Thread(() -> {
|
||||
Call<Void> removeReactionCall = pleromaAPI.removeReaction(token, id, name);
|
||||
if (removeReactionCall != null) {
|
||||
try {
|
||||
removeReactionCall.execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
2
app/src/main/res/drawable/empty_custom_emoji.xml
Normal file
2
app/src/main/res/drawable/empty_custom_emoji.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape />
|
10
app/src/main/res/drawable/ic_baseline_insert_emoticon_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_insert_emoticon_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_baseline_language_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_language_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z" />
|
||||
</vector>
|
|
@ -16,12 +16,27 @@
|
|||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/set_account"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="12dp"
|
||||
android:text="@string/account"
|
||||
android:textAlignment="textStart"
|
||||
android:textColor="@color/cyanea_accent_dark_reference"
|
||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
||||
app:iconGravity="end"
|
||||
app:iconTint="@color/cyanea_accent_dark_reference"
|
||||
app:strokeColor="@color/cyanea_accent_dark_reference" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/set_timelines"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="12dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/settings_category_label_timelines"
|
||||
android:textAlignment="textStart"
|
||||
android:textColor="@color/cyanea_accent_dark_reference"
|
||||
|
|
|
@ -59,64 +59,9 @@
|
|||
tools:maxLines="10"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_reactions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/reactions_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_add_custom_emoji"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/add_reaction"
|
||||
android:src="@drawable/ic_baseline_emoji_emotions_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?attr/iconColor" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_emoji"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/add_reaction"
|
||||
android:src="@drawable/ic_baseline_add_reaction_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?attr/iconColor" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<app.fedilab.android.helper.FedilabAutoCompleteTextView
|
||||
android:id="@+id/fake_edittext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="noExcludeDescendants"
|
||||
android:inputType="text" />
|
||||
</LinearLayout>
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
<include
|
||||
android:id="@+id/layout_reactions"
|
||||
layout="@layout/layout_reactions" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
|
@ -24,7 +24,7 @@
|
|||
android:layout_marginTop="@dimen/card_margin"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
app:cardElevation="2dp">
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
|
@ -34,6 +34,9 @@
|
|||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_booster_info"
|
||||
|
@ -77,10 +80,6 @@
|
|||
tools:text="@tools:sample/full_names" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:id="@+id/booster_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/header_container"
|
||||
|
@ -151,12 +150,19 @@
|
|||
android:maxLines="1"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/visibility_small"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:src="@drawable/ic_baseline_public_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date_short"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="10dp" />
|
||||
tools:text="2m" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
|
@ -196,9 +202,6 @@
|
|||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/spoiler"
|
||||
|
@ -492,6 +495,27 @@
|
|||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/action_share_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="48dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:gravity="end"
|
||||
android:visibility="gone">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_share"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_baseline_share_24" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -577,6 +601,12 @@
|
|||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<include
|
||||
android:id="@+id/layout_reactions"
|
||||
layout="@layout/layout_reactions"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/cardview_container"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:backgroundTint="?backgroundColorLight"
|
||||
android:layout_marginTop="12dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
app:cardElevation="2dp">
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/cardview_container"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:clipChildren="false"
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/join_mastodon"
|
||||
style="@style/MyButtonColored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
|
|
|
@ -151,6 +151,7 @@
|
|||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/signup"
|
||||
style="@style/MyButtonColored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sign_up" />
|
||||
|
|
60
app/src/main/res/layout/layout_reactions.xml
Normal file
60
app/src/main/res/layout/layout_reactions.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/status_reactions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/reactions_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_add_custom_emoji"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/add_reaction"
|
||||
android:src="@drawable/ic_baseline_emoji_emotions_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?attr/iconColor" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_emoji"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/add_reaction"
|
||||
android:src="@drawable/ic_baseline_add_reaction_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?attr/iconColor" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<app.fedilab.android.helper.FedilabAutoCompleteTextView
|
||||
android:id="@+id/fake_edittext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="noExcludeDescendants"
|
||||
android:inputType="text" />
|
||||
</LinearLayout>
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
|
@ -45,8 +45,8 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:contentDescription="@string/profile_picture"
|
||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||
tools:src="@tools:sample/avatars"
|
||||
android:scaleType="fitCenter" />
|
||||
android:scaleType="fitCenter"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/change_account"
|
||||
|
|
|
@ -1,450 +1,452 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView 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:id="@+id/popup_container"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/background"
|
||||
android:id="@+id/popup_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="@dimen/fab_margin"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingEnd="@dimen/fab_margin"
|
||||
android:paddingBottom="20dp">
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
|
||||
android:id="@+id/cardview_container"
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/card_margin"
|
||||
android:layout_marginTop="@dimen/card_margin"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/header_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_user_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:padding="6dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:scaleType="centerInside"
|
||||
tools:src="@drawable/ic_person" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/display_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
tools:text="Display Name" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:alpha="0.7"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
tools:text="\@username\@instance.test" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_booster_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="6dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_boost_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_repeat" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_booster_avatar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_person" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/spoiler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="Warning: Lorem Ipsum below"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/spoiler_expand"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/show_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
|
||||
android:textColor="?colorAccent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/status_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/lorem_ipsum_text"
|
||||
android:textIsSelectable="true"
|
||||
tools:maxLines="10" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/toggle_truncate"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:paddingTop="1dp"
|
||||
android:paddingBottom="1dp"
|
||||
android:text="@string/display_toot_truncate"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:strokeColor="@color/cyanea_accent_dark_reference" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/container_trans"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<View
|
||||
android:id="@+id/translation_border_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/translation_border"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/translation_border_top" />
|
||||
|
||||
<androidx.constraintlayout.widget.Placeholder
|
||||
android:id="@+id/translation_border_top"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="1dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/translation_label"
|
||||
app:layout_constraintEnd_toEndOf="@id/translation_label"
|
||||
app:layout_constraintTop_toTopOf="@id/translation_label" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/translation_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="?backgroundColorLight"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:text="@string/translation"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_content_translated"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/translation_label"
|
||||
app:layout_goneMarginBottom="8dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
android:paddingStart="@dimen/fab_margin"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingEnd="@dimen/fab_margin"
|
||||
android:paddingBottom="20dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card"
|
||||
|
||||
android:id="@+id/cardview_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
android:layout_marginHorizontal="@dimen/card_margin"
|
||||
android:layout_marginTop="@dimen/card_margin"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/card_image_horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:visibility="gone"
|
||||
tools:src="@tools:sample/backgrounds/scenic" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/header_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/card_image_vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/fedilab_logo_bubbles" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_user_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="3"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:padding="6dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/card_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:text="Maecenas sollicitudin, eros quis interdum posuere, quam lorem tempus dui."
|
||||
android:textColor="?colorAccent" />
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:scaleType="centerInside"
|
||||
tools:src="@drawable/ic_person" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/card_description"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/display_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="5"
|
||||
android:text="@string/lorem_ipsum_text_card"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
tools:lines="3" />
|
||||
android:maxLines="1"
|
||||
tools:text="Display Name" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/card_url"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="https://domain.test"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
android:textColor="?linkColor" />
|
||||
android:layout_marginStart="6dp"
|
||||
android:alpha="0.7"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
tools:text="\@username\@instance.test" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_booster_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="6dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_boost_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_repeat" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/status_booster_avatar"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_person" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/spoiler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="Warning: Lorem Ipsum below"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/spoiler_expand"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/show_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
|
||||
android:textColor="?colorAccent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/status_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/lorem_ipsum_text"
|
||||
android:textIsSelectable="true"
|
||||
tools:maxLines="10" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/toggle_truncate"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:paddingTop="1dp"
|
||||
android:paddingBottom="1dp"
|
||||
android:text="@string/display_toot_truncate"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:strokeColor="@color/cyanea_accent_dark_reference" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/container_trans"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<View
|
||||
android:id="@+id/translation_border_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/translation_border"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/translation_border_top" />
|
||||
|
||||
<androidx.constraintlayout.widget.Placeholder
|
||||
android:id="@+id/translation_border_top"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="1dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/translation_label"
|
||||
app:layout_constraintEnd_toEndOf="@id/translation_label"
|
||||
app:layout_constraintTop_toTopOf="@id/translation_label" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/translation_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="?backgroundColorLight"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:text="@string/translation"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_content_translated"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/translation_label"
|
||||
app:layout_goneMarginBottom="8dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/card_image_horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:visibility="gone"
|
||||
tools:src="@tools:sample/backgrounds/scenic" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/card_image_vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/fedilab_logo_bubbles" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="3"
|
||||
android:orientation="vertical"
|
||||
android:padding="6dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/card_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:text="Maecenas sollicitudin, eros quis interdum posuere, quam lorem tempus dui."
|
||||
android:textColor="?colorAccent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/card_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="5"
|
||||
android:text="@string/lorem_ipsum_text_card"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
tools:lines="3" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/card_url"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="https://domain.test"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
android:textColor="?linkColor" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/media_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:alpha="0.8"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="6dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?statusTextColor"
|
||||
tools:text="1 January 2021, 12:00" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/reblog_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/repeat_info"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="12dp"
|
||||
app:srcCompat="@drawable/ic_repeat" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/reblogs_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="10"
|
||||
android:textColor="?statusTextColor" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/favourite_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/fav_info"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="12dp"
|
||||
app:srcCompat="@drawable/ic_star_outline" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/favorites_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="10"
|
||||
android:textColor="?statusTextColor" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/visibility"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_baseline_public_24" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_reply"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_reply" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_favorite"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_star_outline" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_boost"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_repeat" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_more"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_more_horiz" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/media_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/status_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:alpha="0.8"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="6dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?statusTextColor"
|
||||
tools:text="1 January 2021, 12:00" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/reblog_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/repeat_info"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="12dp"
|
||||
app:srcCompat="@drawable/ic_repeat" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/reblogs_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="10"
|
||||
android:textColor="?statusTextColor" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/favourite_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/fav_info"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="12dp"
|
||||
app:srcCompat="@drawable/ic_star_outline" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/favorites_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="10"
|
||||
android:textColor="?statusTextColor" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/visibility"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_baseline_public_24" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_reply"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_reply" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_favorite"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_star_outline" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_boost"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_repeat" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/action_button_more"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:srcCompat="@drawable/ic_more_horiz" />
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?backgroundColorLight"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/fab_margin">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/title"
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
android:background="?backgroundColorLight"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/fab_margin">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/author"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textSize="16sp" />
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/author"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSpinner
|
||||
android:id="@+id/select_theme"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="10dp" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSpinner
|
||||
android:id="@+id/select_theme"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="10dp" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
</ScrollView>
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
android:icon="@drawable/ic_baseline_contact_page_24"
|
||||
android:title="@string/contact"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_language"
|
||||
android:icon="@drawable/ic_baseline_language_24"
|
||||
android:title="@string/languages"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_microphone"
|
||||
android:icon="@drawable/ic_baseline_mic_24"
|
||||
|
|
|
@ -720,4 +720,5 @@
|
|||
<string name="messages_in_cache_for_other_timelines">Messàgios in memòria temporànea pro àteras lìnias de tempus</string>
|
||||
<string name="delete_cache_message">Ses seguru de bòlere isboidare sa memòria temporànea\? Si tenes abbotzos cun cuntenutos multimediales as a pèrdere sos cuntenutos alligados.</string>
|
||||
<string name="clear_cache">Isbòida sa memòria temporànea</string>
|
||||
<string name="default_system_language">Imprea sa limba predefinida de sistema</string>
|
||||
</resources>
|
|
@ -726,4 +726,5 @@
|
|||
<string name="clear_cache">Önbelleği temizle</string>
|
||||
<string name="messages_in_cache_for_other_timelines">Diğer zaman çizelgeleri için önbellekteki mesajlar</string>
|
||||
<string name="messages_stored_in_drafts">Taslaklarda saklanan mesajlar</string>
|
||||
<string name="default_system_language">Öntanımlı sistem dilini kullan</string>
|
||||
</resources>
|
|
@ -16,7 +16,7 @@
|
|||
<string name="download_from" formatted="false">Tập tin: %1$s</string>
|
||||
<string name="password">Mật khẩu</string>
|
||||
<string name="email">Email</string>
|
||||
<string name="accounts">Tài khoản</string>
|
||||
<string name="accounts">Người</string>
|
||||
<string name="toots">Tút</string>
|
||||
<string name="tags">Tag</string>
|
||||
<string name="save">Lưu</string>
|
||||
|
@ -63,7 +63,7 @@
|
|||
<string name="no_emoji">Ứng dụng không thể thu thập emoji tùy chỉnh vào thời điểm này.</string>
|
||||
<string name="logout_account_confirmation">Bạn có chắc muốn đăng xuất @%1$s@%2$s\?</string>
|
||||
<!-- Status -->
|
||||
<string name="no_status">Không có tút nào</string>
|
||||
<string name="no_status">Chưa có</string>
|
||||
<string name="favourite_add">Thêm tút này vào mục yêu thích của bạn\?</string>
|
||||
<string name="favourite_remove">Xóa tút này khỏi mục yêu thích của bạn\?</string>
|
||||
<string name="reblog_add">Đăng lại tút này\?</string>
|
||||
|
@ -75,7 +75,7 @@
|
|||
<string name="more_action_5">Sao chép</string>
|
||||
<string name="more_action_6">Chia sẻ</string>
|
||||
<string name="more_action_7">Nhắc đến</string>
|
||||
<string name="more_action_8">Thời gian ẩn</string>
|
||||
<string name="more_action_8">Ẩn có thời hạn</string>
|
||||
<string name="more_action_9">Xóa & viết lại</string>
|
||||
<string-array name="more_action_confirm">
|
||||
<item>Ẩn tài khoản này?</item>
|
||||
|
@ -143,11 +143,14 @@
|
|||
<string name="about_thekinrar">Tìm máy chủ:</string>
|
||||
<!-- Conversation -->
|
||||
<!-- Accounts -->
|
||||
<string name="no_accounts">Không có tài khoản nào</string>
|
||||
<string name="no_accounts">Không có người nào</string>
|
||||
<string name="no_follow_request">Không có yêu cầu theo dõi</string>
|
||||
<string name="status_cnt">%1$s tút</string>
|
||||
<string name="following_cnt">%1$s Đang theo dõi</string>
|
||||
<string name="followers_cnt">%1$s Người theo dõi</string>
|
||||
<string name="status_cnt">Tút
|
||||
\n %1$s</string>
|
||||
<string name="following_cnt">Đang theo dõi
|
||||
\n %1$s</string>
|
||||
<string name="followers_cnt">Người theo dõi
|
||||
\n %1$s</string>
|
||||
<string name="reject">Từ chối</string>
|
||||
<!-- Scheduled toots -->
|
||||
<string name="no_scheduled_toots">Không có tút đã lên lịch!</string>
|
||||
|
@ -198,10 +201,10 @@
|
|||
<string name="set_notif_follow_share">Khi ai đó đăng lại tút của tôi</string>
|
||||
<string name="set_notif_follow_add">Khi ai đó thích tút của tôi</string>
|
||||
<string name="set_notif_follow_mention">Khi ai đó nhắc tới tôi</string>
|
||||
<string name="set_notif_follow_poll">Nhắc khi một cuộc bình chọn kết thúc</string>
|
||||
<string name="set_notif_status">Nhắc khi có tút mới</string>
|
||||
<string name="set_share_validation">Hiện xác nhận trước khi đăng lại tút</string>
|
||||
<string name="set_share_validation_fav">Hiện xác nhận trước khi thích tút</string>
|
||||
<string name="set_notif_follow_poll">Khi cuộc bình chọn kết thúc</string>
|
||||
<string name="set_notif_status">Khi có tút mới</string>
|
||||
<string name="set_share_validation">Hiện xác nhận trước khi đăng lại</string>
|
||||
<string name="set_share_validation_fav">Hiện xác nhận trước khi thích</string>
|
||||
<string name="set_notify">Thông báo?</string>
|
||||
<string name="set_notif_silent">Tắt thông báo</string>
|
||||
<string name="set_nsfw_timeout">Thời gian chờ của NSFW (giây, 0 = tắt)</string>
|
||||
|
@ -237,7 +240,7 @@
|
|||
<string name="action_unmute">Bỏ ẩn</string>
|
||||
<string name="request_sent">Đã gửi yêu cầu</string>
|
||||
<string name="followed_by">Theo dõi bạn</string>
|
||||
<string name="set_capitalize">Viết hoa chữ đầu khi trả lời</string>
|
||||
<string name="set_capitalize">Tự động xuống dòng khi trả lời</string>
|
||||
<string name="set_resize_picture">Giảm kích cỡ hình ảnh</string>
|
||||
<string name="set_resize_video">Giảm kích thước video</string>
|
||||
<!-- Quick settings for notifications -->
|
||||
|
@ -273,7 +276,7 @@
|
|||
<string name="action_lists_add_to">Thêm vào danh sách</string>
|
||||
<string name="action_lists_delete">Xoá danh sách</string>
|
||||
<string name="action_lists_title_placeholder">Tên danh sách mới</string>
|
||||
<string name="action_lists_add_user">Đã thêm tài khoản vào danh sách!</string>
|
||||
<string name="action_lists_add_user">Đã thêm người này vào danh sách!</string>
|
||||
<string name="action_lists_empty">Bạn chưa có danh sách nào!</string>
|
||||
<!-- Migration -->
|
||||
<string name="account_moved_to">%1$s đã chuyển sang %2$s</string>
|
||||
|
@ -325,7 +328,7 @@
|
|||
<string name="channel_notif_status">Tút mới</string>
|
||||
<string name="channel_notif_media">Tải media</string>
|
||||
<string name="select_sound">Chọn âm thanh</string>
|
||||
<string name="set_enable_time_slot">Hiện thời gian đăng</string>
|
||||
<string name="set_enable_time_slot">Thời gian thông báo</string>
|
||||
<string name="block_domain_confirm_message">Bạn có chắc bỏ chặn %s\?
|
||||
\n
|
||||
\nBạn sẽ không thấy bất kỳ nội dung nào từ máy chủ này trong bảng tin và thông báo của bạn. Những người theo dõi bạn từ máy chủ này cũng sẽ bị xóa.</string>
|
||||
|
@ -405,9 +408,9 @@
|
|||
<string name="poll_choice_s">Lựa chọn %d</string>
|
||||
<string name="poll_invalid_choices">Bạn cần cho ít nhất 2 lựa chọn!</string>
|
||||
<string name="done">Xong</string>
|
||||
<string name="poll_finish_at">kết thúc lúc %s</string>
|
||||
<string name="poll_finish_at">kết thúc %s</string>
|
||||
<string name="vote">Bình chọn</string>
|
||||
<string name="notif_poll">Cuộc bình chọn có bạn tham gia đã kết thúc</string>
|
||||
<string name="notif_poll">Cuộc bình chọn bạn đã tham gia kết thúc</string>
|
||||
<string name="notif_poll_self">Cuộc bình chọn của bạn đã kết thúc</string>
|
||||
<string name="settings_category_notif_categories">Loại</string>
|
||||
<string name="move_timeline">Chuyển bảng tin</string>
|
||||
|
@ -490,7 +493,7 @@
|
|||
<string name="voice_message">Ghi âm</string>
|
||||
<string name="set_enable_time_slot_indication">Ứng dụng sẽ gửi thông báo vào thời điểm chỉ định. Bạn có thể đảo ngược (tức là: im lặng) thời điểm này bằng con quay bên phải.</string>
|
||||
<string name="set_fit_preview_indication">Không cắt ảnh xem trước</string>
|
||||
<string name="set_capitalize_indication">Tự động chèn dấu ngắt dòng sau phần đề cập để viết hoa chữ cái đầu tiên</string>
|
||||
<string name="set_capitalize_indication">Tự động xuống dòng và viết hoa chữ đầu tiên sau khi nhắc đến ai đó.</string>
|
||||
<string name="settings_title_custom_sharing_indication">Chia sẻ tút với nguồn cấp dữ liệu RSS</string>
|
||||
<string name="compose">Soạn thảo</string>
|
||||
<string name="select">Chọn</string>
|
||||
|
@ -502,8 +505,8 @@
|
|||
\n
|
||||
\nBạn có thể thêm nội dung. Cảm ơn bạn!</string>
|
||||
<string name="visibility">Mức độ hiển thị</string>
|
||||
<string name="set_disable_animated_emoji">Tắt emoji dạng GIF</string>
|
||||
<string name="report_account">Báo cáo tài khoản</string>
|
||||
<string name="set_disable_animated_emoji">Tắt emoji GIF</string>
|
||||
<string name="report_account">Báo cáo người này</string>
|
||||
<plurals name="number_of_voters">
|
||||
<item quantity="other">%d bình chọn</item>
|
||||
</plurals>
|
||||
|
@ -527,10 +530,10 @@
|
|||
<string name="poll_duplicated_entry">Có lựa chọn trùng lặp!</string>
|
||||
<string name="set_clear_cache_exit">Xóa bộ nhớ đệm khi thoát</string>
|
||||
<string name="set_clear_cache_exit_indication">Bộ nhớ đệm (media, tút, dữ liệu từ trình duyệt tích hợp) sẽ tự động bị xóa khi thoát ứng dụng.</string>
|
||||
<string name="unfollow_confirm">Bạn có muốn ngưng theo dõi tài khoản này\?</string>
|
||||
<string name="set_unfollow_validation">Yêu cầu xác nhận trước khi hủy theo dõi ai đó</string>
|
||||
<string name="unfollow_confirm">Bạn có muốn ngưng theo dõi người này\?</string>
|
||||
<string name="set_unfollow_validation">Yêu cầu xác nhận trước khi ngưng theo dõi ai đó.</string>
|
||||
<string name="replace_medium">Thay thế liên kết từ Medium</string>
|
||||
<string name="replace_medium_description">Thay thế liên kết từ medium.com với một giao diện mã nguồn mở, chú trọng bảo mật.</string>
|
||||
<string name="replace_medium_description">Dùng một frontend thay thế cho Medium</string>
|
||||
<string name="replace_medium_host">Mặc định: scribe.rip</string>
|
||||
<string name="set_push_notifications">Sử dụng hệ thống thông báo đẩy để nhận thông báo trong thời gian thực.</string>
|
||||
<string name="action_add_notes">Thêm ghi chú</string>
|
||||
|
@ -615,10 +618,10 @@
|
|||
<string name="not_valid_list_name">Tên danh sách không hợp lệ!</string>
|
||||
<string name="no_account_in_list">Không có người dùng nào trong danh sách này!</string>
|
||||
<string name="scheduled">Đã lên lịch</string>
|
||||
<string name="notifications_are">Trong khoảng thời gian</string>
|
||||
<string name="notifications_are">Trong khoảng thời gian này</string>
|
||||
<string name="pref_theme_base">Theme gốc</string>
|
||||
<string name="pref_theme_base_summary">Chọn theme gốc là tối hay sáng</string>
|
||||
<string name="customize_timelines">Tùy chỉnh bảng tin</string>
|
||||
<string name="customize_timelines">Tùy chỉnh</string>
|
||||
<string name="pref_contributor">Theme của cộng đồng</string>
|
||||
<string name="pref_contributor_summary">Chọn một theme được tạo bởi cộng đồng</string>
|
||||
<string name="display">Hiển thị</string>
|
||||
|
@ -644,7 +647,7 @@
|
|||
<string name="toots_visibility_title">Kiểu tút mặc định:</string>
|
||||
<string name="toast_bookmark">Đã thêm tút vào mục yêu thích!</string>
|
||||
<string name="toast_unbookmark">Đã xóa tút khỏi mục yêu thích!</string>
|
||||
<string name="set_accounts_page">Số lượng tài khoản mỗi lần tải</string>
|
||||
<string name="set_accounts_page">Số lượng người dùng mỗi lần tải</string>
|
||||
<string name="set_notifications_page">Số lượng thông báo mỗi lần tải</string>
|
||||
<string name="category_music">Âm nhạc</string>
|
||||
<string name="cannot_be_empty">Không thể để trống mục này!</string>
|
||||
|
@ -665,7 +668,7 @@
|
|||
<string name="instance_not_valid">Địa chỉ máy chủ không hợp lệ!</string>
|
||||
<string name="boosted_by">Đăng lại bởi</string>
|
||||
<string name="favourited_by">Thích bởi</string>
|
||||
<string name="followers_only">Hạn chế</string>
|
||||
<string name="followers_only">Riêng tư</string>
|
||||
<string name="other">Khác</string>
|
||||
<string name="eg_sensitive_content">Vd: Nội Dung Nhạy Cảm</string>
|
||||
<string name="add_status">Thêm trạng thái</string>
|
||||
|
@ -688,11 +691,11 @@
|
|||
<string name="report_val2">Đây là spam</string>
|
||||
<string name="report_val_more2">Liên kết độc hại, giả tương tác hoặc trả lời lặp đi lặp lại</string>
|
||||
<string name="report_val3">Vi phạm quy tắc máy chủ</string>
|
||||
<string name="report_1_unfollow">Bạn đang theo dõi tài khoản này. Để không nhìn thấy tút của họ trong bảng tin nữa, hãy ngưng theo dõi họ.</string>
|
||||
<string name="report_1_unfollow">Bạn đang theo dõi người này. Để không nhìn thấy tút của họ trong bảng tin nữa, hãy ngưng theo dõi họ.</string>
|
||||
<string name="report_1_mute_title">Ẩn %1$s</string>
|
||||
<string name="report_1_mute">Bạn sẽ không thấy tút của họ. Họ vẫn có thể theo dõi bạn và thấy tút của bạn nhưng không biết rằng họ bị ẩn.</string>
|
||||
<string name="report_1_block_title">Chặn %1$s</string>
|
||||
<string name="report_more_remote">Tài khoản này từ một máy chủ khác. Gửi luôn cho kiểm duyệt viên máy chủ đó\?</string>
|
||||
<string name="report_more_remote">Người này từ một máy chủ khác. Gửi luôn cho kiểm duyệt viên máy chủ đó\?</string>
|
||||
<string name="report_more_forward">Chuyển tiếp %1$s</string>
|
||||
<string name="report_sent">Đã gửi báo cáo!</string>
|
||||
<string name="report_1_block">Bạn sẽ không thấy tút của họ. Họ sẽ không thể xem tút của bạn hoặc theo dõi bạn. Họ sẽ biếtrằng họ bị chặn.</string>
|
||||
|
@ -704,7 +707,7 @@
|
|||
<string name="notif_display_poll_results">Kết quả bình chọn</string>
|
||||
<string name="notif_display_updates_from_people">Cập nhật từ mọi người</string>
|
||||
<string name="notif_display_follows">Theo dõi</string>
|
||||
<string name="mark_all_as_read">Đánh dấu tất cả là đã đọc</string>
|
||||
<string name="mark_all_as_read">Đánh dấu đã đọc xong</string>
|
||||
<string name="display_all_categories">Hiện toàn bộ</string>
|
||||
<string name="delete_notification_all_warning">Bạn có chắc muốn xóa tất cả thông báo\? Không thể khôi phục lại.</string>
|
||||
<string name="about_mastodon">\"Mastodon không phải là một trang web duy nhất như Twitter hoặc Facebook, đó là một mạng lưới hàng ngàn cộng đồng được điều hành bởi các tổ chức và cá nhân khác nhau cung cấp trải nghiệm truyền thông xã hội liền mạch.\"</string>
|
||||
|
@ -730,7 +733,7 @@
|
|||
<string name="most_recent">Gần đây nhất</string>
|
||||
<string name="filter">Bộ lọc</string>
|
||||
<string name="domain">Tên miền</string>
|
||||
<string name="origin_report">Nguồn gốc tài khoản bị báo cáo</string>
|
||||
<string name="origin_report">Máy chủ người bị báo cáo</string>
|
||||
<string name="status">Trạng thái</string>
|
||||
<string name="resolved">Đã xử lý</string>
|
||||
<string name="approved">Đã duyệt</string>
|
||||
|
@ -745,10 +748,11 @@
|
|||
<string name="label_line">Đường thẳng</string>
|
||||
<string name="label_eraser_mode">Chế độ Xóa</string>
|
||||
<string name="delete_cache">Xóa cache</string>
|
||||
<string name="messages_in_cache_for_home">Tút trong cache cho Bảng Tin</string>
|
||||
<string name="messages_stored_in_drafts">Tút lưu trong nháp</string>
|
||||
<string name="delete_cache_message">Bạn có chắc muốn xóa cache\? Nếu bạn có tút nháp đính kèm media, nó sẽ bị mất.</string>
|
||||
<string name="messages_in_cache_for_other_timelines">Tút trong cache những Bảng Tin khác</string>
|
||||
<string name="files_cache_size">Kích cỡ cache</string>
|
||||
<string name="clear_cache">Xóa cache</string>
|
||||
<string name="messages_in_cache_for_home">Bộ nhớ đệm tút Bảng Tin</string>
|
||||
<string name="messages_stored_in_drafts">Tút nháp</string>
|
||||
<string name="delete_cache_message">Bạn có chắc muốn xóa bộ nhớ đệm\? Nếu bạn có tút nháp đính kèm media, nó sẽ bị mất.</string>
|
||||
<string name="messages_in_cache_for_other_timelines">Bộ nhớ đệm tút những Bảng Tin khác</string>
|
||||
<string name="files_cache_size">Dung lượng cho phép</string>
|
||||
<string name="clear_cache">Xóa bộ nhớ đệm</string>
|
||||
<string name="default_system_language">Dùng ngôn ngữ hệ thống</string>
|
||||
</resources>
|
|
@ -779,6 +779,7 @@
|
|||
<string name="SET_FEATURED_TAG_ACTION" translatable="false">SET_FEATURED_TAG_ACTION</string>
|
||||
<string name="SET_RETRIEVE_METADATA_IF_URL_FROM_EXTERAL" translatable="false">SET_RETRIEVE_METADATA_IF_URL_FROM_EXTERAL</string>
|
||||
|
||||
<string name="SET_TRANSLATE_VALUES_RESET" translatable="false">SET_TRANSLATE_VALUES_RESET</string>
|
||||
<string-array name="SET_TRANSLATE_ENTRIES" translatable="false">
|
||||
<item>en</item>
|
||||
<item>fr</item>
|
||||
|
@ -863,6 +864,7 @@
|
|||
<string name="SET_TIME_FROM" translatable="false">SET_TIME_FROM</string>
|
||||
<string name="SET_TIME_TO" translatable="false">SET_TIME_TO</string>
|
||||
<string name="SET_MED_DESC_TIMEOUT" translatable="false">SET_MED_DESC_TIMEOUT</string>
|
||||
<string name="SET_COMPOSE_LANGUAGE" translatable="false">SET_COMPOSE_LANGUAGE</string>
|
||||
|
||||
|
||||
<string name="SET_NOTIF_FOLLOW" translatable="false">SET_NOTIF_FOLLOW</string>
|
||||
|
@ -894,7 +896,7 @@
|
|||
<string name="SET_ACCOUNTS_PER_CALL" translatable="false">SET_ACCOUNTS_PER_CALL</string>
|
||||
<string name="SET_STATUSES_PER_CALL" translatable="false">SET_STATUSES_PER_CALL</string>
|
||||
<string name="SET_NOTIFICATIONS_PER_CALL" translatable="false">SET_NOTIFICATIONS_PER_CALL</string>
|
||||
|
||||
<string name="INSTANCE_INFO" translatable="false">INSTANCE_INFO</string>
|
||||
<string name="SET_INVIDIOUS" translatable="false">SET_INVIDIOUS</string>
|
||||
<string name="SET_INVIDIOUS_HOST" translatable="false">SET_INVIDIOUS_HOST</string>
|
||||
<string name="DEFAULT_INVIDIOUS_HOST" translatable="false">invidious.snopyta.org</string>
|
||||
|
@ -978,6 +980,8 @@
|
|||
<string name="files_cache_size">File cache size</string>
|
||||
<string name="clear_cache">Clear cache</string>
|
||||
<string name="delete_cache_message">Are you sure you want to delete cache? If you have drafts with media, the attached media will be lost.</string>
|
||||
<string name="default_system_language">Use the default system language</string>
|
||||
<string name="message_language">Language for messages</string>
|
||||
|
||||
<string-array name="photo_editor_emoji" translatable="false">
|
||||
<!-- Smiles -->
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
<item name="iconTint">@color/cyanea_accent_dark_reference</item>
|
||||
<item name="strokeColor">@color/cyanea_accent_dark_reference</item>
|
||||
<item name="rippleColor">@color/cyanea_accent_dark_reference</item>
|
||||
<item name="android:backgroundTint">@color/cyanea_accent_dark_reference</item>
|
||||
<item name="backgroundTint">@color/cyanea_accent_dark_reference</item>
|
||||
</style>
|
||||
|
||||
<style name="MyOutlinedButton" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
||||
|
|
|
@ -11,4 +11,10 @@
|
|||
app:summary="@string/set_push_notifications"
|
||||
app:title="@string/set_change_locale"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/SET_TRANSLATE_VALUES_RESET"
|
||||
android:summary="@string/default_system_language"
|
||||
android:title="@string/reset"
|
||||
app:iconSpaceReserved="false" />
|
||||
</PreferenceScreen>
|
|
@ -0,0 +1 @@
|
|||
- Fix some bugs reported.
|
|
@ -0,0 +1,6 @@
|
|||
- Keep improving the scroll behaviour
|
||||
- Scroll to top (tab reselection) will fetch new messages and then scroll to top
|
||||
- Remove focus point for fit media preview
|
||||
- Fix cannot share with one account
|
||||
- Fix black theme
|
||||
- Fix some button colors
|
16
src/fdroid/fastlane/metadata/android/en/changelogs/399.txt
Normal file
16
src/fdroid/fastlane/metadata/android/en/changelogs/399.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
Added:
|
||||
- Set compose language (from compose menu -> three vertical dots)
|
||||
- Add reactions support for Pleroma
|
||||
- Add privacy indicator at the top right
|
||||
|
||||
Changed
|
||||
- Improve the scrolling behaviour
|
||||
- Scroll to top (tab reselection) will fetch new messages and then scroll to top
|
||||
|
||||
Fixed:
|
||||
- Empty tag timelines
|
||||
- Remove focus point for fit media preview
|
||||
- Fix cannot share with one account
|
||||
- Fix black theme
|
||||
- Theme cannot be selected
|
||||
- Fix some button colors
|
Loading…
Reference in a new issue