diff --git a/.github/scripts/build-release.sh b/.github/scripts/build-release.sh
index e3efc59df..069aa673e 100755
--- a/.github/scripts/build-release.sh
+++ b/.github/scripts/build-release.sh
@@ -36,6 +36,8 @@ BUILD_NUMBER=$(app-store-connect get-latest-testflight-build-number $ENV_APP_ID
BUILD_NUMBER=$((BUILD_NUMBER+1))
CURRENT_PROJECT_VERSION=${BUILD_NUMBER:-0}
+echo "GITHUB_TAG_NAME=build-$CURRENT_PROJECT_VERSION" >> $GITHUB_ENV
+
agvtool new-version -all $CURRENT_PROJECT_VERSION
xcrun xcodebuild clean \
diff --git a/.github/workflows/develop-build.yml b/.github/workflows/develop-build.yml
index c37f00731..ede061098 100644
--- a/.github/workflows/develop-build.yml
+++ b/.github/workflows/develop-build.yml
@@ -4,6 +4,7 @@ on:
push:
branches:
- develop
+ - release*
- ci-test
jobs:
@@ -11,16 +12,17 @@ jobs:
name: Build
runs-on: macOS-12
steps:
- - name: checkout
+ - name: Checkout
uses: actions/checkout@v2
- - name: setup
+ - name: Setup
env:
NotificationEndpointDebug: ${{ secrets.NotificationEndpointDebug }}
NotificationEndpointRelease: ${{ secrets.NotificationEndpointRelease }}
run: exec ./.github/scripts/setup.sh
- - uses: actions/setup-python@v4
+ - name: Install codemagic-cli-tools
+ uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: |
@@ -43,7 +45,7 @@ jobs:
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
- - name: build
+ - name: Build
env:
ENV_APP_ID: ${{ secrets.APP_ID }}
ENV_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }}
@@ -60,6 +62,12 @@ jobs:
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
+ - name: Tag commit
+ uses: tvdias/github-tagger@v0.0.1
+ with:
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ tag: "${{ env.GITHUB_TAG_NAME }}"
+
- name: Clean up keychain and provisioning profile
if: ${{ always() }}
run: |
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 827276208..1c40b6556 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -6,6 +6,9 @@ on:
- master
- develop
- feature/*
+ - feature-*
+ - issue/*
+ - issue-*
pull_request:
branches:
- develop
diff --git a/Documentation/Setup.md b/Documentation/Setup.md
index ecb518a59..4da3c41ca 100644
--- a/Documentation/Setup.md
+++ b/Documentation/Setup.md
@@ -12,7 +12,7 @@ Install the latest version of Xcode from the App Store or Apple Developer Downlo
This guide may not suit your machine and actually setup procedure may change in the future. Please file the issue or Pull Request if there are any problems.
## CocoaPods
-The app use [CocoaPods]() and [Arkana](https://github.com/rogerluan/arkana). Ruby Gems are managed through Bundler. The M1 Mac needs virtual ruby env to workaround compatibility issues.
+The app use [CocoaPods]() and [Arkana](https://github.com/rogerluan/arkana). Ruby Gems are managed through Bundler. The M1 Mac needs virtual ruby env to workaround compatibility issues. Make sure you have [Rosetta](https://support.apple.com/en-us/HT211861) installed if you are using the M1 Mac.
#### Intel Mac
diff --git a/Gemfile.lock b/Gemfile.lock
index e0ed91c5b..15d02a8ec 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -100,7 +100,9 @@ GEM
PLATFORMS
arm64-darwin-21
+ arm64-darwin-22
x86_64-darwin-21
+ x86_64-darwin-22
DEPENDENCIES
arkana
diff --git a/Localization/Localizable.stringsdict b/Localization/Localizable.stringsdict
index cd97825f4..f8964ca5d 100644
--- a/Localization/Localizable.stringsdict
+++ b/Localization/Localizable.stringsdict
@@ -13,15 +13,15 @@
NSStringFormatValueTypeKey
ld
zero
- no unread notification
+ no unread notifications
one
1 unread notification
few
%ld unread notifications
many
- %ld unread notification
+ %ld unread notifications
other
- %ld unread notification
+ %ld unread notifications
a11y.plural.count.input_limit_exceeds
diff --git a/Localization/StringsConvertor/Intents/input/is.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/is.lproj/Intents.strings
new file mode 100644
index 000000000..196c33e70
--- /dev/null
+++ b/Localization/StringsConvertor/Intents/input/is.lproj/Intents.strings
@@ -0,0 +1,51 @@
+"16wxgf" = "Birta á Mastodon";
+
+"751xkl" = "Efni texta";
+
+"CsR7G2" = "Birta á Mastodon";
+
+"HZSGTr" = "Hvaða efni á að birta?";
+
+"HdGikU" = "Birting færslu mistókst";
+
+"KDNTJ4" = "Ástæða bilunar";
+
+"RHxKOw" = "Senda færslu með textaefni";
+
+"RxSqsb" = "Færsla";
+
+"WCIR3D" = "Birta ${content} á Mastodon";
+
+"ZKJSNu" = "Færsla";
+
+"ZS1XaK" = "${content}";
+
+"ZbSjzC" = "Sýnileiki";
+
+"Zo4jgJ" = "Sýnileiki færslu";
+
+"apSxMG-dYQ5NN" = "Það eru ${count} valkostir sem samsvara ‘Opinbert’.";
+
+"apSxMG-ehFLjY" = "Það eru ${count} valkostir sem samsvara ‘Einungis fylgjendur’.";
+
+"ayoYEb-dYQ5NN" = "${content}, opinbert";
+
+"ayoYEb-ehFLjY" = "${content}, einungis fylgjendur";
+
+"dUyuGg" = "Birta á Mastodon";
+
+"dYQ5NN" = "Opinbert";
+
+"ehFLjY" = "Einungis fylgjendur";
+
+"gfePDu" = "Birting færslu mistókst. ${failureReason}";
+
+"k7dbKQ" = "Það tókst að senda færsluna.";
+
+"oGiqmY-dYQ5NN" = "Bara til að staðfesta, þú vildir 'Opinbert'?";
+
+"oGiqmY-ehFLjY" = "Bara til að staðfesta, þú vildir ''Einungis fylgjendur'?";
+
+"rM6dvp" = "URL-slóð";
+
+"ryJLwG" = "Það tókst að senda færsluna. ";
diff --git a/Localization/StringsConvertor/Intents/input/is.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/is.lproj/Intents.stringsdict
new file mode 100644
index 000000000..fe12c972a
--- /dev/null
+++ b/Localization/StringsConvertor/Intents/input/is.lproj/Intents.stringsdict
@@ -0,0 +1,38 @@
+
+
+
+
+ There are ${count} options matching ‘${content}’. - 2
+
+ NSStringLocalizedFormatKey
+ Það eru %#@count_option@ sem samsvara ‘${content}’.
+ count_option
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ %ld
+ one
+ 1 valkostur
+ other
+ %ld valkostir
+
+
+ There are ${count} options matching ‘${visibility}’.
+
+ NSStringLocalizedFormatKey
+ Það eru %#@count_option@ sem samsvara ‘${visibility}’.
+ count_option
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ %ld
+ one
+ 1 valkostur
+ other
+ %ld valkostir
+
+
+
+
diff --git a/Localization/StringsConvertor/Intents/input/kab.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/kab.lproj/Intents.stringsdict
index a8aeeaaf1..6cead6f34 100644
--- a/Localization/StringsConvertor/Intents/input/kab.lproj/Intents.stringsdict
+++ b/Localization/StringsConvertor/Intents/input/kab.lproj/Intents.stringsdict
@@ -29,9 +29,9 @@
NSStringFormatValueTypeKey
%ld
one
- 1 uɣewwaṛ
+ %ld n uɣewwaṛ
other
- %ld iɣewwaṛen
+ %ld n iɣewwaṛen
diff --git a/Localization/StringsConvertor/Intents/input/pt-BR.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/pt-BR.lproj/Intents.strings
index 4d4e426c6..3e6806953 100644
--- a/Localization/StringsConvertor/Intents/input/pt-BR.lproj/Intents.strings
+++ b/Localization/StringsConvertor/Intents/input/pt-BR.lproj/Intents.strings
@@ -4,9 +4,9 @@
"CsR7G2" = "Postar no Mastodon";
-"HZSGTr" = "What content to post?";
+"HZSGTr" = "Qual conteúdo a publicar?";
-"HdGikU" = "Posting failed";
+"HdGikU" = "Falha na publicação";
"KDNTJ4" = "Motivo da falha";
@@ -22,30 +22,30 @@
"ZbSjzC" = "Visibilidade";
-"Zo4jgJ" = "Post Visibility";
+"Zo4jgJ" = "Visibilidade da publicação";
-"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’.";
+"apSxMG-dYQ5NN" = "Existem ${count} opções correspondentes a ‘Público’.";
-"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’.";
+"apSxMG-ehFLjY" = "Existem ${count} opções correspondentes a ‘Apenas para seguidores’.";
-"ayoYEb-dYQ5NN" = "${content}, Public";
+"ayoYEb-dYQ5NN" = "${content}, Público";
-"ayoYEb-ehFLjY" = "${content}, Followers Only";
+"ayoYEb-ehFLjY" = "${content}, Apenas para seguidores";
-"dUyuGg" = "Post on Mastodon";
+"dUyuGg" = "Postar no Mastodon";
-"dYQ5NN" = "Public";
+"dYQ5NN" = "Público";
-"ehFLjY" = "Followers Only";
+"ehFLjY" = "Apenas para seguidores";
-"gfePDu" = "Posting failed. ${failureReason}";
+"gfePDu" = "Falha na publicação. ${failureReason}";
-"k7dbKQ" = "Post was sent successfully.";
+"k7dbKQ" = "Publicação enviada com sucesso.";
-"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?";
+"oGiqmY-dYQ5NN" = "Só para confirmar, você queria ‘Público’?";
-"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?";
+"oGiqmY-ehFLjY" = "Só para confirmar, você queria ‘Apenas para seguidores’?";
"rM6dvp" = "URL";
-"ryJLwG" = "Post was sent successfully. ";
+"ryJLwG" = "Publicação enviada com sucesso. ";
diff --git a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift
index beba6cb3f..665161e2c 100644
--- a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift
+++ b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift
@@ -53,6 +53,7 @@ private func map(language: String) -> String? {
case "ca.lproj": return "ca" // Catalan
case "zh-Hans.lproj": return "zh-Hans" // Chinese Simplified
case "zh-Hant.lproj": return "zh-Hant" // Chinese Traditional
+ case "cs.lproj": return "cs" // Czech
case "nl.lproj": return "nl" // Dutch
case "en.lproj": return "en"
case "fi.lproj": return "fi" // Finnish
@@ -65,6 +66,7 @@ private func map(language: String) -> String? {
case "kmr.lproj": return "ku" // Kurmanji (Kurdish) [intent mapping]
case "ru.lproj": return "ru" // Russian
case "gd.lproj": return "gd" // Scottish Gaelic
+ case "sl.lproj": return "sl" // Slovenian
case "ckb.lproj": return "ckb" // Sorani (Kurdish)
case "es.lproj": return "es" // Spanish
case "es_AR.lproj": return "es-AR" // Spanish, Argentina
diff --git a/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict
index cd97825f4..f8964ca5d 100644
--- a/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict
@@ -13,15 +13,15 @@
NSStringFormatValueTypeKey
ld
zero
- no unread notification
+ no unread notifications
one
1 unread notification
few
%ld unread notifications
many
- %ld unread notification
+ %ld unread notifications
other
- %ld unread notification
+ %ld unread notifications
a11y.plural.count.input_limit_exceeds
diff --git a/Localization/StringsConvertor/input/Base.lproj/app.json b/Localization/StringsConvertor/input/Base.lproj/app.json
index f90b2bef6..ea046bfbc 100644
--- a/Localization/StringsConvertor/input/Base.lproj/app.json
+++ b/Localization/StringsConvertor/input/Base.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -719,4 +724,4 @@
"title": "Bookmarks"
}
}
-}
\ No newline at end of file
+}
diff --git a/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict
index 862d98184..91368a4fb 100644
--- a/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict
@@ -74,6 +74,30 @@
%ld حَرف
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ zero
+ لَا حَرف
+ one
+ حَرفٌ واحِد
+ two
+ حَرفانِ اِثنان
+ few
+ %ld characters
+ many
+ %ld characters
+ other
+ %ld حَرف
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/ar.lproj/app.json b/Localization/StringsConvertor/input/ar.lproj/app.json
index 4c5ac4c8b..bf4bf454e 100644
--- a/Localization/StringsConvertor/input/ar.lproj/app.json
+++ b/Localization/StringsConvertor/input/ar.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "اِلتِقاطُ صُورَة",
"save_photo": "حفظ الصورة",
"copy_photo": "نسخ الصورة",
- "sign_in": "تسجيل الدخول",
- "sign_up": "إنشاء حِساب",
+ "sign_in": "تسجيلُ الدخول",
+ "sign_up": "Create account",
"see_more": "عرض المزيد",
"preview": "مُعاينة",
"share": "المُشارك",
@@ -218,10 +218,16 @@
"get_started": "ابدأ الآن",
"log_in": "تسجيلُ الدخول"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "اِختر خادِم،\nأيًّا مِنهُم.",
- "subtitle": "اختر مجتمعًا بناءً على اهتماماتك، منطقتك أو يمكنك حتى اختيارُ مجتمعٍ ذي غرضٍ عام.",
- "subtitle_extend": "اختر مجتمعًا بناءً على اهتماماتك، منطقتك أو يمكنك حتى اختيارُ مجتمعٍ ذي غرضٍ عام. تُشغَّل جميعُ المجتمعِ مِن قِبَلِ مُنظمَةٍ أو فردٍ مُستقلٍ تمامًا.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "الكُل",
@@ -248,8 +254,7 @@
"category": "الفئة"
},
"input": {
- "placeholder": "اِبحَث عن خادِم أو انضم إلى آخر خاص بك...",
- "search_servers_or_enter_url": "اِبحَث فِي الخَوادِم أو أدخِل رابِط"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "يجري إيجاد خوادم متوفِّرَة...",
@@ -383,10 +388,12 @@
"attachment_broken": "هذا ال%s مُعطَّل\nويتعذَّرُ رفعُه إلى ماستودون.",
"description_photo": "صِف الصورة للمَكفوفين...",
"description_video": "صِف المقطع المرئي للمَكفوفين...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "فَشَلَ التَّحميل",
+ "upload_failed": "فَشَلَ الرَّفع",
+ "can_not_recognize_this_media_attachment": "يتعذَّرُ التعرُّفُ على وسائِطِ هذا المُرفَق",
+ "attachment_too_large": "المُرفَق كَبيرٌ جِدًّا",
+ "compressing_state": "يجري الضغط...",
+ "server_processing_state": "مُعالجة الخادم جارِيَة..."
},
"poll": {
"duration_time": "المُدَّة: %s",
@@ -396,7 +403,9 @@
"one_day": "يومٌ واحِد",
"three_days": "ثلاثةُ أيام",
"seven_days": "سبعةُ أيام",
- "option_number": "الخيار %ld"
+ "option_number": "الخيار %ld",
+ "the_poll_is_invalid": "الاِستِطلاعُ غيرُ صالِح",
+ "the_poll_has_empty_option": "يوجَدُ خِيارٌ فارِغٌ فِي الاِستِطلاع"
},
"content_warning": {
"placeholder": "اكتب تَحذيرًا دَقيقًا هُنا..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "منتقي الرموز التعبيرية المُخصَّص",
"enable_content_warning": "تفعيل تحذير المُحتَوى",
"disable_content_warning": "تعطيل تحذير المُحتَوى",
- "post_visibility_menu": "قائمة ظهور المنشور"
+ "post_visibility_menu": "قائمة ظهور المنشور",
+ "post_options": "Post Options",
+ "posting_as": "نَشر كَـ %s"
},
"keyboard": {
"discard_post": "تجاهُل المنشور",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "التسمية",
"content": "المُحتَوى"
+ },
+ "verified": {
+ "short": "تمَّ التَّحقق بِتاريخ %s",
+ "long": "تمَّ التَّحقق مِن مِلكية هذا الرابِطِ بِتاريخ %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict
index cc28edbc6..947597417 100644
--- a/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld caràcters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ resten %#@character_count@
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 caràcter
+ other
+ %ld caràcters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/ca.lproj/app.json b/Localization/StringsConvertor/input/ca.lproj/app.json
index 7164d1d12..52bb67c77 100644
--- a/Localization/StringsConvertor/input/ca.lproj/app.json
+++ b/Localization/StringsConvertor/input/ca.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Desa la foto",
"copy_photo": "Copia la foto",
"sign_in": "Iniciar sessió",
- "sign_up": "Registre",
+ "sign_up": "Crea un compte",
"see_more": "Veure més",
"preview": "Vista prèvia",
"share": "Comparteix",
@@ -218,10 +218,16 @@
"get_started": "Comença",
"log_in": "Inicia sessió"
},
+ "login": {
+ "title": "Ben tornat",
+ "subtitle": "T'inicia sessió en el servidor on has creat el teu compte.",
+ "server_search_field": {
+ "placeholder": "Insereix la URL o cerca el teu servidor"
+ }
+ },
"server_picker": {
"title": "Mastodon està fet d'usuaris en diferents comunitats.",
- "subtitle": "Tria una comunitat segons els teus interessos, regió o una de propòsit general.",
- "subtitle_extend": "Tria una comunitat segons els teus interessos, regió o una de propòsit general. Cada comunitat és operada per una organització totalment independent o individualment.",
+ "subtitle": "Tria un servidor en funció de la teva regió, interessos o un de propòsit general. Seguiràs podent connectar amb tothom a Mastodon, independentment del servidor.",
"button": {
"category": {
"all": "Totes",
@@ -248,8 +254,7 @@
"category": "CATEGORIA"
},
"input": {
- "placeholder": "Cerca servidors",
- "search_servers_or_enter_url": "Cerca servidors o introdueix l'enllaç"
+ "search_servers_or_enter_url": "Cerca comunitats o introdueix l'URL"
},
"empty_state": {
"finding_servers": "Cercant els servidors disponibles...",
@@ -385,8 +390,10 @@
"description_video": "Descriu el vídeo per als disminuïts visuals...",
"load_failed": "Ha fallat la càrrega",
"upload_failed": "Pujada fallida",
- "can_not_recognize_this_media_attachment": "No es pot reconèixer l'adjunt multimèdia",
- "attachment_too_large": "El fitxer adjunt és massa gran"
+ "can_not_recognize_this_media_attachment": "No es pot reconèixer aquest adjunt multimèdia",
+ "attachment_too_large": "El fitxer adjunt és massa gran",
+ "compressing_state": "Comprimint...",
+ "server_processing_state": "Servidor processant..."
},
"poll": {
"duration_time": "Durada: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Dia",
"three_days": "3 Dies",
"seven_days": "7 Dies",
- "option_number": "Opció %ld"
+ "option_number": "Opció %ld",
+ "the_poll_is_invalid": "L'enquesta no és vàlida",
+ "the_poll_has_empty_option": "L'enquesta té una opció buida"
},
"content_warning": {
"placeholder": "Escriu un advertiment precís aquí..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Selector d'Emoji Personalitzat",
"enable_content_warning": "Activa l'Avís de Contingut",
"disable_content_warning": "Desactiva l'Avís de Contingut",
- "post_visibility_menu": "Menú de Visibilitat de Publicació"
+ "post_visibility_menu": "Menú de Visibilitat de Publicació",
+ "post_options": "Opcions del tut",
+ "posting_as": "Publicant com a %s"
},
"keyboard": {
"discard_post": "Descarta la Publicació",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Etiqueta",
"content": "Contingut"
+ },
+ "verified": {
+ "short": "Verificat a %s",
+ "long": "La propietat d'aquest enllaç es va verificar el dia %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/ckb.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ckb.lproj/Localizable.stringsdict
index 001a8a608..8116226ec 100644
--- a/Localization/StringsConvertor/input/ckb.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/ckb.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld نووسە
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/ckb.lproj/app.json b/Localization/StringsConvertor/input/ckb.lproj/app.json
index 25452f38b..787bbea36 100644
--- a/Localization/StringsConvertor/input/ckb.lproj/app.json
+++ b/Localization/StringsConvertor/input/ckb.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "وێنە بگرە",
"save_photo": "هەڵی بگرە",
"copy_photo": "لەبەری بگرەوە",
- "sign_in": "بچۆ ژوورەوە",
- "sign_up": "خۆت تۆمار بکە",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "زیاتر ببینە",
"preview": "پێشبینین",
"share": "هاوبەشی بکە",
@@ -218,10 +218,16 @@
"get_started": "دەست پێ بکە",
"log_in": "بچۆ ژوورەوە"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "ماستۆدۆن لە چەندان بەکارهێنەر پێک دێت کە لە ڕاژەکاری جیاواز دان.",
- "subtitle": "ڕاژەکارێکێکی گشتی یان دانەیەک لەسەر بنەمای حەزەکانت و هەرێمەکەت هەڵبژێرە.",
- "subtitle_extend": "ڕاژەکارێکێکی گشتی یان دانەیەک لەسەر بنەمای حەزەکانت و هەرێمەکەت هەڵبژێرە. هەر ڕاژەکارێک لەلایەن ڕێکخراوێک یان تاکەکەسێک بەڕێوە دەبرێت.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "هەموو",
@@ -248,8 +254,7 @@
"category": "بەش"
},
"input": {
- "placeholder": "بگەڕێ",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "ڕاژەکار دەدۆزرێتەوە...",
@@ -385,8 +390,10 @@
"description_video": "ڤیدیۆکەت بۆ نابیناکان باس بکە...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "کات: %s",
@@ -396,7 +403,9 @@
"one_day": "1 ڕۆژ",
"three_days": "3 ڕۆژ",
"seven_days": "7 ڕۆژ",
- "option_number": "بژاردەی %ld"
+ "option_number": "بژاردەی %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "ئاگادارییەکەت لێرە بنووسە..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "هەڵبژێری ئیمۆجی",
"enable_content_warning": "ئاگاداریی ناوەڕۆک چالاک بکە",
"disable_content_warning": "ئاگاداریی ناوەڕۆک ناچالاک بکە",
- "post_visibility_menu": "پێڕستی شێوازی دەرکەوتنی پۆست"
+ "post_visibility_menu": "پێڕستی شێوازی دەرکەوتنی پۆست",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "پۆستەکە هەڵوەشێنەوە",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "ناونیشان",
"content": "ناوەڕۆک"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict
index 827bd79e6..6e44e9f0a 100644
--- a/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict
@@ -62,6 +62,26 @@
%ld znaků
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 znak
+ few
+ %ld znaky
+ many
+ %ld znaků
+ other
+ %ld znaků
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
@@ -288,13 +308,13 @@
NSStringFormatValueTypeKey
ld
one
- 1 following
+ 1 sledující
few
- %ld following
+ %ld sledující
many
- %ld following
+ %ld sledujících
other
- %ld following
+ %ld sledujících
plural.count.follower
@@ -328,13 +348,13 @@
NSStringFormatValueTypeKey
ld
one
- 1 year left
+ Zbývá 1 rok
few
- %ld years left
+ Zbývají %ld roky
many
- %ld years left
+ Zbývá %ld roků
other
- %ld years left
+ Zbývá %ld roků
date.month.left
@@ -348,7 +368,7 @@
NSStringFormatValueTypeKey
ld
one
- 1 months left
+ Zbývá 1 měsíc
few
%ld months left
many
diff --git a/Localization/StringsConvertor/input/cs.lproj/app.json b/Localization/StringsConvertor/input/cs.lproj/app.json
index 4050352f4..680eb01bb 100644
--- a/Localization/StringsConvertor/input/cs.lproj/app.json
+++ b/Localization/StringsConvertor/input/cs.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Uložit fotku",
"copy_photo": "Kopírovat fotografii",
"sign_in": "Přihlásit se",
- "sign_up": "Zaregistrovat se",
+ "sign_up": "Vytvořit účet",
"see_more": "Zobrazit více",
"preview": "Náhled",
"share": "Sdílet",
@@ -218,10 +218,16 @@
"get_started": "Začínáme",
"log_in": "Přihlásit se"
},
+ "login": {
+ "title": "Vítejte zpět",
+ "subtitle": "Přihlaste se na serveru, na kterém jste si vytvořili účet.",
+ "server_search_field": {
+ "placeholder": "Zadejte URL nebo vyhledávejte váš server"
+ }
+ },
"server_picker": {
"title": "Mastodon tvoří uživatelé z různých serverů.",
- "subtitle": "Vyberte server založený na vašich zájmech, regionu nebo obecném účelu.",
- "subtitle_extend": "Vyberte server založený na vašich zájmech, regionu nebo obecném účelu. Každý server je provozován zcela nezávislou organizací nebo jednotlivcem.",
+ "subtitle": "Vyberte server založený ve vašem regionu, podle zájmů nebo podle obecného účelu. Stále můžete chatovat s kýmkoli na Mastodonu bez ohledu na vaše servery.",
"button": {
"category": {
"all": "Vše",
@@ -248,8 +254,7 @@
"category": "KATEGORIE"
},
"input": {
- "placeholder": "Hledat servery",
- "search_servers_or_enter_url": "Hledat servery nebo zadat URL"
+ "search_servers_or_enter_url": "Hledejte komunity nebo zadejte URL"
},
"empty_state": {
"finding_servers": "Hledání dostupných serverů...",
@@ -386,7 +391,9 @@
"load_failed": "Načtení se nezdařilo",
"upload_failed": "Nahrání selhalo",
"can_not_recognize_this_media_attachment": "Nelze rozpoznat toto medium přílohy",
- "attachment_too_large": "Příloha je příliš velká"
+ "attachment_too_large": "Příloha je příliš velká",
+ "compressing_state": "Probíhá komprese...",
+ "server_processing_state": "Zpracování serveru..."
},
"poll": {
"duration_time": "Doba trvání: %s",
@@ -396,7 +403,9 @@
"one_day": "1 den",
"three_days": "3 dny",
"seven_days": "7 dní",
- "option_number": "Možnost %ld"
+ "option_number": "Možnost %ld",
+ "the_poll_is_invalid": "Anketa je neplatná",
+ "the_poll_has_empty_option": "Anketa má prázdnou možnost"
},
"content_warning": {
"placeholder": "Zde napište přesné varování..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Vlastní výběr Emoji",
"enable_content_warning": "Povolit upozornění na obsah",
"disable_content_warning": "Vypnout upozornění na obsah",
- "post_visibility_menu": "Menu viditelnosti příspěvku"
+ "post_visibility_menu": "Menu viditelnosti příspěvku",
+ "post_options": "Možnosti příspěvku",
+ "posting_as": "Odesílání jako %s"
},
"keyboard": {
"discard_post": "Zahodit příspěvek",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Označení",
"content": "Obsah"
+ },
+ "verified": {
+ "short": "Ověřeno na %s",
+ "long": "Vlastnictví tohoto odkazu bylo zkontrolováno na %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict
index 038eaffda..9e4c09959 100644
--- a/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict
@@ -74,6 +74,30 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ zero
+ %ld characters
+ one
+ 1 character
+ two
+ %ld characters
+ few
+ %ld characters
+ many
+ %ld characters
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/cy.lproj/app.json b/Localization/StringsConvertor/input/cy.lproj/app.json
index f36fe7d16..fec3197be 100644
--- a/Localization/StringsConvertor/input/cy.lproj/app.json
+++ b/Localization/StringsConvertor/input/cy.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict
index bdcae6ac9..eabdc3c32 100644
--- a/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/da.lproj/app.json b/Localization/StringsConvertor/input/da.lproj/app.json
index a6a971860..3113ada74 100644
--- a/Localization/StringsConvertor/input/da.lproj/app.json
+++ b/Localization/StringsConvertor/input/da.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict
index f60c6b0d7..1965fd02b 100644
--- a/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld Zeichen
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/de.lproj/app.json b/Localization/StringsConvertor/input/de.lproj/app.json
index 481f07a4a..894a0245e 100644
--- a/Localization/StringsConvertor/input/de.lproj/app.json
+++ b/Localization/StringsConvertor/input/de.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Foto speichern",
"copy_photo": "Foto kopieren",
"sign_in": "Anmelden",
- "sign_up": "Registrieren",
+ "sign_up": "Konto erstellen",
"see_more": "Mehr anzeigen",
"preview": "Vorschau",
"share": "Teilen",
@@ -218,10 +218,16 @@
"get_started": "Registrieren",
"log_in": "Anmelden"
},
+ "login": {
+ "title": "Willkommen zurück",
+ "subtitle": "Melden Sie sich auf dem Server an, auf dem Sie Ihr Konto erstellt haben.",
+ "server_search_field": {
+ "placeholder": "URL eingeben oder nach Server suchen"
+ }
+ },
"server_picker": {
"title": "Wähle einen Server,\nbeliebigen Server.",
- "subtitle": "Wähle eine Gemeinschaft, die auf deinen Interessen, Region oder einem allgemeinen Zweck basiert.",
- "subtitle_extend": "Wähle eine Gemeinschaft basierend auf deinen Interessen, deiner Region oder einem allgemeinen Zweck. Jede Gemeinschaft wird von einer völlig unabhängigen Organisation oder Einzelperson betrieben.",
+ "subtitle": "Wähle einen Server basierend auf deinen Interessen oder deiner Region – oder einfach einen allgemeinen. Du kannst trotzdem mit jedem interagieren, egal auf welchem Server.",
"button": {
"category": {
"all": "Alle",
@@ -248,8 +254,7 @@
"category": "KATEGORIE"
},
"input": {
- "placeholder": "Nach Server suchen oder URL eingeben",
- "search_servers_or_enter_url": "Nach Server suchen oder URL eingeben"
+ "search_servers_or_enter_url": "Suche nach einer Community oder gib eine URL ein"
},
"empty_state": {
"finding_servers": "Verfügbare Server werden gesucht...",
@@ -386,7 +391,9 @@
"load_failed": "Laden fehlgeschlagen",
"upload_failed": "Upload fehlgeschlagen",
"can_not_recognize_this_media_attachment": "Medienanhang wurde nicht erkannt",
- "attachment_too_large": "Anhang zu groß"
+ "attachment_too_large": "Anhang zu groß",
+ "compressing_state": "Komprimieren...",
+ "server_processing_state": "Serververarbeitung..."
},
"poll": {
"duration_time": "Dauer: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Tag",
"three_days": "3 Tage",
"seven_days": "7 Tage",
- "option_number": "Auswahlmöglichkeit %ld"
+ "option_number": "Auswahlmöglichkeit %ld",
+ "the_poll_is_invalid": "Die Umfrage ist ungültig",
+ "the_poll_has_empty_option": "Die Umfrage hat eine leere Option"
},
"content_warning": {
"placeholder": "Schreibe eine Inhaltswarnung hier..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Benutzerdefinierter Emojiwähler",
"enable_content_warning": "Inhaltswarnung einschalten",
"disable_content_warning": "Inhaltswarnung ausschalten",
- "post_visibility_menu": "Sichtbarkeitsmenü"
+ "post_visibility_menu": "Sichtbarkeitsmenü",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Beitrag verwerfen",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Bezeichnung",
"content": "Inhalt"
+ },
+ "verified": {
+ "short": "Überprüft am %s",
+ "long": "Besitz des Links wurde überprüft am %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict
index bdcae6ac9..eabdc3c32 100644
--- a/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/en-US.lproj/app.json b/Localization/StringsConvertor/input/en-US.lproj/app.json
index a6a971860..3113ada74 100644
--- a/Localization/StringsConvertor/input/en-US.lproj/app.json
+++ b/Localization/StringsConvertor/input/en-US.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/en.lproj/app.json b/Localization/StringsConvertor/input/en.lproj/app.json
index 25f06ad83..3113ada74 100644
--- a/Localization/StringsConvertor/input/en.lproj/app.json
+++ b/Localization/StringsConvertor/input/en.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -444,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/es-AR.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/es-AR.lproj/Localizable.stringsdict
index 2bd66395a..fb939a040 100644
--- a/Localization/StringsConvertor/input/es-AR.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/es-AR.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld caracteres
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ Quedan %#@character_count@
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 caracter
+ other
+ %ld caracteres
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/es-AR.lproj/app.json b/Localization/StringsConvertor/input/es-AR.lproj/app.json
index 309cf4d34..5be543f98 100644
--- a/Localization/StringsConvertor/input/es-AR.lproj/app.json
+++ b/Localization/StringsConvertor/input/es-AR.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Guardar foto",
"copy_photo": "Copiar foto",
"sign_in": "Iniciar sesión",
- "sign_up": "Registrarse",
+ "sign_up": "Crear cuenta",
"see_more": "Ver más",
"preview": "Previsualización",
"share": "Compartir",
@@ -137,10 +137,10 @@
"closed": "Cerrada"
},
"meta_entity": {
- "url": "Link: %s",
- "hashtag": "Hashtag: %s",
- "mention": "Show Profile: %s",
- "email": "Email address: %s"
+ "url": "Enlace: %s",
+ "hashtag": "Etiqueta: %s",
+ "mention": "Mostrar perfil: %s",
+ "email": "Dirección de correo electrónico: %s"
},
"actions": {
"reply": "Responder",
@@ -218,10 +218,16 @@
"get_started": "Comenzá",
"log_in": "Iniciar sesión"
},
+ "login": {
+ "title": "Hola de nuevo",
+ "subtitle": "Iniciá sesión en el servidor en donde creaste tu cuenta.",
+ "server_search_field": {
+ "placeholder": "Ingresá la dirección web o buscá tu servidor"
+ }
+ },
"server_picker": {
"title": "Mastodon está compuesto de cuentas en diferentes servidores.",
- "subtitle": "Elegí un servidor basado en tus intereses, región, o de propósitos generales.",
- "subtitle_extend": "Elegí un servidor basado en tus intereses, región, o de propósitos generales. Cada servidor es operado por una organización o individuo totalmente independientes.",
+ "subtitle": "Elegí un servidor basado en tu región, en tus intereses o uno de propósitos generales. Vas a poder interactuar con cualquier cuenta de Mastodon, independientemente del servidor.",
"button": {
"category": {
"all": "Todas",
@@ -248,8 +254,7 @@
"category": "CATEGORÍA"
},
"input": {
- "placeholder": "Buscar servidores",
- "search_servers_or_enter_url": "Buscar servidores o introducir dirección web"
+ "search_servers_or_enter_url": "Buscá comunidades o ingresá la dirección web"
},
"empty_state": {
"finding_servers": "Buscando servidores disponibles…",
@@ -386,7 +391,9 @@
"load_failed": "Falló la descarga",
"upload_failed": "Falló la subida",
"can_not_recognize_this_media_attachment": "No se pudo reconocer este archivo adjunto",
- "attachment_too_large": "Adjunto demasiado grande"
+ "attachment_too_large": "Adjunto demasiado grande",
+ "compressing_state": "Comprimiendo…",
+ "server_processing_state": "Servidor procesando…"
},
"poll": {
"duration_time": "Duración: %s",
@@ -396,7 +403,9 @@
"one_day": "1 día",
"three_days": "3 días",
"seven_days": "7 días",
- "option_number": "Opción %ld"
+ "option_number": "Opción %ld",
+ "the_poll_is_invalid": "La encuesta no es válida",
+ "the_poll_has_empty_option": "La encuesta tiene opción vacía"
},
"content_warning": {
"placeholder": "Escribí una advertencia precisa acá…"
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Selector de emoji personalizado",
"enable_content_warning": "Habilitar advertencia de contenido",
"disable_content_warning": "Deshabilitar advertencia de contenido",
- "post_visibility_menu": "Menú de visibilidad del mensaje"
+ "post_visibility_menu": "Menú de visibilidad del mensaje",
+ "post_options": "Opciones de mensaje",
+ "posting_as": "Enviar como %s"
},
"keyboard": {
"discard_post": "Descartar mensaje",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Nombre de campo",
"content": "Valor de campo"
+ },
+ "verified": {
+ "short": "Verificado en %s",
+ "long": "La propiedad de este enlace fue verificada el %s"
}
},
"segmented_control": {
@@ -706,7 +721,7 @@
"accessibility_hint": "Tocá dos veces para descartar este asistente"
},
"bookmark": {
- "title": "Bookmarks"
+ "title": "Marcadores"
}
}
}
diff --git a/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict
index def3d7bba..ca07b6b28 100644
--- a/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld caracteres
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/es.lproj/app.json b/Localization/StringsConvertor/input/es.lproj/app.json
index 7eaff340d..1b90bfa10 100644
--- a/Localization/StringsConvertor/input/es.lproj/app.json
+++ b/Localization/StringsConvertor/input/es.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Tomar foto",
"save_photo": "Guardar foto",
"copy_photo": "Copiar foto",
- "sign_in": "Iniciar sesión",
- "sign_up": "Regístrate",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "Ver más",
"preview": "Vista previa",
"share": "Compartir",
@@ -218,10 +218,16 @@
"get_started": "Empezar",
"log_in": "Iniciar sesión"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Elige un servidor,\ncualquier servidor.",
- "subtitle": "Elige una comunidad relacionada con tus intereses, con tu región o una más genérica.",
- "subtitle_extend": "Elige una comunidad relacionada con tus intereses, con tu región o una más genérica. Cada comunidad está operada por una organización o individuo completamente independiente.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Todas",
@@ -248,8 +254,7 @@
"category": "CATEGORÍA"
},
"input": {
- "placeholder": "Encuentra un servidor o únete al tuyo propio...",
- "search_servers_or_enter_url": "Buscar servidores o introducir la URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Encontrando servidores disponibles...",
@@ -385,8 +390,10 @@
"description_video": "Describe el vídeo para los usuarios con dificultad visual...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duración: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Día",
"three_days": "4 Días",
"seven_days": "7 Días",
- "option_number": "Opción %ld"
+ "option_number": "Opción %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Escribe una advertencia precisa aquí..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Selector de Emojis Personalizados",
"enable_content_warning": "Activar Advertencia de Contenido",
"disable_content_warning": "Desactivar Advertencia de Contenido",
- "post_visibility_menu": "Menú de Visibilidad de la Publicación"
+ "post_visibility_menu": "Menú de Visibilidad de la Publicación",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Descartar Publicación",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Nombre para el campo",
"content": "Contenido"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict
index 0159a7da9..057ca4010 100644
--- a/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld karaktere
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/eu.lproj/app.json b/Localization/StringsConvertor/input/eu.lproj/app.json
index 3f58f522c..3da0d6a00 100644
--- a/Localization/StringsConvertor/input/eu.lproj/app.json
+++ b/Localization/StringsConvertor/input/eu.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Atera argazkia",
"save_photo": "Gorde argazkia",
"copy_photo": "Kopiatu argazkia",
- "sign_in": "Hasi saioa",
- "sign_up": "Eman Izena",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "Ikusi gehiago",
"preview": "Aurrebista",
"share": "Partekatu",
@@ -218,10 +218,16 @@
"get_started": "Nola hasi",
"log_in": "Hasi saioa"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Aukeratu zerbitzari bat,\nedozein zerbitzari.",
- "subtitle": "Aukeratu komunitate bat zure interes edo lurraldearen arabera, edo erabilera orokorreko bat.",
- "subtitle_extend": "Aukeratu komunitate bat zure interes edo lurraldearen arabera, edo erabilera orokorreko bat. Komunitate bakoitza erakunde edo norbanako independente batek kudeatzen du.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Guztiak",
@@ -248,8 +254,7 @@
"category": "KATEGORIA"
},
"input": {
- "placeholder": "Bilatu zerbitzari bat edo sortu zurea...",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Erabilgarri dauden zerbitzariak bilatzen...",
@@ -385,8 +390,10 @@
"description_video": "Deskribatu bideoa ikusmen arazoak dituztenentzat...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Iraupena: %s",
@@ -396,7 +403,9 @@
"one_day": "Egun 1",
"three_days": "3 egun",
"seven_days": "7 egun",
- "option_number": "%ld aukera"
+ "option_number": "%ld aukera",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Idatzi abisu zehatz bat hemen..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Emoji pertsonalizatuen hautatzailea",
"enable_content_warning": "Gaitu edukiaren abisua",
"disable_content_warning": "Desgaitu edukiaren abisua",
- "post_visibility_menu": "Bidalketaren ikusgaitasunaren menua"
+ "post_visibility_menu": "Bidalketaren ikusgaitasunaren menua",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Baztertu bidalketa",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Etiketa",
"content": "Edukia"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/fi.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/fi.lproj/Localizable.stringsdict
index 8048edf2d..ccfee35c9 100644
--- a/Localization/StringsConvertor/input/fi.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/fi.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld merkkiä
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/fi.lproj/app.json b/Localization/StringsConvertor/input/fi.lproj/app.json
index a42642786..7dafe7fd1 100644
--- a/Localization/StringsConvertor/input/fi.lproj/app.json
+++ b/Localization/StringsConvertor/input/fi.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Ota kuva",
"save_photo": "Tallenna kuva",
"copy_photo": "Kopioi kuva",
- "sign_in": "Kirjaudu sisään",
- "sign_up": "Rekisteröidy",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "Näytä lisää",
"preview": "Esikatselu",
"share": "Jaa",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Valitse palvelin,\nmikä tahansa palvelin.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Kaikki",
@@ -248,8 +254,7 @@
"category": "KATEGORIA"
},
"input": {
- "placeholder": "Etsi palvelin tai liity omaan...",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Etsistään saatavilla olevia palvelimia...",
@@ -385,8 +390,10 @@
"description_video": "Kuvaile video näkövammaisille...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Kesto: %s",
@@ -396,7 +403,9 @@
"one_day": "1 päivä",
"three_days": "3 päivää",
"seven_days": "7 päivää",
- "option_number": "Vaihtoehto %ld"
+ "option_number": "Vaihtoehto %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Kirjoita tarkka varoitus tähän..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Mukautettu emojivalitsin",
"enable_content_warning": "Ota sisältövaroitus käyttöön",
"disable_content_warning": "Poista sisältövaroitus käytöstä",
- "post_visibility_menu": "Julkaisun näkyvyysvalikko"
+ "post_visibility_menu": "Julkaisun näkyvyysvalikko",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Hylkää julkaisu",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Nimi",
"content": "Sisältö"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/fr.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/fr.lproj/Localizable.stringsdict
index d9d860a47..4eb068697 100644
--- a/Localization/StringsConvertor/input/fr.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/fr.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld caractères
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ restants
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 caractère
+ other
+ %ld caractères
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/fr.lproj/app.json b/Localization/StringsConvertor/input/fr.lproj/app.json
index 25bb6e511..fc8fd0e7a 100644
--- a/Localization/StringsConvertor/input/fr.lproj/app.json
+++ b/Localization/StringsConvertor/input/fr.lproj/app.json
@@ -218,10 +218,16 @@
"get_started": "Prise en main",
"log_in": "Se connecter"
},
+ "login": {
+ "title": "Content de vous revoir",
+ "subtitle": "Connectez-vous sur le serveur sur lequel vous avez créé votre compte.",
+ "server_search_field": {
+ "placeholder": "Entrez l'URL ou recherchez votre serveur"
+ }
+ },
"server_picker": {
"title": "Choisissez un serveur,\nn'importe quel serveur.",
- "subtitle": "Choisissez une communauté en fonction de vos intérêts, de votre région ou de votre objectif général.",
- "subtitle_extend": "Choisissez une communauté basée sur vos intérêts, votre région ou un but général. Chaque communauté est gérée par une organisation ou un individu entièrement indépendant.",
+ "subtitle": "Choisissez un serveur basé sur votre région, vos intérêts ou un généraliste. Vous pouvez toujours discuter avec n'importe qui sur Mastodon, indépendamment de vos serveurs.",
"button": {
"category": {
"all": "Tout",
@@ -248,8 +254,7 @@
"category": "CATÉGORIE"
},
"input": {
- "placeholder": "Trouvez un serveur ou rejoignez le vôtre...",
- "search_servers_or_enter_url": "Rechercher des serveurs ou entrer une URL"
+ "search_servers_or_enter_url": "Rechercher parmi les communautés ou renseigner une URL"
},
"empty_state": {
"finding_servers": "Recherche des serveurs disponibles...",
@@ -383,10 +388,12 @@
"attachment_broken": "Ce %s est brisé et ne peut pas être\ntéléversé sur Mastodon.",
"description_photo": "Décrire cette photo pour les personnes malvoyantes...",
"description_video": "Décrire cette vidéo pour les personnes malvoyantes...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "Échec du chargement",
+ "upload_failed": "Échec de l’envoi",
+ "can_not_recognize_this_media_attachment": "Impossible de reconnaître cette pièce jointe",
+ "attachment_too_large": "La pièce jointe est trop volumineuse",
+ "compressing_state": "Compression...",
+ "server_processing_state": "Traitement du serveur..."
},
"poll": {
"duration_time": "Durée: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Jour",
"three_days": "3 jour",
"seven_days": "7 jour",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "Le sondage est invalide",
+ "the_poll_has_empty_option": "Le sondage n'a pas d'options"
},
"content_warning": {
"placeholder": "Écrivez un avertissement précis ici..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Sélecteur d’émojis personnalisés",
"enable_content_warning": "Basculer l’avertissement de contenu",
"disable_content_warning": "Désactiver l'avertissement de contenu",
- "post_visibility_menu": "Menu de Visibilité de la publication"
+ "post_visibility_menu": "Menu de Visibilité de la publication",
+ "post_options": "Options de publication",
+ "posting_as": "Publié en tant que %s"
},
"keyboard": {
"discard_post": "Rejeter la publication",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Étiquette",
"content": "Contenu"
+ },
+ "verified": {
+ "short": "Vérifié le %s",
+ "long": "La propriété de ce lien a été vérifiée le %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/gd.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/gd.lproj/Localizable.stringsdict
index d0ccb5f41..9b3e69ea7 100644
--- a/Localization/StringsConvertor/input/gd.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/gd.lproj/Localizable.stringsdict
@@ -62,6 +62,26 @@
%ld caractar
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ air fhàgail
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ %ld charactar
+ two
+ %ld charactar
+ few
+ %ld caractaran
+ other
+ %ld caractar
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/gd.lproj/app.json b/Localization/StringsConvertor/input/gd.lproj/app.json
index c1d17f813..74666cb0c 100644
--- a/Localization/StringsConvertor/input/gd.lproj/app.json
+++ b/Localization/StringsConvertor/input/gd.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Sàbhail an dealbh",
"copy_photo": "Dèan lethbhreac dhen dealbh",
"sign_in": "Clàraich a-steach",
- "sign_up": "Clàraich leinn",
+ "sign_up": "Cruthaich cunntas",
"see_more": "Seall a bharrachd",
"preview": "Ro-sheall",
"share": "Co-roinn",
@@ -137,10 +137,10 @@
"closed": "Dùinte"
},
"meta_entity": {
- "url": "Link: %s",
- "hashtag": "Hashtag: %s",
- "mention": "Show Profile: %s",
- "email": "Email address: %s"
+ "url": "Ceangal: %s",
+ "hashtag": "Taga hais: %s",
+ "mention": "Seall a’ phròifil: %s",
+ "email": "Seòladh puist-d: %s"
},
"actions": {
"reply": "Freagair",
@@ -187,8 +187,8 @@
"unmute_user": "Dì-mhùch %s",
"muted": "’Ga mhùchadh",
"edit_info": "Deasaich",
- "show_reblogs": "Show Reblogs",
- "hide_reblogs": "Hide Reblogs"
+ "show_reblogs": "Seall na brosnachaidhean",
+ "hide_reblogs": "Falaich na brosnachaidhean"
},
"timeline": {
"filtered": "Criathraichte",
@@ -218,10 +218,16 @@
"get_started": "Dèan toiseach-tòiseachaidh",
"log_in": "Clàraich a-steach"
},
+ "login": {
+ "title": "Fàilte air ais",
+ "subtitle": "Clàraich a-steach air an fhrithealaiche far an do chruthaich thu an cunntas agad.",
+ "server_search_field": {
+ "placeholder": "Cuir a-steach URL an fhrithealaiche agad"
+ }
+ },
"server_picker": {
"title": "Tha cleachdaichean Mhastodon air iomadh frithealaiche eadar-dhealaichte.",
- "subtitle": "Tagh frithealaiche stèidhichte air d’ ùidhean, air far a bheil thu no fear coitcheann.",
- "subtitle_extend": "Tagh frithealaiche stèidhichte air d’ ùidhean, air far a bheil thu no fear coitcheann. Tha gach frithealaiche fo stiùireadh buidhinn no neach neo-eisimeilich fa leth.",
+ "subtitle": "Tagh frithealaiche stèidhichte air na sgìre agad, d’ ùidhean, air far a bheil thu no fear coitcheann. ’S urrainn dhut fhathast conaltradh le duine sam bith air Mastodon ge b’ e na frithealaichean agaibh-se.",
"button": {
"category": {
"all": "Na h-uile",
@@ -248,8 +254,7 @@
"category": "ROINN-SEÒRSA"
},
"input": {
- "placeholder": "Lorg frithealaiche",
- "search_servers_or_enter_url": "Lorg frithealaiche no cuir a-steach URL"
+ "search_servers_or_enter_url": "Lorg coimhearsnachd no cuir a-steach URL"
},
"empty_state": {
"finding_servers": "A’ lorg nam frithealaichean ri am faighinn…",
@@ -383,10 +388,12 @@
"attachment_broken": "Seo %s a tha briste is cha ghabh\na luchdadh suas gu Mastodon.",
"description_photo": "Mìnich an dealbh dhan fheadhainn air a bheil cion-lèirsinne…",
"description_video": "Mìnich a’ video dhan fheadhainn air a bheil cion-lèirsinne…",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "Dh’fhàillig leis an luchdadh",
+ "upload_failed": "Dh’fhàillig leis an luchdadh suas",
+ "can_not_recognize_this_media_attachment": "Cha do dh’aithnich sinn an ceanglachan meadhain seo",
+ "attachment_too_large": "Tha an ceanglachan ro mhòr",
+ "compressing_state": "’Ga dhùmhlachadh…",
+ "server_processing_state": "Tha am frithealaiche ’ga phròiseasadh…"
},
"poll": {
"duration_time": "Faide: %s",
@@ -396,7 +403,9 @@
"one_day": "Latha",
"three_days": "3 làithean",
"seven_days": "Seachdain",
- "option_number": "Roghainn %ld"
+ "option_number": "Roghainn %ld",
+ "the_poll_is_invalid": "Tha an cunntas-bheachd mì-dhligheach",
+ "the_poll_has_empty_option": "Tha roghainn fhalamh aig a’ chunntas-bheachd"
},
"content_warning": {
"placeholder": "Sgrìobh rabhadh pongail an-seo…"
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Roghnaichear nan Emoji gnàthaichte",
"enable_content_warning": "Cuir rabhadh susbainte an comas",
"disable_content_warning": "Cuir rabhadh susbainte à comas",
- "post_visibility_menu": "Clàr-taice faicsinneachd a’ phuist"
+ "post_visibility_menu": "Clàr-taice faicsinneachd a’ phuist",
+ "post_options": "Roghainnean postaidh",
+ "posting_as": "A’ postadh mar %s"
},
"keyboard": {
"discard_post": "Tilg air falbh am post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Leubail",
"content": "Susbaint"
+ },
+ "verified": {
+ "short": "Air a dhearbhadh %s",
+ "long": "Chaidh dearbhadh cò leis a tha an ceangal seo %s"
}
},
"segmented_control": {
@@ -469,12 +484,12 @@
"message": "Dearbh dì-bhacadh %s"
},
"confirm_show_reblogs": {
- "title": "Show Reblogs",
- "message": "Confirm to show reblogs"
+ "title": "Seall na brosnachaidhean",
+ "message": "Dearbh sealladh nam brosnachaidhean"
},
"confirm_hide_reblogs": {
- "title": "Hide Reblogs",
- "message": "Confirm to hide reblogs"
+ "title": "Falaich na brosnachaidhean",
+ "message": "Dearbh falach nam brosnachaidhean"
}
},
"accessibility": {
@@ -706,7 +721,7 @@
"accessibility_hint": "Thoir gnogag dhùbailte a’ leigeil seachad an draoidh seo"
},
"bookmark": {
- "title": "Bookmarks"
+ "title": "Comharran-lìn"
}
}
}
diff --git a/Localization/StringsConvertor/input/gl.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/gl.lproj/Localizable.stringsdict
index ff9d87c18..51b146ed4 100644
--- a/Localization/StringsConvertor/input/gl.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/gl.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld caracteres
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ restantes
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 caracter
+ other
+ %ld caracteres
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/gl.lproj/app.json b/Localization/StringsConvertor/input/gl.lproj/app.json
index 3c394be95..15c7a612a 100644
--- a/Localization/StringsConvertor/input/gl.lproj/app.json
+++ b/Localization/StringsConvertor/input/gl.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Gardar foto",
"copy_photo": "Copiar foto",
"sign_in": "Acceder",
- "sign_up": "Inscribirse",
+ "sign_up": "Crear conta",
"see_more": "Ver máis",
"preview": "Vista previa",
"share": "Compartir",
@@ -218,10 +218,16 @@
"get_started": "Crear conta",
"log_in": "Acceder"
},
+ "login": {
+ "title": "Benvido outra vez",
+ "subtitle": "Conéctate ao servidor no que creaches a conta.",
+ "server_search_field": {
+ "placeholder": "Escribe o URL ou busca o teu servidor"
+ }
+ },
"server_picker": {
"title": "Mastodon fórmano as persoas das diferentes comunidades.",
- "subtitle": "Elixe unha comunidade en función dos teus intereses, rexión ou unha de propósito xeral.",
- "subtitle_extend": "Elixe unha comunidade en función dos teus intereses, rexión ou unha de propósito xeral. Cada comunidade está xestionada por unha organización totalmente independente ou unha única persoa.",
+ "subtitle": "Elixe un servidor en función dos teus intereses, rexión o un de propósito xeral. Poderás conversar con calquera en Mastodon, independentemente do servidor que elixas.",
"button": {
"category": {
"all": "Todo",
@@ -248,8 +254,7 @@
"category": "CATEGORÍA"
},
"input": {
- "placeholder": "Buscar comunidades",
- "search_servers_or_enter_url": "Busca un servidor ou escribe URL"
+ "search_servers_or_enter_url": "Busca comunidades ou escribe URL"
},
"empty_state": {
"finding_servers": "Buscando servidores dispoñibles...",
@@ -386,7 +391,9 @@
"load_failed": "Fallou a carga",
"upload_failed": "Erro na subida",
"can_not_recognize_this_media_attachment": "Non se recoñece o tipo de multimedia",
- "attachment_too_large": "Adxunto demasiado grande"
+ "attachment_too_large": "Adxunto demasiado grande",
+ "compressing_state": "Comprimindo...",
+ "server_processing_state": "Procesando no servidor..."
},
"poll": {
"duration_time": "Duración: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Día",
"three_days": "3 Días",
"seven_days": "7 Días",
- "option_number": "Opción %ld"
+ "option_number": "Opción %ld",
+ "the_poll_is_invalid": "A enquisa non é válida",
+ "the_poll_has_empty_option": "A enquisa ten unha opción baleira"
},
"content_warning": {
"placeholder": "Escribe o teu aviso aquí..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Selector emoji personalizado",
"enable_content_warning": "Marcar con Aviso sobre o contido",
"disable_content_warning": "Retirar Aviso sobre o contido",
- "post_visibility_menu": "Visibilidade da publicación"
+ "post_visibility_menu": "Visibilidade da publicación",
+ "post_options": "Opcións da publicación",
+ "posting_as": "Publicando como %s"
},
"keyboard": {
"discard_post": "Descartar publicación",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Etiqueta",
"content": "Contido"
+ },
+ "verified": {
+ "short": "Verificada en %s",
+ "long": "A propiedade desta ligazón foi verificada o %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict
index bdcae6ac9..eabdc3c32 100644
--- a/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/hi.lproj/app.json b/Localization/StringsConvertor/input/hi.lproj/app.json
index f0fedf75f..f9414b6c0 100644
--- a/Localization/StringsConvertor/input/hi.lproj/app.json
+++ b/Localization/StringsConvertor/input/hi.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict
index 2635defb8..9b8aca01c 100644
--- a/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict
@@ -44,6 +44,20 @@
%ld karakter
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/id.lproj/app.json b/Localization/StringsConvertor/input/id.lproj/app.json
index d942a22ad..4f2050792 100644
--- a/Localization/StringsConvertor/input/id.lproj/app.json
+++ b/Localization/StringsConvertor/input/id.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Simpan Foto",
"copy_photo": "Salin Foto",
"sign_in": "Masuk",
- "sign_up": "Daftar",
+ "sign_up": "Buat akun",
"see_more": "Lihat lebih banyak",
"preview": "Pratinjau",
"share": "Bagikan",
@@ -129,31 +129,31 @@
"show_post": "Tampilkan Postingan",
"show_user_profile": "Tampilkan Profil Pengguna",
"content_warning": "Peringatan Konten",
- "sensitive_content": "Sensitive Content",
+ "sensitive_content": "Konten Sensitif",
"media_content_warning": "Ketuk di mana saja untuk melihat",
- "tap_to_reveal": "Tap to reveal",
+ "tap_to_reveal": "Ketuk untuk mengungkap",
"poll": {
- "vote": "Vote",
+ "vote": "Pilih",
"closed": "Ditutup"
},
"meta_entity": {
- "url": "Link: %s",
- "hashtag": "Hashtag: %s",
- "mention": "Show Profile: %s",
- "email": "Email address: %s"
+ "url": "Tautan: %s",
+ "hashtag": "Tagar: %s",
+ "mention": "Tampilkan Profile: %s",
+ "email": "Alamat email: %s"
},
"actions": {
"reply": "Balas",
"reblog": "Reblog",
- "unreblog": "Undo reblog",
+ "unreblog": "Batalkan reblog",
"favorite": "Favorit",
- "unfavorite": "Unfavorite",
+ "unfavorite": "Batalkan favorit",
"menu": "Menu",
- "hide": "Hide",
- "show_image": "Show image",
- "show_gif": "Show GIF",
- "show_video_player": "Show video player",
- "tap_then_hold_to_show_menu": "Tap then hold to show menu"
+ "hide": "Sembunyikan",
+ "show_image": "Tampilkan gambar",
+ "show_gif": "Tampilkan GIF",
+ "show_video_player": "Tampilkan pemutar video",
+ "tap_then_hold_to_show_menu": "Ketuk lalu tahan untuk menampilkan menu"
},
"tag": {
"url": "URL",
@@ -165,16 +165,16 @@
},
"visibility": {
"unlisted": "Everyone can see this post but not display in the public timeline.",
- "private": "Only their followers can see this post.",
- "private_from_me": "Only my followers can see this post.",
- "direct": "Only mentioned user can see this post."
+ "private": "Hanya pengikut mereka yang dapat melihat postingan ini.",
+ "private_from_me": "Hanya pengikut saya yang dapat melihat postingan ini.",
+ "direct": "Hanya pengguna yang disebut yang dapat melihat postingan ini."
}
},
"friendship": {
"follow": "Ikuti",
"following": "Mengikuti",
- "request": "Request",
- "pending": "Pending",
+ "request": "Minta",
+ "pending": "Tertunda",
"block": "Blokir",
"block_user": "Blokir %s",
"block_domain": "Blokir %s",
@@ -187,8 +187,8 @@
"unmute_user": "Berhenti membisukan %s",
"muted": "Dibisukan",
"edit_info": "Sunting Info",
- "show_reblogs": "Show Reblogs",
- "hide_reblogs": "Hide Reblogs"
+ "show_reblogs": "Tampilkan Reblog",
+ "hide_reblogs": "Sembunyikan Reblog"
},
"timeline": {
"filtered": "Tersaring",
@@ -196,32 +196,38 @@
"now": "Sekarang"
},
"loader": {
- "load_missing_posts": "Load missing posts",
- "loading_missing_posts": "Loading missing posts...",
+ "load_missing_posts": "Muat postingan yang hilang",
+ "loading_missing_posts": "Memuat postingan yang hilang...",
"show_more_replies": "Tampilkan lebih banyak balasan"
},
"header": {
- "no_status_found": "No Post Found",
- "blocking_warning": "You can’t view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.",
- "user_blocking_warning": "You can’t view %s’s profile\nuntil you unblock them.\nYour profile looks like this to them.",
- "blocked_warning": "You can’t view this user’s profile\nuntil they unblock you.",
- "user_blocked_warning": "You can’t view %s’s profile\nuntil they unblock you.",
- "suspended_warning": "This user has been suspended.",
- "user_suspended_warning": "%s’s account has been suspended."
+ "no_status_found": "Tidak Ditemukan Postingan",
+ "blocking_warning": "Anda tidak dapat melihat profil pengguna ini sampai Anda membuka blokir mereka.\nProfil Anda terlihat seperti ini bagi mereka.",
+ "user_blocking_warning": "Anda tidak dapat melihat profil %s sampai Anda membuka blokir mereka.\nProfil Anda terlihat seperti ini bagi mereka.",
+ "blocked_warning": "Anda tidak dapat melihat profil pengguna ini sampai mereka membuka blokir Anda.",
+ "user_blocked_warning": "Anda tidak dapat melihat profil %s sampai mereka membuka blokir Anda.",
+ "suspended_warning": "Pengguna ini telah ditangguhkan.",
+ "user_suspended_warning": "Akun %s telah ditangguhkan."
}
}
}
},
"scene": {
"welcome": {
- "slogan": "Social networking\nback in your hands.",
- "get_started": "Get Started",
- "log_in": "Log In"
+ "slogan": "Jejaring sosial dalam genggaman Anda.",
+ "get_started": "Mulai",
+ "log_in": "Login"
+ },
+ "login": {
+ "title": "Selamat datang kembali",
+ "subtitle": "Masuklah pada server yang Anda buat di mana akun Anda berada.",
+ "server_search_field": {
+ "placeholder": "Masukkan URL atau pencarian di server Anda"
+ }
},
"server_picker": {
"title": "Pilih sebuah server,\nserver manapun.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pilih server berdasarkan agamamu, minat, atau subjek umum lainnya. Kamu masih bisa berkomunikasi dengan semua orang di Mastodon, tanpa memperdulikan server Anda.",
"button": {
"category": {
"all": "Semua",
@@ -248,8 +254,7 @@
"category": "KATEGORI"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Cari komunitas atau masukkan URL"
},
"empty_state": {
"finding_servers": "Mencari server yang tersedia...",
@@ -259,7 +264,7 @@
},
"register": {
"title": "Beritahu kami tentang diri Anda.",
- "lets_get_you_set_up_on_domain": "Let’s get you set up on %s",
+ "lets_get_you_set_up_on_domain": "Mari kita siapkan Anda di %s",
"input": {
"avatar": {
"delete": "Hapus"
@@ -269,18 +274,18 @@
"duplicate_prompt": "Nama pengguna ini sudah diambil."
},
"display_name": {
- "placeholder": "display name"
+ "placeholder": "nama yang ditampilkan"
},
"email": {
"placeholder": "surel"
},
"password": {
"placeholder": "kata sandi",
- "require": "Your password needs at least:",
- "character_limit": "8 characters",
+ "require": "Kata sandi Anda harus memiliki setidaknya:",
+ "character_limit": "8 karakter",
"accessibility": {
- "checked": "checked",
- "unchecked": "unchecked"
+ "checked": "dicentang",
+ "unchecked": "tidak dicentang"
},
"hint": "Kata sandi Anda harus memiliki sekurang-kurangnya delapan karakter"
},
@@ -294,7 +299,7 @@
"email": "Surel",
"password": "Kata sandi",
"agreement": "Persetujuan",
- "locale": "Locale",
+ "locale": "Lokal",
"reason": "Alasan"
},
"reason": {
@@ -310,7 +315,7 @@
"inclusion": "%s is not a supported value"
},
"special": {
- "username_invalid": "Username must only contain alphanumeric characters and underscores",
+ "username_invalid": "Nama pengguna hanya berisi angka karakter dan garis bawah",
"username_too_long": "Nama pengguna terlalu panjang (tidak boleh lebih dari 30 karakter)",
"email_invalid": "Ini bukan alamat surel yang valid",
"password_too_short": "Kata sandi terlalu pendek (harus sekurang-kurangnya 8 karakter)"
@@ -367,12 +372,12 @@
"compose": {
"title": {
"new_post": "Postingan Baru",
- "new_reply": "New Reply"
+ "new_reply": "Pesan Baru"
},
"media_selection": {
- "camera": "Take Photo",
+ "camera": "Ambil Foto",
"photo_library": "Photo Library",
- "browse": "Browse"
+ "browse": "Telusuri"
},
"content_input_placeholder": "Ketik atau tempel apa yang Anda pada pikiran Anda",
"compose_action": "Publikasikan",
@@ -383,10 +388,12 @@
"attachment_broken": "%s ini rusak dan tidak dapat diunggah ke Mastodon.",
"description_photo": "Jelaskan fotonya untuk mereka yang tidak dapat melihat dengan jelas...",
"description_video": "Jelaskan videonya untuk mereka yang tidak dapat melihat dengan jelas...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "Gagal Memuat",
+ "upload_failed": "Gagal Mengunggah",
+ "can_not_recognize_this_media_attachment": "Tidak dapat mengenali lampiran media ini",
+ "attachment_too_large": "Lampiran terlalu besar",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Durasi: %s",
@@ -396,14 +403,16 @@
"one_day": "1 Hari",
"three_days": "3 Hari",
"seven_days": "7 Hari",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Tulis peringatan yang akurat di sini..."
},
"visibility": {
"public": "Publik",
- "unlisted": "Unlisted",
+ "unlisted": "Tidak terdaftar",
"private": "Pengikut saja",
"direct": "Hanya orang yang saya sebut"
},
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Aktifkan Peringatan Konten",
"disable_content_warning": "Nonaktifkan Peringatan Konten",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Isi"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/is.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/is.lproj/Localizable.stringsdict
new file mode 100644
index 000000000..03b29f09b
--- /dev/null
+++ b/Localization/StringsConvertor/input/is.lproj/Localizable.stringsdict
@@ -0,0 +1,465 @@
+
+
+
+
+ a11y.plural.count.unread.notification
+
+ NSStringLocalizedFormatKey
+ %#@notification_count_unread_notification@
+ notification_count_unread_notification
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 ólesin tilkynning
+ other
+ %ld ólesnar tilkynningar
+
+
+ a11y.plural.count.input_limit_exceeds
+
+ NSStringLocalizedFormatKey
+ Inntak fer fram úr takmörkunum %#@character_count@
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 stafur
+ other
+ %ld stafir
+
+
+ a11y.plural.count.input_limit_remains
+
+ NSStringLocalizedFormatKey
+ Inntakstakmörk haldast %#@character_count@
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 stafur
+ other
+ %ld stafir
+
+
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ eftir
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 stafur
+ other
+ %ld stafir
+
+
+ plural.count.followed_by_and_mutual
+
+ NSStringLocalizedFormatKey
+ %#@names@%#@count_mutual@
+ names
+
+ one
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+
+
+ count_mutual
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ Fylgt af %1$@ og öðrum sameiginlegum
+ other
+ Fylgt af %1$@ og %ld sameiginlegum
+
+
+ plural.count.metric_formatted.post
+
+ NSStringLocalizedFormatKey
+ %@ %#@post_count@
+ post_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ færsla
+ other
+ færslur
+
+
+ plural.count.media
+
+ NSStringLocalizedFormatKey
+ %#@media_count@
+ media_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 gagnamiðill
+ other
+ %ld gagnamiðlar
+
+
+ plural.count.post
+
+ NSStringLocalizedFormatKey
+ %#@post_count@
+ post_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 færsla
+ other
+ %ld færslur
+
+
+ plural.count.favorite
+
+ NSStringLocalizedFormatKey
+ %#@favorite_count@
+ favorite_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 eftirlæti
+ other
+ %ld eftirlæti
+
+
+ plural.count.reblog
+
+ NSStringLocalizedFormatKey
+ %#@reblog_count@
+ reblog_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 endurbirting
+ other
+ %ld endurbirtingar
+
+
+ plural.count.reply
+
+ NSStringLocalizedFormatKey
+ %#@reply_count@
+ reply_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 svar
+ other
+ %ld svör
+
+
+ plural.count.vote
+
+ NSStringLocalizedFormatKey
+ %#@vote_count@
+ vote_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 atkvæði
+ other
+ %ld atkvæði
+
+
+ plural.count.voter
+
+ NSStringLocalizedFormatKey
+ %#@voter_count@
+ voter_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 kjósandi
+ other
+ %ld kjósendur
+
+
+ plural.people_talking
+
+ NSStringLocalizedFormatKey
+ %#@count_people_talking@
+ count_people_talking
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 aðili að spjalla
+ other
+ %ld aðilar að spjalla
+
+
+ plural.count.following
+
+ NSStringLocalizedFormatKey
+ %#@count_following@
+ count_following
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 fylgist með
+ other
+ %ld fylgjast með
+
+
+ plural.count.follower
+
+ NSStringLocalizedFormatKey
+ %#@count_follower@
+ count_follower
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 fylgjandi
+ other
+ %ld fylgjendur
+
+
+ date.year.left
+
+ NSStringLocalizedFormatKey
+ %#@count_year_left@
+ count_year_left
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 ár eftir
+ other
+ %ld ár eftir
+
+
+ date.month.left
+
+ NSStringLocalizedFormatKey
+ %#@count_month_left@
+ count_month_left
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 mánuður eftir
+ other
+ %ld mánuðir eftir
+
+
+ date.day.left
+
+ NSStringLocalizedFormatKey
+ %#@count_day_left@
+ count_day_left
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 dagur eftir
+ other
+ %ld dagar eftir
+
+
+ date.hour.left
+
+ NSStringLocalizedFormatKey
+ %#@count_hour_left@
+ count_hour_left
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 klukkustund eftir
+ other
+ %ld klukkustundir eftir
+
+
+ date.minute.left
+
+ NSStringLocalizedFormatKey
+ %#@count_minute_left@
+ count_minute_left
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 mínúta eftir
+ other
+ %ld mínútur eftir
+
+
+ date.second.left
+
+ NSStringLocalizedFormatKey
+ %#@count_second_left@
+ count_second_left
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 sekúnda eftir
+ other
+ %ld sekúndur eftir
+
+
+ date.year.ago.abbr
+
+ NSStringLocalizedFormatKey
+ %#@count_year_ago_abbr@
+ count_year_ago_abbr
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ Fyrir 1 ári síðan
+ other
+ Fyrir %ld árum síðan
+
+
+ date.month.ago.abbr
+
+ NSStringLocalizedFormatKey
+ %#@count_month_ago_abbr@
+ count_month_ago_abbr
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ Fyrir 1mín síðan
+ other
+ Fyrir %ldmín síðan
+
+
+ date.day.ago.abbr
+
+ NSStringLocalizedFormatKey
+ %#@count_day_ago_abbr@
+ count_day_ago_abbr
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ Fyrir 1 degi síðan
+ other
+ Fyrir %ld dögum síðan
+
+
+ date.hour.ago.abbr
+
+ NSStringLocalizedFormatKey
+ %#@count_hour_ago_abbr@
+ count_hour_ago_abbr
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1klst síðan
+ other
+ %ldklst síðan
+
+
+ date.minute.ago.abbr
+
+ NSStringLocalizedFormatKey
+ %#@count_minute_ago_abbr@
+ count_minute_ago_abbr
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1m síðan
+ other
+ %ldm síðan
+
+
+ date.second.ago.abbr
+
+ NSStringLocalizedFormatKey
+ %#@count_second_ago_abbr@
+ count_second_ago_abbr
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1s síðan
+ other
+ %lds síðan
+
+
+
+
diff --git a/Localization/StringsConvertor/input/is.lproj/app.json b/Localization/StringsConvertor/input/is.lproj/app.json
new file mode 100644
index 000000000..191a670ed
--- /dev/null
+++ b/Localization/StringsConvertor/input/is.lproj/app.json
@@ -0,0 +1,727 @@
+{
+ "common": {
+ "alerts": {
+ "common": {
+ "please_try_again": "Endilega reyndu aftur.",
+ "please_try_again_later": "Reyndu aftur síðar."
+ },
+ "sign_up_failure": {
+ "title": "Innskráning mistókst"
+ },
+ "server_error": {
+ "title": "Villa á þjóni"
+ },
+ "vote_failure": {
+ "title": "Greiðsla atkvæðis mistókst",
+ "poll_ended": "Könnuninni er lokið"
+ },
+ "discard_post_content": {
+ "title": "Henda drögum",
+ "message": "Staðfestu til að henda efni úr saminni færslu."
+ },
+ "publish_post_failure": {
+ "title": "Mistókst að birta",
+ "message": "Mistókst að birta færsluna.\nAthugaðu nettenginguna þína.",
+ "attachments_message": {
+ "video_attach_with_photo": "Ekki er hægt að hengja myndskeið við færslu sem þegar inniheldur myndir.",
+ "more_than_one_video": "Ekki er hægt að hengja við fleiri en eitt myndskeið."
+ }
+ },
+ "edit_profile_failure": {
+ "title": "Villa við breytingu á notandasniði",
+ "message": "Mistókst að breyta notandasniði. Endilega reyndu aftur."
+ },
+ "sign_out": {
+ "title": "Skrá út",
+ "message": "Ertu viss um að þú viljir skrá þig út?",
+ "confirm": "Skrá út"
+ },
+ "block_domain": {
+ "title": "Ertu alveg algjörlega viss um að þú viljir loka á allt %s? Í flestum tilfellum er vænlegra að nota færri en markvissari útilokanir eða að þagga niður tiltekna aðila. Þú munt ekki sjá neitt efni frá þessu léni og fylgjendur þínir frá þessu léni verða fjarlægðir.",
+ "block_entire_domain": "Útiloka lén"
+ },
+ "save_photo_failure": {
+ "title": "Mistókst að vista mynd",
+ "message": "Virkjaðu heimild til aðgangs að ljósmyndasafninu til að vista myndina."
+ },
+ "delete_post": {
+ "title": "Eyða færslu",
+ "message": "Ertu viss um að þú viljir eyða þessari færslu?"
+ },
+ "clean_cache": {
+ "title": "Hreinsa skyndiminni",
+ "message": "Tókst að hreinsa %s skyndiminni."
+ }
+ },
+ "controls": {
+ "actions": {
+ "back": "Til baka",
+ "next": "Næsta",
+ "previous": "Fyrri",
+ "open": "Opna",
+ "add": "Bæta við",
+ "remove": "Fjarlægja",
+ "edit": "Breyta",
+ "save": "Vista",
+ "ok": "Í lagi",
+ "done": "Lokið",
+ "confirm": "Staðfesta",
+ "continue": "Halda áfram",
+ "compose": "Skrifa",
+ "cancel": "Hætta við",
+ "discard": "Henda",
+ "try_again": "Reyna aftur",
+ "take_photo": "Taka ljósmynd",
+ "save_photo": "Vista mynd",
+ "copy_photo": "Afrita mynd",
+ "sign_in": "Skrá inn",
+ "sign_up": "Stofna notandaaðgang",
+ "see_more": "Sjá fleira",
+ "preview": "Forskoða",
+ "share": "Deila",
+ "share_user": "Deila %s",
+ "share_post": "Deila færslu",
+ "open_in_safari": "Opna í Safari",
+ "open_in_browser": "Opna í vafra",
+ "find_people": "Finna fólk til að fylgjast með",
+ "manually_search": "Leita handvirkt í staðinn",
+ "skip": "Sleppa",
+ "reply": "Svara",
+ "report_user": "Kæra %s",
+ "block_domain": "Útiloka %s",
+ "unblock_domain": "Opna á %s",
+ "settings": "Stillingar",
+ "delete": "Eyða"
+ },
+ "tabs": {
+ "home": "Heim",
+ "search": "Leita",
+ "notification": "Tilkynning",
+ "profile": "Notandasnið"
+ },
+ "keyboard": {
+ "common": {
+ "switch_to_tab": "Skipta yfir í %s",
+ "compose_new_post": "Semja nýja færslu",
+ "show_favorites": "Birta eftirlæti",
+ "open_settings": "Opna stillingar"
+ },
+ "timeline": {
+ "previous_status": "Fyrri færsla",
+ "next_status": "Næsta færsla",
+ "open_status": "Opna færslu",
+ "open_author_profile": "Opna notandasnið höfundar",
+ "open_reblogger_profile": "Opna notandasnið þess sem endurbirtir",
+ "reply_status": "Svara færslu",
+ "toggle_reblog": "Víxla endurbirtingu færslu af/á",
+ "toggle_favorite": "Víxla eftirlæti færslu af/á",
+ "toggle_content_warning": "Víxla af/á viðvörun vegna efnis",
+ "preview_image": "Forskoða mynd"
+ },
+ "segmented_control": {
+ "previous_section": "Fyrri hluti",
+ "next_section": "Næsti hluti"
+ }
+ },
+ "status": {
+ "user_reblogged": "%s endurbirti",
+ "user_replied_to": "Svaraði %s",
+ "show_post": "Sýna færslu",
+ "show_user_profile": "Birta notandasnið",
+ "content_warning": "Viðvörun vegna efnis",
+ "sensitive_content": "Viðkvæmt efni",
+ "media_content_warning": "Ýttu hvar sem er til að birta",
+ "tap_to_reveal": "Ýttu til að birta",
+ "poll": {
+ "vote": "Greiða atkvæði",
+ "closed": "Lokið"
+ },
+ "meta_entity": {
+ "url": "Tengill: %s",
+ "hashtag": "Myllumerki: %s",
+ "mention": "Sýna notandasnið: %s",
+ "email": "Tölvupóstfang: %s"
+ },
+ "actions": {
+ "reply": "Svara",
+ "reblog": "Endurbirta",
+ "unreblog": "Afturkalla endurbirtingu",
+ "favorite": "Eftirlæti",
+ "unfavorite": "Taka úr eftirlætum",
+ "menu": "Valmynd",
+ "hide": "Fela",
+ "show_image": "Sýna mynd",
+ "show_gif": "Birta GIF-myndir",
+ "show_video_player": "Sýna myndspilara",
+ "tap_then_hold_to_show_menu": "Ýttu og haltu til að sýna valmynd"
+ },
+ "tag": {
+ "url": "URL-slóð",
+ "mention": "Minnst á",
+ "link": "Tengill",
+ "hashtag": "Myllumerki",
+ "email": "Tölvupóstur",
+ "emoji": "Tjáningartákn"
+ },
+ "visibility": {
+ "unlisted": "Allir geta skoðað þessa færslu, en er ekki birt á opinberum tímalínum.",
+ "private": "Einungis fylgjendur þeirra geta séð þessa færslu.",
+ "private_from_me": "Einungis fylgjendur mínir geta séð þessa færslu.",
+ "direct": "Einungis notendur sem minnst er á geta séð þessa færslu."
+ }
+ },
+ "friendship": {
+ "follow": "Fylgja",
+ "following": "Fylgist með",
+ "request": "Beiðni",
+ "pending": "Í bið",
+ "block": "Útilokun",
+ "block_user": "Útiloka %s",
+ "block_domain": "Útiloka %s",
+ "unblock": "Aflétta útilokun",
+ "unblock_user": "Opna á %s",
+ "blocked": "Útilokað",
+ "mute": "Þagga niður",
+ "mute_user": "Þagga niður í %s",
+ "unmute": "Afþagga",
+ "unmute_user": "Afþagga %s",
+ "muted": "Þaggað",
+ "edit_info": "Breyta upplýsingum",
+ "show_reblogs": "Sýna endurbirtingar",
+ "hide_reblogs": "Fela endurbirtingar"
+ },
+ "timeline": {
+ "filtered": "Síað",
+ "timestamp": {
+ "now": "Núna"
+ },
+ "loader": {
+ "load_missing_posts": "Hlaða inn færslum sem vantar",
+ "loading_missing_posts": "Hleð inn færslum sem vantar...",
+ "show_more_replies": "Birta fleiri svör"
+ },
+ "header": {
+ "no_status_found": "Engar færslur fundust",
+ "blocking_warning": "Þú getur ekki séð snið þessa notanda\nfyrr en þú hættir að útiloka hann.\nSniðið þitt lítur svona út hjá honum.",
+ "user_blocking_warning": "Þú getur ekki séð sniðið hjá %s\nfyrr en þú hættir að útiloka hann.\nSniðið þitt lítur svona út hjá honum.",
+ "blocked_warning": "Þú getur ekki séð sniðið hjá þessum notanda\nfyrr en hann hættir að útiloka þig.",
+ "user_blocked_warning": "Þú getur ekki séð sniðið hjá %s\nfyrr en hann hættir að útiloka þig.",
+ "suspended_warning": "Þessi notandi hefur verið settur í bið.",
+ "user_suspended_warning": "Notandaaðgangurinn %s hefur verið settur í bið."
+ }
+ }
+ }
+ },
+ "scene": {
+ "welcome": {
+ "slogan": "Samfélagsmiðlar\naftur í þínar hendur.",
+ "get_started": "Komast í gang",
+ "log_in": "Skrá inn"
+ },
+ "login": {
+ "title": "Velkomin aftur",
+ "subtitle": "Skráðu þig inn á netþjóninum þar sem þú útbjóst aðganginn þinn.",
+ "server_search_field": {
+ "placeholder": "Settu inn slóð eða leitaðu að þjóninum þínum"
+ }
+ },
+ "server_picker": {
+ "title": "Mastodon samanstendur af notendum á mismunandi netþjónum.",
+ "subtitle": "Veldu netþjón út frá svæðinu þínu, áhugamálum, nú eða einhvern almennan. Þú getur samt spjallað við hvern sem er á Mastodon, burtséð frá á hvaða netþjóni þú ert.",
+ "button": {
+ "category": {
+ "all": "Allt",
+ "all_accessiblity_description": "Flokkur: Allt",
+ "academia": "akademískt",
+ "activism": "aðgerðasinnar",
+ "food": "matur",
+ "furry": "loðið",
+ "games": "leikir",
+ "general": "almennt",
+ "journalism": "blaðamennska",
+ "lgbt": "lgbt",
+ "regional": "svæðisbundið",
+ "art": "listir",
+ "music": "tónlist",
+ "tech": "tækni"
+ },
+ "see_less": "Sjá minna",
+ "see_more": "Sjá meira"
+ },
+ "label": {
+ "language": "TUNGUMÁL",
+ "users": "NOTENDUR",
+ "category": "FLOKKUR"
+ },
+ "input": {
+ "search_servers_or_enter_url": "Leitaðu að samfélögum eða settu inn slóð"
+ },
+ "empty_state": {
+ "finding_servers": "Finn tiltæka netþjóna...",
+ "bad_network": "Eitthvað fór úrskeiðis við að hlaða inn gögnunum. Athugaðu nettenginguna þína.",
+ "no_results": "Engar niðurstöður"
+ }
+ },
+ "register": {
+ "title": "Við skulum koma þér í gang á %s",
+ "lets_get_you_set_up_on_domain": "Við skulum koma þér í gang á %s",
+ "input": {
+ "avatar": {
+ "delete": "Eyða"
+ },
+ "username": {
+ "placeholder": "notandanafn",
+ "duplicate_prompt": "Þetta notandanafn er þegar í notkun."
+ },
+ "display_name": {
+ "placeholder": "birtingarnafn"
+ },
+ "email": {
+ "placeholder": "tölvupóstur"
+ },
+ "password": {
+ "placeholder": "lykilorð",
+ "require": "Lykilorðið þitt þarf að minnsta kosti:",
+ "character_limit": "8 stafi",
+ "accessibility": {
+ "checked": "merkt",
+ "unchecked": "ekki merkt"
+ },
+ "hint": "Lykilorðið þitt verður að vera að minnsta kosti 8 stafa langt"
+ },
+ "invite": {
+ "registration_user_invite_request": "Hvers vegna vilt þú taka þátt?"
+ }
+ },
+ "error": {
+ "item": {
+ "username": "Notandanafn",
+ "email": "Tölvupóstur",
+ "password": "Lykilorð",
+ "agreement": "Notkunarskilmálar",
+ "locale": "Staðfærsla",
+ "reason": "Ástæða"
+ },
+ "reason": {
+ "blocked": "%s notar óleyfilega tölvupóstþjónustu",
+ "unreachable": "%s virðist ekki vera til",
+ "taken": "%s er þegar í notkun",
+ "reserved": "%s er frátekið stikkorð",
+ "accepted": "%s verður að samþykkja",
+ "blank": "%s ier nauðsynlegt",
+ "invalid": "%s er ógilt",
+ "too_long": "%s er of langt",
+ "too_short": "%s er of stutt",
+ "inclusion": "%s er ekki stutt gildi"
+ },
+ "special": {
+ "username_invalid": "Notendanöfn geta einungis innihaldið bókstafi og undirstrikun",
+ "username_too_long": "Notandanafnið er of langt (má ekki vera lengra en 30 stafir)",
+ "email_invalid": "Þetta lítur ekki út eins og löglegt tölvupóstfang",
+ "password_too_short": "Lykilorð er of stutt (verður að hafa minnst 8 stafi)"
+ }
+ }
+ },
+ "server_rules": {
+ "title": "Nokkrar grunnreglur.",
+ "subtitle": "Þær eru settar og séð um að þeim sé fylgt af umsjónarmönnum %s.",
+ "prompt": "Með því að halda áfram samþykkir þú þjónustuskilmála og persónuverndarstefnu %s.",
+ "terms_of_service": "þjónustuskilmálar",
+ "privacy_policy": "persónuverndarstefna",
+ "button": {
+ "confirm": "Ég samþykki"
+ }
+ },
+ "confirm_email": {
+ "title": "Eitt að lokum.",
+ "subtitle": "Ýttu á tengilinn sem við sendum þér til að staðfesta tölvupóstfangið þitt.",
+ "tap_the_link_we_emailed_to_you_to_verify_your_account": "Ýttu á tengilinn sem við sendum þér til að staðfesta tölvupóstfangið þitt",
+ "button": {
+ "open_email_app": "Opna tölvupóstforrit",
+ "resend": "Endursenda"
+ },
+ "dont_receive_email": {
+ "title": "Athugaðu tölvupóstinn þinn",
+ "description": "Athugaðu hvort tölvupóstfangið þitt sé rétt auk þess að skoða í ruslpóstmöppuna þína ef þú hefur ekki gert það.",
+ "resend_email": "Endursenda tölvupóst"
+ },
+ "open_email_app": {
+ "title": "Athugaðu pósthólfið þitt.",
+ "description": "Við vorum að senda þér tölvupóst. Skoðaðu í ruslpóstmöppuna þína ef þú hefur ekki gert það.",
+ "mail": "Tölvupóstur",
+ "open_email_client": "Opna tölvupóstforrit"
+ }
+ },
+ "home_timeline": {
+ "title": "Heim",
+ "navigation_bar_state": {
+ "offline": "Ónettengt",
+ "new_posts": "Skoða nýjar færslur",
+ "published": "Birt!",
+ "Publishing": "Birti færslu...",
+ "accessibility": {
+ "logo_label": "Hnappur með táknmerki",
+ "logo_hint": "Ýttu til að skruna efst og ýttu aftur til að fara aftur á fyrri staðsetningu"
+ }
+ }
+ },
+ "suggestion_account": {
+ "title": "Finndu fólk til að fylgjast með",
+ "follow_explain": "Þegar þú fylgist með einhverjum, muntu sjá færslur frá viðkomandi á streyminu þínu."
+ },
+ "compose": {
+ "title": {
+ "new_post": "Ný færsla",
+ "new_reply": "Nýtt svar"
+ },
+ "media_selection": {
+ "camera": "Taktu mynd",
+ "photo_library": "Myndasafn",
+ "browse": "Flakka"
+ },
+ "content_input_placeholder": "Skrifaðu eða límdu það sem þér liggur á hjarta",
+ "compose_action": "Birta",
+ "replying_to_user": "svarar til @%s",
+ "attachment": {
+ "photo": "ljósmynd",
+ "video": "myndskeið",
+ "attachment_broken": "Þetta %s er skemmt og því ekki\nhægt að senda inn á Mastodon.",
+ "description_photo": "Lýstu myndinni fyrir sjónskerta...",
+ "description_video": "Lýstu myndskeiðinu fyrir sjónskerta...",
+ "load_failed": "Hleðsla mistókst",
+ "upload_failed": "Innsending mistókst",
+ "can_not_recognize_this_media_attachment": "Þekki ekki þetta myndviðhengi",
+ "attachment_too_large": "Viðhengi of stórt",
+ "compressing_state": "Þjappa...",
+ "server_processing_state": "Netþjónn er að vinna..."
+ },
+ "poll": {
+ "duration_time": "Tímalengd: %s",
+ "thirty_minutes": "30 mínútur",
+ "one_hour": "1 klukkustund",
+ "six_hours": "6 klukkustundir",
+ "one_day": "1 dagur",
+ "three_days": "3 dagar",
+ "seven_days": "7 dagar",
+ "option_number": "Valkostur %ld",
+ "the_poll_is_invalid": "Könnunin er ógild",
+ "the_poll_has_empty_option": "Könnunin er með auðan valkost"
+ },
+ "content_warning": {
+ "placeholder": "Skrifaðu nákvæma aðvörun hér..."
+ },
+ "visibility": {
+ "public": "Opinbert",
+ "unlisted": "Óskráð",
+ "private": "Einungis fylgjendur",
+ "direct": "Einungis fólk sem ég minnist á"
+ },
+ "auto_complete": {
+ "space_to_add": "Bil sem á að bæta við"
+ },
+ "accessibility": {
+ "append_attachment": "Bæta við viðhengi",
+ "append_poll": "Bæta við könnun",
+ "remove_poll": "Fjarlægja könnun",
+ "custom_emoji_picker": "Sérsniðið emoji-tánmyndaval",
+ "enable_content_warning": "Virkja viðvörun vegna efnis",
+ "disable_content_warning": "Gera viðvörun vegna efnis óvirka",
+ "post_visibility_menu": "Sýnileikavalmynd færslu",
+ "post_options": "Valkostir færslu",
+ "posting_as": "Birti sem %s"
+ },
+ "keyboard": {
+ "discard_post": "Henda færslu",
+ "publish_post": "Birta færslu",
+ "toggle_poll": "Víxla könnun af/á",
+ "toggle_content_warning": "Víxla af/á viðvörun vegna efnis",
+ "append_attachment_entry": "Bæta við viðhengi - %s",
+ "select_visibility_entry": "Veldu sýnileika - %s"
+ }
+ },
+ "profile": {
+ "header": {
+ "follows_you": "Fylgist með þér"
+ },
+ "dashboard": {
+ "posts": "færslur",
+ "following": "fylgist með",
+ "followers": "fylgjendur"
+ },
+ "fields": {
+ "add_row": "Bæta við röð",
+ "placeholder": {
+ "label": "Skýring",
+ "content": "Efni"
+ },
+ "verified": {
+ "short": "Sannreynt þann %s",
+ "long": "Eignarhald á þessum tengli var athugað þann %s"
+ }
+ },
+ "segmented_control": {
+ "posts": "Færslur",
+ "replies": "Svör",
+ "posts_and_replies": "Færslur og svör",
+ "media": "Gagnamiðlar",
+ "about": "Um hugbúnaðinn"
+ },
+ "relationship_action_alert": {
+ "confirm_mute_user": {
+ "title": "Þagga niður í aðgangi",
+ "message": "Staðfestu til að þagga niður í %s"
+ },
+ "confirm_unmute_user": {
+ "title": "Hætta að þagga niður í aðgangi",
+ "message": "Staðfestu til hætta að að þagga niður í %s"
+ },
+ "confirm_block_user": {
+ "title": "Útiloka notandaaðgang",
+ "message": "Staðfestu til að útiloka %s"
+ },
+ "confirm_unblock_user": {
+ "title": "Aflétta útilokun aðgangs",
+ "message": "Staðfestu til að hætta að útiloka %s"
+ },
+ "confirm_show_reblogs": {
+ "title": "Sýna endurbirtingar",
+ "message": "Staðfestu til að sýna endurbirtingar"
+ },
+ "confirm_hide_reblogs": {
+ "title": "Fela endurbirtingar",
+ "message": "Staðfestu til að fela endurbirtingar"
+ }
+ },
+ "accessibility": {
+ "show_avatar_image": "Sýna auðkennismynd",
+ "edit_avatar_image": "Breyta auðkennismynd",
+ "show_banner_image": "Sýna myndborða",
+ "double_tap_to_open_the_list": "Tvípikkaðu til að opna listann"
+ }
+ },
+ "follower": {
+ "title": "fylgjandi",
+ "footer": "Fylgjendur af öðrum netþjónum birtast ekki."
+ },
+ "following": {
+ "title": "fylgist með",
+ "footer": "Fylgjendur af öðrum netþjónum birtast ekki."
+ },
+ "familiarFollowers": {
+ "title": "Fylgjendur sem þú kannast við",
+ "followed_by_names": "Fylgt af %s"
+ },
+ "favorited_by": {
+ "title": "Sett í eftirlæti af"
+ },
+ "reblogged_by": {
+ "title": "Endurbirt af"
+ },
+ "search": {
+ "title": "Leita",
+ "search_bar": {
+ "placeholder": "Leita að myllumerkjum og notendum",
+ "cancel": "Hætta við"
+ },
+ "recommend": {
+ "button_text": "Sjá allt",
+ "hash_tag": {
+ "title": "Vinsælt á Mastodon",
+ "description": "Myllumerki sem eru að fá þónokkra athygli",
+ "people_talking": "%s manns eru að spjalla"
+ },
+ "accounts": {
+ "title": "Notandaaðgangar sem þú gætir haft áhuga á",
+ "description": "Þú gætir viljað fylgjast með þessum aðgöngum",
+ "follow": "Fylgjast með"
+ }
+ },
+ "searching": {
+ "segment": {
+ "all": "Allt",
+ "people": "Fólk",
+ "hashtags": "Myllumerki",
+ "posts": "Færslur"
+ },
+ "empty_state": {
+ "no_results": "Engar niðurstöður"
+ },
+ "recent_search": "Nýlegar leitir",
+ "clear": "Hreinsa"
+ }
+ },
+ "discovery": {
+ "tabs": {
+ "posts": "Færslur",
+ "hashtags": "Myllumerki",
+ "news": "Fréttir",
+ "community": "Samfélag",
+ "for_you": "Fyrir þig"
+ },
+ "intro": "Þetta eru færslurnar sem eru að fá aukna athygli í þínu horni á Mastodon."
+ },
+ "favorite": {
+ "title": "Eftirlætin þín"
+ },
+ "notification": {
+ "title": {
+ "Everything": "Allt",
+ "Mentions": "Minnst á"
+ },
+ "notification_description": {
+ "followed_you": "fylgdi þér",
+ "favorited_your_post": "setti færslu frá þér í eftirlæti",
+ "reblogged_your_post": "endurbirti færsluna þína",
+ "mentioned_you": "minntist á þig",
+ "request_to_follow_you": "bað um að fylgjast með þér",
+ "poll_has_ended": "könnun er lokið"
+ },
+ "keyobard": {
+ "show_everything": "Sýna allt",
+ "show_mentions": "Sýna þegar minnst er á"
+ },
+ "follow_request": {
+ "accept": "Samþykkja",
+ "accepted": "Samþykkt",
+ "reject": "hafna",
+ "rejected": "Hafnað"
+ }
+ },
+ "thread": {
+ "back_title": "Færsla",
+ "title": "Færsla frá %s"
+ },
+ "settings": {
+ "title": "Stillingar",
+ "section": {
+ "appearance": {
+ "title": "Útlit",
+ "automatic": "Sjálfvirkt",
+ "light": "Alltaf ljóst",
+ "dark": "Alltaf dökkt"
+ },
+ "look_and_feel": {
+ "title": "Útlit og viðmót",
+ "use_system": "Nota stillingar kerfis",
+ "really_dark": "Mjög dökkt",
+ "sorta_dark": "Nokkuð dökkt",
+ "light": "Ljóst"
+ },
+ "notifications": {
+ "title": "Tilkynningar",
+ "favorites": "Setur færsluna mína í eftirlæti",
+ "follows": "Fylgist með mér",
+ "boosts": "Endurbirtir færsluna mína",
+ "mentions": "Minnist á mig",
+ "trigger": {
+ "anyone": "hver sem er",
+ "follower": "fylgjandi",
+ "follow": "hverjum sá sem ég fylgi",
+ "noone": "enginn",
+ "title": "Tilkynna mér þegar"
+ }
+ },
+ "preference": {
+ "title": "Kjörstillingar",
+ "true_black_dark_mode": "Sannur svartur dökkur hamur",
+ "disable_avatar_animation": "Gera auðkennismyndir með hreyfingu óvirkar",
+ "disable_emoji_animation": "Gera tjáningartákn með hreyfingu óvirkar",
+ "using_default_browser": "Nota sjálfgefinn vafra til að opna tengla",
+ "open_links_in_mastodon": "Opna tengla í Mastodon"
+ },
+ "boring_zone": {
+ "title": "Óhressa svæðið",
+ "account_settings": "Stillingar aðgangs",
+ "terms": "Þjónustuskilmálar",
+ "privacy": "Meðferð persónuupplýsinga"
+ },
+ "spicy_zone": {
+ "title": "Kryddaða svæðið",
+ "clear": "Hreinsa skyndiminni margmiðlunarefnis",
+ "signout": "Skrá út"
+ }
+ },
+ "footer": {
+ "mastodon_description": "Mastodon er frjáls hugbúnaður með opinn grunnkóða. Þú getur tilkynnt vandamál í gegnum GitHub á %s (%s)"
+ },
+ "keyboard": {
+ "close_settings_window": "Loka stillingaglugga"
+ }
+ },
+ "report": {
+ "title_report": "Kæra",
+ "title": "Kæra %s",
+ "step1": "Skref 1 af 2",
+ "step2": "Skref 2 af 2",
+ "content1": "Eru einhverjar færslur sem þú myndir vilja bæta við kæruna?",
+ "content2": "Er eitthvað fleira sem umsjónarmenn ættu að vita varðandi þessa kæru?",
+ "report_sent_title": "Takk fyrir tilkynninguna, við munum skoða málið.",
+ "send": "Senda kæru",
+ "skip_to_send": "Senda án athugasemdar",
+ "text_placeholder": "Skrifaðu eða límdu aðrar athugasemdir",
+ "reported": "TILKYNNT",
+ "step_one": {
+ "step_1_of_4": "Skref 1 af 4",
+ "whats_wrong_with_this_post": "Hvað er athugavert við þessa færslu?",
+ "whats_wrong_with_this_account": "Hvað er athugavert við þennan notandaaðgang?",
+ "whats_wrong_with_this_username": "Hvað er athugavert við %s?",
+ "select_the_best_match": "Velja bestu samsvörun",
+ "i_dont_like_it": "Mér líkar það ekki",
+ "it_is_not_something_you_want_to_see": "Þetta er ekki eitthvað sem þið viljið sjá",
+ "its_spam": "Þetta er ruslpóstur",
+ "malicious_links_fake_engagement_or_repetetive_replies": "Slæmir tenglar, fölsk samskipti eða endurtekin svör",
+ "it_violates_server_rules": "Það gengur þvert á reglur fyrir netþjóninn",
+ "you_are_aware_that_it_breaks_specific_rules": "Þið eruð meðvituð um að þetta brýtur sértækar reglur",
+ "its_something_else": "Það er eitthvað annað",
+ "the_issue_does_not_fit_into_other_categories": "Vandamálið fellur ekki í aðra flokka"
+ },
+ "step_two": {
+ "step_2_of_4": "Skref 2 af 4",
+ "which_rules_are_being_violated": "Hvaða reglur eru brotnar?",
+ "select_all_that_apply": "Veldu allt sem á við",
+ "i_just_don’t_like_it": "Mér bara líkar það ekki"
+ },
+ "step_three": {
+ "step_3_of_4": "Skref 3 af 4",
+ "are_there_any_posts_that_back_up_this_report": "Eru einhverjar færslur sem styðja þessa kæru?",
+ "select_all_that_apply": "Veldu allt sem á við"
+ },
+ "step_four": {
+ "step_4_of_4": "Skref 4 af 4",
+ "is_there_anything_else_we_should_know": "Er eitthvað fleira sem við ættum að vita?"
+ },
+ "step_final": {
+ "dont_want_to_see_this": "Langar þig ekki að sjá þetta?",
+ "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Þegar þú sér eitthvað á Mastodon sem þér líkar ekki, þá geturðu fjarlægt viðkomandi eintakling úr umhverfinu þínu.",
+ "unfollow": "Hætta að fylgjast með",
+ "unfollowed": "Hætti að fylgjast með",
+ "unfollow_user": "Hætta að fylgjast með %s",
+ "mute_user": "Þagga niður í %s",
+ "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "Þú munt ekki sjá færslur eða endurbirtingar frá viðkomandi á streyminu þínu. Viðkomandi aðilar munu ekki vita að þaggað hefur verið niður í þeim.",
+ "block_user": "Útiloka %s",
+ "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Viðkomandi mun ekki lengur geta fylgst með eða séð færslurnar þínar, en munu sjá ef viðkomandi hefur verið útilokaður.",
+ "while_we_review_this_you_can_take_action_against_user": "Á meðan við yfirförum þetta, geturðu tekið til aðgerða gegn %s"
+ }
+ },
+ "preview": {
+ "keyboard": {
+ "close_preview": "Loka forskoðun",
+ "show_next": "Sýna næsta",
+ "show_previous": "Sýna fyrri"
+ }
+ },
+ "account_list": {
+ "tab_bar_hint": "Fyrirliggjandi valið notandasnið: %s. Tvípikkaðu og haltu niðri til að birta aðgangaskiptinn",
+ "dismiss_account_switcher": "Loka aðgangaskipti",
+ "add_account": "Bæta við notandaaðgangi"
+ },
+ "wizard": {
+ "new_in_mastodon": "Nýtt í Mastodon",
+ "multiple_account_switch_intro_description": "Skiptu milli notandaaðganga með því að halda niðri notandasniðshnappnum.",
+ "accessibility_hint": "Tvípikkaðu til að loka þessum leiðarvísi"
+ },
+ "bookmark": {
+ "title": "Bókamerki"
+ }
+ }
+}
diff --git a/Localization/StringsConvertor/input/is.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/is.lproj/ios-infoPlist.json
new file mode 100644
index 000000000..24af18431
--- /dev/null
+++ b/Localization/StringsConvertor/input/is.lproj/ios-infoPlist.json
@@ -0,0 +1,6 @@
+{
+ "NSCameraUsageDescription": "Notað til að taka mynd fyrir stöðufærslu",
+ "NSPhotoLibraryAddUsageDescription": "Notað til að vista mynd inn í ljósmyndasafnið",
+ "NewPostShortcutItemTitle": "Ný færsla",
+ "SearchShortcutItemTitle": "Leita"
+}
diff --git a/Localization/StringsConvertor/input/it.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/it.lproj/Localizable.stringsdict
index 38f986521..3a8549914 100644
--- a/Localization/StringsConvertor/input/it.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/it.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld caratteri
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ rimanenti
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 carattere
+ other
+ %ld caratteri
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/it.lproj/app.json b/Localization/StringsConvertor/input/it.lproj/app.json
index 73f42d1eb..f4f21762b 100644
--- a/Localization/StringsConvertor/input/it.lproj/app.json
+++ b/Localization/StringsConvertor/input/it.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Salva foto",
"copy_photo": "Copia foto",
"sign_in": "Accedi",
- "sign_up": "Registrati",
+ "sign_up": "Crea un account",
"see_more": "Visualizza altro",
"preview": "Anteprima",
"share": "Condividi",
@@ -218,10 +218,16 @@
"get_started": "Inizia",
"log_in": "Accedi"
},
+ "login": {
+ "title": "Bentornato/a",
+ "subtitle": "Accedi al server sul quale hai creato il tuo account.",
+ "server_search_field": {
+ "placeholder": "Inserisci l'URL o cerca il tuo server"
+ }
+ },
"server_picker": {
"title": "Mastodon è fatto di utenti in diverse comunità.",
- "subtitle": "Scegli una comunità basata sui tuoi interessi, regione o uno scopo generale.",
- "subtitle_extend": "Scegli una comunità basata sui tuoi interessi, regione o uno scopo generale. Ogni comunità è gestita da un'organizzazione completamente indipendente o individuale.",
+ "subtitle": "Scegli un server in base alla tua regione, ai tuoi interessi o uno generico. Puoi comunque chattare con chiunque su Mastodon, indipendentemente dai tuoi server.",
"button": {
"category": {
"all": "Tutti",
@@ -248,8 +254,7 @@
"category": "CATEGORIA"
},
"input": {
- "placeholder": "Cerca comunità",
- "search_servers_or_enter_url": "Cerca i server o inserisci l'URL"
+ "search_servers_or_enter_url": "Cerca le comunità o inserisci l'URL"
},
"empty_state": {
"finding_servers": "Ricerca server disponibili...",
@@ -386,7 +391,9 @@
"load_failed": "Caricamento fallito",
"upload_failed": "Caricamento fallito",
"can_not_recognize_this_media_attachment": "Impossibile riconoscere questo allegato multimediale",
- "attachment_too_large": "Allegato troppo grande"
+ "attachment_too_large": "Allegato troppo grande",
+ "compressing_state": "Compressione in corso...",
+ "server_processing_state": "Elaborazione del server in corso..."
},
"poll": {
"duration_time": "Durata: %s",
@@ -396,7 +403,9 @@
"one_day": "1 giorno",
"three_days": "3 giorni",
"seven_days": "7 giorni",
- "option_number": "Opzione %ld"
+ "option_number": "Opzione %ld",
+ "the_poll_is_invalid": "Il sondaggio non è valido",
+ "the_poll_has_empty_option": "Il sondaggio ha un'opzione vuota"
},
"content_warning": {
"placeholder": "Scrivi un avviso accurato qui..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Selettore Emoji personalizzato",
"enable_content_warning": "Abilita avvertimento contenuti",
"disable_content_warning": "Disabilita avviso di contenuti",
- "post_visibility_menu": "Menu di visibilità del post"
+ "post_visibility_menu": "Menu di visibilità del post",
+ "post_options": "Opzioni del messaggio",
+ "posting_as": "Pubblicazione come %s"
},
"keyboard": {
"discard_post": "Scarta post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Etichetta",
"content": "Contenuto"
+ },
+ "verified": {
+ "short": "Verificato il %s",
+ "long": "La proprietà di questo collegamento è stata verificata il %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/ja.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ja.lproj/Localizable.stringsdict
index cbc999738..795a971b7 100644
--- a/Localization/StringsConvertor/input/ja.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/ja.lproj/Localizable.stringsdict
@@ -44,6 +44,20 @@
%ld 文字
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/ja.lproj/app.json b/Localization/StringsConvertor/input/ja.lproj/app.json
index 9ff2a60a6..f73faabd4 100644
--- a/Localization/StringsConvertor/input/ja.lproj/app.json
+++ b/Localization/StringsConvertor/input/ja.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "写真を撮る",
"save_photo": "写真を撮る",
"copy_photo": "写真をコピー",
- "sign_in": "サインイン",
- "sign_up": "サインアップ",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "もっと見る",
"preview": "プレビュー",
"share": "共有",
@@ -218,10 +218,16 @@
"get_started": "はじめる",
"log_in": "ログイン"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "サーバーを選択",
- "subtitle": "あなたの興味分野・地域に合ったコミュニティや、汎用のものを選択してください。",
- "subtitle_extend": "あなたの興味分野・地域に合ったコミュニティや、汎用のものを選択してください。各コミュニティはそれぞれ完全に独立した組織や個人によって運営されています。",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "すべて",
@@ -248,8 +254,7 @@
"category": "カテゴリー"
},
"input": {
- "placeholder": "サーバーを探す",
- "search_servers_or_enter_url": "サーバーを検索またはURLを入力"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "利用可能なサーバーの検索...",
@@ -385,8 +390,10 @@
"description_video": "閲覧が難しいユーザーへの映像説明",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "期間: %s",
@@ -396,7 +403,9 @@
"one_day": "1日",
"three_days": "3日",
"seven_days": "7日",
- "option_number": "オプション %ld"
+ "option_number": "オプション %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "ここに警告を書いてください..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "カスタム絵文字ピッカー",
"enable_content_warning": "閲覧注意を有効にする",
"disable_content_warning": "閲覧注意を無効にする",
- "post_visibility_menu": "投稿の表示メニュー"
+ "post_visibility_menu": "投稿の表示メニュー",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "投稿を破棄",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "ラベル",
"content": "コンテンツ"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/kab.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/kab.lproj/Localizable.stringsdict
index 7fc6a50bb..f18a906c0 100644
--- a/Localization/StringsConvertor/input/kab.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/kab.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld yisekkilen
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 n usekkil
+ other
+ %ld n isekkilen
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
@@ -120,7 +136,7 @@
NSStringFormatValueTypeKey
ld
one
- 1 tsuffeɣt
+ 1 n tsuffeɣt
other
%ld n tsuffaɣ
@@ -296,9 +312,9 @@
NSStringFormatValueTypeKey
ld
one
- Yeqqim-d 1 wass
+ Yeqqim-d 1 n wass
other
- Qqimen-d %ld wussan
+ Qqimen-d %ld n wussan
date.hour.left
@@ -312,9 +328,9 @@
NSStringFormatValueTypeKey
ld
one
- Yeqqim-d 1 usrag
+ Yeqqim-d 1 n wesrag
other
- Qqimen-d %ld yisragen
+ Qqimen-d %ld n yisragen
date.minute.left
@@ -328,9 +344,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 tesdat i d-yeqqimen
+ 1 n tesdat i d-yeqqimen
other
- %ld tesdatin i d-yeqqimen
+ %ld n tesdatin i d-yeqqimen
date.second.left
@@ -344,9 +360,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 tasint i d-yeqqimen
+ 1 n tasint i d-yeqqimen
other
- %ld tsinin i d-yeqqimen
+ %ld n tasinin i d-yeqqimen
date.year.ago.abbr
@@ -360,9 +376,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 useggas aya
+ %ld n useggas aya
other
- %ld yiseggasen aya
+ %ld n yiseggasen aya
date.month.ago.abbr
@@ -376,9 +392,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 wayyur aya
+ %ld n wayyur aya
other
- %ld wayyuren aya
+ %ld n wayyuren aya
date.day.ago.abbr
@@ -392,9 +408,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 wass aya
+ %ld n wass aya
other
- %ld wussan aya
+ %ld n wussan aya
date.hour.ago.abbr
@@ -408,9 +424,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 usrag aya
+ %ld n wesrag aya
other
- %ld yisragen aya
+ %ld n yisragen aya
date.minute.ago.abbr
@@ -424,9 +440,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 tesdat aya
+ %ld n tesdat aya
other
- %ld tesdatin aya
+ %ld n tesdatin aya
date.second.ago.abbr
@@ -440,9 +456,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 tasint aya
+ %ld n tasint aya
other
- %ld tsinin aya
+ %ld n tasinin aya
diff --git a/Localization/StringsConvertor/input/kab.lproj/app.json b/Localization/StringsConvertor/input/kab.lproj/app.json
index 9c5d7659a..62cea8780 100644
--- a/Localization/StringsConvertor/input/kab.lproj/app.json
+++ b/Localization/StringsConvertor/input/kab.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Sekles tawlaft",
"copy_photo": "Nɣel tawlaft",
"sign_in": "Qqen",
- "sign_up": "Jerred amiḍan",
+ "sign_up": "Snulfu-d amiḍan",
"see_more": "Wali ugar",
"preview": "Taskant",
"share": "Bḍu",
@@ -137,10 +137,10 @@
"closed": "Ifukk"
},
"meta_entity": {
- "url": "Link: %s",
- "hashtag": "Hashtag: %s",
- "mention": "Show Profile: %s",
- "email": "Email address: %s"
+ "url": "Asaɣ : %s",
+ "hashtag": "Ahacṭag : %s",
+ "mention": "Sken-d amaɣnu : %s",
+ "email": "Tansa imayl : %s"
},
"actions": {
"reply": "Err",
@@ -218,10 +218,16 @@
"get_started": "Aha bdu tura",
"log_in": "Qqen"
},
+ "login": {
+ "title": "Ansuf yess·ek·em",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Sekcem URL neɣ nadi ɣef uqeddac-ik·im"
+ }
+ },
"server_picker": {
"title": "Mastodon yettwaxdem i yiseqdacen deg waṭas n temɣiwnin.",
- "subtitle": "Fren tamɣiwent almend n wayen tḥemmleḍ, n tmurt-ik neɣ n yiswi-inek amatu.",
- "subtitle_extend": "Fren tamɣiwent almend n wayen tḥemmleḍ, n tmurt-ik neɣ n yiswi-inek amatu. Yal tamɣiwent tsedday-itt tkebbanit neɣ amdan ilelliyen.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Akk",
@@ -248,7 +254,6 @@
"category": "TAGGAYT"
},
"input": {
- "placeholder": "Nadi timɣiwnin",
"search_servers_or_enter_url": "Nadi timɣiwnin neɣ sekcem URL"
},
"empty_state": {
@@ -352,8 +357,8 @@
"navigation_bar_state": {
"offline": "Beṛṛa n tuqqna",
"new_posts": "Tissufaɣ timaynutin",
- "published": "Yettwasuffeɣ!",
- "Publishing": "Asuffeɣ tasuffeɣt...",
+ "published": "Tettwasuffeɣ!",
+ "Publishing": "Asuffeɣ n tasuffeɣt...",
"accessibility": {
"logo_label": "Taqeffalt n ulugu",
"logo_hint": "Sit i wakken ad tɛeddiḍ i usawen, sit tikkelt-nniḍen i wakken ad tɛeddiḍ ɣer wadig yezrin"
@@ -385,8 +390,10 @@
"description_video": "Glem-d tavidyut i wid yesɛan ugur deg yiẓri...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Tangazt: %s",
@@ -396,7 +403,9 @@
"one_day": "1 n wass",
"three_days": "3 n wussan",
"seven_days": "7 n wussan",
- "option_number": "Taxtiṛt %ld"
+ "option_number": "Taxtiṛt %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Aru alɣu-inek s telqeyt da..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Amefran n yimujiten udmawanen",
"enable_content_warning": "Rmed alɣu n ugbur",
"disable_content_warning": "Sens alɣu n ugbur",
- "post_visibility_menu": "Umuɣ n ubani n tsuffeɣt"
+ "post_visibility_menu": "Umuɣ n ubani n tsuffeɣt",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Sefsex tasuffeɣt",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Tabzimt",
"content": "Agbur"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
@@ -656,7 +671,7 @@
"its_spam": "D aspam",
"malicious_links_fake_engagement_or_repetetive_replies": "Yir iseɣwan, yir agman d tririyin i d-yettuɣalen",
"it_violates_server_rules": "Truẓi n yilugan n uqeddac",
- "you_are_aware_that_it_breaks_specific_rules": "Teẓriḍ y•tettruẓu kra n yilugan",
+ "you_are_aware_that_it_breaks_specific_rules": "Teẓriḍ y·tettruẓu kra n yilugan",
"its_something_else": "Ɣef ssebba-nniḍen",
"the_issue_does_not_fit_into_other_categories": "Ugur ur yemṣada ara akk d taggayin-nniḍen"
},
diff --git a/Localization/StringsConvertor/input/kmr.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/kmr.lproj/Localizable.stringsdict
index 77571439f..c904186d8 100644
--- a/Localization/StringsConvertor/input/kmr.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/kmr.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld tîp
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ maye
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 peyv
+ other
+ %ld peyv
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/kmr.lproj/app.json b/Localization/StringsConvertor/input/kmr.lproj/app.json
index 098f514ee..eb553885c 100644
--- a/Localization/StringsConvertor/input/kmr.lproj/app.json
+++ b/Localization/StringsConvertor/input/kmr.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Wêneyê tomar bike",
"copy_photo": "Wêneyê jê bigire",
"sign_in": "Têkeve",
- "sign_up": "Tomar bibe",
+ "sign_up": "Ajimêr biafirîne",
"see_more": "Bêtir bibîne",
"preview": "Pêşdîtin",
"share": "Parve bike",
@@ -218,10 +218,16 @@
"get_started": "Dest pê bike",
"log_in": "Têkeve"
},
+ "login": {
+ "title": "Dîsa bi xêr hatî",
+ "subtitle": "Têketinê bike ser rajekarê ku te ajimêrê xwe tê de çê kiriye.",
+ "server_search_field": {
+ "placeholder": "Girêdanê têxe an jî li rajekarê xwe bigere"
+ }
+ },
"server_picker": {
"title": "Mastodon ji bikarhênerên di civakên cuda de pêk tê.",
- "subtitle": "Li gorî berjewendî, herêm, an jî armancek gelemperî civakekê hilbijêre.",
- "subtitle_extend": "Li gorî berjewendî, herêm, an jî armancek gelemperî civakekê hilbijêre. Her civakek ji hêla rêxistinek an kesek bi tevahî serbixwe ve tê xebitandin.",
+ "subtitle": "Li gorî herêm, berjewendî, an jî armanceke giştî rajekarekê hilbijêre. Tu hîn jî dikarî li ser Mastodon bi her kesî re biaxivî, her rajekarê te çi be.",
"button": {
"category": {
"all": "Hemû",
@@ -248,8 +254,7 @@
"category": "BEŞ"
},
"input": {
- "placeholder": "Li rajekaran bigere",
- "search_servers_or_enter_url": "Li rajekaran bigere an jî girêdanê têxe"
+ "search_servers_or_enter_url": "Li civakan bigere an jî girêdanê têxe"
},
"empty_state": {
"finding_servers": "Peydakirina rajekarên berdest...",
@@ -386,7 +391,9 @@
"load_failed": "Barkirin têk çû",
"upload_failed": "Barkirin têk çû",
"can_not_recognize_this_media_attachment": "Nikare ev pêveka medyayê nas bike",
- "attachment_too_large": "Pêvek pir mezin e"
+ "attachment_too_large": "Pêvek pir mezin e",
+ "compressing_state": "Tê guvaştin...",
+ "server_processing_state": "Pêvajoya rajekar pêş de diçe..."
},
"poll": {
"duration_time": "Dirêjî: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Roj",
"three_days": "3 Roj",
"seven_days": "7 Roj",
- "option_number": "Vebijêrk %ld"
+ "option_number": "Vebijêrk %ld",
+ "the_poll_is_invalid": "Ev dengdayîn ne derbasdar e",
+ "the_poll_has_empty_option": "Vebijêrkên vê dengdayînê vala ne"
},
"content_warning": {
"placeholder": "Li vir hişyariyek hûrgilî binivîsine..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Hilbijêrê emojî yên kesanekirî",
"enable_content_warning": "Hişyariya naverokê çalak bike",
"disable_content_warning": "Hişyariya naverokê neçalak bike",
- "post_visibility_menu": "Kulîna xuyabûna şandiyê"
+ "post_visibility_menu": "Kulîna xuyabûna şandiyê",
+ "post_options": "Vebijêrkên şandiyê",
+ "posting_as": "Biweşîne wekî %s"
},
"keyboard": {
"discard_post": "Şandî paşguh bike",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Nîşan",
"content": "Naverok"
+ },
+ "verified": {
+ "short": "Hate piştrastkirin li ser %s",
+ "long": "Xwedaniya li vê girêdanê di %s de hatiye kontrolkirin"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/ko.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ko.lproj/Localizable.stringsdict
index 9628be614..77aac5569 100644
--- a/Localization/StringsConvertor/input/ko.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/ko.lproj/Localizable.stringsdict
@@ -44,6 +44,20 @@
%ld 글자
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ 글자 남음
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+ %ld 글자
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/ko.lproj/app.json b/Localization/StringsConvertor/input/ko.lproj/app.json
index 826ac389c..070386bf9 100644
--- a/Localization/StringsConvertor/input/ko.lproj/app.json
+++ b/Localization/StringsConvertor/input/ko.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "사진 저장",
"copy_photo": "사진 복사",
"sign_in": "로그인",
- "sign_up": "회원가입",
+ "sign_up": "계정 생성",
"see_more": "더 보기",
"preview": "미리보기",
"share": "공유",
@@ -218,10 +218,16 @@
"get_started": "시작하기",
"log_in": "로그인"
},
+ "login": {
+ "title": "돌아오신 것을 환영합니다",
+ "subtitle": "계정을 만든 서버에 로그인.",
+ "server_search_field": {
+ "placeholder": "URL을 입력하거나 서버를 검색"
+ }
+ },
"server_picker": {
"title": "서버를 고르세요,\n아무 서버나 좋습니다.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "당신의 지역이나, 관심사에 따라, 혹은 그냥 일반적인 목적의 서버를 고르세요. 어떤 서버를 고르더라도 마스토돈의 다른 모두와 소통할 수 있습니다.",
"button": {
"category": {
"all": "모두",
@@ -248,8 +254,7 @@
"category": "분류"
},
"input": {
- "placeholder": "서버 검색",
- "search_servers_or_enter_url": "서버를 검색하거나 URL을 입력하세요"
+ "search_servers_or_enter_url": "커뮤니티를 검색하거나 URL을 입력"
},
"empty_state": {
"finding_servers": "사용 가능한 서버를 찾는 중입니다...",
@@ -385,8 +390,10 @@
"description_video": "시각장애인을 위한 영상 설명…",
"load_failed": "불러오기 실패",
"upload_failed": "업로드 실패",
- "can_not_recognize_this_media_attachment": "이 미디어 첨부파일을 인식할 수 없습니다",
- "attachment_too_large": "첨부파일이 너무 큽니다"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "첨부파일이 너무 큽니다",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "기간: %s",
@@ -396,7 +403,9 @@
"one_day": "1일",
"three_days": "3일",
"seven_days": "7일",
- "option_number": "옵션 %ld"
+ "option_number": "옵션 %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "정확한 경고 문구를 여기에 작성하세요…"
@@ -417,7 +426,9 @@
"custom_emoji_picker": "커스텀 에모지 선택기",
"enable_content_warning": "열람 주의 설정",
"disable_content_warning": "열람 주의 해제",
- "post_visibility_menu": "게시물 공개범위 메뉴"
+ "post_visibility_menu": "게시물 공개범위 메뉴",
+ "post_options": "게시물 옵션",
+ "posting_as": "%s로 게시"
},
"keyboard": {
"discard_post": "글 버리기",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "라벨",
"content": "내용"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict
index 25f32c98d..ac30b4f8b 100644
--- a/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict
@@ -56,6 +56,24 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ zero
+ %ld characters
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/lv.lproj/app.json b/Localization/StringsConvertor/input/lv.lproj/app.json
index 2835f0887..1ca18400b 100644
--- a/Localization/StringsConvertor/input/lv.lproj/app.json
+++ b/Localization/StringsConvertor/input/lv.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Uzņemt bildi",
"save_photo": "Saglabāt bildi",
"copy_photo": "Kopēt bildi",
- "sign_in": "Pieteikties",
- "sign_up": "Reģistrēties",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "Skatīt vairāk",
"preview": "Priekšskatījums",
"share": "Dalīties",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Pieteikties"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Visi",
@@ -248,8 +254,7 @@
"category": "KATEGORIJA"
},
"input": {
- "placeholder": "Meklēt serverus",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Diena",
"three_days": "3 Dienas",
"seven_days": "7 Dienas",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Saturs"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict
index 314600ff7..84769b0c1 100644
--- a/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld tekens
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/nl.lproj/app.json b/Localization/StringsConvertor/input/nl.lproj/app.json
index e0b2872fb..589c51d2d 100644
--- a/Localization/StringsConvertor/input/nl.lproj/app.json
+++ b/Localization/StringsConvertor/input/nl.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Maak foto",
"save_photo": "Bewaar foto",
"copy_photo": "Kopieer foto",
- "sign_in": "Aanmelden",
- "sign_up": "Registreren",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "Meer",
"preview": "Voorvertoning",
"share": "Deel",
@@ -218,10 +218,16 @@
"get_started": "Aan de slag",
"log_in": "Log in"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Kies een server, welke dan ook.",
- "subtitle": "Kies een gemeenschap gebaseerd op jouw interesses, regio of een algemeen doel.",
- "subtitle_extend": "Kies een gemeenschap gebaseerd op jouw interesses, regio, of een algemeen doel. Elke gemeenschap wordt beheerd door een volledig onafhankelijke organisatie of individu.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Alles",
@@ -248,8 +254,7 @@
"category": "CATEGORIE"
},
"input": {
- "placeholder": "Zoek uw server of sluit u bij een nieuwe server aan...",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Beschikbare servers zoeken...",
@@ -385,8 +390,10 @@
"description_video": "Omschrijf de video voor mensen met een visuele beperking...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duur: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Dag",
"three_days": "3 Dagen",
"seven_days": "7 Dagen",
- "option_number": "Optie %ld"
+ "option_number": "Optie %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Schrijf hier een nauwkeurige waarschuwing..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Eigen Emojikiezer",
"enable_content_warning": "Inhoudswaarschuwing inschakelen",
"disable_content_warning": "Inhoudswaarschuwing Uitschakelen",
- "post_visibility_menu": "Berichtzichtbaarheidsmenu"
+ "post_visibility_menu": "Berichtzichtbaarheidsmenu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Bericht Verwijderen",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Etiket",
"content": "Inhoud"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/pt-BR.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/pt-BR.lproj/Localizable.stringsdict
index ba1532740..02fbf2d20 100644
--- a/Localization/StringsConvertor/input/pt-BR.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/pt-BR.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld caracteres
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ restantes
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 carácter
+ other
+ %ld carácteres
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
@@ -72,9 +88,9 @@
NSStringFormatValueTypeKey
ld
one
- Followed by %1$@, and another mutual
+ Seguido por %1$@, e outro em comum
other
- Followed by %1$@, and %ld mutuals
+ Seguido por %1$@, e %ld em comum
plural.count.metric_formatted.post
@@ -104,9 +120,9 @@
NSStringFormatValueTypeKey
ld
one
- 1 media
+ 1 mídia
other
- %ld media
+ %ld mídias
plural.count.post
diff --git a/Localization/StringsConvertor/input/pt-BR.lproj/app.json b/Localization/StringsConvertor/input/pt-BR.lproj/app.json
index 26e6edb76..60d858235 100644
--- a/Localization/StringsConvertor/input/pt-BR.lproj/app.json
+++ b/Localization/StringsConvertor/input/pt-BR.lproj/app.json
@@ -2,7 +2,7 @@
"common": {
"alerts": {
"common": {
- "please_try_again": "Por favor tente novamente.",
+ "please_try_again": "Por favor, tente novamente.",
"please_try_again_later": "Tente novamente mais tarde."
},
"sign_up_failure": {
@@ -164,7 +164,7 @@
"emoji": "Emoji"
},
"visibility": {
- "unlisted": "Everyone can see this post but not display in the public timeline.",
+ "unlisted": "Todos podem ver esta postagem, mas não são exibidos na linha do tempo pública.",
"private": "Somente seus seguidores podem ver essa postagem.",
"private_from_me": "Somente meus seguidores podem ver essa postagem.",
"direct": "Somente o usuário mencionado pode ver essa postagem."
@@ -202,8 +202,8 @@
},
"header": {
"no_status_found": "Nenhuma postagem encontrada",
- "blocking_warning": "You can’t view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.",
- "user_blocking_warning": "You can’t view %s’s profile\nuntil you unblock them.\nYour profile looks like this to them.",
+ "blocking_warning": "Você não pode ver o perfil deste usuário até desbloqueá-lo.\nSeu perfil aparece assim para esse usuário.",
+ "user_blocking_warning": "Você não pode ver o perfil de %s até desbloqueá-lo.\nSeu perfil aparece assim para esse usuário.",
"blocked_warning": "Você não pode ver o perfil desse usuário até que ele o desbloqueie.",
"user_blocked_warning": "Você não pode ver o perfil de %s até que ele o desbloqueie.",
"suspended_warning": "Esse usuário foi suspenso.",
@@ -218,10 +218,16 @@
"get_started": "Comece já",
"log_in": "Entrar"
},
+ "login": {
+ "title": "Bem-vindo de volta",
+ "subtitle": "Logado na instância em que você criou a sua conta.",
+ "server_search_field": {
+ "placeholder": "Insira a URL ou procure pela sua instância"
+ }
+ },
"server_picker": {
"title": "Mastodon é feito de usuários em instâncias diferentes.",
- "subtitle": "Escolha uma instância baseada nos seus interesses, região, ou em uma proposta geral.",
- "subtitle_extend": "Escolha uma instância baseada nos seus interesses, região, ou em uma proposta geral. Cada instância é operada por um indivíduo ou uma organização totalmente independente.",
+ "subtitle": "Escolha uma instância baseada na sua região, interesses, ou uma de uso geral. Você ainda poderá conversar com qualquer um no Mastodon, independente da instância.",
"button": {
"category": {
"all": "Todos",
@@ -248,8 +254,7 @@
"category": "Categoria"
},
"input": {
- "placeholder": "Procurar instâncias",
- "search_servers_or_enter_url": "Procurar instâncias ou inserir URL"
+ "search_servers_or_enter_url": "Procurar comunidades ou inserir URL"
},
"empty_state": {
"finding_servers": "Procurando instâncias disponíveis...",
@@ -259,7 +264,7 @@
},
"register": {
"title": "Vamos configurar você em %s",
- "lets_get_you_set_up_on_domain": "Let’s get you set up on %s",
+ "lets_get_you_set_up_on_domain": "Vamos configurar você em %s",
"input": {
"avatar": {
"delete": "Excluir"
@@ -279,13 +284,13 @@
"require": "Sua senha deve ter pelo menos:",
"character_limit": "8 carácteres",
"accessibility": {
- "checked": "checked",
- "unchecked": "unchecked"
+ "checked": "marcado",
+ "unchecked": "desmarcado"
},
"hint": "Sua senha precisa ter pelo menos oito carácteres"
},
"invite": {
- "registration_user_invite_request": "Why do you want to join?"
+ "registration_user_invite_request": "Por que você deseja se inscrever?"
}
},
"error": {
@@ -298,80 +303,80 @@
"reason": "Motivo"
},
"reason": {
- "blocked": "%s contains a disallowed email provider",
+ "blocked": "%s contém um provedor de e-mail não permitido",
"unreachable": "%s parece não existir",
"taken": "%s já está em uso",
- "reserved": "%s is a reserved keyword",
- "accepted": "%s must be accepted",
- "blank": "%s is required",
- "invalid": "%s is invalid",
- "too_long": "%s is too long",
- "too_short": "%s is too short",
- "inclusion": "%s is not a supported value"
+ "reserved": "%s é uma palavra-chave reservada",
+ "accepted": "%s deve ser aceite",
+ "blank": "%s é obrigatório",
+ "invalid": "%s é inválido",
+ "too_long": "%s é muito longo",
+ "too_short": "%s é muito curto",
+ "inclusion": "%s não é um valor suportado"
},
"special": {
- "username_invalid": "Username must only contain alphanumeric characters and underscores",
- "username_too_long": "Username is too long (can’t be longer than 30 characters)",
- "email_invalid": "This is not a valid email address",
- "password_too_short": "Password is too short (must be at least 8 characters)"
+ "username_invalid": "O nome de usuário só pode conter caracteres alfanuméricos e underlines (_)",
+ "username_too_long": "Nome de usuário é muito longo (não pode ter mais de 30 caracteres)",
+ "email_invalid": "Este não é um endereço de e-mail válido",
+ "password_too_short": "A senha é muito curta (deve ter pelo menos 8 caracteres)"
}
}
},
"server_rules": {
- "title": "Some ground rules.",
- "subtitle": "These are set and enforced by the %s moderators.",
- "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.",
- "terms_of_service": "terms of service",
- "privacy_policy": "privacy policy",
+ "title": "Algumas regras básicas.",
+ "subtitle": "Estes são definidos e aplicados pelos moderadores da %s.",
+ "prompt": "Ao continuar, você estará sujeito aos termos de serviço e política de privacidade para %s.",
+ "terms_of_service": "termos de serviço",
+ "privacy_policy": "política de privacidade",
"button": {
- "confirm": "I Agree"
+ "confirm": "Eu concordo"
}
},
"confirm_email": {
- "title": "One last thing.",
- "subtitle": "Tap the link we emailed to you to verify your account.",
- "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account",
+ "title": "Uma última coisa.",
+ "subtitle": "Clique no link que te enviamos por e-mail para verificar a sua conta.",
+ "tap_the_link_we_emailed_to_you_to_verify_your_account": "Clique no link que te enviamos por e-mail para verificar a sua conta",
"button": {
- "open_email_app": "Open Email App",
- "resend": "Resend"
+ "open_email_app": "Abrir aplicativo de e-mail",
+ "resend": "Reenviar"
},
"dont_receive_email": {
- "title": "Check your email",
- "description": "Check if your email address is correct as well as your junk folder if you haven’t.",
- "resend_email": "Resend Email"
+ "title": "Verifique o seu e-mail",
+ "description": "Verifique se o seu endereço de e-mail está correto, e também a sua pasta de spam caso não tenha verificado.",
+ "resend_email": "Reenviar e-mail"
},
"open_email_app": {
- "title": "Check your inbox.",
- "description": "We just sent you an email. Check your junk folder if you haven’t.",
- "mail": "Mail",
- "open_email_client": "Open Email Client"
+ "title": "Verifique sua caixa de entrada.",
+ "description": "Enviamos um e-mail para você. Verifique sua pasta de spam caso ainda tenha verificado.",
+ "mail": "Correio",
+ "open_email_client": "Abrir Cliente de Email"
}
},
"home_timeline": {
- "title": "Home",
+ "title": "Início",
"navigation_bar_state": {
- "offline": "Offline",
- "new_posts": "See new posts",
- "published": "Published!",
- "Publishing": "Publishing post...",
+ "offline": "Desconectado",
+ "new_posts": "Ver novas postagens",
+ "published": "Publicado!",
+ "Publishing": "Publicando toot...",
"accessibility": {
- "logo_label": "Logo Button",
- "logo_hint": "Tap to scroll to top and tap again to previous location"
+ "logo_label": "Botão do logotipo",
+ "logo_hint": "Toque para rolar para o topo e toque novamente para a localização anterior"
}
}
},
"suggestion_account": {
- "title": "Find People to Follow",
- "follow_explain": "When you follow someone, you’ll see their posts in your home feed."
+ "title": "Encontre pessoas para seguir",
+ "follow_explain": "Ao seguir alguém, você verá as publicações dessa pessoa na sua página inicial."
},
"compose": {
"title": {
- "new_post": "New Post",
- "new_reply": "New Reply"
+ "new_post": "Novo toot",
+ "new_reply": "Nova resposta"
},
"media_selection": {
- "camera": "Take Photo",
- "photo_library": "Photo Library",
+ "camera": "Tirar foto",
+ "photo_library": "Galeria",
"browse": "Navegar"
},
"content_input_placeholder": "Digite ou cole o que está na sua mente",
@@ -380,13 +385,15 @@
"attachment": {
"photo": "foto",
"video": "vídeo",
- "attachment_broken": "This %s is broken and can’t be\nuploaded to Mastodon.",
- "description_photo": "Describe the photo for the visually-impaired...",
- "description_video": "Describe the video for the visually-impaired...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "attachment_broken": "Este %s está quebrado e não pode ser\nenviado para o Mastodon.",
+ "description_photo": "Descreva a foto para deficientes visuais...",
+ "description_video": "Descreva o vídeo para os deficientes visuais...",
+ "load_failed": "Falha ao carregar",
+ "upload_failed": "Falha no carregamento",
+ "can_not_recognize_this_media_attachment": "Não é possível reconhecer este anexo de mídia",
+ "attachment_too_large": "O anexo é muito grande",
+ "compressing_state": "Compactando...",
+ "server_processing_state": "Servidor processando..."
},
"poll": {
"duration_time": "Duração: %s",
@@ -396,41 +403,45 @@
"one_day": "1 dia",
"three_days": "3 dias",
"seven_days": "7 dias",
- "option_number": "Opção %ld"
+ "option_number": "Opção %ld",
+ "the_poll_is_invalid": "A enquete é inválida",
+ "the_poll_has_empty_option": "A enquete tem uma opção vazia"
},
"content_warning": {
- "placeholder": "Write an accurate warning here..."
+ "placeholder": "Escreva um aviso de conteúdo preciso aqui..."
},
"visibility": {
- "public": "Public",
- "unlisted": "Unlisted",
- "private": "Followers only",
- "direct": "Only people I mention"
+ "public": "Público",
+ "unlisted": "Não listado",
+ "private": "Apenas seguidores",
+ "direct": "Apenas pessoas que menciono"
},
"auto_complete": {
- "space_to_add": "Space to add"
+ "space_to_add": "Espaço a adicionar"
},
"accessibility": {
- "append_attachment": "Add Attachment",
- "append_poll": "Add Poll",
- "remove_poll": "Remove Poll",
- "custom_emoji_picker": "Custom Emoji Picker",
- "enable_content_warning": "Enable Content Warning",
- "disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "append_attachment": "Adicionar anexo",
+ "append_poll": "Adicionar enquete",
+ "remove_poll": "Remover enquete",
+ "custom_emoji_picker": "Seletor de emoji personalizado",
+ "enable_content_warning": "Ativar Aviso de Conteúdo",
+ "disable_content_warning": "Desativar Aviso de Conteúdo",
+ "post_visibility_menu": "Menu de Visibilidade do Post",
+ "post_options": "Opções de postagem",
+ "posting_as": "Publicando como %s"
},
"keyboard": {
- "discard_post": "Discard Post",
- "publish_post": "Publish Post",
- "toggle_poll": "Toggle Poll",
- "toggle_content_warning": "Toggle Content Warning",
- "append_attachment_entry": "Add Attachment - %s",
- "select_visibility_entry": "Select Visibility - %s"
+ "discard_post": "Descartar postagem",
+ "publish_post": "Publicar postagem",
+ "toggle_poll": "Alternar enquete",
+ "toggle_content_warning": "Ativar/desativar Aviso de Conteúdo",
+ "append_attachment_entry": "Adicionar Anexo - %s",
+ "select_visibility_entry": "Selecionar Visibilidade - %s"
}
},
"profile": {
"header": {
- "follows_you": "Follows You"
+ "follows_you": "Segue você"
},
"dashboard": {
"posts": "toots",
@@ -438,86 +449,90 @@
"followers": "seguidores"
},
"fields": {
- "add_row": "Add Row",
+ "add_row": "Adicionar linha",
"placeholder": {
- "label": "Label",
- "content": "Content"
+ "label": "Descrição",
+ "content": "Conteúdo"
+ },
+ "verified": {
+ "short": "Verificado em %s",
+ "long": "O link foi verificado em %s"
}
},
"segmented_control": {
- "posts": "Posts",
- "replies": "Replies",
- "posts_and_replies": "Posts and Replies",
- "media": "Media",
- "about": "About"
+ "posts": "Toots",
+ "replies": "Respostas",
+ "posts_and_replies": "Toots e respostas",
+ "media": "Mídia",
+ "about": "Sobre"
},
"relationship_action_alert": {
"confirm_mute_user": {
- "title": "Mute Account",
- "message": "Confirm to mute %s"
+ "title": "Silenciar conta",
+ "message": "Confirme para silenciar %s"
},
"confirm_unmute_user": {
- "title": "Unmute Account",
- "message": "Confirm to unmute %s"
+ "title": "Tirar conta do silenciado",
+ "message": "Confirme para tirar %s do silenciado"
},
"confirm_block_user": {
- "title": "Block Account",
- "message": "Confirm to block %s"
+ "title": "Bloquear conta",
+ "message": "Confirme para bloquear %s"
},
"confirm_unblock_user": {
- "title": "Unblock Account",
- "message": "Confirm to unblock %s"
+ "title": "Desbloquear conta",
+ "message": "Confirme para desbloquear %s"
},
"confirm_show_reblogs": {
- "title": "Show Reblogs",
- "message": "Confirm to show reblogs"
+ "title": "Mostrar reblogs",
+ "message": "Confirmar para mostrar reblogs"
},
"confirm_hide_reblogs": {
- "title": "Hide Reblogs",
- "message": "Confirm to hide reblogs"
+ "title": "Ocultar reblogs",
+ "message": "Confirmar para ocultar reblogs"
}
},
"accessibility": {
- "show_avatar_image": "Show avatar image",
- "edit_avatar_image": "Edit avatar image",
- "show_banner_image": "Show banner image",
- "double_tap_to_open_the_list": "Double tap to open the list"
+ "show_avatar_image": "Mostrar foto de perfil",
+ "edit_avatar_image": "Editar foto de perfil",
+ "show_banner_image": "Mostrar foto de capa",
+ "double_tap_to_open_the_list": "Toque duas vezes para abrir a lista"
}
},
"follower": {
- "title": "follower",
- "footer": "Followers from other servers are not displayed."
+ "title": "seguidor",
+ "footer": "Seguidores de outras instâncias não são exibidos."
},
"following": {
- "title": "following",
- "footer": "Follows from other servers are not displayed."
+ "title": "seguindo",
+ "footer": "Contas que você segue de outras instâncias não são exibidas."
},
"familiarFollowers": {
- "title": "Followers you familiar",
- "followed_by_names": "Followed by %s"
+ "title": "Seguidores que você conhece",
+ "followed_by_names": "Seguido por %s"
},
"favorited_by": {
- "title": "Favorited By"
+ "title": "Favoritado por"
},
"reblogged_by": {
- "title": "Reblogged By"
+ "title": "Reblogado por"
},
"search": {
- "title": "Search",
+ "title": "Buscar",
"search_bar": {
- "placeholder": "Search hashtags and users",
- "cancel": "Cancel"
+ "placeholder": "Buscar hashtags e usuários",
+ "cancel": "Cancelar"
},
"recommend": {
- "button_text": "See All",
+ "button_text": "Ver tudo",
"hash_tag": {
- "title": "Trending on Mastodon",
- "description": "Hashtags that are getting quite a bit of attention",
- "people_talking": "%s people are talking"
+ "title": "Em tendência no Mastodon",
+ "description": "Hashtags que estão recebendo bastante atenção",
+ "people_talking": "%s pessoas estão falando"
},
"accounts": {
- "title": "Accounts you might like",
- "description": "You may like to follow these accounts",
+ "title": "Contas que você deve gostar",
+ "description": "Você pode gostar de seguir estas contas",
"follow": "Seguir"
}
},
@@ -543,170 +558,170 @@
"community": "Comunidade",
"for_you": "Para você"
},
- "intro": "These are the posts gaining traction in your corner of Mastodon."
+ "intro": "Esses são os posts que estão ganhando força no seu canto do Mastodon."
},
"favorite": {
- "title": "Your Favorites"
+ "title": "Seus favoritos"
},
"notification": {
"title": {
- "Everything": "Everything",
- "Mentions": "Mentions"
+ "Everything": "Tudo",
+ "Mentions": "Menções"
},
"notification_description": {
- "followed_you": "followed you",
- "favorited_your_post": "favorited your post",
- "reblogged_your_post": "reblogged your post",
- "mentioned_you": "mentioned you",
- "request_to_follow_you": "request to follow you",
- "poll_has_ended": "poll has ended"
+ "followed_you": "seguiu você",
+ "favorited_your_post": "favoritou seu toot",
+ "reblogged_your_post": "reblogou seu toot",
+ "mentioned_you": "te mencionou",
+ "request_to_follow_you": "solicitação para te seguir",
+ "poll_has_ended": "enquete encerrada"
},
"keyobard": {
- "show_everything": "Show Everything",
- "show_mentions": "Show Mentions"
+ "show_everything": "Mostrar tudo",
+ "show_mentions": "Mostrar menções"
},
"follow_request": {
- "accept": "Accept",
- "accepted": "Accepted",
- "reject": "reject",
- "rejected": "Rejected"
+ "accept": "Aceitar",
+ "accepted": "Aceito",
+ "reject": "rejeitar",
+ "rejected": "Rejeitado"
}
},
"thread": {
- "back_title": "Post",
- "title": "Post from %s"
+ "back_title": "Toot",
+ "title": "Publicação de %s"
},
"settings": {
- "title": "Settings",
+ "title": "Configurações",
"section": {
"appearance": {
- "title": "Appearance",
- "automatic": "Automatic",
- "light": "Always Light",
- "dark": "Always Dark"
+ "title": "Aparência",
+ "automatic": "Automático",
+ "light": "Sempre Claro",
+ "dark": "Sempre Escuro"
},
"look_and_feel": {
- "title": "Look and Feel",
- "use_system": "Use System",
- "really_dark": "Really Dark",
- "sorta_dark": "Sorta Dark",
- "light": "Light"
+ "title": "Aparência e Comportamento",
+ "use_system": "Usar configuração do sistema",
+ "really_dark": "Bem escuro",
+ "sorta_dark": "Meio escuro",
+ "light": "Claro"
},
"notifications": {
- "title": "Notifications",
- "favorites": "Favorites my post",
- "follows": "Follows me",
- "boosts": "Reblogs my post",
- "mentions": "Mentions me",
+ "title": "Notificações",
+ "favorites": "Favoritaram minha publicação",
+ "follows": "Me segue",
+ "boosts": "Rebloga minha publicação",
+ "mentions": "Me menciona",
"trigger": {
- "anyone": "anyone",
- "follower": "a follower",
- "follow": "anyone I follow",
- "noone": "no one",
- "title": "Notify me when"
+ "anyone": "qualquer pessoa",
+ "follower": "um seguidor",
+ "follow": "qualquer um que eu siga",
+ "noone": "ninguém",
+ "title": "Me notificar quando"
}
},
"preference": {
- "title": "Preferences",
- "true_black_dark_mode": "True black dark mode",
- "disable_avatar_animation": "Disable animated avatars",
- "disable_emoji_animation": "Disable animated emojis",
- "using_default_browser": "Use default browser to open links",
- "open_links_in_mastodon": "Open links in Mastodon"
+ "title": "Preferências",
+ "true_black_dark_mode": "Modo preto",
+ "disable_avatar_animation": "Desativar fotos animadas",
+ "disable_emoji_animation": "Desativar emojis animados",
+ "using_default_browser": "Usar o navegador padrão pra abrir links",
+ "open_links_in_mastodon": "Abrir links no Mastodon"
},
"boring_zone": {
- "title": "The Boring Zone",
- "account_settings": "Account Settings",
- "terms": "Terms of Service",
- "privacy": "Privacy Policy"
+ "title": "A zona chata",
+ "account_settings": "Configurações da conta",
+ "terms": "Termos de serviço",
+ "privacy": "Política de privacidade"
},
"spicy_zone": {
- "title": "The Spicy Zone",
- "clear": "Clear Media Cache",
- "signout": "Sign Out"
+ "title": "A zona apimentada",
+ "clear": "Limpar cachê de mídia",
+ "signout": "Sair"
}
},
"footer": {
- "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)"
+ "mastodon_description": "Mastodon é um software de código aberto. Você pode reportar problemas no GitHub em %s (%s)"
},
"keyboard": {
- "close_settings_window": "Close Settings Window"
+ "close_settings_window": "Fechar janela de configurações"
}
},
"report": {
- "title_report": "Report",
- "title": "Report %s",
- "step1": "Step 1 of 2",
- "step2": "Step 2 of 2",
- "content1": "Are there any other posts you’d like to add to the report?",
- "content2": "Is there anything the moderators should know about this report?",
- "report_sent_title": "Thanks for reporting, we’ll look into this.",
- "send": "Send Report",
- "skip_to_send": "Send without comment",
- "text_placeholder": "Type or paste additional comments",
- "reported": "REPORTED",
+ "title_report": "Denunciar",
+ "title": "Denunciar %s",
+ "step1": "Passo 1 de 2",
+ "step2": "Passo 2 de 2",
+ "content1": "Há outras postagens que você gostaria de adicionar na denúncia?",
+ "content2": "Há algo que os moderadores deveriam saber sobre esta denúncia?",
+ "report_sent_title": "Obrigado por denunciar, iremos analisar.",
+ "send": "Enviar denúncia",
+ "skip_to_send": "Enviar sem comentário",
+ "text_placeholder": "Digite ou cole comentários adicionais",
+ "reported": "DENUNCIADO",
"step_one": {
- "step_1_of_4": "Step 1 of 4",
- "whats_wrong_with_this_post": "What's wrong with this post?",
- "whats_wrong_with_this_account": "What's wrong with this account?",
- "whats_wrong_with_this_username": "What's wrong with %s?",
- "select_the_best_match": "Select the best match",
- "i_dont_like_it": "I don’t like it",
- "it_is_not_something_you_want_to_see": "It is not something you want to see",
- "its_spam": "It’s spam",
- "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies",
- "it_violates_server_rules": "It violates server rules",
- "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules",
- "its_something_else": "It’s something else",
- "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories"
+ "step_1_of_4": "Passo 1 de 4",
+ "whats_wrong_with_this_post": "O que há de errado com essa publicação?",
+ "whats_wrong_with_this_account": "O que há de errado com essa conta?",
+ "whats_wrong_with_this_username": "O que há de errado com %s?",
+ "select_the_best_match": "Selecione a melhor alternativa",
+ "i_dont_like_it": "Eu não gosto disso",
+ "it_is_not_something_you_want_to_see": "Não é algo que você gostaria de ver",
+ "its_spam": "É spam",
+ "malicious_links_fake_engagement_or_repetetive_replies": "Links maliciosos, engajamento falso, ou respostas repetitivas",
+ "it_violates_server_rules": "Isso viola as regras do servidor",
+ "you_are_aware_that_it_breaks_specific_rules": "Você está ciente que isso quebra regras específicas",
+ "its_something_else": "É outra coisa",
+ "the_issue_does_not_fit_into_other_categories": "O problema não se encaixa em outras categorias"
},
"step_two": {
- "step_2_of_4": "Step 2 of 4",
- "which_rules_are_being_violated": "Which rules are being violated?",
- "select_all_that_apply": "Select all that apply",
- "i_just_don’t_like_it": "I just don’t like it"
+ "step_2_of_4": "Passo 2 de 4",
+ "which_rules_are_being_violated": "Quais regras estão sendo violadas?",
+ "select_all_that_apply": "Selecione todas que se aplicam",
+ "i_just_don’t_like_it": "Simplesmente não gosto"
},
"step_three": {
- "step_3_of_4": "Step 3 of 4",
- "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?",
- "select_all_that_apply": "Select all that apply"
+ "step_3_of_4": "Passo 3 de 4",
+ "are_there_any_posts_that_back_up_this_report": "Existem postagens que apoiam essa denúncia?",
+ "select_all_that_apply": "Selecione todos que se aplicam"
},
"step_four": {
- "step_4_of_4": "Step 4 of 4",
- "is_there_anything_else_we_should_know": "Is there anything else we should know?"
+ "step_4_of_4": "Passo 4 de 4",
+ "is_there_anything_else_we_should_know": "Há algo a mais que deveríamos saber?"
},
"step_final": {
- "dont_want_to_see_this": "Don’t want to see this?",
- "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.",
- "unfollow": "Unfollow",
- "unfollowed": "Unfollowed",
- "unfollow_user": "Unfollow %s",
- "mute_user": "Mute %s",
- "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.",
- "block_user": "Block %s",
- "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.",
- "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s"
+ "dont_want_to_see_this": "Não quer ver isso?",
+ "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Quando você vê algo que não gosta no Mastodon, você pode remover essa pessoa da sua experiência.",
+ "unfollow": "Deixar de seguir",
+ "unfollowed": "Deixou de seguir",
+ "unfollow_user": "Deixar de seguir %s",
+ "mute_user": "Silenciar %s",
+ "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "Você não verá as postagens ou reblogs dessa conta na sua pagina inicial. Essa pessoa não saberá que foi silenciada.",
+ "block_user": "Bloquear %s",
+ "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Essa conta não poderá mais te seguir ou ver suas postagens, mas ela poderá ver que foi bloqueada.",
+ "while_we_review_this_you_can_take_action_against_user": "Enquanto revisamos isso, você pode tomar medidas contra %s"
}
},
"preview": {
"keyboard": {
- "close_preview": "Close Preview",
- "show_next": "Show Next",
- "show_previous": "Show Previous"
+ "close_preview": "Fechar prévia",
+ "show_next": "Mostrar a próxima",
+ "show_previous": "Mostrar a anterior"
}
},
"account_list": {
- "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
- "dismiss_account_switcher": "Dismiss Account Switcher",
- "add_account": "Add Account"
+ "tab_bar_hint": "Perfil selecionado nesse momento: %s. Toque duas vezes e segure para mostrar o alternador de conta",
+ "dismiss_account_switcher": "Descartar alternador de conta",
+ "add_account": "Adicionar conta"
},
"wizard": {
- "new_in_mastodon": "New in Mastodon",
- "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
- "accessibility_hint": "Double tap to dismiss this wizard"
+ "new_in_mastodon": "Novo no Mastodon",
+ "multiple_account_switch_intro_description": "Alterne entre múltiplas contas segurando o botão de perfil.",
+ "accessibility_hint": "Toque duas vezes para descartar este assistente"
},
"bookmark": {
- "title": "Bookmarks"
+ "title": "Marcados"
}
}
}
diff --git a/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict
index bdcae6ac9..eabdc3c32 100644
--- a/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/pt.lproj/app.json b/Localization/StringsConvertor/input/pt.lproj/app.json
index a6a971860..3113ada74 100644
--- a/Localization/StringsConvertor/input/pt.lproj/app.json
+++ b/Localization/StringsConvertor/input/pt.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict
index 7ae5a1c79..9df2162b0 100644
--- a/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict
@@ -56,6 +56,24 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ few
+ %ld characters
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/ro.lproj/app.json b/Localization/StringsConvertor/input/ro.lproj/app.json
index a9d3804fa..75a77184c 100644
--- a/Localization/StringsConvertor/input/ro.lproj/app.json
+++ b/Localization/StringsConvertor/input/ro.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict
index afb29a6aa..c9552a9e4 100644
--- a/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict
@@ -62,6 +62,26 @@
%ld символа осталось
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ few
+ %ld characters
+ many
+ %ld characters
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/ru.lproj/app.json b/Localization/StringsConvertor/input/ru.lproj/app.json
index 798cdb4c5..25314102a 100644
--- a/Localization/StringsConvertor/input/ru.lproj/app.json
+++ b/Localization/StringsConvertor/input/ru.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Сделать фото",
"save_photo": "Сохранить изображение",
"copy_photo": "Скопировать изображение",
- "sign_in": "Войти",
- "sign_up": "Зарегистрироваться",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "Ещё",
"preview": "Предпросмотр",
"share": "Поделиться",
@@ -218,10 +218,16 @@
"get_started": "Присоединиться",
"log_in": "Вход"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Выберите сервер,\nлюбой сервер.",
- "subtitle": "Выберите сообщество на основе своих интересов, региона или общей тематики.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Все",
@@ -248,8 +254,7 @@
"category": "КАТЕГОРИЯ"
},
"input": {
- "placeholder": "Найдите сервер или присоединитесь к своему...",
- "search_servers_or_enter_url": "Поиск по серверам или ссылке"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Ищем доступные сервера...",
@@ -385,8 +390,10 @@
"description_video": "Опишите видео для людей с нарушениями зрения...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Продолжительность: %s",
@@ -396,7 +403,9 @@
"one_day": "1 день",
"three_days": "3 дня",
"seven_days": "7 дней",
- "option_number": "Вариант %ld"
+ "option_number": "Вариант %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Напишите предупреждение здесь..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Меню пользовательских эмодзи",
"enable_content_warning": "Добавить предупреждение о содержании",
"disable_content_warning": "Убрать предупреждение о содержании",
- "post_visibility_menu": "Меню видимости поста"
+ "post_visibility_menu": "Меню видимости поста",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Удалить пост",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Ярлык",
"content": "Содержимое"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict
index bdcae6ac9..eabdc3c32 100644
--- a/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/si.lproj/app.json b/Localization/StringsConvertor/input/si.lproj/app.json
index 816536440..a4542b9e9 100644
--- a/Localization/StringsConvertor/input/si.lproj/app.json
+++ b/Localization/StringsConvertor/input/si.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "පිවිසෙන්න",
- "sign_up": "ලියාපදිංචිය",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "තව බලන්න",
"preview": "පෙරදසුන",
"share": "බෙදාගන්න",
@@ -218,10 +218,16 @@
"get_started": "පටන් ගන්න",
"log_in": "පිවිසෙන්න"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "සියල්ල",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "නම්පත",
"content": "අන්තර්ගතය"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/sl.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/sl.lproj/Localizable.stringsdict
index 8f0bcb42b..87cc42142 100644
--- a/Localization/StringsConvertor/input/sl.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/sl.lproj/Localizable.stringsdict
@@ -62,6 +62,26 @@
%ld znakov
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ preostaja %#@character_count@
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ %ld znak
+ two
+ %ld znaka
+ few
+ %ld znaki
+ other
+ %ld znakov
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/sl.lproj/app.json b/Localization/StringsConvertor/input/sl.lproj/app.json
index 37b62a45d..0aed7bc15 100644
--- a/Localization/StringsConvertor/input/sl.lproj/app.json
+++ b/Localization/StringsConvertor/input/sl.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Shrani fotografijo",
"copy_photo": "Kopiraj fotografijo",
"sign_in": "Prijava",
- "sign_up": "Registracija",
+ "sign_up": "Ustvari račun",
"see_more": "Pokaži več",
"preview": "Predogled",
"share": "Deli",
@@ -218,10 +218,16 @@
"get_started": "Začnite",
"log_in": "Prijava"
},
+ "login": {
+ "title": "Dobrodošli nazaj",
+ "subtitle": "Prijavite se na strežniku, na katerem ste ustvarili račun.",
+ "server_search_field": {
+ "placeholder": "Vnesite URL ali poiščite svoj strežnik"
+ }
+ },
"server_picker": {
"title": "Mastodon tvorijo uporabniki z različnih strežnikov.",
- "subtitle": "Strežnik izberite glede na svoje interese, regijo ali pa izberite splošnega.",
- "subtitle_extend": "Strežnik izberite glede na svoje interese, regijo ali pa izberite splošnega. Z vsakim strežnikom upravlja povsem neodvisna organizacija ali posameznik.",
+ "subtitle": "Strežnik izberite glede na svojo regijo, zanimanje ali pa kar splošno. Še vedno lahko klepetate s komer koli na Mastodonu, ne glede na strežnik.",
"button": {
"category": {
"all": "Vse",
@@ -248,8 +254,7 @@
"category": "KATEGORIJA"
},
"input": {
- "placeholder": "Išči strežnike",
- "search_servers_or_enter_url": "Iščite strežnike ali vnesite URL"
+ "search_servers_or_enter_url": "Iščite po skupnostih ali vnesite URL"
},
"empty_state": {
"finding_servers": "Iskanje razpoložljivih strežnikov ...",
@@ -383,10 +388,12 @@
"attachment_broken": "To %s je okvarjeno in ga ni\nmožno naložiti v Mastodon.",
"description_photo": "Opiši fotografijo za slabovidne in osebe z okvaro vida ...",
"description_video": "Opiši video za slabovidne in osebe z okvaro vida ...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "Nalaganje ni uspelo",
+ "upload_failed": "Nalaganje na strežnik ni uspelo",
+ "can_not_recognize_this_media_attachment": "Te medijske priponke ni mogoče prepoznati",
+ "attachment_too_large": "Priponka je prevelika",
+ "compressing_state": "Stiskanje ...",
+ "server_processing_state": "Obdelovanje na strežniku ..."
},
"poll": {
"duration_time": "Trajanje: %s",
@@ -396,7 +403,9 @@
"one_day": "1 dan",
"three_days": "3 dni",
"seven_days": "7 dni",
- "option_number": "Možnost %ld"
+ "option_number": "Možnost %ld",
+ "the_poll_is_invalid": "Anketa je neveljavna",
+ "the_poll_has_empty_option": "Anketa ima prazno izbiro"
},
"content_warning": {
"placeholder": "Tukaj zapišite opozorilo ..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Izbirnik čustvenčkov po meri",
"enable_content_warning": "Omogoči opozorilo o vsebini",
"disable_content_warning": "Onemogoči opozorilo o vsebini",
- "post_visibility_menu": "Meni vidnosti objave"
+ "post_visibility_menu": "Meni vidnosti objave",
+ "post_options": "Možnosti objave",
+ "posting_as": "Objavljate kot %s"
},
"keyboard": {
"discard_post": "Opusti objavo",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Oznaka",
"content": "Vsebina"
+ },
+ "verified": {
+ "short": "Preverjeno %s",
+ "long": "Lastništvo te povezave je bilo preverjeno %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict
index c7317903d..3cbfeae6d 100644
--- a/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld tecken
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ kvar
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ %ld tecken
+ other
+ %ld tecken
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/sv.lproj/app.json b/Localization/StringsConvertor/input/sv.lproj/app.json
index c740609c9..7951e1958 100644
--- a/Localization/StringsConvertor/input/sv.lproj/app.json
+++ b/Localization/StringsConvertor/input/sv.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Spara foto",
"copy_photo": "Kopiera foto",
"sign_in": "Logga in",
- "sign_up": "Registrera dig",
+ "sign_up": "Skapa konto",
"see_more": "Visa mer",
"preview": "Förhandsvisa",
"share": "Dela",
@@ -218,10 +218,16 @@
"get_started": "Kom igång",
"log_in": "Logga in"
},
+ "login": {
+ "title": "Välkommen tillbaka",
+ "subtitle": "Logga in på servern där du skapade ditt konto.",
+ "server_search_field": {
+ "placeholder": "Ange URL eller sök efter din server"
+ }
+ },
"server_picker": {
"title": "Mastodon utgörs av användare på olika servrar.",
- "subtitle": "Välj en server baserat på dina intressen, region eller ett allmänt syfte.",
- "subtitle_extend": "Välj en server baserat på dina intressen, region eller ett allmänt syfte. Varje server drivs av en helt oberoende organisation eller individ.",
+ "subtitle": "Välj en server baserat på dina intressen, region eller en allmän server. Du kan fortfarande nå alla, oavsett server.",
"button": {
"category": {
"all": "Alla",
@@ -248,8 +254,7 @@
"category": "KATEGORI"
},
"input": {
- "placeholder": "Sök gemenskaper",
- "search_servers_or_enter_url": "Sök servrar eller ange URL"
+ "search_servers_or_enter_url": "Sök gemenskaper eller ange URL"
},
"empty_state": {
"finding_servers": "Söker tillgängliga servrar...",
@@ -386,7 +391,9 @@
"load_failed": "Det gick inte att läsa in",
"upload_failed": "Uppladdning misslyckades",
"can_not_recognize_this_media_attachment": "Känner inte igen mediebilagan",
- "attachment_too_large": "Bilagan är för stor"
+ "attachment_too_large": "Bilagan är för stor",
+ "compressing_state": "Komprimerar...",
+ "server_processing_state": "Behandlas av servern..."
},
"poll": {
"duration_time": "Längd: %s",
@@ -396,7 +403,9 @@
"one_day": "1 dag",
"three_days": "3 dagar",
"seven_days": "7 dagar",
- "option_number": "Alternativ %ld"
+ "option_number": "Alternativ %ld",
+ "the_poll_is_invalid": "Undersökningen är ogiltig",
+ "the_poll_has_empty_option": "Undersökningen har ett tomt alternativ"
},
"content_warning": {
"placeholder": "Skriv en noggrann varning här..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Anpassad emoji-väljare",
"enable_content_warning": "Aktivera innehållsvarning",
"disable_content_warning": "Inaktivera innehållsvarning",
- "post_visibility_menu": "Inläggssynlighetsmeny"
+ "post_visibility_menu": "Inläggssynlighetsmeny",
+ "post_options": "Inläggsalternativ",
+ "posting_as": "Postar som %s"
},
"keyboard": {
"discard_post": "Släng inlägget",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Etikett",
"content": "Innehåll"
+ },
+ "verified": {
+ "short": "Verifierad på %s",
+ "long": "Ägarskap för denna länk kontrollerades den %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/th.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/th.lproj/Localizable.stringsdict
index 897d07eca..f25561ad6 100644
--- a/Localization/StringsConvertor/input/th.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/th.lproj/Localizable.stringsdict
@@ -44,6 +44,20 @@
%ld ตัวอักษร
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ เหลืออีก %#@character_count@
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+ %ld ตัวอักษร
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/th.lproj/app.json b/Localization/StringsConvertor/input/th.lproj/app.json
index 9b4316025..7b1a3d08e 100644
--- a/Localization/StringsConvertor/input/th.lproj/app.json
+++ b/Localization/StringsConvertor/input/th.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "ถ่ายรูป",
"save_photo": "บันทึกรูปภาพ",
"copy_photo": "คัดลอกรูปภาพ",
- "sign_in": "ลงชื่อเข้า",
- "sign_up": "ลงทะเบียน",
+ "sign_in": "เข้าสู่ระบบ",
+ "sign_up": "สร้างบัญชี",
"see_more": "ดูเพิ่มเติม",
"preview": "แสดงตัวอย่าง",
"share": "แบ่งปัน",
@@ -218,10 +218,16 @@
"get_started": "เริ่มต้นใช้งาน",
"log_in": "เข้าสู่ระบบ"
},
+ "login": {
+ "title": "ยินดีต้อนรับกลับมา",
+ "subtitle": "นำคุณเข้าสู่ระบบในเซิร์ฟเวอร์ที่คุณได้สร้างบัญชีของคุณไว้ใน",
+ "server_search_field": {
+ "placeholder": "ป้อน URL หรือค้นหาสำหรับเซิร์ฟเวอร์ของคุณ"
+ }
+ },
"server_picker": {
"title": "Mastodon ประกอบด้วยผู้ใช้ในเซิร์ฟเวอร์ต่าง ๆ",
- "subtitle": "เลือกเซิร์ฟเวอร์ตามความสนใจ, ภูมิภาค หรือวัตถุประสงค์ทั่วไปของคุณ",
- "subtitle_extend": "เลือกเซิร์ฟเวอร์ตามความสนใจ, ภูมิภาค หรือวัตถุประสงค์ทั่วไปของคุณ แต่ละเซิร์ฟเวอร์ได้รับการดำเนินงานโดยองค์กรหรือบุคคลที่เป็นอิสระโดยสิ้นเชิง",
+ "subtitle": "เลือกเซิร์ฟเวอร์ตามภูมิภาค, ความสนใจ หรือวัตถุประสงค์ทั่วไปของคุณ คุณยังคงสามารถแชทกับใครก็ตามใน Mastodon โดยไม่คำนึงถึงเซิร์ฟเวอร์ของคุณ",
"button": {
"category": {
"all": "ทั้งหมด",
@@ -248,8 +254,7 @@
"category": "หมวดหมู่"
},
"input": {
- "placeholder": "ค้นหาเซิร์ฟเวอร์",
- "search_servers_or_enter_url": "ค้นหาเซิร์ฟเวอร์หรือป้อน URL"
+ "search_servers_or_enter_url": "ค้นหาชุมชนหรือป้อน URL"
},
"empty_state": {
"finding_servers": "กำลังค้นหาเซิร์ฟเวอร์ที่พร้อมใช้งาน...",
@@ -299,7 +304,7 @@
},
"reason": {
"blocked": "%s มีผู้ให้บริการอีเมลที่ไม่ได้รับอนุญาต",
- "unreachable": "ดูเหมือนว่า %s จะไม่มีอยู่",
+ "unreachable": "ดูเหมือนว่าจะไม่มี %s อยู่",
"taken": "%s ถูกใช้งานแล้ว",
"reserved": "%s เป็นคำสงวน",
"accepted": "ต้องยอมรับ %s",
@@ -337,12 +342,12 @@
},
"dont_receive_email": {
"title": "ตรวจสอบอีเมลของคุณ",
- "description": "หากคุณยังไม่ได้รับอีเมล ตรวจสอบว่าที่อยู่อีเมลของคุณถูกต้อง รวมถึงโฟลเดอร์อีเมลขยะของคุณ",
+ "description": "ตรวจสอบว่าที่อยู่อีเมลของคุณถูกต้องเช่นเดียวกับโฟลเดอร์อีเมลขยะหากคุณยังไม่ได้ทำ",
"resend_email": "ส่งอีเมลใหม่"
},
"open_email_app": {
"title": "ตรวจสอบกล่องขาเข้าของคุณ",
- "description": "เราเพิ่งส่งอีเมลหาคุณ หากคุณยังไม่ได้รับอีเมล โปรดตรวจสอบโฟลเดอร์อีเมลขยะ",
+ "description": "เราเพิ่งส่งอีเมลถึงคุณ ตรวจสอบโฟลเดอร์อีเมลขยะของคุณหากคุณยังไม่ได้ทำ",
"mail": "จดหมาย",
"open_email_client": "เปิดไคลเอ็นต์อีเมล"
}
@@ -385,8 +390,10 @@
"description_video": "อธิบายวิดีโอสำหรับผู้บกพร่องทางการมองเห็น...",
"load_failed": "การโหลดล้มเหลว",
"upload_failed": "การอัปโหลดล้มเหลว",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "ไฟล์แนบใหญ่เกินไป"
+ "can_not_recognize_this_media_attachment": "ไม่สามารถระบุไฟล์แนบสื่อนี้",
+ "attachment_too_large": "ไฟล์แนบใหญ่เกินไป",
+ "compressing_state": "กำลังบีบอัด...",
+ "server_processing_state": "เซิร์ฟเวอร์กำลังประมวลผล..."
},
"poll": {
"duration_time": "ระยะเวลา: %s",
@@ -396,7 +403,9 @@
"one_day": "1 วัน",
"three_days": "3 วัน",
"seven_days": "7 วัน",
- "option_number": "ตัวเลือก %ld"
+ "option_number": "ตัวเลือก %ld",
+ "the_poll_is_invalid": "การสำรวจความคิดเห็นไม่ถูกต้อง",
+ "the_poll_has_empty_option": "การสำรวจความคิดเห็นมีตัวเลือกที่ว่างเปล่า"
},
"content_warning": {
"placeholder": "เขียนคำเตือนที่ถูกต้องที่นี่..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "ตัวเลือกอีโมจิที่กำหนดเอง",
"enable_content_warning": "เปิดใช้งานคำเตือนเนื้อหา",
"disable_content_warning": "ปิดใช้งานคำเตือนเนื้อหา",
- "post_visibility_menu": "เมนูการมองเห็นโพสต์"
+ "post_visibility_menu": "เมนูการมองเห็นโพสต์",
+ "post_options": "ตัวเลือกโพสต์",
+ "posting_as": "กำลังโพสต์เป็น %s"
},
"keyboard": {
"discard_post": "ละทิ้งโพสต์",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "ป้ายชื่อ",
"content": "เนื้อหา"
+ },
+ "verified": {
+ "short": "ตรวจสอบเมื่อ %s",
+ "long": "ตรวจสอบความเป็นเจ้าของของลิงก์นี้เมื่อ %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict
index 29df92c2b..6ef7f4c75 100644
--- a/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict
@@ -50,6 +50,22 @@
%ld karakter
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/tr.lproj/app.json b/Localization/StringsConvertor/input/tr.lproj/app.json
index 2abb92845..37325cf05 100644
--- a/Localization/StringsConvertor/input/tr.lproj/app.json
+++ b/Localization/StringsConvertor/input/tr.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Fotoğraf Çek",
"save_photo": "Fotoğrafı Kaydet",
"copy_photo": "Fotoğrafı Kopyala",
- "sign_in": "Giriş Yap",
- "sign_up": "Kaydol",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "Daha Fazla Gör",
"preview": "Önizleme",
"share": "Paylaş",
@@ -218,10 +218,16 @@
"get_started": "Başlayın",
"log_in": "Oturum Aç"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon, farklı topluluklardaki kullanıcılardan oluşur.",
- "subtitle": "İlgi alanlarınıza, bölgenize veya genel amaçlı bir topluluk seçin.",
- "subtitle_extend": "İlgi alanlarınıza, bölgenize veya genel amaçlı bir topluluk seçin. Her topluluk tamamen bağımsız bir kuruluş veya kişi tarafından işletilmektedir.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "Tümü",
@@ -248,8 +254,7 @@
"category": "KATEGORİ"
},
"input": {
- "placeholder": "Toplulukları ara",
- "search_servers_or_enter_url": "Sunucuları ara ya da bir bağlantı gir"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Mevcut sunucular aranıyor...",
@@ -385,8 +390,10 @@
"description_video": "Görme engelliler için videoyu tarif edin...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Süre: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Gün",
"three_days": "3 Gün",
"seven_days": "7 Gün",
- "option_number": "Seçenek %ld"
+ "option_number": "Seçenek %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Buraya kesin bir uyarı yazın..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Özel Emoji Seçici",
"enable_content_warning": "İçerik Uyarısını Etkinleştir",
"disable_content_warning": "İçerik Uyarısını Kapat",
- "post_visibility_menu": "Gönderi Görünürlüğü Menüsü"
+ "post_visibility_menu": "Gönderi Görünürlüğü Menüsü",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Gönderiyi İptal Et",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Etiket",
"content": "İçerik"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict
index cdf35477e..32e4cf9aa 100644
--- a/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict
@@ -62,6 +62,26 @@
%ld characters
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ left
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ one
+ 1 character
+ few
+ %ld characters
+ many
+ %ld characters
+ other
+ %ld characters
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/uk.lproj/app.json b/Localization/StringsConvertor/input/uk.lproj/app.json
index a6a971860..3113ada74 100644
--- a/Localization/StringsConvertor/input/uk.lproj/app.json
+++ b/Localization/StringsConvertor/input/uk.lproj/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -385,8 +390,10 @@
"description_video": "Describe the video for the visually-impaired...",
"load_failed": "Load Failed",
"upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "can_not_recognize_this_media_attachment": "Can not recognize this media attachment",
+ "attachment_too_large": "Attachment too large",
+ "compressing_state": "Compressing...",
+ "server_processing_state": "Server Processing..."
},
"poll": {
"duration_time": "Duration: %s",
@@ -396,7 +403,9 @@
"one_day": "1 Day",
"three_days": "3 Days",
"seven_days": "7 Days",
- "option_number": "Option %ld"
+ "option_number": "Option %ld",
+ "the_poll_is_invalid": "The poll is invalid",
+ "the_poll_has_empty_option": "The poll has empty option"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Custom Emoji Picker",
"enable_content_warning": "Enable Content Warning",
"disable_content_warning": "Disable Content Warning",
- "post_visibility_menu": "Post Visibility Menu"
+ "post_visibility_menu": "Post Visibility Menu",
+ "post_options": "Post Options",
+ "posting_as": "Posting as %s"
},
"keyboard": {
"discard_post": "Discard Post",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Label",
"content": "Content"
+ },
+ "verified": {
+ "short": "Verified on %s",
+ "long": "Ownership of this link was checked on %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/vi.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/vi.lproj/Localizable.stringsdict
index 6905b240e..4c772f014 100644
--- a/Localization/StringsConvertor/input/vi.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/vi.lproj/Localizable.stringsdict
@@ -44,6 +44,20 @@
%ld ký tự
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ còn lại
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+ %ld ký tự
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/vi.lproj/app.json b/Localization/StringsConvertor/input/vi.lproj/app.json
index 5b7696727..963be39c9 100644
--- a/Localization/StringsConvertor/input/vi.lproj/app.json
+++ b/Localization/StringsConvertor/input/vi.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "Lưu ảnh",
"copy_photo": "Sao chép ảnh",
"sign_in": "Đăng nhập",
- "sign_up": "Đăng ký",
+ "sign_up": "Tạo tài khoản",
"see_more": "Xem thêm",
"preview": "Xem trước",
"share": "Chia sẻ",
@@ -218,10 +218,16 @@
"get_started": "Bắt đầu",
"log_in": "Đăng nhập"
},
+ "login": {
+ "title": "Chào mừng trở lại!",
+ "subtitle": "Đăng nhập vào máy chủ mà bạn đã tạo tài khoản.",
+ "server_search_field": {
+ "placeholder": "Nhập URL hoặc tìm máy chủ"
+ }
+ },
"server_picker": {
"title": "Mastodon gồm nhiều máy chủ với thành viên riêng.",
- "subtitle": "Chọn một máy chủ dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn.",
- "subtitle_extend": "Chọn một máy chủ dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn. Mỗi máy chủ có thể được vận hành bởi một cá nhân hoặc một tổ chức.",
+ "subtitle": "Chọn một máy chủ dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn. Bạn vẫn có thể giao tiếp với bất cứ ai mà không phụ thuộc vào máy chủ của họ.",
"button": {
"category": {
"all": "Toàn bộ",
@@ -248,8 +254,7 @@
"category": "PHÂN LOẠI"
},
"input": {
- "placeholder": "Tìm máy chủ",
- "search_servers_or_enter_url": "Tìm máy chủ hoặc nhập URL"
+ "search_servers_or_enter_url": "Tìm một máy chủ hoặc nhập URL"
},
"empty_state": {
"finding_servers": "Đang tìm máy chủ hoạt động...",
@@ -383,10 +388,12 @@
"attachment_broken": "%s này bị lỗi và không thể\ntải lên Mastodon.",
"description_photo": "Mô tả hình ảnh cho người khiếm thị...",
"description_video": "Mô tả video cho người khiếm thị...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "Tải thất bại",
+ "upload_failed": "Tải lên thất bại",
+ "can_not_recognize_this_media_attachment": "Không xem được tập tin đính kèm",
+ "attachment_too_large": "Tập tin đính kèm quá lớn",
+ "compressing_state": "Đang nén...",
+ "server_processing_state": "Máy chủ đang xử lý..."
},
"poll": {
"duration_time": "Thời hạn: %s",
@@ -396,7 +403,9 @@
"one_day": "1 ngày",
"three_days": "3 ngày",
"seven_days": "7 ngày",
- "option_number": "Lựa chọn %ld"
+ "option_number": "Lựa chọn %ld",
+ "the_poll_is_invalid": "Bình chọn không hợp lệ",
+ "the_poll_has_empty_option": "Thiếu lựa chọn"
},
"content_warning": {
"placeholder": "Viết nội dung ẩn của bạn ở đây..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "Chọn emoji",
"enable_content_warning": "Bật nội dung ẩn",
"disable_content_warning": "Tắt nội dung ẩn",
- "post_visibility_menu": "Menu hiển thị tút"
+ "post_visibility_menu": "Menu hiển thị tút",
+ "post_options": "Tùy chọn đăng",
+ "posting_as": "Đăng dưới dạng %s"
},
"keyboard": {
"discard_post": "Hủy đăng tút",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "Nhãn",
"content": "Nội dung"
+ },
+ "verified": {
+ "short": "Đã xác minh %s",
+ "long": "Liên kết này đã được xác minh trên %s"
}
},
"segmented_control": {
diff --git a/Localization/StringsConvertor/input/zh-Hans.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/zh-Hans.lproj/Localizable.stringsdict
index 5a7af3752..362d55c4f 100644
--- a/Localization/StringsConvertor/input/zh-Hans.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/zh-Hans.lproj/Localizable.stringsdict
@@ -44,6 +44,20 @@
%ld 个字符
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ %#@character_count@ 剩余
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+ %ld 个字符
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/zh-Hans.lproj/app.json b/Localization/StringsConvertor/input/zh-Hans.lproj/app.json
index ddf89e159..c503c5186 100644
--- a/Localization/StringsConvertor/input/zh-Hans.lproj/app.json
+++ b/Localization/StringsConvertor/input/zh-Hans.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "保存照片",
"copy_photo": "拷贝照片",
"sign_in": "登录",
- "sign_up": "注册",
+ "sign_up": "创建账户",
"see_more": "查看更多",
"preview": "预览",
"share": "分享",
@@ -137,10 +137,10 @@
"closed": "已关闭"
},
"meta_entity": {
- "url": "Link: %s",
- "hashtag": "Hashtag: %s",
- "mention": "Show Profile: %s",
- "email": "Email address: %s"
+ "url": "链接:%s",
+ "hashtag": "话题:%s",
+ "mention": "显示用户资料:%s",
+ "email": "邮箱地址:%s"
},
"actions": {
"reply": "回复",
@@ -187,8 +187,8 @@
"unmute_user": "取消静音 %s",
"muted": "已静音",
"edit_info": "编辑",
- "show_reblogs": "Show Reblogs",
- "hide_reblogs": "Hide Reblogs"
+ "show_reblogs": "显示转发",
+ "hide_reblogs": "隐藏转发"
},
"timeline": {
"filtered": "已过滤",
@@ -218,10 +218,16 @@
"get_started": "开始使用",
"log_in": "登录"
},
+ "login": {
+ "title": "欢迎回来",
+ "subtitle": "登入您账户所在的服务器。",
+ "server_search_field": {
+ "placeholder": "输入网址或搜索您的服务器"
+ }
+ },
"server_picker": {
"title": "挑选一个服务器,\n任意服务器。",
- "subtitle": "根据你的兴趣、区域或一般目的选择一个社区。",
- "subtitle_extend": "根据你的兴趣、区域或一般目的选择一个社区。每个社区都由完全独立的组织或个人管理。",
+ "subtitle": "根据你的地区、兴趣挑选一个服务器。无论你选择哪个服务器,你都可以跟其他服务器的任何人一起聊天。",
"button": {
"category": {
"all": "全部",
@@ -248,8 +254,7 @@
"category": "类别"
},
"input": {
- "placeholder": "查找或加入你自己的服务器...",
- "search_servers_or_enter_url": "搜索服务器或输入 URL"
+ "search_servers_or_enter_url": "搜索社区或输入 URL"
},
"empty_state": {
"finding_servers": "正在查找可用的服务器...",
@@ -383,10 +388,12 @@
"attachment_broken": "%s已损坏\n无法上传到 Mastodon",
"description_photo": "为视觉障碍人士添加照片的文字说明...",
"description_video": "为视觉障碍人士添加视频的文字说明...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "加载失败",
+ "upload_failed": "上传失败",
+ "can_not_recognize_this_media_attachment": "无法识别此媒体",
+ "attachment_too_large": "附件太大",
+ "compressing_state": "压缩中...",
+ "server_processing_state": "服务器正在处理..."
},
"poll": {
"duration_time": "时长:%s",
@@ -396,7 +403,9 @@
"one_day": "1 天",
"three_days": "3 天",
"seven_days": "7 天",
- "option_number": "选项 %ld"
+ "option_number": "选项 %ld",
+ "the_poll_is_invalid": "投票无效",
+ "the_poll_has_empty_option": "投票含有空选项"
},
"content_warning": {
"placeholder": "在这里写下内容的警告消息..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "自定义表情选择器",
"enable_content_warning": "启用内容警告",
"disable_content_warning": "关闭内容警告",
- "post_visibility_menu": "帖子可见性"
+ "post_visibility_menu": "帖子可见性",
+ "post_options": "帖子选项",
+ "posting_as": "以 %s 身份发布"
},
"keyboard": {
"discard_post": "丢弃帖子",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "标签",
"content": "内容"
+ },
+ "verified": {
+ "short": "验证于 %s",
+ "long": "此链接的所有权已在 %s 上检查通过"
}
},
"segmented_control": {
@@ -469,12 +484,12 @@
"message": "确认取消屏蔽 %s"
},
"confirm_show_reblogs": {
- "title": "Show Reblogs",
- "message": "Confirm to show reblogs"
+ "title": "显示转发",
+ "message": "确认显示转发"
},
"confirm_hide_reblogs": {
- "title": "Hide Reblogs",
- "message": "Confirm to hide reblogs"
+ "title": "隐藏转发",
+ "message": "确认隐藏转发"
}
},
"accessibility": {
@@ -706,7 +721,7 @@
"accessibility_hint": "双击关闭此向导"
},
"bookmark": {
- "title": "Bookmarks"
+ "title": "书签"
}
}
}
diff --git a/Localization/StringsConvertor/input/zh-Hant.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/zh-Hant.lproj/Localizable.stringsdict
index c0ce0f9a2..d545fd6a4 100644
--- a/Localization/StringsConvertor/input/zh-Hant.lproj/Localizable.stringsdict
+++ b/Localization/StringsConvertor/input/zh-Hant.lproj/Localizable.stringsdict
@@ -44,6 +44,20 @@
%ld 個字
+ a11y.plural.count.characters_left
+
+ NSStringLocalizedFormatKey
+ 剩餘 %#@character_count@ 字
+ character_count
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ ld
+ other
+ %ld 個字
+
+
plural.count.followed_by_and_mutual
NSStringLocalizedFormatKey
diff --git a/Localization/StringsConvertor/input/zh-Hant.lproj/app.json b/Localization/StringsConvertor/input/zh-Hant.lproj/app.json
index ab7343c99..e2dfaad64 100644
--- a/Localization/StringsConvertor/input/zh-Hant.lproj/app.json
+++ b/Localization/StringsConvertor/input/zh-Hant.lproj/app.json
@@ -75,7 +75,7 @@
"save_photo": "儲存照片",
"copy_photo": "複製照片",
"sign_in": "登入",
- "sign_up": "註冊",
+ "sign_up": "新增帳號",
"see_more": "檢視更多",
"preview": "預覽",
"share": "分享",
@@ -218,10 +218,16 @@
"get_started": "新手上路",
"log_in": "登入"
},
+ "login": {
+ "title": "歡迎回來",
+ "subtitle": "登入您新增帳號之伺服器",
+ "server_search_field": {
+ "placeholder": "請輸入 URL 或搜尋您的伺服器"
+ }
+ },
"server_picker": {
"title": "Mastodon 由不同伺服器的使用者組成。",
- "subtitle": "基於您的興趣、地區、或一般用途選定一個伺服器。",
- "subtitle_extend": "基於您的興趣、地區、或一般用途選定一個伺服器。每個伺服器是由完全獨立的組織或個人營運。",
+ "subtitle": "基於您的興趣、地區、或一般用途選定一個伺服器。您仍會與任何伺服器中的每個人連結。",
"button": {
"category": {
"all": "全部",
@@ -248,8 +254,7 @@
"category": "分類"
},
"input": {
- "placeholder": "搜尋伺服器",
- "search_servers_or_enter_url": "搜尋伺服器或輸入網址"
+ "search_servers_or_enter_url": "搜尋社群或輸入 URL 地址"
},
"empty_state": {
"finding_servers": "尋找可用的伺服器...",
@@ -383,10 +388,12 @@
"attachment_broken": "此 %s 已損毀,並無法被上傳至 Mastodon。",
"description_photo": "為視障人士提供圖片說明...",
"description_video": "為視障人士提供影片說明...",
- "load_failed": "Load Failed",
- "upload_failed": "Upload Failed",
- "can_not_recognize_this_media_attachment": "Can not regonize this media attachment",
- "attachment_too_large": "Attachment too large"
+ "load_failed": "讀取失敗",
+ "upload_failed": "上傳失敗",
+ "can_not_recognize_this_media_attachment": "無法識別此媒體附加檔案",
+ "attachment_too_large": "附加檔案大小過大",
+ "compressing_state": "正在壓縮...",
+ "server_processing_state": "伺服器處理中..."
},
"poll": {
"duration_time": "持續時間:%s",
@@ -396,7 +403,9 @@
"one_day": "一天",
"three_days": "三天",
"seven_days": "七天",
- "option_number": "選項 %ld"
+ "option_number": "選項 %ld",
+ "the_poll_is_invalid": "此投票是無效的",
+ "the_poll_has_empty_option": "此投票有空白選項"
},
"content_warning": {
"placeholder": "請於此處寫下精準的警告..."
@@ -417,7 +426,9 @@
"custom_emoji_picker": "自訂 emoji 選擇器",
"enable_content_warning": "啟用內容警告",
"disable_content_warning": "停用內容警告",
- "post_visibility_menu": "嘟文可見性選單"
+ "post_visibility_menu": "嘟文可見性選單",
+ "post_options": "嘟文選項",
+ "posting_as": "以 %s 發嘟"
},
"keyboard": {
"discard_post": "捨棄嘟文",
@@ -442,6 +453,10 @@
"placeholder": {
"label": "標籤",
"content": "內容"
+ },
+ "verified": {
+ "short": "於 %s 上已驗證",
+ "long": "已在 %s 檢查此連結的擁有者權限"
}
},
"segmented_control": {
diff --git a/Localization/app.json b/Localization/app.json
index f90b2bef6..ea046bfbc 100644
--- a/Localization/app.json
+++ b/Localization/app.json
@@ -74,8 +74,8 @@
"take_photo": "Take Photo",
"save_photo": "Save Photo",
"copy_photo": "Copy Photo",
- "sign_in": "Sign In",
- "sign_up": "Sign Up",
+ "sign_in": "Log in",
+ "sign_up": "Create account",
"see_more": "See More",
"preview": "Preview",
"share": "Share",
@@ -218,10 +218,16 @@
"get_started": "Get Started",
"log_in": "Log In"
},
+ "login": {
+ "title": "Welcome back",
+ "subtitle": "Log you in on the server you created your account on.",
+ "server_search_field": {
+ "placeholder": "Enter URL or search for your server"
+ }
+ },
"server_picker": {
"title": "Mastodon is made of users in different servers.",
- "subtitle": "Pick a server based on your interests, region, or a general purpose one.",
- "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.",
+ "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.",
"button": {
"category": {
"all": "All",
@@ -248,8 +254,7 @@
"category": "CATEGORY"
},
"input": {
- "placeholder": "Search servers",
- "search_servers_or_enter_url": "Search servers or enter URL"
+ "search_servers_or_enter_url": "Search communities or enter URL"
},
"empty_state": {
"finding_servers": "Finding available servers...",
@@ -719,4 +724,4 @@
"title": "Bookmarks"
}
}
-}
\ No newline at end of file
+}
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index 434926d94..0c43b71df 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -23,6 +23,8 @@
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; };
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
+ 2A82294F29262EE000D2A1F7 /* AppContext+NextAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */; };
+ 2AE244482927831100BDBF7C /* UIImage+SFSymbols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */; };
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198642261BF09500F0B013 /* SearchResultItem.swift */; };
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198648261C0B8500F0B013 /* SearchResultSection.swift */; };
2D206B8625F5FB0900143C56 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D206B8525F5FB0900143C56 /* Double.swift */; };
@@ -87,6 +89,12 @@
62FD27D32893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D22893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift */; };
62FD27D52893708A00B205C5 /* BookmarkViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D42893708A00B205C5 /* BookmarkViewModel+Diffable.swift */; };
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */; };
+ C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24C97022922F30500BAE8CB /* RefreshControl.swift */; };
+ D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */; };
+ D87BFC8D291EB81200FEE264 /* MastodonLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */; };
+ D87BFC8F291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */; };
+ D8916DC029211BE500124085 /* ContentSizedTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8916DBF29211BE500124085 /* ContentSizedTableView.swift */; };
+ D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */; };
DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; };
DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; };
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; };
@@ -512,6 +520,8 @@
0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = ""; };
164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = ""; };
1D6D967E77A5357E2C6110D9 /* Pods-Mastodon.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - debug.xcconfig"; sourceTree = ""; };
+ 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppContext+NextAccount.swift"; sourceTree = ""; };
+ 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SFSymbols.swift"; sourceTree = ""; };
2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = ""; };
2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = ""; };
2D206B8525F5FB0900143C56 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = ""; };
@@ -603,9 +613,15 @@
B44342AC2B6585F8295F1DDF /* Pods-Mastodon-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-Mastodon-NotificationService/Pods-Mastodon-NotificationService.release.xcconfig"; sourceTree = ""; };
BB482D32A7B9825BF5327C4F /* Pods-Mastodon-MastodonUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.release.xcconfig"; sourceTree = ""; };
BD7598A87F4497045EDEF252 /* Pods-Mastodon.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - release.xcconfig"; sourceTree = ""; };
+ C24C97022922F30500BAE8CB /* RefreshControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshControl.swift; sourceTree = ""; };
C3789232A52F43529CA67E95 /* Pods-MastodonIntent.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - debug.xcconfig"; sourceTree = ""; };
CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D7D7CF93E262178800077512 /* Pods-Mastodon-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.debug.xcconfig"; sourceTree = ""; };
+ D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginView.swift; sourceTree = ""; };
+ D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginViewModel.swift; sourceTree = ""; };
+ D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginServerTableViewCell.swift; sourceTree = ""; };
+ D8916DBF29211BE500124085 /* ContentSizedTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSizedTableView.swift; sourceTree = ""; };
+ D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginViewController.swift; sourceTree = ""; };
DB0009A826AEE5DC009B9D2D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = ""; };
DB0009AD26AEE5E4009B9D2D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Intents.strings; sourceTree = ""; };
DB0140CE25C42AEE00F9F3CF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; };
@@ -630,7 +646,6 @@
DB0618022785A7100030EE79 /* RegisterSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterSection.swift; sourceTree = ""; };
DB0618042785A73D0030EE79 /* RegisterItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterItem.swift; sourceTree = ""; };
DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonRegisterViewModel+Diffable.swift"; sourceTree = ""; };
- DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterAvatarTableViewCell.swift; sourceTree = ""; };
DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryIntroBannerView.swift; sourceTree = ""; };
DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAvatarButton.swift; sourceTree = ""; };
DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListCollectionViewCell.swift; sourceTree = ""; };
@@ -853,8 +868,6 @@
DB7A9F922818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonServerRulesViewController+Debug.swift"; sourceTree = ""; };
DB7F48442620241000796008 /* ProfileHeaderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHeaderViewModel.swift; sourceTree = ""; };
DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentContainerView.swift; sourceTree = ""; };
- DB8481142788121200BBEABA /* MastodonRegisterTextFieldTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterTextFieldTableViewCell.swift; sourceTree = ""; };
- DB84811627883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterPasswordHintTableViewCell.swift; sourceTree = ""; };
DB848E32282B62A800A302CC /* ReportResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultView.swift; sourceTree = ""; };
DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarViewController.swift; sourceTree = ""; };
DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootSplitViewController.swift; sourceTree = ""; };
@@ -886,6 +899,12 @@
DB938F0826240F3C00E5B6C1 /* RemoteThreadViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteThreadViewModel.swift; sourceTree = ""; };
DB938F0E2624119800E5B6C1 /* ThreadViewModel+LoadThreadState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadViewModel+LoadThreadState.swift"; sourceTree = ""; };
DB938F1E2624382F00E5B6C1 /* ThreadViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThreadViewModel+Diffable.swift"; sourceTree = ""; };
+ DB96C25D292505FE00F3B85D /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Intents.strings; sourceTree = ""; };
+ DB96C25E292505FF00F3B85D /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/InfoPlist.strings; sourceTree = ""; };
+ DB96C25F292505FF00F3B85D /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = cs; path = cs.lproj/Intents.stringsdict; sourceTree = ""; };
+ DB96C260292506D600F3B85D /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Intents.strings; sourceTree = ""; };
+ DB96C261292506D700F3B85D /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/InfoPlist.strings; sourceTree = ""; };
+ DB96C262292506D700F3B85D /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sl; path = sl.lproj/Intents.stringsdict; sourceTree = ""; };
DB98EB4627B0DFAA0082E365 /* ReportStatusViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReportStatusViewModel+State.swift"; sourceTree = ""; };
DB98EB4827B0F0CD0082E365 /* ReportStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusTableViewCell.swift; sourceTree = ""; };
DB98EB4B27B0F2BC0082E365 /* ReportStatusTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReportStatusTableViewCell+ViewModel.swift"; sourceTree = ""; };
@@ -1495,9 +1514,22 @@
path = Bookmark;
sourceTree = "";
};
+ D8A6AB68291C50F3003AB663 /* Login */ = {
+ isa = PBXGroup;
+ children = (
+ D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */,
+ D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */,
+ D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */,
+ D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */,
+ D8916DBF29211BE500124085 /* ContentSizedTableView.swift */,
+ );
+ path = Login;
+ sourceTree = "";
+ };
DB01409B25C40BB600F9F3CF /* Onboarding */ = {
isa = PBXGroup;
children = (
+ D8A6AB68291C50F3003AB663 /* Login */,
DB68A03825E900CC00CFDF14 /* Share */,
0FAA0FDD25E0B5700017CCDE /* Welcome */,
0FAA102525E1125D0017CCDE /* PickServer */,
@@ -1562,16 +1594,6 @@
path = Cell;
sourceTree = "";
};
- DB06180B2785B2AF0030EE79 /* Cell */ = {
- isa = PBXGroup;
- children = (
- DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */,
- DB8481142788121200BBEABA /* MastodonRegisterTextFieldTableViewCell.swift */,
- DB84811627883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift */,
- );
- path = Cell;
- sourceTree = "";
- };
DB0A322F280EEA00001729D2 /* View */ = {
isa = PBXGroup;
children = (
@@ -2204,6 +2226,7 @@
isa = PBXGroup;
children = (
2DF123A625C3B0210020F248 /* ActiveLabel.swift */,
+ 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */,
5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */,
2D206B8525F5FB0900143C56 /* Double.swift */,
DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */,
@@ -2223,6 +2246,7 @@
2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */,
2D84350425FF858100EECE90 /* UIScrollView.swift */,
DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */,
+ 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */,
DBCC3B2F261440A50045B23D /* UITabBarController.swift */,
DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */,
DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */,
@@ -2423,6 +2447,7 @@
isa = PBXGroup;
children = (
DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */,
+ C24C97022922F30500BAE8CB /* RefreshControl.swift */,
);
path = Control;
sourceTree = "";
@@ -2537,7 +2562,6 @@
DBE0821A25CD382900FD6BBD /* Register */ = {
isa = PBXGroup;
children = (
- DB06180B2785B2AF0030EE79 /* Cell */,
DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */,
2D939AE725EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift */,
DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */,
@@ -2680,9 +2704,9 @@
DB427DCF25BAA00100D1B89D /* Frameworks */,
DB89BA0825C10FD0008580ED /* Embed Frameworks */,
DBF8AE1B263293E400C9C23C /* Embed Foundation Extensions */,
- DB3D100425BAA71500EAA174 /* ShellScript */,
- DB025B8E278D6448002F581E /* ShellScript */,
- DB697DD2278F48D5004EF2F7 /* ShellScript */,
+ DB3D100425BAA71500EAA174 /* Run SwiftGen */,
+ DB025B8E278D6448002F581E /* Run Sourcery: Core Data */,
+ DB697DD2278F48D5004EF2F7 /* Run Sourcery */,
);
buildRules = (
);
@@ -2860,6 +2884,8 @@
gd,
"es-AR",
fi,
+ cs,
+ sl,
);
mainGroup = DB427DC925BAA00100D1B89D;
packageReferences = (
@@ -2998,7 +3024,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- DB025B8E278D6448002F581E /* ShellScript */ = {
+ DB025B8E278D6448002F581E /* Run Sourcery: Core Data */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 12;
@@ -3008,6 +3034,7 @@
);
inputPaths = (
);
+ name = "Run Sourcery: Core Data";
outputFileListPaths = (
);
outputPaths = (
@@ -3016,7 +3043,7 @@
shellPath = /bin/sh;
shellScript = "if [[ -f \"${PODS_ROOT}/Sourcery/bin/sourcery\" ]]; then\n \"${PODS_ROOT}/Sourcery/bin/sourcery\" --config ./MastodonSDK/Sources/CoreDataStack\nelse\n echo \"warning: Sourcery is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n";
};
- DB3D100425BAA71500EAA174 /* ShellScript */ = {
+ DB3D100425BAA71500EAA174 /* Run SwiftGen */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 12;
@@ -3026,6 +3053,7 @@
);
inputPaths = (
);
+ name = "Run SwiftGen";
outputFileListPaths = (
);
outputPaths = (
@@ -3034,7 +3062,7 @@
shellPath = /bin/sh;
shellScript = "if [[ -f \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" ]]; then\n \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" \nelse\n echo \"warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n";
};
- DB697DD2278F48D5004EF2F7 /* ShellScript */ = {
+ DB697DD2278F48D5004EF2F7 /* Run Sourcery */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 12;
@@ -3044,6 +3072,7 @@
);
inputPaths = (
);
+ name = "Run Sourcery";
outputFileListPaths = (
);
outputPaths = (
@@ -3182,6 +3211,7 @@
DB5B54A32833BD1A00DEF8B2 /* UserListViewModel.swift in Sources */,
DBF156DF2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift in Sources */,
DB0617F1278413D00030EE79 /* PickServerServerSectionTableHeaderView.swift in Sources */,
+ D87BFC8F291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift in Sources */,
DB0FCB7E27958957006C02E2 /* StatusThreadRootTableViewCell+ViewModel.swift in Sources */,
DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */,
DB938F0926240F3C00E5B6C1 /* RemoteThreadViewModel.swift in Sources */,
@@ -3249,6 +3279,7 @@
DB73BF4927140BA300781945 /* UICollectionViewDiffableDataSource.swift in Sources */,
DBA5E7AB263BD3F5004598BB /* TimelineTableViewCellContextMenuConfiguration.swift in Sources */,
DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */,
+ 2AE244482927831100BDBF7C /* UIImage+SFSymbols.swift in Sources */,
DB63F7492799126300455B82 /* FollowerListViewController+DataSourceProvider.swift in Sources */,
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */,
2DAC9E38262FC2320062E1A6 /* SuggestionAccountViewController.swift in Sources */,
@@ -3301,9 +3332,11 @@
DB63F769279A5EBB00455B82 /* NotificationTimelineViewModel+Diffable.swift in Sources */,
DBFEEC9B279BDDD9004F81DD /* ProfileAboutViewModel+Diffable.swift in Sources */,
DBB525562611EDCA002F1F29 /* UserTimelineViewModel.swift in Sources */,
+ D8916DC029211BE500124085 /* ContentSizedTableView.swift in Sources */,
DB0618012785732C0030EE79 /* ServerRulesTableViewCell.swift in Sources */,
DB98EB5C27B10A730082E365 /* ReportSupplementaryViewModel.swift in Sources */,
DB0617EF277F12720030EE79 /* NavigationActionView.swift in Sources */,
+ D87BFC8D291EB81200FEE264 /* MastodonLoginViewModel.swift in Sources */,
DB1FD43625F26899004CFCFC /* MastodonPickServerViewModel+LoadIndexedServerState.swift in Sources */,
2D939AE825EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift in Sources */,
DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */,
@@ -3372,6 +3405,7 @@
DBCC3B8F26148F7B0045B23D /* CachedProfileViewModel.swift in Sources */,
DB4F097526A037F500D62E92 /* SearchHistoryViewModel.swift in Sources */,
DB3EA8E9281B7A3700598866 /* DiscoveryCommunityViewModel.swift in Sources */,
+ D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */,
DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */,
DBEFCD71282A12B200C0ABEA /* ReportReasonViewController.swift in Sources */,
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
@@ -3433,6 +3467,7 @@
DB697DDB278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift in Sources */,
DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */,
DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */,
+ D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */,
DB0FCB8027968F70006C02E2 /* MastodonStatusThreadViewModel.swift in Sources */,
DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */,
DB6746EB278ED8B0008A6B94 /* PollOptionView+Configuration.swift in Sources */,
@@ -3440,6 +3475,7 @@
DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */,
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */,
DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */,
+ 2A82294F29262EE000D2A1F7 /* AppContext+NextAccount.swift in Sources */,
DBB525302611EBF3002F1F29 /* ProfilePagingViewModel.swift in Sources */,
DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */,
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
@@ -3466,6 +3502,7 @@
5BB04FF5262F0E6D0043BFF6 /* ReportSection.swift in Sources */,
DBEFCD82282A2AB100C0ABEA /* ReportServerRulesView.swift in Sources */,
DBA94436265CBB7400C537E1 /* ProfileFieldItem.swift in Sources */,
+ C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */,
DB023D2A27A0FE5C005AC798 /* DataSourceProvider+NotificationTableViewCellDelegate.swift in Sources */,
DB98EB6027B10E150082E365 /* ReportCommentTableViewCell.swift in Sources */,
DB0FCB962797E6C2006C02E2 /* SearchResultViewController+DataSourceProvider.swift in Sources */,
@@ -3589,6 +3626,8 @@
DBC9E3A6282E15190063A4D9 /* gd */,
DBC9E3A9282E17DF0063A4D9 /* es-AR */,
DB8F40042835EE5E006E7513 /* fi */,
+ DB96C25D292505FE00F3B85D /* cs */,
+ DB96C260292506D600F3B85D /* sl */,
);
name = Intents.intentdefinition;
sourceTree = "";
@@ -3620,6 +3659,8 @@
DBC9E3A7282E15190063A4D9 /* gd */,
DBC9E3AA282E17DF0063A4D9 /* es-AR */,
DB8F40052835EE5E006E7513 /* fi */,
+ DB96C25E292505FF00F3B85D /* cs */,
+ DB96C261292506D700F3B85D /* sl */,
);
name = InfoPlist.strings;
sourceTree = "";
@@ -3667,6 +3708,8 @@
DBC9E3A8282E15190063A4D9 /* gd */,
DBC9E3AB282E17DF0063A4D9 /* es-AR */,
DB8F40062835EE5E006E7513 /* fi */,
+ DB96C25F292505FF00F3B85D /* cs */,
+ DB96C262292506D700F3B85D /* sl */,
);
name = Intents.stringsdict;
sourceTree = "";
@@ -3821,7 +3864,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.4.7;
+ MARKETING_VERSION = 1.4.8;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -3850,7 +3893,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.4.7;
+ MARKETING_VERSION = 1.4.8;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4023,7 +4066,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.4.7;
+ MARKETING_VERSION = 1.4.8;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4306,7 +4349,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.4.7;
+ MARKETING_VERSION = 1.4.8;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index 78a3a9e70..b2b5b312a 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -117,12 +117,12 @@
NotificationService.xcscheme_^#shared#^_
orderHint
- 16
+ 17
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 17
+ 16
SuppressBuildableAutocreation
diff --git a/Mastodon/Activity/SafariActivity.swift b/Mastodon/Activity/SafariActivity.swift
index 62a193eaf..e20a9f815 100644
--- a/Mastodon/Activity/SafariActivity.swift
+++ b/Mastodon/Activity/SafariActivity.swift
@@ -58,7 +58,7 @@ final class SafariActivity: UIActivity {
}
Task {
- await sceneCoordinator?.present(scene: .safari(url: url as URL), from: nil, transition: .safariPresent(animated: true, completion: nil))
+ _ = await sceneCoordinator?.present(scene: .safari(url: url as URL), from: nil, transition: .safariPresent(animated: true, completion: nil))
activityDidFinish(true)
}
}
diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift
index 737d74d7e..3d774ba0e 100644
--- a/Mastodon/Coordinator/SceneCoordinator.swift
+++ b/Mastodon/Coordinator/SceneCoordinator.swift
@@ -149,6 +149,7 @@ extension SceneCoordinator {
case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel)
case mastodonResendEmail(viewModel: MastodonResendEmailViewModel)
case mastodonWebView(viewModel: WebViewModel)
+ case mastodonLogin
// search
case searchDetail(viewModel: SearchDetailViewModel)
@@ -199,6 +200,7 @@ extension SceneCoordinator {
case .welcome,
.mastodonPickServer,
.mastodonRegister,
+ .mastodonLogin,
.mastodonServerRules,
.mastodonConfirmEmail,
.mastodonResendEmail:
@@ -403,6 +405,13 @@ private extension SceneCoordinator {
let _viewController = MastodonConfirmEmailViewController()
_viewController.viewModel = viewModel
viewController = _viewController
+ case .mastodonLogin:
+ let loginViewController = MastodonLoginViewController(appContext: appContext,
+ authenticationViewModel: AuthenticationViewModel(context: appContext, coordinator: self, isAuthenticationExist: false),
+ sceneCoordinator: self)
+ loginViewController.delegate = self
+
+ viewController = loginViewController
case .mastodonResendEmail(let viewModel):
let _viewController = MastodonResendEmailViewController()
_viewController.viewModel = viewModel
@@ -529,5 +538,16 @@ private extension SceneCoordinator {
needs?.context = appContext
needs?.coordinator = self
}
-
+}
+
+//MARK: - MastodonLoginViewControllerDelegate
+
+extension SceneCoordinator: MastodonLoginViewControllerDelegate {
+ func backButtonPressed(_ viewController: MastodonLoginViewController) {
+ viewController.navigationController?.popViewController(animated: true)
+ }
+
+ func nextButtonPressed(_ viewController: MastodonLoginViewController) {
+ viewController.login()
+ }
}
diff --git a/Mastodon/Diffable/Onboarding/CategoryPickerSection.swift b/Mastodon/Diffable/Onboarding/CategoryPickerSection.swift
index b53b378d6..191d4d166 100644
--- a/Mastodon/Diffable/Onboarding/CategoryPickerSection.swift
+++ b/Mastodon/Diffable/Onboarding/CategoryPickerSection.swift
@@ -21,7 +21,6 @@ extension CategoryPickerSection {
UICollectionViewDiffableDataSource(collectionView: collectionView) { [weak dependency] collectionView, indexPath, item -> UICollectionViewCell? in
guard let _ = dependency else { return nil }
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: PickServerCategoryCollectionViewCell.self), for: indexPath) as! PickServerCategoryCollectionViewCell
- cell.categoryView.emojiLabel.text = item.emoji
cell.categoryView.titleLabel.text = item.title
cell.observe(\.isSelected, options: [.initial, .new]) { cell, _ in
cell.categoryView.highlightedIndicatorView.alpha = cell.isSelected ? 1 : 0
diff --git a/Mastodon/Diffable/Onboarding/PickServerSection.swift b/Mastodon/Diffable/Onboarding/PickServerSection.swift
index 01a31f6f6..ef7ca5972 100644
--- a/Mastodon/Diffable/Onboarding/PickServerSection.swift
+++ b/Mastodon/Diffable/Onboarding/PickServerSection.swift
@@ -18,16 +18,14 @@ enum PickServerSection: Equatable, Hashable {
extension PickServerSection {
static func tableViewDiffableDataSource(
for tableView: UITableView,
- dependency: NeedsDependency,
- pickServerCellDelegate: PickServerCellDelegate
+ dependency: NeedsDependency
) -> UITableViewDiffableDataSource {
tableView.register(OnboardingHeadlineTableViewCell.self, forCellReuseIdentifier: String(describing: OnboardingHeadlineTableViewCell.self))
tableView.register(PickServerCell.self, forCellReuseIdentifier: String(describing: PickServerCell.self))
tableView.register(PickServerLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: PickServerLoaderTableViewCell.self))
return UITableViewDiffableDataSource(tableView: tableView) { [
- weak dependency,
- weak pickServerCellDelegate
+ weak dependency
] tableView, indexPath, item -> UITableViewCell? in
guard let _ = dependency else { return nil }
switch item {
@@ -37,7 +35,6 @@ extension PickServerSection {
case .server(let server, let attribute):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCell.self), for: indexPath) as! PickServerCell
PickServerSection.configure(cell: cell, server: server, attribute: attribute)
- cell.delegate = pickServerCellDelegate
return cell
case .loader(let attribute):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerLoaderTableViewCell.self), for: indexPath) as! PickServerLoaderTableViewCell
diff --git a/Mastodon/Extension/AppContext+NextAccount.swift b/Mastodon/Extension/AppContext+NextAccount.swift
new file mode 100644
index 000000000..a8eae1e13
--- /dev/null
+++ b/Mastodon/Extension/AppContext+NextAccount.swift
@@ -0,0 +1,47 @@
+//
+// AppContext+NextAccount.swift
+// Mastodon
+//
+// Created by Marcus Kida on 17.11.22.
+//
+
+import CoreData
+import CoreDataStack
+import MastodonCore
+import MastodonSDK
+
+extension AppContext {
+ func nextAccount(in authContext: AuthContext) -> MastodonAuthentication? {
+ let request = MastodonAuthentication.sortedFetchRequest
+ guard
+ let accounts = try? managedObjectContext.fetch(request),
+ accounts.count > 1
+ else { return nil }
+
+ let nextSelectedAccountIndex: Int? = {
+ for (index, account) in accounts.enumerated() {
+ guard account == authContext.mastodonAuthenticationBox
+ .authenticationRecord
+ .object(in: managedObjectContext)
+ else { continue }
+
+ let nextAccountIndex = index + 1
+
+ if accounts.count > nextAccountIndex {
+ return nextAccountIndex
+ } else {
+ return 0
+ }
+ }
+
+ return nil
+ }()
+
+ guard
+ let nextSelectedAccountIndex = nextSelectedAccountIndex,
+ accounts.count > nextSelectedAccountIndex
+ else { return nil }
+
+ return accounts[nextSelectedAccountIndex]
+ }
+}
diff --git a/Mastodon/Extension/String.swift b/Mastodon/Extension/String.swift
index bf70c8937..0aa8acb3a 100644
--- a/Mastodon/Extension/String.swift
+++ b/Mastodon/Extension/String.swift
@@ -15,6 +15,8 @@ extension String {
mutating func capitalizeFirstLetter() {
self = self.capitalizingFirstLetter()
}
+
+ static let empty = ""
}
extension String {
diff --git a/Mastodon/Extension/UIImage+SFSymbols.swift b/Mastodon/Extension/UIImage+SFSymbols.swift
new file mode 100644
index 000000000..cf20055ea
--- /dev/null
+++ b/Mastodon/Extension/UIImage+SFSymbols.swift
@@ -0,0 +1,12 @@
+//
+// UIImage+SFSymbols.swift
+// Mastodon
+//
+// Created by Marcus Kida on 18.11.22.
+//
+
+import UIKit
+
+extension UIImage {
+ static let chevronUpChevronDown = UIImage(systemName: "chevron.up.chevron.down")
+}
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift
index b3812f198..a85de703a 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift
@@ -94,7 +94,7 @@ extension DataSourceFacade {
let alertController = await UIAlertController(for: error, title: nil, preferredStyle: .alert)
let okAction = await UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default)
await alertController.addAction(okAction)
- await dependency.coordinator.present(
+ _ = await dependency.coordinator.present(
scene: .alertController(alertController: alertController),
from: nil,
transition: .alertController(animated: true, completion: nil)
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift
index 43d6b954b..6135c904a 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Hashtag.swift
@@ -35,7 +35,7 @@ extension DataSourceFacade {
hashtag: tag.name
)
- provider.coordinator.present(
+ _ = provider.coordinator.present(
scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel),
from: provider,
transition: .show
@@ -61,7 +61,7 @@ extension DataSourceFacade {
hashtag: name
)
- provider.coordinator.present(
+ _ = provider.coordinator.present(
scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel),
from: provider,
transition: .show
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Media.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Media.swift
index 3e767f2d3..9dd97f38a 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Media.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Media.swift
@@ -24,7 +24,7 @@ extension DataSourceFacade {
item: mediaPreviewItem,
transitionItem: mediaPreviewTransitionItem
)
- dependency.coordinator.present(
+ _ = dependency.coordinator.present(
scene: .mediaPreview(viewModel: mediaPreviewViewModel),
from: dependency,
transition: .custom(transitioningDelegate: dependency.mediaPreviewTransitionController)
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift
index 7e0ed37fc..dd3c4903a 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift
@@ -56,13 +56,13 @@ extension DataSourceFacade {
url.pathComponents[2] == "statuses" {
let statusID = url.pathComponents[3]
let threadViewModel = RemoteThreadViewModel(context: provider.context, authContext: provider.authContext, statusID: statusID)
- await provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show)
+ _ = await provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show)
} else {
- await provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
+ _ = await provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
}
case .hashtag(_, let hashtag, _):
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, authContext: provider.authContext, hashtag: hashtag)
- await provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show)
+ _ = await provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show)
case .mention(_, let mention, let userInfo):
await coordinateToProfileScene(
provider: provider,
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift
index ef01b8394..3c0509d2c 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift
@@ -47,7 +47,7 @@ extension DataSourceFacade {
mastodonUser: user
)
- provider.coordinator.present(
+ _ = provider.coordinator.present(
scene: .profile(viewModel: profileViewModel),
from: provider,
transition: .show
@@ -75,7 +75,7 @@ extension DataSourceFacade {
}
guard let mention = mentions?.first(where: { $0.username == mention }) else {
- await provider.coordinator.present(
+ _ = await provider.coordinator.present(
scene: .safari(url: url),
from: provider,
transition: .safariPresent(animated: true, completion: nil)
@@ -102,7 +102,7 @@ extension DataSourceFacade {
}
}()
- await provider.coordinator.present(
+ _ = await provider.coordinator.present(
scene: .profile(viewModel: profileViewModel),
from: provider,
transition: .show
diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift
index 332ed75e4..ac9da6e81 100644
--- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift
+++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift
@@ -43,7 +43,7 @@ extension DataSourceFacade {
dependency: provider,
status: status
)
- provider.coordinator.present(
+ _ = provider.coordinator.present(
scene: .activityViewController(
activityViewController: activityViewController,
sourceView: button,
@@ -84,7 +84,7 @@ extension DataSourceFacade {
self.url = url
self.metadata = LPLinkMetadata()
metadata.url = url
- metadata.title = "\(status.author.displayName) (@\(status.author.username)@\(status.author.domain))"
+ metadata.title = "\(status.author.displayName) (@\(status.author.acctWithDomain))"
metadata.iconProvider = NSItemProvider(object: IconProvider(url: status.author.avatarImageURLWithFallback(domain: status.author.domain)))
}
@@ -358,7 +358,8 @@ extension DataSourceFacade {
dependency: dependency,
status: status
)
- await dependency.coordinator.present(
+
+ _ = dependency.coordinator.present(
scene: .activityViewController(
activityViewController: activityViewController,
sourceView: menuContext.button,
diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift
index 82c25d040..c157b7086 100644
--- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift
+++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift
@@ -487,7 +487,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
authContext: authContext,
kind: .rebloggedBy(status: status)
)
- await coordinator.present(
+ _ = await coordinator.present(
scene: .rebloggedBy(viewModel: userListViewModel),
from: self,
transition: .show
@@ -511,7 +511,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
authContext: authContext,
kind: .favoritedBy(status: status)
)
- await coordinator.present(
+ _ = await coordinator.present(
scene: .favoritedBy(viewModel: userListViewModel),
from: self,
transition: .show
diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift
index 3a71e5346..6ced42601 100644
--- a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift
+++ b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift
@@ -143,7 +143,7 @@ extension UITableViewDelegate where Self: DataSourceProvider & MediaPreviewableV
title: L10n.Common.Alerts.SavePhotoFailure.title,
message: L10n.Common.Alerts.SavePhotoFailure.message
)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .alertController(alertController: alertController),
from: self,
transition: .alertController(animated: true, completion: nil)
diff --git a/Mastodon/Resources/Base.lproj/infoPlist.strings b/Mastodon/Resources/Base.lproj/infoPlist.strings
new file mode 100644
index 000000000..710865573
--- /dev/null
+++ b/Mastodon/Resources/Base.lproj/infoPlist.strings
@@ -0,0 +1,4 @@
+"NSCameraUsageDescription" = "Used to take photo for post status";
+"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
+"NewPostShortcutItemTitle" = "New Post";
+"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
diff --git a/Mastodon/Resources/ar.lproj/InfoPlist.strings b/Mastodon/Resources/ar.lproj/InfoPlist.strings
index c3b26f14a..ecb81ddd4 100644
--- a/Mastodon/Resources/ar.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/ar.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
"NSCameraUsageDescription" = "يُستخدم لالتقاط الصورة عِندَ نشر الحالات";
"NSPhotoLibraryAddUsageDescription" = "يُستخدم لحِفظ الصورة في مكتبة الصور";
-"NewPostShortcutItemTitle" = "منشور جديد";
+"NewPostShortcutItemTitle" = "مَنشُورٌ جَديد";
"SearchShortcutItemTitle" = "البحث";
\ No newline at end of file
diff --git a/Mastodon/Resources/ckb.lproj/InfoPlist.strings b/Mastodon/Resources/ckb.lproj/InfoPlist.strings
index 710865573..8c4946d2d 100644
--- a/Mastodon/Resources/ckb.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/ckb.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "بەکار دێت بۆ گرتنی وێنەیەک بۆ پۆستەکە";
+"NSPhotoLibraryAddUsageDescription" = "بەکار دێت بۆ هەڵگرتنی وێنە";
+"NewPostShortcutItemTitle" = "پۆستی نوێ";
+"SearchShortcutItemTitle" = "بگەڕێ";
\ No newline at end of file
diff --git a/Mastodon/Resources/cs.lproj/InfoPlist.strings b/Mastodon/Resources/cs.lproj/InfoPlist.strings
new file mode 100644
index 000000000..6989cfcb1
--- /dev/null
+++ b/Mastodon/Resources/cs.lproj/InfoPlist.strings
@@ -0,0 +1,4 @@
+"NSCameraUsageDescription" = "Slouží k pořízení fotografie pro příspěvek";
+"NSPhotoLibraryAddUsageDescription" = "Slouží k uložení fotografie do knihovny fotografií";
+"NewPostShortcutItemTitle" = "Nový příspěvek";
+"SearchShortcutItemTitle" = "Hledat";
\ No newline at end of file
diff --git a/Mastodon/Resources/de.lproj/infoPlist.strings b/Mastodon/Resources/de.lproj/infoPlist.strings
index 9c5feae53..9c8438653 100644
--- a/Mastodon/Resources/de.lproj/infoPlist.strings
+++ b/Mastodon/Resources/de.lproj/infoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Verwendet um Fotos für neue Beiträge aufzunehmen";
-"NSPhotoLibraryAddUsageDescription" = "Verwendet um Fotos zu speichern";
+"NSCameraUsageDescription" = "Wird verwendet, um Fotos für neue Beiträge aufzunehmen";
+"NSPhotoLibraryAddUsageDescription" = "Wird verwendet, um Foto in der Foto-Mediathek zu speichern";
"NewPostShortcutItemTitle" = "Neuer Beitrag";
-"SearchShortcutItemTitle" = "Suche";
\ No newline at end of file
+"SearchShortcutItemTitle" = "Suchen";
\ No newline at end of file
diff --git a/Mastodon/Resources/eu.lproj/InfoPlist.strings b/Mastodon/Resources/eu.lproj/InfoPlist.strings
index 710865573..e9d36a901 100644
--- a/Mastodon/Resources/eu.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/eu.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Bidalketetarako argazkiak ateratzeko erabiltzen da";
+"NSPhotoLibraryAddUsageDescription" = "Argazkiak Argazki-liburutegian gordetzeko erabiltzen da";
+"NewPostShortcutItemTitle" = "Bidalketa berria";
+"SearchShortcutItemTitle" = "Bilatu";
\ No newline at end of file
diff --git a/Mastodon/Resources/fi.lproj/InfoPlist.strings b/Mastodon/Resources/fi.lproj/InfoPlist.strings
index 710865573..040b25d69 100644
--- a/Mastodon/Resources/fi.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/fi.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Käytetään kuvan ottamiseen julkaisua varten";
+"NSPhotoLibraryAddUsageDescription" = "Käytetään kuvan tallentamiseen kuvakirjastoon";
+"NewPostShortcutItemTitle" = "Uusi julkaisu";
+"SearchShortcutItemTitle" = "Haku";
\ No newline at end of file
diff --git a/Mastodon/Resources/gd.lproj/InfoPlist.strings b/Mastodon/Resources/gd.lproj/InfoPlist.strings
index 710865573..ccb39b44e 100644
--- a/Mastodon/Resources/gd.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/gd.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "’Ga chleachdadh airson dealbh a thogail do staid puist";
+"NSPhotoLibraryAddUsageDescription" = "’Ga chleachdadh airson dealbh a shàbhaladh ann an tasg-lann nan dealbhan";
+"NewPostShortcutItemTitle" = "Post ùr";
+"SearchShortcutItemTitle" = "Lorg";
\ No newline at end of file
diff --git a/Mastodon/Resources/gl.lproj/InfoPlist.strings b/Mastodon/Resources/gl.lproj/InfoPlist.strings
index 710865573..3d6df3f0f 100644
--- a/Mastodon/Resources/gl.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/gl.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Utilizado para facer foto e publicar estado";
+"NSPhotoLibraryAddUsageDescription" = "Utilizado para gardar a foto na Biblioteca";
+"NewPostShortcutItemTitle" = "Nova publicación";
+"SearchShortcutItemTitle" = "Buscar";
\ No newline at end of file
diff --git a/Mastodon/Resources/it.lproj/InfoPlist.strings b/Mastodon/Resources/it.lproj/InfoPlist.strings
index 710865573..0da468639 100644
--- a/Mastodon/Resources/it.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/it.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Usato per scattare foto per lo stato del post";
+"NSPhotoLibraryAddUsageDescription" = "Utilizzato per salvare la foto nella galleria immagini";
+"NewPostShortcutItemTitle" = "Nuovo post";
+"SearchShortcutItemTitle" = "Cerca";
\ No newline at end of file
diff --git a/Mastodon/Resources/kab.lproj/InfoPlist.strings b/Mastodon/Resources/kab.lproj/InfoPlist.strings
index 710865573..42adc4cfc 100644
--- a/Mastodon/Resources/kab.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/kab.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Yettwaseqdac i tuṭṭfa n tewlafin deg usuffeɣ n waddaden";
+"NSPhotoLibraryAddUsageDescription" = "Yettwaseqdac i usekles n tewlafin deg temkarḍit n tewlafin";
+"NewPostShortcutItemTitle" = "Tasuffeɣt tamaynut";
+"SearchShortcutItemTitle" = "Nadi";
\ No newline at end of file
diff --git a/Mastodon/Resources/ku.lproj/InfoPlist.strings b/Mastodon/Resources/ku.lproj/InfoPlist.strings
index 710865573..669ecfacf 100644
--- a/Mastodon/Resources/ku.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/ku.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Bo kişandina wêneyê ji bo rewşa şandiyan tê bikaranîn";
+"NSPhotoLibraryAddUsageDescription" = "Ji bo tomarkirina wêneyê di pirtûkxaneya wêneyan de tê bikaranîn";
+"NewPostShortcutItemTitle" = "Şandiya nû";
+"SearchShortcutItemTitle" = "Bigere";
\ No newline at end of file
diff --git a/Mastodon/Resources/nl.lproj/InfoPlist.strings b/Mastodon/Resources/nl.lproj/InfoPlist.strings
index a45991068..36b6e9802 100644
--- a/Mastodon/Resources/nl.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/nl.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
"NSCameraUsageDescription" = "Gebruikt om foto's te nemen voor je berichten";
"NSPhotoLibraryAddUsageDescription" = "Gebruikt om foto's op te slaan in de fotobibliotheek";
"NewPostShortcutItemTitle" = "Nieuw Bericht";
-"SearchShortcutItemTitle" = "Zoeken";
\ No newline at end of file
+"SearchShortcutItemTitle" = "Zoek";
\ No newline at end of file
diff --git a/Mastodon/Resources/sl.lproj/InfoPlist.strings b/Mastodon/Resources/sl.lproj/InfoPlist.strings
new file mode 100644
index 000000000..57c8319f5
--- /dev/null
+++ b/Mastodon/Resources/sl.lproj/InfoPlist.strings
@@ -0,0 +1,4 @@
+"NSCameraUsageDescription" = "Uporabljeno za zajem fotografij za stanje objave";
+"NSPhotoLibraryAddUsageDescription" = "Uporabljeno za shranjevanje fotografije v knjižnico fotografij";
+"NewPostShortcutItemTitle" = "Nova objava";
+"SearchShortcutItemTitle" = "Iskanje";
\ No newline at end of file
diff --git a/Mastodon/Resources/sv.lproj/InfoPlist.strings b/Mastodon/Resources/sv.lproj/InfoPlist.strings
index 710865573..e0facc1d2 100644
--- a/Mastodon/Resources/sv.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/sv.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Används för att ta foto till inlägg";
+"NSPhotoLibraryAddUsageDescription" = "Används för att spara foto till bildbiblioteket";
+"NewPostShortcutItemTitle" = "Nytt inlägg";
+"SearchShortcutItemTitle" = "Sök";
\ No newline at end of file
diff --git a/Mastodon/Resources/tr.lproj/InfoPlist.strings b/Mastodon/Resources/tr.lproj/InfoPlist.strings
index 710865573..1c4e05659 100644
--- a/Mastodon/Resources/tr.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/tr.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Fotoğraf çekerek durum paylaşmak için kullanılır";
+"NSPhotoLibraryAddUsageDescription" = "Fotoğraf Albümü'ne fotoğraf kaydetmek için kullanılır";
+"NewPostShortcutItemTitle" = "Yeni Gönderi";
+"SearchShortcutItemTitle" = "Arama";
\ No newline at end of file
diff --git a/Mastodon/Resources/vi.lproj/InfoPlist.strings b/Mastodon/Resources/vi.lproj/InfoPlist.strings
index 710865573..5dd27b7bc 100644
--- a/Mastodon/Resources/vi.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/vi.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "Được sử dụng để chụp ảnh cho tút";
+"NSPhotoLibraryAddUsageDescription" = "Được sử dụng để lưu ảnh vào Thư viện ảnh";
+"NewPostShortcutItemTitle" = "Viết tút";
+"SearchShortcutItemTitle" = "Tìm kiếm";
\ No newline at end of file
diff --git a/Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings b/Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings
index 710865573..737d2f857 100644
--- a/Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings
@@ -1,4 +1,4 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
-"NewPostShortcutItemTitle" = "New Post";
-"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
+"NSCameraUsageDescription" = "用來拍照發嘟文";
+"NSPhotoLibraryAddUsageDescription" = "用來儲存照片到圖片庫";
+"NewPostShortcutItemTitle" = "新增嘟文";
+"SearchShortcutItemTitle" = "搜尋";
\ No newline at end of file
diff --git a/Mastodon/Scene/Account/AccountListViewModel.swift b/Mastodon/Scene/Account/AccountListViewModel.swift
index e0aaf97fc..75797fd47 100644
--- a/Mastodon/Scene/Account/AccountListViewModel.swift
+++ b/Mastodon/Scene/Account/AccountListViewModel.swift
@@ -166,7 +166,7 @@ extension AccountListViewModel {
cell.badgeButton.accessibilityLabel
]
.compactMap { $0 }
- .joined(separator: " ")
+ .joined(separator: ", ")
}
}
diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift
index e25c75b01..7a0e529cc 100644
--- a/Mastodon/Scene/Account/AccountViewController.swift
+++ b/Mastodon/Scene/Account/AccountViewController.swift
@@ -34,7 +34,9 @@ final class AccountListViewController: UIViewController, NeedsDependency {
return barButtonItem
}()
- let dragIndicatorView = DragIndicatorView()
+ lazy var dragIndicatorView = DragIndicatorView { [weak self] in
+ self?.dismiss(animated: true, completion: nil)
+ }
var hasLoaded = false
private(set) lazy var tableView: UITableView = {
@@ -130,14 +132,6 @@ extension AccountListViewController {
self.panModalTransition(to: .shortForm)
}
.store(in: &disposeBag)
-
- if UIAccessibility.isVoiceOverRunning {
- let dragIndicatorTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
- dragIndicatorView.addGestureRecognizer(dragIndicatorTapGestureRecognizer)
- dragIndicatorTapGestureRecognizer.addTarget(self, action: #selector(AccountListViewController.dragIndicatorTapGestureRecognizerHandler(_:)))
- dragIndicatorView.isAccessibilityElement = true
- dragIndicatorView.accessibilityLabel = L10n.Scene.AccountList.dismissAccountSwitcher
- }
}
private func setupBackgroundColor(theme: Theme) {
@@ -160,10 +154,11 @@ extension AccountListViewController {
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
_ = coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil))
}
-
- @objc private func dragIndicatorTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
+
+ override func accessibilityPerformEscape() -> Bool {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
dismiss(animated: true, completion: nil)
+ return true
}
}
diff --git a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift
index 66f49efe8..cd214f2c7 100644
--- a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift
+++ b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift
@@ -69,6 +69,7 @@ extension AccountListTableViewCell {
])
avatarButton.setContentHuggingPriority(.defaultLow, for: .horizontal)
avatarButton.setContentHuggingPriority(.defaultLow, for: .vertical)
+ avatarButton.isAccessibilityElement = false
let labelContainerStackView = UIStackView()
labelContainerStackView.axis = .vertical
@@ -124,6 +125,8 @@ extension AccountListTableViewCell {
badgeButton.setBadge(number: 0)
checkmarkImageView.isHidden = true
+
+ accessibilityTraits.insert(.button)
}
}
diff --git a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift
index 3ff3066a2..bc47aef43 100644
--- a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift
+++ b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift
@@ -108,6 +108,8 @@ extension AddAccountTableViewCell {
separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)),
])
+
+ accessibilityTraits.insert(.button)
}
}
diff --git a/Mastodon/Scene/Account/View/DragIndicatorView.swift b/Mastodon/Scene/Account/View/DragIndicatorView.swift
index 9e0ab77d5..a04d9cd8c 100644
--- a/Mastodon/Scene/Account/View/DragIndicatorView.swift
+++ b/Mastodon/Scene/Account/View/DragIndicatorView.swift
@@ -15,17 +15,17 @@ final class DragIndicatorView: UIView {
let barView = UIView()
let separatorLine = UIView.separatorLine
+ let onDismiss: () -> Void
- override init(frame: CGRect) {
- super.init(frame: frame)
+ init(onDismiss: @escaping () -> Void) {
+ self.onDismiss = onDismiss
+ super.init(frame: .zero)
_init()
}
required init?(coder: NSCoder) {
- super.init(coder: coder)
- _init()
+ fatalError("init(coder:) is not supported")
}
-
}
extension DragIndicatorView {
@@ -52,6 +52,14 @@ extension DragIndicatorView {
separatorLine.bottomAnchor.constraint(equalTo: bottomAnchor),
separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: self)),
])
+
+ isAccessibilityElement = true
+ accessibilityTraits = .button
+ accessibilityLabel = L10n.Scene.AccountList.dismissAccountSwitcher
}
+ override func accessibilityActivate() -> Bool {
+ self.onDismiss()
+ return true
+ }
}
diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift
index fd5ed5817..ca33487ab 100644
--- a/Mastodon/Scene/Compose/ComposeViewController.swift
+++ b/Mastodon/Scene/Compose/ComposeViewController.swift
@@ -58,12 +58,7 @@ final class ComposeViewController: UIViewController, NeedsDependency {
let shadowBackgroundContainer = ShadowBackgroundContainer()
publishButton.translatesAutoresizingMaskIntoConstraints = false
shadowBackgroundContainer.addSubview(publishButton)
- NSLayoutConstraint.activate([
- publishButton.topAnchor.constraint(equalTo: shadowBackgroundContainer.topAnchor),
- publishButton.leadingAnchor.constraint(equalTo: shadowBackgroundContainer.leadingAnchor),
- publishButton.trailingAnchor.constraint(equalTo: shadowBackgroundContainer.trailingAnchor),
- publishButton.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor),
- ])
+ publishButton.pinToParent()
let barButtonItem = UIBarButtonItem(customView: shadowBackgroundContainer)
return barButtonItem
}()
@@ -93,10 +88,7 @@ extension ComposeViewController {
.sink { [weak self] _ in
guard let self = self else { return }
guard self.traitCollection.userInterfaceIdiom == .pad else { return }
- var items = [self.publishBarButtonItem]
- // if self.traitCollection.horizontalSizeClass == .regular {
- // items.append(self.characterCountBarButtonItem)
- // }
+ let items = [self.publishBarButtonItem]
self.navigationItem.rightBarButtonItems = items
}
.store(in: &disposeBag)
@@ -105,12 +97,7 @@ extension ComposeViewController {
addChild(composeContentViewController)
composeContentViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(composeContentViewController.view)
- NSLayoutConstraint.activate([
- composeContentViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- composeContentViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- composeContentViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- composeContentViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ composeContentViewController.view.pinToParent()
composeContentViewController.didMove(toParent: self)
// bind title
@@ -175,7 +162,7 @@ extension ComposeViewController {
let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert)
let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil)
alertController.addAction(okAction)
- coordinator.present(scene: .alertController(alertController: alertController), from: nil, transition: .alertController(animated: true, completion: nil))
+ _ = coordinator.present(scene: .alertController(alertController: alertController), from: nil, transition: .alertController(animated: true, completion: nil))
return
}
diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift
index d592c3033..870bfc72a 100644
--- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift
+++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift
@@ -33,7 +33,7 @@ final class DiscoveryCommunityViewController: UIViewController, NeedsDependency,
return tableView
}()
- let refreshControl = UIRefreshControl()
+ let refreshControl = RefreshControl()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
@@ -57,12 +57,7 @@ extension DiscoveryCommunityViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.refreshControl = refreshControl
refreshControl.addTarget(self, action: #selector(DiscoveryCommunityViewController.refreshControlValueChanged(_:)), for: .valueChanged)
@@ -108,7 +103,7 @@ extension DiscoveryCommunityViewController {
extension DiscoveryCommunityViewController {
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
if !viewModel.stateMachine.enter(DiscoveryCommunityViewModel.State.Reloading.self) {
refreshControl.endRefreshing()
}
diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift
index 476832b69..5045e825a 100644
--- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift
+++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift
@@ -125,7 +125,7 @@ extension DiscoveryCommunityViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let viewModel else { return }
switch previousState {
case is Reloading:
diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift
index ce1aadbb4..dec1d9c72 100644
--- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift
+++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift
@@ -32,7 +32,7 @@ final class DiscoveryForYouViewController: UIViewController, NeedsDependency, Me
return tableView
}()
- let refreshControl = UIRefreshControl()
+ let refreshControl = RefreshControl()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
@@ -56,12 +56,7 @@ extension DiscoveryForYouViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
@@ -93,7 +88,7 @@ extension DiscoveryForYouViewController {
extension DiscoveryForYouViewController {
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
Task {
try await viewModel.fetch()
}
diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift
index e315f04ee..64d1231fe 100644
--- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift
+++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift
@@ -32,7 +32,7 @@ final class DiscoveryHashtagsViewController: UIViewController, NeedsDependency,
return tableView
}()
- let refreshControl = UIRefreshControl()
+ let refreshControl = RefreshControl()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
@@ -56,12 +56,7 @@ extension DiscoveryHashtagsViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.refreshControl = refreshControl
refreshControl.addTarget(self, action: #selector(DiscoveryHashtagsViewController.refreshControlValueChanged(_:)), for: .valueChanged)
@@ -88,7 +83,7 @@ extension DiscoveryHashtagsViewController {
extension DiscoveryHashtagsViewController {
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
Task { @MainActor in
do {
try await viewModel.fetch()
@@ -108,7 +103,7 @@ extension DiscoveryHashtagsViewController: UITableViewDelegate {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)")
guard case let .hashtag(tag) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return }
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, authContext: viewModel.authContext, hashtag: tag.name)
- coordinator.present(
+ _ = coordinator.present(
scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel),
from: self,
transition: .show
@@ -218,7 +213,7 @@ extension DiscoveryHashtagsViewController: TableViewControllerNavigateable {
guard case let .hashtag(tag) = item else { return }
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, authContext: viewModel.authContext, hashtag: tag.name)
- coordinator.present(
+ _ = coordinator.present(
scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel),
from: self,
transition: .show
diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift
index 7f9efb0d9..4884aafac 100644
--- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift
+++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift
@@ -32,7 +32,7 @@ final class DiscoveryNewsViewController: UIViewController, NeedsDependency, Medi
return tableView
}()
- let refreshControl = UIRefreshControl()
+ let refreshControl = RefreshControl()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
@@ -56,12 +56,7 @@ extension DiscoveryNewsViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
@@ -101,7 +96,7 @@ extension DiscoveryNewsViewController {
extension DiscoveryNewsViewController {
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
guard viewModel.stateMachine.enter(DiscoveryNewsViewModel.State.Reloading.self) else {
sender.endRefreshing()
return
@@ -117,7 +112,7 @@ extension DiscoveryNewsViewController: UITableViewDelegate {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)")
guard case let .link(link) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return }
guard let url = URL(string: link.url) else { return }
- coordinator.present(
+ _ = coordinator.present(
scene: .safari(url: url),
from: self,
transition: .safariPresent(animated: true, completion: nil)
@@ -214,7 +209,7 @@ extension DiscoveryNewsViewController: TableViewControllerNavigateable {
guard case let .link(link) = item else { return }
guard let url = URL(string: link.url) else { return }
- coordinator.present(
+ _ = coordinator.present(
scene: .safari(url: url),
from: self,
transition: .safariPresent(animated: true, completion: nil)
diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift
index 7c802cde3..8170d5b1c 100644
--- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift
+++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift
@@ -125,8 +125,7 @@ extension DiscoveryNewsViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
-
+ guard let viewModel else { return }
switch previousState {
case is Reloading:
diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift
index ee3538885..9d772a27e 100644
--- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift
+++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift
@@ -32,7 +32,7 @@ final class DiscoveryPostsViewController: UIViewController, NeedsDependency, Med
return tableView
}()
- let refreshControl = UIRefreshControl()
+ let refreshControl = RefreshControl()
let discoveryIntroBannerView = DiscoveryIntroBannerView()
@@ -58,12 +58,7 @@ extension DiscoveryPostsViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
discoveryIntroBannerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(discoveryIntroBannerView)
@@ -119,7 +114,7 @@ extension DiscoveryPostsViewController {
extension DiscoveryPostsViewController {
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
guard viewModel.stateMachine.enter(DiscoveryPostsViewModel.State.Reloading.self) else {
sender.endRefreshing()
return
diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift
index 3ed245e99..fd413927e 100644
--- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift
+++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift
@@ -126,7 +126,7 @@ extension DiscoveryPostsViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let viewModel else { return }
switch previousState {
case is Reloading:
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
index 42079a91e..4a0be3816 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
@@ -48,7 +48,7 @@ final class HashtagTimelineViewController: UIViewController, NeedsDependency, Me
return tableView
}()
- let refreshControl = UIRefreshControl()
+ let refreshControl = RefreshControl()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", ((#file as NSString).lastPathComponent), #line, #function)
@@ -80,12 +80,7 @@ extension HashtagTimelineViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
@@ -158,7 +153,7 @@ extension HashtagTimelineViewController {
extension HashtagTimelineViewController {
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
guard viewModel.stateMachine.enter(HashtagTimelineViewModel.State.Reloading.self) else {
sender.endRefreshing()
return
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift
index deb9de0a2..c35715f1e 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+State.swift
@@ -70,7 +70,7 @@ extension HashtagTimelineViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let stateMachine = stateMachine else { return }
stateMachine.enter(Loading.self)
}
@@ -127,7 +127,7 @@ extension HashtagTimelineViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let viewModel else { return }
switch previousState {
case is Reloading:
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
index d057c0376..ff90775ff 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
@@ -300,7 +300,7 @@ extension HomeTimelineViewController {
}
@objc private func showWelcomeAction(_ sender: UIAction) {
- coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil))
}
@objc private func showRegisterAction(_ sender: UIAction) {
@@ -332,12 +332,12 @@ extension HomeTimelineViewController {
@objc private func showConfirmEmail(_ sender: UIAction) {
let mastodonConfirmEmailViewModel = MastodonConfirmEmailViewModel()
- coordinator.present(scene: .mastodonConfirmEmail(viewModel: mastodonConfirmEmailViewModel), from: nil, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .mastodonConfirmEmail(viewModel: mastodonConfirmEmailViewModel), from: nil, transition: .modal(animated: true, completion: nil))
}
@objc private func showAccountList(_ sender: UIAction) {
let accountListViewModel = AccountListViewModel(context: context, authContext: viewModel.authContext)
- coordinator.present(scene: .accountList(viewModel: accountListViewModel), from: self, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .accountList(viewModel: accountListViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
@objc private func showProfileAction(_ sender: UIAction) {
@@ -347,12 +347,12 @@ extension HomeTimelineViewController {
guard let self = self else { return }
guard let textField = alertController?.textFields?.first else { return }
let profileViewModel = RemoteProfileViewModel(context: self.context, authContext: self.viewModel.authContext, userID: textField.text ?? "")
- self.coordinator.present(scene: .profile(viewModel: profileViewModel), from: self, transition: .show)
+ _ = self.coordinator.present(scene: .profile(viewModel: profileViewModel), from: self, transition: .show)
}
alertController.addAction(showAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
- coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
+ _ = coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
}
@objc private func showThreadAction(_ sender: UIAction) {
@@ -362,12 +362,12 @@ extension HomeTimelineViewController {
guard let self = self else { return }
guard let textField = alertController?.textFields?.first else { return }
let threadViewModel = RemoteThreadViewModel(context: self.context, authContext: self.viewModel.authContext, statusID: textField.text ?? "")
- self.coordinator.present(scene: .thread(viewModel: threadViewModel), from: self, transition: .show)
+ _ = self.coordinator.present(scene: .thread(viewModel: threadViewModel), from: self, transition: .show)
}
alertController.addAction(showAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
- coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
+ _ = coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
}
private func showNotification(_ sender: UIAction, notificationType: Mastodon.Entity.Notification.NotificationType) {
@@ -436,7 +436,7 @@ extension HomeTimelineViewController {
authContext: viewModel.authContext,
setting: currentSetting
)
- coordinator.present(
+ _ = coordinator.present(
scene: .settings(viewModel: settingsViewModel),
from: self,
transition: .modal(animated: true, completion: nil)
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
index 3efcd5cbe..3caafef3d 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
@@ -74,7 +74,7 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
return progressView
}()
- let refreshControl = UIRefreshControl()
+ let refreshControl = RefreshControl()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", ((#file as NSString).lastPathComponent), #line, #function)
@@ -158,12 +158,7 @@ extension HomeTimelineViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
// // layout publish progress
publishProgressView.translatesAutoresizingMaskIntoConstraints = false
@@ -388,17 +383,17 @@ extension HomeTimelineViewController {
@objc private func manuallySearchButtonPressed(_ sender: UIButton) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
let searchDetailViewModel = SearchDetailViewModel(authContext: viewModel.authContext)
- coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
@objc private func settingBarButtonItemPressed(_ sender: UIBarButtonItem) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
guard let setting = context.settingService.currentSetting.value else { return }
let settingsViewModel = SettingsViewModel(context: context, authContext: viewModel.authContext, setting: setting)
- coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
guard viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.Loading.self) else {
sender.endRefreshing()
return
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift
index 41cea6b58..8bf1421b1 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift
@@ -62,7 +62,7 @@ extension HomeTimelineViewModel.LoadLatestState {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let viewModel else { return }
let latestFeedRecords = viewModel.fetchedResultsController.records.prefix(APIService.onceRequestStatusMaxCount)
let parentManagedObjectContext = viewModel.fetchedResultsController.fetchedResultsController.managedObjectContext
diff --git a/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift b/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift
index 400b4ee98..38b80fe28 100644
--- a/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift
+++ b/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift
@@ -47,12 +47,7 @@ extension HomeTimelineNavigationBarTitleView {
private func _init() {
containerView.translatesAutoresizingMaskIntoConstraints = false
addSubview(containerView)
- NSLayoutConstraint.activate([
- containerView.topAnchor.constraint(equalTo: topAnchor),
- containerView.leadingAnchor.constraint(equalTo: leadingAnchor),
- containerView.trailingAnchor.constraint(equalTo: trailingAnchor),
- containerView.bottomAnchor.constraint(equalTo: bottomAnchor),
- ])
+ containerView.pinToParent()
containerView.addArrangedSubview(logoButton)
button.translatesAutoresizingMaskIntoConstraints = false
diff --git a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift
index c6552bcba..5dede76df 100644
--- a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift
+++ b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift
@@ -65,12 +65,7 @@ extension MediaPreviewViewController {
pagingViewController.view.translatesAutoresizingMaskIntoConstraints = false
addChild(pagingViewController)
visualEffectView.contentView.addSubview(pagingViewController.view)
- NSLayoutConstraint.activate([
- visualEffectView.topAnchor.constraint(equalTo: pagingViewController.view.topAnchor),
- visualEffectView.bottomAnchor.constraint(equalTo: pagingViewController.view.bottomAnchor),
- visualEffectView.leadingAnchor.constraint(equalTo: pagingViewController.view.leadingAnchor),
- visualEffectView.trailingAnchor.constraint(equalTo: pagingViewController.view.trailingAnchor),
- ])
+ visualEffectView.pinTo(to: pagingViewController.view)
pagingViewController.didMove(toParent: self)
closeButtonBackground.translatesAutoresizingMaskIntoConstraints = false
@@ -276,7 +271,7 @@ extension MediaPreviewViewController: MediaPreviewImageViewControllerDelegate {
title: L10n.Common.Alerts.SavePhotoFailure.title,
message: L10n.Common.Alerts.SavePhotoFailure.message
)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .alertController(alertController: alertController),
from: self,
transition: .alertController(animated: true, completion: nil)
diff --git a/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewController.swift b/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewController.swift
index 7bdbbfed2..254b9b2c5 100644
--- a/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewController.swift
+++ b/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewController.swift
@@ -39,23 +39,13 @@ extension MediaPreviewVideoViewController {
addChild(playerViewController)
playerViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(playerViewController.view)
- NSLayoutConstraint.activate([
- playerViewController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
- playerViewController.view.centerYAnchor.constraint(equalTo: view.centerYAnchor),
- playerViewController.view.widthAnchor.constraint(equalTo: view.widthAnchor),
- playerViewController.view.heightAnchor.constraint(equalTo: view.heightAnchor),
- ])
+ playerViewController.view.pinToParent()
playerViewController.didMove(toParent: self)
if let contentOverlayView = playerViewController.contentOverlayView {
previewImageView.translatesAutoresizingMaskIntoConstraints = false
contentOverlayView.addSubview(previewImageView)
- NSLayoutConstraint.activate([
- previewImageView.topAnchor.constraint(equalTo: contentOverlayView.topAnchor),
- previewImageView.leadingAnchor.constraint(equalTo: contentOverlayView.leadingAnchor),
- previewImageView.trailingAnchor.constraint(equalTo: contentOverlayView.trailingAnchor),
- previewImageView.bottomAnchor.constraint(equalTo: contentOverlayView.bottomAnchor),
- ])
+ previewImageView.pinToParent()
}
playerViewController.delegate = self
@@ -90,6 +80,12 @@ extension MediaPreviewVideoViewController {
}
}
+ override func viewDidLayoutSubviews() {
+ super.viewDidLayoutSubviews()
+
+ playerViewController.didMove(toParent: self)
+ }
+
}
// MARK: - ShareActivityProvider
diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift
index 00e2a9fc8..9b7416afc 100644
--- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift
+++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift
@@ -26,8 +26,8 @@ final class NotificationTimelineViewController: UIViewController, NeedsDependenc
var viewModel: NotificationTimelineViewModel!
- private(set) lazy var refreshControl: UIRefreshControl = {
- let refreshControl = UIRefreshControl()
+ private(set) lazy var refreshControl: RefreshControl = {
+ let refreshControl = RefreshControl()
refreshControl.addTarget(self, action: #selector(NotificationTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged)
return refreshControl
}()
@@ -55,12 +55,7 @@ extension NotificationTimelineViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
@@ -137,7 +132,7 @@ extension NotificationTimelineViewController: CellFrameCacheContainer {
extension NotificationTimelineViewController {
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
Task {
diff --git a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift
index a90da1e81..ae8a4933e 100644
--- a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift
+++ b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift
@@ -189,7 +189,7 @@ extension MastodonConfirmEmailViewController {
alertController.addAction(openEmailAction)
alertController.addAction(cancelAction)
alertController.preferredAction = openEmailAction
- self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
+ _ = self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
}
@objc private func resendButtonPressed(_ sender: UIButton) {
@@ -197,18 +197,17 @@ extension MastodonConfirmEmailViewController {
let resendAction = UIAlertAction(title: L10n.Scene.ConfirmEmail.DontReceiveEmail.resendEmail, style: .default) { _ in
let url = Mastodon.API.resendEmailURL(domain: self.viewModel.authenticateInfo.domain)
let viewModel = MastodonResendEmailViewModel(resendEmailURL: url, email: self.viewModel.email)
- self.coordinator.present(scene: .mastodonResendEmail(viewModel: viewModel), from: self, transition: .modal(animated: true, completion: nil))
+ _ = self.coordinator.present(scene: .mastodonResendEmail(viewModel: viewModel), from: self, transition: .modal(animated: true, completion: nil))
}
let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default) { _ in
}
alertController.addAction(resendAction)
alertController.addAction(okAction)
- self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
+ _ = self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
}
func showEmailAppAlert() {
let clients = ThirdPartyMailClient.clients
- let application = UIApplication.shared
let availableClients = clients.filter { client -> Bool in
ThirdPartyMailer.isMailClientAvailable(client)
}
@@ -220,14 +219,14 @@ extension MastodonConfirmEmailViewController {
alertController.addAction(alertAction)
_ = availableClients.compactMap { client -> UIAlertAction in
let alertAction = UIAlertAction(title: client.name, style: .default) { _ in
- _ = ThirdPartyMailer.open(client, completionHandler: nil)
+ ThirdPartyMailer.open(client, completionHandler: nil)
}
alertController.addAction(alertAction)
return alertAction
}
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel, handler: nil)
alertController.addAction(cancelAction)
- self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
+ _ = self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
}
}
diff --git a/Mastodon/Scene/Onboarding/Login/ContentSizedTableView.swift b/Mastodon/Scene/Onboarding/Login/ContentSizedTableView.swift
new file mode 100644
index 000000000..e0c8a9228
--- /dev/null
+++ b/Mastodon/Scene/Onboarding/Login/ContentSizedTableView.swift
@@ -0,0 +1,22 @@
+//
+// MastodonLoginTableView.swift
+// Mastodon
+//
+// Created by Nathan Mattes on 13.11.22.
+//
+
+import UIKit
+
+// Source: https://stackoverflow.com/a/48623673
+final class ContentSizedTableView: UITableView {
+ override var contentSize:CGSize {
+ didSet {
+ invalidateIntrinsicContentSize()
+ }
+ }
+
+ override var intrinsicContentSize: CGSize {
+ layoutIfNeeded()
+ return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
+ }
+}
diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginServerTableViewCell.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginServerTableViewCell.swift
new file mode 100644
index 000000000..2fb599015
--- /dev/null
+++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginServerTableViewCell.swift
@@ -0,0 +1,12 @@
+//
+// MastodonLoginServerTableViewCell.swift
+// Mastodon
+//
+// Created by Nathan Mattes on 11.11.22.
+//
+
+import UIKit
+
+class MastodonLoginServerTableViewCell: UITableViewCell {
+ static let reuseIdentifier = "MastodonLoginServerTableViewCell"
+}
diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginView.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginView.swift
new file mode 100644
index 000000000..d5f8b51d4
--- /dev/null
+++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginView.swift
@@ -0,0 +1,151 @@
+//
+// MastodonLoginView.swift
+// Mastodon
+//
+// Created by Nathan Mattes on 10.11.22.
+//
+
+import UIKit
+import MastodonAsset
+import MastodonLocalization
+
+class MastodonLoginView: UIView {
+
+ // List with (filtered) domains
+
+ let titleLabel: UILabel
+ let subtitleLabel: UILabel
+ private let headerStackView: UIStackView
+
+ let searchTextField: UITextField
+ private let searchTextFieldLeftView: UIView
+ private let searchTextFieldMagnifyingGlass: UIImageView
+ private let searchContainerLeftPaddingView: UIView
+
+ let tableView: UITableView
+ let navigationActionView: NavigationActionView
+ var bottomConstraint: NSLayoutConstraint?
+
+ override init(frame: CGRect) {
+
+ titleLabel = UILabel()
+ titleLabel.font = MastodonLoginViewController.largeTitleFont
+ titleLabel.textColor = MastodonLoginViewController.largeTitleTextColor
+ titleLabel.text = L10n.Scene.Login.title
+ titleLabel.numberOfLines = 0
+
+ subtitleLabel = UILabel()
+ subtitleLabel.font = MastodonLoginViewController.subTitleFont
+ subtitleLabel.textColor = MastodonLoginViewController.subTitleTextColor
+ subtitleLabel.text = L10n.Scene.Login.subtitle
+ subtitleLabel.numberOfLines = 0
+
+ headerStackView = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel])
+ headerStackView.axis = .vertical
+ headerStackView.spacing = 16
+ headerStackView.translatesAutoresizingMaskIntoConstraints = false
+
+ searchTextFieldMagnifyingGlass = UIImageView(image: UIImage(
+ systemName: "magnifyingglass",
+ withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .regular)
+ ))
+ searchTextFieldMagnifyingGlass.tintColor = Asset.Colors.Label.secondary.color.withAlphaComponent(0.6)
+ searchTextFieldMagnifyingGlass.translatesAutoresizingMaskIntoConstraints = false
+
+ searchContainerLeftPaddingView = UIView()
+ searchContainerLeftPaddingView.translatesAutoresizingMaskIntoConstraints = false
+
+ searchTextFieldLeftView = UIView()
+ searchTextFieldLeftView.addSubview(searchTextFieldMagnifyingGlass)
+ searchTextFieldLeftView.addSubview(searchContainerLeftPaddingView)
+
+ searchTextField = UITextField()
+ searchTextField.translatesAutoresizingMaskIntoConstraints = false
+ searchTextField.backgroundColor = Asset.Scene.Onboarding.searchBarBackground.color
+ searchTextField.placeholder = L10n.Scene.Login.ServerSearchField.placeholder
+ searchTextField.leftView = searchTextFieldLeftView
+ searchTextField.leftViewMode = .always
+ searchTextField.layer.cornerRadius = 10
+ searchTextField.keyboardType = .URL
+ searchTextField.autocorrectionType = .no
+ searchTextField.autocapitalizationType = .none
+
+ tableView = ContentSizedTableView()
+ tableView.translatesAutoresizingMaskIntoConstraints = false
+ tableView.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color
+ tableView.keyboardDismissMode = .onDrag
+ tableView.layer.cornerRadius = 10
+
+ navigationActionView = NavigationActionView()
+ navigationActionView.translatesAutoresizingMaskIntoConstraints = false
+
+ super.init(frame: frame)
+
+ addSubview(headerStackView)
+ addSubview(searchTextField)
+ addSubview(tableView)
+ addSubview(navigationActionView)
+ backgroundColor = Asset.Scene.Onboarding.background.color
+
+ setupConstraints()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ private func setupConstraints() {
+
+ let bottomConstraint = safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: navigationActionView.bottomAnchor)
+
+ let constraints = [
+
+ headerStackView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
+ headerStackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
+ headerStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
+
+ searchTextField.topAnchor.constraint(equalTo: headerStackView.bottomAnchor, constant: 32),
+ searchTextField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
+ searchTextField.heightAnchor.constraint(equalToConstant: 55),
+ trailingAnchor.constraint(equalTo: searchTextField.trailingAnchor, constant: 16),
+
+ searchTextFieldMagnifyingGlass.topAnchor.constraint(equalTo: searchTextFieldLeftView.topAnchor),
+ searchTextFieldMagnifyingGlass.leadingAnchor.constraint(equalTo: searchTextFieldLeftView.leadingAnchor, constant: 8),
+ searchTextFieldMagnifyingGlass.bottomAnchor.constraint(equalTo: searchTextFieldLeftView.bottomAnchor),
+
+ searchContainerLeftPaddingView.topAnchor.constraint(equalTo: searchTextFieldLeftView.topAnchor),
+ searchContainerLeftPaddingView.leadingAnchor.constraint(equalTo: searchTextFieldMagnifyingGlass.trailingAnchor),
+ searchContainerLeftPaddingView.trailingAnchor.constraint(equalTo: searchTextFieldLeftView.trailingAnchor),
+ searchContainerLeftPaddingView.bottomAnchor.constraint(equalTo: searchTextFieldLeftView.bottomAnchor),
+ searchContainerLeftPaddingView.widthAnchor.constraint(equalToConstant: 4).priority(.defaultHigh),
+
+ tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 2),
+ tableView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
+ trailingAnchor.constraint(equalTo: tableView.trailingAnchor, constant: 16),
+ tableView.bottomAnchor.constraint(lessThanOrEqualTo: navigationActionView.topAnchor),
+
+ navigationActionView.leadingAnchor.constraint(equalTo: leadingAnchor),
+ navigationActionView.trailingAnchor.constraint(equalTo: trailingAnchor),
+ bottomConstraint,
+ ]
+
+ self.bottomConstraint = bottomConstraint
+ NSLayoutConstraint.activate(constraints)
+ }
+
+ func updateCorners(numberOfResults: Int = 0) {
+
+ tableView.isHidden = (numberOfResults == 0)
+ tableView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
+
+ let maskedCorners: CACornerMask
+
+ if numberOfResults == 0 {
+ maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
+ } else {
+ maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
+ }
+
+ searchTextField.layer.maskedCorners = maskedCorners
+ }
+}
diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift
new file mode 100644
index 000000000..e9965fdde
--- /dev/null
+++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift
@@ -0,0 +1,288 @@
+//
+// MastodonLoginViewController.swift
+// Mastodon
+//
+// Created by Nathan Mattes on 09.11.22.
+//
+
+import UIKit
+import MastodonSDK
+import MastodonCore
+import MastodonAsset
+import Combine
+import AuthenticationServices
+
+protocol MastodonLoginViewControllerDelegate: AnyObject {
+ func backButtonPressed(_ viewController: MastodonLoginViewController)
+ func nextButtonPressed(_ viewController: MastodonLoginViewController)
+}
+
+enum MastodonLoginViewSection: Hashable {
+ case servers
+}
+
+class MastodonLoginViewController: UIViewController, NeedsDependency {
+
+ weak var delegate: MastodonLoginViewControllerDelegate?
+ var dataSource: UITableViewDiffableDataSource?
+ let viewModel: MastodonLoginViewModel
+ let authenticationViewModel: AuthenticationViewModel
+ var mastodonAuthenticationController: MastodonAuthenticationController?
+
+ weak var context: AppContext!
+ weak var coordinator: SceneCoordinator!
+
+ var disposeBag = Set()
+
+ var contentView: MastodonLoginView {
+ view as! MastodonLoginView
+ }
+
+ init(appContext: AppContext, authenticationViewModel: AuthenticationViewModel, sceneCoordinator: SceneCoordinator) {
+
+ viewModel = MastodonLoginViewModel(appContext: appContext)
+ self.authenticationViewModel = authenticationViewModel
+ self.context = appContext
+ self.coordinator = sceneCoordinator
+
+ super.init(nibName: nil, bundle: nil)
+ viewModel.delegate = self
+
+ navigationItem.hidesBackButton = true
+ }
+
+ required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
+
+ override func loadView() {
+ let loginView = MastodonLoginView()
+
+ loginView.navigationActionView.nextButton.addTarget(self, action: #selector(MastodonLoginViewController.nextButtonPressed(_:)), for: .touchUpInside)
+ loginView.navigationActionView.backButton.addTarget(self, action: #selector(MastodonLoginViewController.backButtonPressed(_:)), for: .touchUpInside)
+ loginView.searchTextField.addTarget(self, action: #selector(MastodonLoginViewController.textfieldDidChange(_:)), for: .editingChanged)
+ loginView.tableView.delegate = self
+ loginView.tableView.register(MastodonLoginServerTableViewCell.self, forCellReuseIdentifier: MastodonLoginServerTableViewCell.reuseIdentifier)
+ loginView.navigationActionView.nextButton.isEnabled = false
+
+ view = loginView
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
+
+ let dataSource = UITableViewDiffableDataSource(tableView: contentView.tableView) { [weak self] tableView, indexPath, itemIdentifier in
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: MastodonLoginServerTableViewCell.reuseIdentifier, for: indexPath) as? MastodonLoginServerTableViewCell,
+ let self = self else {
+ fatalError("Wrong cell")
+ }
+
+ let server = self.viewModel.filteredServers[indexPath.row]
+ var configuration = cell.defaultContentConfiguration()
+ configuration.text = server.domain
+
+ cell.contentConfiguration = configuration
+ cell.accessoryType = .disclosureIndicator
+
+ cell.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color
+
+ return cell
+ }
+
+ contentView.tableView.dataSource = dataSource
+ self.dataSource = dataSource
+
+ contentView.updateCorners()
+
+ defer { setupNavigationBarBackgroundView() }
+ setupOnboardingAppearance()
+ }
+
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+
+ viewModel.updateServers()
+ }
+
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+
+ contentView.searchTextField.becomeFirstResponder()
+ }
+
+ //MARK: - Actions
+
+ @objc func backButtonPressed(_ sender: Any) {
+ contentView.searchTextField.resignFirstResponder()
+ delegate?.backButtonPressed(self)
+ }
+
+ @objc func nextButtonPressed(_ sender: Any) {
+ contentView.searchTextField.resignFirstResponder()
+ delegate?.nextButtonPressed(self)
+ }
+
+ @objc func login() {
+ guard let server = viewModel.selectedServer else { return }
+
+ authenticationViewModel
+ .authenticated
+ .asyncMap { domain, user -> Result in
+ do {
+ let result = try await self.context.authenticationService.activeMastodonUser(domain: domain, userID: user.id)
+ return .success(result)
+ } catch {
+ return .failure(error)
+ }
+ }
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] result in
+ guard let self = self else { return }
+ switch result {
+ case .failure(let error):
+ assertionFailure(error.localizedDescription)
+ case .success(let isActived):
+ assert(isActived)
+ self.coordinator.setup()
+ }
+ }
+ .store(in: &disposeBag)
+
+ authenticationViewModel.isAuthenticating.send(true)
+ context.apiService.createApplication(domain: server.domain)
+ .tryMap { response -> AuthenticationViewModel.AuthenticateInfo in
+ let application = response.value
+ guard let info = AuthenticationViewModel.AuthenticateInfo(
+ domain: server.domain,
+ application: application,
+ redirectURI: response.value.redirectURI ?? APIService.oauthCallbackURL
+ ) else {
+ throw APIService.APIError.explicit(.badResponse)
+ }
+ return info
+ }
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] completion in
+ guard let self = self else { return }
+ self.authenticationViewModel.isAuthenticating.send(false)
+
+ switch completion {
+ case .failure(let error):
+ let alert = UIAlertController.standardAlert(of: error)
+ self.present(alert, animated: true)
+ case .finished:
+ // do nothing. There's a subscriber above resulting in `coordinator.setup()`
+ break
+ }
+ } receiveValue: { [weak self] info in
+ guard let self else { return }
+ let authenticationController = MastodonAuthenticationController(
+ context: self.context,
+ authenticateURL: info.authorizeURL
+ )
+
+ self.mastodonAuthenticationController = authenticationController
+ authenticationController.authenticationSession?.presentationContextProvider = self
+ authenticationController.authenticationSession?.start()
+
+ self.authenticationViewModel.authenticate(
+ info: info,
+ pinCodePublisher: authenticationController.pinCodePublisher
+ )
+ }
+ .store(in: &disposeBag)
+ }
+
+ @objc func textfieldDidChange(_ textField: UITextField) {
+ viewModel.filterServers(withText: textField.text)
+
+
+ if let text = textField.text,
+ let domain = AuthenticationViewModel.parseDomain(from: text) {
+
+ viewModel.selectedServer = .init(domain: domain, instance: .init(domain: domain))
+ contentView.navigationActionView.nextButton.isEnabled = true
+ } else {
+ viewModel.selectedServer = nil
+ contentView.navigationActionView.nextButton.isEnabled = false
+ }
+ }
+
+ // MARK: - Notifications
+ @objc func keyboardWillShowNotification(_ notification: Notification) {
+
+ guard let userInfo = notification.userInfo,
+ let keyboardFrameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
+ let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber
+ else { return }
+
+ // inspired by https://stackoverflow.com/a/30245044
+ let keyboardFrame = keyboardFrameValue.cgRectValue
+
+ let keyboardOrigin = view.convert(keyboardFrame.origin, from: nil)
+ let intersectionY = CGRectGetMaxY(view.frame) - keyboardOrigin.y;
+
+ if intersectionY >= 0 {
+ contentView.bottomConstraint?.constant = intersectionY - view.safeAreaInsets.bottom
+ }
+
+ UIView.animate(withDuration: duration.doubleValue, delay: 0, options: .curveEaseInOut) {
+ self.view.layoutIfNeeded()
+ }
+ }
+
+ @objc func keyboardWillHideNotification(_ notification: Notification) {
+
+ guard let userInfo = notification.userInfo,
+ let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber
+ else { return }
+
+ contentView.bottomConstraint?.constant = 0
+
+ UIView.animate(withDuration: duration.doubleValue, delay: 0, options: .curveEaseInOut) {
+ self.view.layoutIfNeeded()
+ }
+ }
+}
+
+// MARK: - OnboardingViewControllerAppearance
+extension MastodonLoginViewController: OnboardingViewControllerAppearance { }
+
+// MARK: - UITableViewDelegate
+extension MastodonLoginViewController: UITableViewDelegate {
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let server = viewModel.filteredServers[indexPath.row]
+ viewModel.selectedServer = server
+
+ contentView.searchTextField.text = server.domain
+ viewModel.filterServers(withText: " ")
+
+ contentView.navigationActionView.nextButton.isEnabled = true
+ tableView.deselectRow(at: indexPath, animated: true)
+ }
+}
+
+// MARK: - MastodonLoginViewModelDelegate
+extension MastodonLoginViewController: MastodonLoginViewModelDelegate {
+ func serversUpdated(_ viewModel: MastodonLoginViewModel) {
+ var snapshot = NSDiffableDataSourceSnapshot()
+
+ snapshot.appendSections([MastodonLoginViewSection.servers])
+ snapshot.appendItems(viewModel.filteredServers)
+
+ dataSource?.applySnapshot(snapshot, animated: false)
+
+ OperationQueue.main.addOperation {
+ let numberOfResults = viewModel.filteredServers.count
+ self.contentView.updateCorners(numberOfResults: numberOfResults)
+ }
+ }
+}
+
+// MARK: - ASWebAuthenticationPresentationContextProviding
+extension MastodonLoginViewController: ASWebAuthenticationPresentationContextProviding {
+ func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
+ return view.window!
+ }
+}
diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewModel.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewModel.swift
new file mode 100644
index 000000000..61311a1b9
--- /dev/null
+++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewModel.swift
@@ -0,0 +1,57 @@
+//
+// MastodonLoginViewModel.swift
+// Mastodon
+//
+// Created by Nathan Mattes on 11.11.22.
+//
+
+import Foundation
+import MastodonSDK
+import MastodonCore
+import Combine
+
+protocol MastodonLoginViewModelDelegate: AnyObject {
+ func serversUpdated(_ viewModel: MastodonLoginViewModel)
+}
+
+class MastodonLoginViewModel {
+
+ private var serverList: [Mastodon.Entity.Server] = []
+ var selectedServer: Mastodon.Entity.Server?
+ var filteredServers: [Mastodon.Entity.Server] = []
+
+ weak var appContext: AppContext?
+ weak var delegate: MastodonLoginViewModelDelegate?
+ var disposeBag = Set()
+
+ init(appContext: AppContext) {
+ self.appContext = appContext
+ }
+
+ func updateServers() {
+ appContext?.apiService.servers().sink(receiveCompletion: { [weak self] completion in
+ switch completion {
+ case .finished:
+ guard let self = self else { return }
+
+ self.delegate?.serversUpdated(self)
+ case .failure(let error):
+ print(error)
+ }
+ }, receiveValue: { content in
+ let servers = content.value
+ self.serverList = servers
+ }).store(in: &disposeBag)
+ }
+
+ func filterServers(withText query: String?) {
+ guard let query else {
+ filteredServers = serverList
+ delegate?.serversUpdated(self)
+ return
+ }
+
+ filteredServers = serverList.filter { $0.domain.lowercased().contains(query) }.sorted {$0.totalUsers > $1.totalUsers }
+ delegate?.serversUpdated(self)
+ }
+}
diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift
index eb26f75be..7e832ddca 100644
--- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift
@@ -143,8 +143,7 @@ extension MastodonPickServerViewController {
viewModel.setupDiffableDataSource(
for: tableView,
dependency: self,
- pickServerServerSectionTableHeaderViewDelegate: self,
- pickServerCellDelegate: self
+ pickServerServerSectionTableHeaderViewDelegate: self
)
KeyboardResponderService
@@ -172,7 +171,7 @@ extension MastodonPickServerViewController {
let alertController = UIAlertController(for: error, title: "Error", preferredStyle: .alert)
let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil)
alertController.addAction(okAction)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .alertController(alertController: alertController),
from: nil,
transition: .alertController(animated: true, completion: nil)
@@ -271,59 +270,6 @@ extension MastodonPickServerViewController {
}
@objc private func nextButtonDidPressed(_ sender: UIButton) {
- switch viewModel.mode {
- case .signIn: doSignIn()
- case .signUp: doSignUp()
- }
- }
-
- private func doSignIn() {
- guard let server = viewModel.selectedServer.value else { return }
- authenticationViewModel.isAuthenticating.send(true)
- context.apiService.createApplication(domain: server.domain)
- .tryMap { response -> AuthenticationViewModel.AuthenticateInfo in
- let application = response.value
- guard let info = AuthenticationViewModel.AuthenticateInfo(
- domain: server.domain,
- application: application,
- redirectURI: response.value.redirectURI ?? APIService.oauthCallbackURL
- ) else {
- throw APIService.APIError.explicit(.badResponse)
- }
- return info
- }
- .receive(on: DispatchQueue.main)
- .sink { [weak self] completion in
- guard let self = self else { return }
- self.authenticationViewModel.isAuthenticating.send(false)
-
- switch completion {
- case .failure(let error):
- os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: sign in fail: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
- self.viewModel.error.send(error)
- case .finished:
- break
- }
- } receiveValue: { [weak self] info in
- guard let self = self else { return }
- let authenticationController = MastodonAuthenticationController(
- context: self.context,
- authenticateURL: info.authorizeURL
- )
-
- self.mastodonAuthenticationController = authenticationController
- authenticationController.authenticationSession?.presentationContextProvider = self
- authenticationController.authenticationSession?.start()
-
- self.authenticationViewModel.authenticate(
- info: info,
- pinCodePublisher: authenticationController.pinCodePublisher
- )
- }
- .store(in: &disposeBag)
- }
-
- private func doSignUp() {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
guard let server = viewModel.selectedServer.value else { return }
authenticationViewModel.isAuthenticating.send(true)
@@ -394,7 +340,7 @@ extension MastodonPickServerViewController {
instance: response.instance.value,
applicationToken: response.applicationToken.value
)
- self.coordinator.present(scene: .mastodonServerRules(viewModel: mastodonServerRulesViewModel), from: self, transition: .show)
+ _ = self.coordinator.present(scene: .mastodonServerRules(viewModel: mastodonServerRulesViewModel), from: self, transition: .show)
} else {
let mastodonRegisterViewModel = MastodonRegisterViewModel(
context: self.context,
@@ -403,7 +349,7 @@ extension MastodonPickServerViewController {
instance: response.instance.value,
applicationToken: response.applicationToken.value
)
- self.coordinator.present(scene: .mastodonRegister(viewModel: mastodonRegisterViewModel), from: nil, transition: .show)
+ _ = self.coordinator.present(scene: .mastodonRegister(viewModel: mastodonRegisterViewModel), from: nil, transition: .show)
}
}
.store(in: &disposeBag)
@@ -503,17 +449,5 @@ extension MastodonPickServerViewController: PickServerServerSectionTableHeaderVi
}
}
-// MARK: - PickServerCellDelegate
-extension MastodonPickServerViewController: PickServerCellDelegate {
-
-}
-
// MARK: - OnboardingViewControllerAppearance
extension MastodonPickServerViewController: OnboardingViewControllerAppearance { }
-
-// MARK: - ASWebAuthenticationPresentationContextProviding
-extension MastodonPickServerViewController: ASWebAuthenticationPresentationContextProviding {
- func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
- return view.window!
- }
-}
diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift
index 35de40b8f..7edbfd2ac 100644
--- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift
@@ -13,8 +13,7 @@ extension MastodonPickServerViewModel {
func setupDiffableDataSource(
for tableView: UITableView,
dependency: NeedsDependency,
- pickServerServerSectionTableHeaderViewDelegate: PickServerServerSectionTableHeaderViewDelegate,
- pickServerCellDelegate: PickServerCellDelegate
+ pickServerServerSectionTableHeaderViewDelegate: PickServerServerSectionTableHeaderViewDelegate
) {
// set section header
serverSectionHeaderView.diffableDataSource = CategoryPickerSection.collectionViewDiffableDataSource(
@@ -34,8 +33,7 @@ extension MastodonPickServerViewModel {
// set tableView
diffableDataSource = PickServerSection.tableViewDiffableDataSource(
for: tableView,
- dependency: dependency,
- pickServerCellDelegate: pickServerCellDelegate
+ dependency: dependency
)
var snapshot = NSDiffableDataSourceSnapshot()
diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift
index 50c1d7aac..ebbcfe7fd 100644
--- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift
@@ -17,12 +17,7 @@ import MastodonCore
import MastodonUI
class MastodonPickServerViewModel: NSObject {
-
- enum PickServerMode {
- case signUp
- case signIn
- }
-
+
enum EmptyStateViewState {
case none
case loading
@@ -34,7 +29,6 @@ class MastodonPickServerViewModel: NSObject {
let serverSectionHeaderView = PickServerServerSectionTableHeaderView()
// input
- let mode: PickServerMode
let context: AppContext
var categoryPickerItems: [CategoryPickerItem] = {
var items: [CategoryPickerItem] = []
@@ -72,9 +66,8 @@ class MastodonPickServerViewModel: NSObject {
let loadingIndexedServersError = CurrentValueSubject(nil)
let emptyStateViewState = CurrentValueSubject(.none)
- init(context: AppContext, mode: PickServerMode) {
+ init(context: AppContext) {
self.context = context
- self.mode = mode
super.init()
configure()
@@ -115,9 +108,7 @@ extension MastodonPickServerViewModel {
.map { indexedServers, selectCategoryItem, searchText -> [Mastodon.Entity.Server] in
// ignore approval required servers when sign-up
var indexedServers = indexedServers
- if self.mode == .signUp {
- indexedServers = indexedServers.filter { !$0.approvalRequired }
- }
+ indexedServers = indexedServers.filter { !$0.approvalRequired }
// Note:
// sort by calculate last week users count
// and make medium size (~800) server to top
diff --git a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift
index 669067770..4cbe77b9c 100644
--- a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift
@@ -14,14 +14,8 @@ import Kanna
import MastodonAsset
import MastodonLocalization
-protocol PickServerCellDelegate: AnyObject {
-// func pickServerCell(_ cell: PickServerCell, expandButtonPressed button: UIButton)
-}
-
class PickServerCell: UITableViewCell {
- weak var delegate: PickServerCellDelegate?
-
var disposeBag = Set()
let containerView: UIStackView = {
@@ -88,7 +82,7 @@ class PickServerCell: UITableViewCell {
label.adjustsFontForContentSizeCategory = true
return label
}()
-
+
private var collapseConstraints: [NSLayoutConstraint] = []
private var expandConstraints: [NSLayoutConstraint] = []
diff --git a/Mastodon/Scene/Onboarding/PickServer/View/PickServerCategoryView.swift b/Mastodon/Scene/Onboarding/PickServer/View/PickServerCategoryView.swift
index 9d6cfc85f..aba5a87dc 100644
--- a/Mastodon/Scene/Onboarding/PickServer/View/PickServerCategoryView.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/View/PickServerCategoryView.swift
@@ -19,13 +19,6 @@ class PickServerCategoryView: UIView {
return view
}()
- let emojiLabel: UILabel = {
- let label = UILabel()
- label.textAlignment = .center
- label.font = .systemFont(ofSize: 34, weight: .regular)
- return label
- }()
-
let titleLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
@@ -50,23 +43,18 @@ extension PickServerCategoryView {
private func configure() {
let container = UIStackView()
container.axis = .vertical
+ container.spacing = 2
container.distribution = .fillProportionally
container.translatesAutoresizingMaskIntoConstraints = false
addSubview(container)
- NSLayoutConstraint.activate([
- container.topAnchor.constraint(equalTo: topAnchor),
- container.leadingAnchor.constraint(equalTo: leadingAnchor),
- container.trailingAnchor.constraint(equalTo: trailingAnchor),
- container.bottomAnchor.constraint(equalTo: bottomAnchor),
- ])
+ container.pinToParent()
- container.addArrangedSubview(emojiLabel)
container.addArrangedSubview(titleLabel)
highlightedIndicatorView.translatesAutoresizingMaskIntoConstraints = false
container.addArrangedSubview(highlightedIndicatorView)
NSLayoutConstraint.activate([
- highlightedIndicatorView.heightAnchor.constraint(equalToConstant: 3).priority(.required - 1),
+ highlightedIndicatorView.heightAnchor.constraint(equalToConstant: 3)//.priority(.required - 1),
])
titleLabel.setContentHuggingPriority(.required - 1, for: .vertical)
}
diff --git a/Mastodon/Scene/Onboarding/PickServer/View/PickServerServerSectionTableHeaderView.swift b/Mastodon/Scene/Onboarding/PickServer/View/PickServerServerSectionTableHeaderView.swift
index d50c62afe..ae8c16bb8 100644
--- a/Mastodon/Scene/Onboarding/PickServer/View/PickServerServerSectionTableHeaderView.swift
+++ b/Mastodon/Scene/Onboarding/PickServer/View/PickServerServerSectionTableHeaderView.swift
@@ -19,7 +19,7 @@ protocol PickServerServerSectionTableHeaderViewDelegate: AnyObject {
final class PickServerServerSectionTableHeaderView: UIView {
- static let collectionViewHeight: CGFloat = 88
+ static let collectionViewHeight: CGFloat = 30
static let searchTextFieldHeight: CGFloat = 38
static let spacing: CGFloat = 11
@@ -177,7 +177,6 @@ extension PickServerServerSectionTableHeaderView {
extension PickServerServerSectionTableHeaderView: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
- os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: indexPath: %s", ((#file as NSString).lastPathComponent), #line, #function, indexPath.debugDescription)
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
delegate?.pickServerServerSectionTableHeaderView(self, collectionView: collectionView, didSelectItemAt: indexPath)
}
@@ -205,5 +204,5 @@ extension PickServerServerSectionTableHeaderView: UITextFieldDelegate {
textField.resignFirstResponder()
return false
}
-
+
}
diff --git a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterAvatarTableViewCell.swift b/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterAvatarTableViewCell.swift
deleted file mode 100644
index 154385e6a..000000000
--- a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterAvatarTableViewCell.swift
+++ /dev/null
@@ -1,116 +0,0 @@
-//
-// MastodonRegisterAvatarTableViewCell.swift
-// Mastodon
-//
-// Created by MainasuK on 2022-1-5.
-//
-
-import UIKit
-import Combine
-import MastodonAsset
-import MastodonLocalization
-
-final class MastodonRegisterAvatarTableViewCell: UITableViewCell {
-
- static let containerSize = CGSize(width: 88, height: 88)
-
- var disposeBag = Set()
-
- let containerView: UIView = {
- let view = UIView()
- view.backgroundColor = .clear
- view.layer.masksToBounds = true
- view.layer.cornerCurve = .continuous
- view.layer.cornerRadius = 22
- return view
- }()
-
- let avatarButton: HighlightDimmableButton = {
- let button = HighlightDimmableButton()
- button.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
- button.setImage(Asset.Scene.Onboarding.avatarPlaceholder.image, for: .normal)
- return button
- }()
-
- let editBannerView: UIView = {
- let bannerView = UIView()
- bannerView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
- bannerView.isUserInteractionEnabled = false
-
- let label: UILabel = {
- let label = UILabel()
- label.textColor = .white
- label.text = L10n.Common.Controls.Actions.edit
- label.font = .systemFont(ofSize: 13, weight: .semibold)
- label.textAlignment = .center
- label.minimumScaleFactor = 0.5
- label.adjustsFontSizeToFitWidth = true
- return label
- }()
-
- label.translatesAutoresizingMaskIntoConstraints = false
- bannerView.addSubview(label)
- NSLayoutConstraint.activate([
- label.topAnchor.constraint(equalTo: bannerView.topAnchor),
- label.leadingAnchor.constraint(equalTo: bannerView.leadingAnchor),
- label.trailingAnchor.constraint(equalTo: bannerView.trailingAnchor),
- label.bottomAnchor.constraint(equalTo: bannerView.bottomAnchor),
- ])
-
- return bannerView
- }()
-
- override func prepareForReuse() {
- super.prepareForReuse()
-
- disposeBag.removeAll()
- }
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- _init()
- }
-
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- _init()
- }
-
-}
-
-extension MastodonRegisterAvatarTableViewCell {
-
- private func _init() {
- selectionStyle = .none
- backgroundColor = .clear
-
- containerView.translatesAutoresizingMaskIntoConstraints = false
- contentView.addSubview(containerView)
- NSLayoutConstraint.activate([
- containerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 22),
- containerView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
- contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 8),
- containerView.widthAnchor.constraint(equalToConstant: MastodonRegisterAvatarTableViewCell.containerSize.width).priority(.required - 1),
- containerView.heightAnchor.constraint(equalToConstant: MastodonRegisterAvatarTableViewCell.containerSize.height).priority(.required - 1),
- ])
-
- avatarButton.translatesAutoresizingMaskIntoConstraints = false
- containerView.addSubview(avatarButton)
- NSLayoutConstraint.activate([
- avatarButton.topAnchor.constraint(equalTo: containerView.topAnchor),
- avatarButton.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
- avatarButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
- avatarButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
- ])
-
- editBannerView.translatesAutoresizingMaskIntoConstraints = false
- containerView.addSubview(editBannerView)
- NSLayoutConstraint.activate([
- editBannerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
- editBannerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
- editBannerView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
- editBannerView.heightAnchor.constraint(equalToConstant: 22),
- ])
- }
-
-}
diff --git a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterPasswordHintTableViewCell.swift b/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterPasswordHintTableViewCell.swift
deleted file mode 100644
index 1324c2822..000000000
--- a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterPasswordHintTableViewCell.swift
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// MastodonRegisterPasswordHintTableViewCell.swift
-// Mastodon
-//
-// Created by MainasuK on 2022-1-7.
-//
-
-import UIKit
-import MastodonAsset
-import MastodonLocalization
-
-final class MastodonRegisterPasswordHintTableViewCell: UITableViewCell {
-
- let passwordRuleLabel: UILabel = {
- let label = UILabel()
- label.font = .preferredFont(forTextStyle: .footnote)
- label.textColor = Asset.Colors.Label.secondary.color
- label.text = L10n.Scene.Register.Input.Password.hint
- return label
- }()
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- _init()
- }
-
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- _init()
- }
-
-}
-
-extension MastodonRegisterPasswordHintTableViewCell {
-
- private func _init() {
- selectionStyle = .none
- backgroundColor = .clear
-
- passwordRuleLabel.translatesAutoresizingMaskIntoConstraints = false
- contentView.addSubview(passwordRuleLabel)
- NSLayoutConstraint.activate([
- passwordRuleLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
- passwordRuleLabel.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
- passwordRuleLabel.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor),
- passwordRuleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
- ])
- }
-
-}
diff --git a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift b/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift
deleted file mode 100644
index 15f234834..000000000
--- a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift
+++ /dev/null
@@ -1,142 +0,0 @@
-//
-// MastodonRegisterTextFieldTableViewCell.swift
-// Mastodon
-//
-// Created by MainasuK on 2022-1-7.
-//
-
-import UIKit
-import Combine
-import MastodonUI
-import MastodonAsset
-import MastodonLocalization
-
-final class MastodonRegisterTextFieldTableViewCell: UITableViewCell {
-
- static let textFieldHeight: CGFloat = 50
- static let textFieldLabelFont = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 22)
-
- var disposeBag = Set()
-
- let textFieldShadowContainer = ShadowBackgroundContainer()
- let textField: UITextField = {
- let textField = UITextField()
- textField.font = MastodonRegisterTextFieldTableViewCell.textFieldLabelFont
- textField.backgroundColor = Asset.Scene.Onboarding.textFieldBackground.color
- textField.layer.masksToBounds = true
- textField.layer.cornerRadius = 10
- textField.layer.cornerCurve = .continuous
- return textField
- }()
-
- override func prepareForReuse() {
- super.prepareForReuse()
-
- disposeBag.removeAll()
- textFieldShadowContainer.shadowColor = .black
- textFieldShadowContainer.shadowAlpha = 0.25
- resetTextField()
- }
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- _init()
- }
-
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- _init()
- }
-
-}
-
-extension MastodonRegisterTextFieldTableViewCell {
-
- private func _init() {
- selectionStyle = .none
- backgroundColor = .clear
-
- textFieldShadowContainer.translatesAutoresizingMaskIntoConstraints = false
- contentView.addSubview(textFieldShadowContainer)
- NSLayoutConstraint.activate([
- textFieldShadowContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6),
- textFieldShadowContainer.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
- textFieldShadowContainer.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor),
- contentView.bottomAnchor.constraint(equalTo: textFieldShadowContainer.bottomAnchor, constant: 6),
- ])
-
- textField.translatesAutoresizingMaskIntoConstraints = false
- textFieldShadowContainer.addSubview(textField)
- NSLayoutConstraint.activate([
- textField.topAnchor.constraint(equalTo: textFieldShadowContainer.topAnchor),
- textField.leadingAnchor.constraint(equalTo: textFieldShadowContainer.leadingAnchor),
- textField.trailingAnchor.constraint(equalTo: textFieldShadowContainer.trailingAnchor),
- textField.bottomAnchor.constraint(equalTo: textFieldShadowContainer.bottomAnchor),
- textField.heightAnchor.constraint(equalToConstant: MastodonRegisterTextFieldTableViewCell.textFieldHeight).priority(.required - 1),
- ])
-
- resetTextField()
- }
-
-}
-
-extension MastodonRegisterTextFieldTableViewCell {
- func resetTextField() {
- textField.keyboardType = .default
- textField.autocorrectionType = .default
- textField.autocapitalizationType = .none
- textField.attributedPlaceholder = nil
- textField.isSecureTextEntry = false
- textField.textAlignment = .natural
- textField.semanticContentAttribute = .unspecified
-
- let paddingRect = CGRect(x: 0, y: 0, width: 16, height: 10)
- textField.leftView = UIView(frame: paddingRect)
- textField.leftViewMode = .always
- textField.rightView = UIView(frame: paddingRect)
- textField.rightViewMode = .always
- }
-
- func setupTextViewRightView(text: String) {
- textField.rightView = {
- let containerView = UIView()
-
- let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 8, height: MastodonRegisterTextFieldTableViewCell.textFieldHeight))
- paddingView.translatesAutoresizingMaskIntoConstraints = false
- containerView.addSubview(paddingView)
- NSLayoutConstraint.activate([
- paddingView.topAnchor.constraint(equalTo: containerView.topAnchor),
- paddingView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
- paddingView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
- paddingView.widthAnchor.constraint(equalToConstant: 8).priority(.defaultHigh),
- ])
-
- let label = UILabel()
- label.font = MastodonRegisterTextFieldTableViewCell.textFieldLabelFont
- label.textColor = Asset.Colors.Label.primary.color
- label.text = text
- label.lineBreakMode = .byTruncatingMiddle
-
- label.translatesAutoresizingMaskIntoConstraints = false
- containerView.addSubview(label)
- NSLayoutConstraint.activate([
- label.topAnchor.constraint(equalTo: containerView.topAnchor),
- label.leadingAnchor.constraint(equalTo: paddingView.trailingAnchor),
- containerView.trailingAnchor.constraint(equalTo: label.trailingAnchor, constant: 16),
- label.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
- label.widthAnchor.constraint(lessThanOrEqualToConstant: 180).priority(.required - 1),
- ])
- return containerView
- }()
- }
-
- func setupTextViewPlaceholder(text: String) {
- textField.attributedPlaceholder = NSAttributedString(
- string: text,
- attributes: [
- .foregroundColor: Asset.Colors.Label.secondary.color,
- .font: MastodonRegisterTextFieldTableViewCell.textFieldLabelFont
- ]
- )
- }
-}
diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift
index 2be7c61d7..4f28353b0 100644
--- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift
+++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift
@@ -168,21 +168,27 @@ struct MastodonRegisterView: View {
func body(content: Content) -> some View {
ZStack {
- let shadowColor: Color = {
+ let borderColor: Color = {
switch validateState {
- case .empty: return .black.opacity(0.125)
- case .invalid: return Color(Asset.Colors.TextField.invalid.color)
- case .valid: return Color(Asset.Colors.TextField.valid.color)
+ case .empty: return Color(Asset.Scene.Onboarding.textFieldBackground.color)
+ case .invalid: return Color(Asset.Colors.TextField.invalid.color)
+ case .valid: return Color(Asset.Scene.Onboarding.textFieldBackground.color)
}
}()
+
Color(Asset.Scene.Onboarding.textFieldBackground.color)
.cornerRadius(10)
- .shadow(color: shadowColor, radius: 1, x: 0, y: 2)
- .animation(.easeInOut, value: validateState)
+ .shadow(color: .black.opacity(0.125), radius: 1, x: 0, y: 2)
+
content
.padding()
.background(Color(Asset.Scene.Onboarding.textFieldBackground.color))
.cornerRadius(10)
+ .overlay(
+ RoundedRectangle(cornerRadius: 10)
+ .stroke(borderColor, lineWidth: 1)
+ .animation(.easeInOut, value: validateState)
+ )
}
}
}
diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController+Avatar.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController+Avatar.swift
index 9260f9e21..81924d812 100644
--- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController+Avatar.swift
+++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController+Avatar.swift
@@ -49,7 +49,7 @@ extension MastodonRegisterViewController: PHPickerViewControllerDelegate {
let alertController = UIAlertController(for: error, title: "", preferredStyle: .alert)
let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil)
alertController.addAction(okAction)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .alertController(alertController: alertController),
from: nil,
transition: .alertController(animated: true, completion: nil)
diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift
index 9b10bd48e..f239e59b7 100644
--- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift
+++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift
@@ -85,12 +85,7 @@ extension MastodonRegisterViewController {
addChild(hostingViewController)
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingViewController.view)
- NSLayoutConstraint.activate([
- hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ hostingViewController.view.pinToParent()
navigationActionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navigationActionView)
@@ -145,7 +140,7 @@ extension MastodonRegisterViewController {
let alertController = UIAlertController(for: error, title: "Sign Up Failure", preferredStyle: .alert)
let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil)
alertController.addAction(okAction)
- self.coordinator.present(
+ _ = self.coordinator.present(
scene: .alertController(alertController: alertController),
from: nil,
transition: .alertController(animated: true, completion: nil)
@@ -322,7 +317,7 @@ extension MastodonRegisterViewController {
)
}()
let viewModel = MastodonConfirmEmailViewModel(context: self.context, email: email, authenticateInfo: self.viewModel.authenticateInfo, userToken: userToken, updateCredentialQuery: updateCredentialQuery)
- self.coordinator.present(scene: .mastodonConfirmEmail(viewModel: viewModel), from: self, transition: .show)
+ _ = self.coordinator.present(scene: .mastodonConfirmEmail(viewModel: viewModel), from: self, transition: .show)
}
.store(in: &disposeBag)
}
diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift
index dda59843a..b3e2a2cdb 100644
--- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift
+++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift
@@ -10,145 +10,6 @@ import Combine
import MastodonAsset
import MastodonLocalization
-extension MastodonRegisterViewModel {
- func setupDiffableDataSource(
- tableView: UITableView
- ) {
- tableView.register(OnboardingHeadlineTableViewCell.self, forCellReuseIdentifier: String(describing: OnboardingHeadlineTableViewCell.self))
- tableView.register(MastodonRegisterAvatarTableViewCell.self, forCellReuseIdentifier: String(describing: MastodonRegisterAvatarTableViewCell.self))
- tableView.register(MastodonRegisterTextFieldTableViewCell.self, forCellReuseIdentifier: String(describing: MastodonRegisterTextFieldTableViewCell.self))
- tableView.register(MastodonRegisterPasswordHintTableViewCell.self, forCellReuseIdentifier: String(describing: MastodonRegisterPasswordHintTableViewCell.self))
-
- diffableDataSource = UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in
- switch item {
- case .header(let domain):
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: OnboardingHeadlineTableViewCell.self), for: indexPath) as! OnboardingHeadlineTableViewCell
- cell.titleLabel.text = L10n.Scene.Register.letsGetYouSetUpOnDomain(domain)
- cell.subTitleLabel.isHidden = true
- return cell
- case .avatar:
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MastodonRegisterAvatarTableViewCell.self), for: indexPath) as! MastodonRegisterAvatarTableViewCell
- self.configureAvatar(cell: cell)
- return cell
- case .name:
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MastodonRegisterTextFieldTableViewCell.self), for: indexPath) as! MastodonRegisterTextFieldTableViewCell
- cell.setupTextViewPlaceholder(text: L10n.Scene.Register.Input.DisplayName.placeholder)
- cell.textField.keyboardType = .default
- cell.textField.autocapitalizationType = .words
- cell.textField.text = self.name
- NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: cell.textField)
- .receive(on: DispatchQueue.main)
- .compactMap { notification in
- guard let textField = notification.object as? UITextField else {
- assertionFailure()
- return nil
- }
- return textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
- }
- .assign(to: \.name, on: self)
- .store(in: &cell.disposeBag)
- return cell
- case .username:
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MastodonRegisterTextFieldTableViewCell.self), for: indexPath) as! MastodonRegisterTextFieldTableViewCell
- cell.setupTextViewRightView(text: "@" + self.domain)
- cell.setupTextViewPlaceholder(text: L10n.Scene.Register.Input.Username.placeholder)
- cell.textField.keyboardType = .alphabet
- cell.textField.autocorrectionType = .no
- cell.textField.text = self.username
- cell.textField.textAlignment = .left
- cell.textField.semanticContentAttribute = .forceLeftToRight
- NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: cell.textField)
- .receive(on: DispatchQueue.main)
- .compactMap { notification in
- guard let textField = notification.object as? UITextField else {
- assertionFailure()
- return nil
- }
- return textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
- }
- .assign(to: \.username, on: self)
- .store(in: &cell.disposeBag)
- self.configureTextFieldCell(cell: cell, validateState: self.$usernameValidateState)
- return cell
- case .email:
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MastodonRegisterTextFieldTableViewCell.self), for: indexPath) as! MastodonRegisterTextFieldTableViewCell
- cell.setupTextViewPlaceholder(text: L10n.Scene.Register.Input.Email.placeholder)
- cell.textField.keyboardType = .emailAddress
- cell.textField.autocorrectionType = .no
- cell.textField.text = self.email
- NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: cell.textField)
- .receive(on: DispatchQueue.main)
- .compactMap { notification in
- guard let textField = notification.object as? UITextField else {
- assertionFailure()
- return nil
- }
- return textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
- }
- .assign(to: \.email, on: self)
- .store(in: &cell.disposeBag)
- self.configureTextFieldCell(cell: cell, validateState: self.$emailValidateState)
- return cell
- case .password:
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MastodonRegisterTextFieldTableViewCell.self), for: indexPath) as! MastodonRegisterTextFieldTableViewCell
- cell.setupTextViewPlaceholder(text: L10n.Scene.Register.Input.Password.placeholder)
- cell.textField.keyboardType = .alphabet
- cell.textField.autocorrectionType = .no
- cell.textField.isSecureTextEntry = true
- cell.textField.text = self.password
- cell.textField.textAlignment = .left
- cell.textField.semanticContentAttribute = .forceLeftToRight
- NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: cell.textField)
- .receive(on: DispatchQueue.main)
- .compactMap { notification in
- guard let textField = notification.object as? UITextField else {
- assertionFailure()
- return nil
- }
- return textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
- }
- .assign(to: \.password, on: self)
- .store(in: &cell.disposeBag)
- self.configureTextFieldCell(cell: cell, validateState: self.$passwordValidateState)
- return cell
- case .hint:
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MastodonRegisterPasswordHintTableViewCell.self), for: indexPath) as! MastodonRegisterPasswordHintTableViewCell
- return cell
- case .reason:
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MastodonRegisterTextFieldTableViewCell.self), for: indexPath) as! MastodonRegisterTextFieldTableViewCell
- cell.setupTextViewPlaceholder(text: L10n.Scene.Register.Input.Invite.registrationUserInviteRequest)
- cell.textField.keyboardType = .default
- cell.textField.text = self.reason
- NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: cell.textField)
- .receive(on: DispatchQueue.main)
- .compactMap { notification in
- guard let textField = notification.object as? UITextField else {
- assertionFailure()
- return nil
- }
- return textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
- }
- .assign(to: \.reason, on: self)
- .store(in: &cell.disposeBag)
- self.configureTextFieldCell(cell: cell, validateState: self.$reasonValidateState)
- return cell
- default:
- assertionFailure()
- return UITableViewCell()
- }
- }
-
- var snapshot = NSDiffableDataSourceSnapshot()
- snapshot.appendSections([.main])
- snapshot.appendItems([.header(domain: domain)], toSection: .main)
- snapshot.appendItems([.avatar, .name, .username, .email, .password, .hint], toSection: .main)
- if approvalRequired {
- snapshot.appendItems([.reason], toSection: .main)
- }
- diffableDataSource?.applySnapshot(snapshot, animated: false, completion: nil)
- }
-}
-
extension MastodonRegisterViewModel {
private func configureAvatar(cell: MastodonRegisterAvatarTableViewCell) {
self.$avatarImage
diff --git a/Mastodon/Scene/Onboarding/ResendEmail/MastodonResendEmailViewController.swift b/Mastodon/Scene/Onboarding/ResendEmail/MastodonResendEmailViewController.swift
index 178d489be..d6870785c 100644
--- a/Mastodon/Scene/Onboarding/ResendEmail/MastodonResendEmailViewController.swift
+++ b/Mastodon/Scene/Onboarding/ResendEmail/MastodonResendEmailViewController.swift
@@ -49,12 +49,7 @@ extension MastodonResendEmailViewController {
webView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(webView)
- NSLayoutConstraint.activate([
- webView.topAnchor.constraint(equalTo: view.topAnchor),
- webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ webView.pinToParent()
let request = URLRequest(url: viewModel.resendEmailURL)
webView.navigationDelegate = self.viewModel.navigationDelegate
diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift
index 0d4e27d98..ea0b58e28 100644
--- a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift
+++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift
@@ -69,12 +69,7 @@ extension MastodonServerRulesViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
navigationActionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navigationActionView)
@@ -127,7 +122,7 @@ extension MastodonServerRulesViewController {
instance: viewModel.instance,
applicationToken: viewModel.applicationToken
)
- coordinator.present(scene: .mastodonRegister(viewModel: viewModel), from: self, transition: .show)
+ _ = coordinator.present(scene: .mastodonRegister(viewModel: viewModel), from: self, transition: .show)
}
}
diff --git a/Mastodon/Scene/Onboarding/Share/NavigationActionView.swift b/Mastodon/Scene/Onboarding/Share/NavigationActionView.swift
index c3236bdb4..54b473df8 100644
--- a/Mastodon/Scene/Onboarding/Share/NavigationActionView.swift
+++ b/Mastodon/Scene/Onboarding/Share/NavigationActionView.swift
@@ -84,21 +84,11 @@ extension NavigationActionView {
backButton.translatesAutoresizingMaskIntoConstraints = false
backButtonShadowContainer.addSubview(backButton)
- NSLayoutConstraint.activate([
- backButton.topAnchor.constraint(equalTo: backButtonShadowContainer.topAnchor),
- backButton.leadingAnchor.constraint(equalTo: backButtonShadowContainer.leadingAnchor),
- backButton.trailingAnchor.constraint(equalTo: backButtonShadowContainer.trailingAnchor),
- backButton.bottomAnchor.constraint(equalTo: backButtonShadowContainer.bottomAnchor),
- ])
+ backButton.pinToParent()
nextButton.translatesAutoresizingMaskIntoConstraints = false
nextButtonShadowContainer.addSubview(nextButton)
- NSLayoutConstraint.activate([
- nextButton.topAnchor.constraint(equalTo: nextButtonShadowContainer.topAnchor),
- nextButton.leadingAnchor.constraint(equalTo: nextButtonShadowContainer.leadingAnchor),
- nextButton.trailingAnchor.constraint(equalTo: nextButtonShadowContainer.trailingAnchor),
- nextButton.bottomAnchor.constraint(equalTo: nextButtonShadowContainer.bottomAnchor),
- ])
+ nextButton.pinToParent()
}
}
diff --git a/Mastodon/Scene/Onboarding/Share/OnboardingNavigationController.swift b/Mastodon/Scene/Onboarding/Share/OnboardingNavigationController.swift
index 537102dc9..ac2e5b171 100644
--- a/Mastodon/Scene/Onboarding/Share/OnboardingNavigationController.swift
+++ b/Mastodon/Scene/Onboarding/Share/OnboardingNavigationController.swift
@@ -20,12 +20,7 @@ extension OnboardingNavigationController {
gradientBorderView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(gradientBorderView)
- NSLayoutConstraint.activate([
- gradientBorderView.topAnchor.constraint(equalTo: view.topAnchor),
- gradientBorderView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- gradientBorderView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- gradientBorderView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ gradientBorderView.pinToParent()
updateBorderViewDisplay()
}
diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift
index 0530539a2..1fca1afef 100644
--- a/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift
+++ b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift
@@ -96,12 +96,7 @@ extension WelcomeIllustrationView {
].forEach { imageView in
imageView.translatesAutoresizingMaskIntoConstraints = false
addSubview(imageView)
- NSLayoutConstraint.activate([
- imageView.topAnchor.constraint(equalTo: cloudBaseImageView.topAnchor),
- imageView.leadingAnchor.constraint(equalTo: cloudBaseImageView.leadingAnchor),
- imageView.trailingAnchor.constraint(equalTo: cloudBaseImageView.trailingAnchor),
- imageView.bottomAnchor.constraint(equalTo: cloudBaseImageView.bottomAnchor),
- ])
+ imageView.pinTo(to: cloudBaseImageView)
}
aspectLayoutConstraint = cloudBaseImageView.widthAnchor.constraint(equalTo: cloudBaseImageView.heightAnchor, multiplier: layout.artworkImageSize.width / layout.artworkImageSize.height)
diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift
index a2b8df83a..86a4af800 100644
--- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift
+++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift
@@ -124,22 +124,12 @@ extension WelcomeViewController {
signUpButtonShadowView.translatesAutoresizingMaskIntoConstraints = false
buttonContainer.addSubview(signUpButtonShadowView)
buttonContainer.sendSubviewToBack(signUpButtonShadowView)
- NSLayoutConstraint.activate([
- signUpButtonShadowView.topAnchor.constraint(equalTo: signUpButton.topAnchor),
- signUpButtonShadowView.leadingAnchor.constraint(equalTo: signUpButton.leadingAnchor),
- signUpButtonShadowView.trailingAnchor.constraint(equalTo: signUpButton.trailingAnchor),
- signUpButtonShadowView.bottomAnchor.constraint(equalTo: signUpButton.bottomAnchor),
- ])
+ signUpButtonShadowView.pinTo(to: signUpButton)
signInButtonShadowView.translatesAutoresizingMaskIntoConstraints = false
buttonContainer.addSubview(signInButtonShadowView)
buttonContainer.sendSubviewToBack(signInButtonShadowView)
- NSLayoutConstraint.activate([
- signInButtonShadowView.topAnchor.constraint(equalTo: signInButton.topAnchor),
- signInButtonShadowView.leadingAnchor.constraint(equalTo: signInButton.leadingAnchor),
- signInButtonShadowView.trailingAnchor.constraint(equalTo: signInButton.trailingAnchor),
- signInButtonShadowView.bottomAnchor.constraint(equalTo: signInButton.bottomAnchor),
- ])
+ signInButtonShadowView.pinTo(to: signInButton)
signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside)
signInButton.addTarget(self, action: #selector(signInButtonDidClicked(_:)), for: .touchUpInside)
@@ -243,7 +233,7 @@ extension WelcomeViewController {
logoImageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
logoImageView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 35),
view.readableContentGuide.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor, constant: 35),
- logoImageView.heightAnchor.constraint(equalTo: logoImageView.widthAnchor, multiplier: 65.4/265.1),
+ logoImageView.heightAnchor.constraint(equalTo: logoImageView.widthAnchor, multiplier: 75.0/269.0),
])
logoImageView.setContentHuggingPriority(.defaultHigh, for: .vertical)
}
@@ -317,12 +307,12 @@ extension WelcomeViewController {
extension WelcomeViewController {
@objc
private func signUpButtonDidClicked(_ sender: UIButton) {
- coordinator.present(scene: .mastodonPickServer(viewMode: MastodonPickServerViewModel(context: context, mode: .signUp)), from: self, transition: .show)
+ _ = coordinator.present(scene: .mastodonPickServer(viewMode: MastodonPickServerViewModel(context: context)), from: self, transition: .show)
}
@objc
private func signInButtonDidClicked(_ sender: UIButton) {
- coordinator.present(scene: .mastodonPickServer(viewMode: MastodonPickServerViewModel(context: context, mode: .signIn)), from: self, transition: .show)
+ _ = coordinator.present(scene: .mastodonLogin, from: self, transition: .show)
}
@objc
diff --git a/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift b/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift
index eb1e6b39c..fe92d2ac4 100644
--- a/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift
+++ b/Mastodon/Scene/Profile/About/ProfileAboutViewController.swift
@@ -60,12 +60,7 @@ extension ProfileAboutViewController {
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
- NSLayoutConstraint.activate([
- collectionView.topAnchor.constraint(equalTo: view.topAnchor),
- collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ collectionView.pinToParent()
collectionView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift b/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift
index 5edec2618..458c47335 100644
--- a/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift
+++ b/Mastodon/Scene/Profile/Bookmark/BookmarkViewController.swift
@@ -64,12 +64,7 @@ extension BookmarkViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift
index b6d6f8313..3595303d9 100644
--- a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift
+++ b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift
@@ -53,12 +53,7 @@ extension FamiliarFollowersViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
index c15adcf83..19f25f3ad 100644
--- a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
+++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
@@ -67,12 +67,7 @@ extension FavoriteViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift
index 803a9d45e..c2dc27201 100644
--- a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift
+++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+State.swift
@@ -46,7 +46,7 @@ extension FavoriteViewModel {
extension FavoriteViewModel.State {
class Initial: FavoriteViewModel.State {
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
- guard let viewModel = viewModel else { return false }
+ guard viewModel != nil else { return false }
switch stateClass {
case is Reloading.Type:
return true
@@ -130,13 +130,12 @@ extension FavoriteViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let viewModel else { return }
if previousState is Reloading {
maxID = nil
}
-
Task {
do {
let response = try await viewModel.context.apiService.favoritedStatuses(
diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift
index 190fa27e5..c111d13d0 100644
--- a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift
+++ b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift
@@ -58,12 +58,7 @@ extension FollowerListViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewController.swift b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift
index e16b600c2..3fa65918a 100644
--- a/Mastodon/Scene/Profile/Following/FollowingListViewController.swift
+++ b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift
@@ -58,12 +58,7 @@ extension FollowingListViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
index c5dbbecd4..7ca819b41 100644
--- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
+++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
@@ -60,7 +60,8 @@ final class ProfileHeaderViewController: UIViewController, NeedsDependency, Medi
// private var isAdjustBannerImageViewForSafeAreaInset = false
private var containerSafeAreaInset: UIEdgeInsets = .zero
-
+
+ private var currentImageType = ImageType.avatar
private(set) lazy var imagePicker: PHPickerViewController = {
var configuration = PHPickerConfiguration()
configuration.filter = .images
@@ -125,7 +126,9 @@ extension ProfileHeaderViewController {
}
.store(in: &disposeBag)
- profileHeaderView.editAvatarButtonOverlayIndicatorView.menu = createAvatarContextMenu()
+ profileHeaderView.editBannerButton.menu = createImageContextMenu(.banner)
+ profileHeaderView.editBannerButton.showsMenuAsPrimaryAction = true
+ profileHeaderView.editAvatarButtonOverlayIndicatorView.menu = createImageContextMenu(.avatar)
profileHeaderView.editAvatarButtonOverlayIndicatorView.showsMenuAsPrimaryAction = true
profileHeaderView.delegate = self
@@ -156,6 +159,9 @@ extension ProfileHeaderViewController {
viewModel.$isUpdating
.assign(to: \.isUpdating, on: profileHeaderView.viewModel)
.store(in: &disposeBag)
+ viewModel.profileInfoEditing.$header
+ .assign(to: \.headerImageEditing, on: profileHeaderView.viewModel)
+ .store(in: &disposeBag)
viewModel.profileInfoEditing.$avatar
.assign(to: \.avatarImageEditing, on: profileHeaderView.viewModel)
.store(in: &disposeBag)
@@ -173,7 +179,7 @@ extension ProfileHeaderViewController {
profileHeaderView.viewModel.viewDidAppear.send()
// set display after view appear
- profileHeaderView.setupAvatarOverlayViews()
+ profileHeaderView.setupImageOverlayViews()
}
override func viewDidLayoutSubviews() {
@@ -185,11 +191,16 @@ extension ProfileHeaderViewController {
}
extension ProfileHeaderViewController {
- private func createAvatarContextMenu() -> UIMenu {
+ fileprivate enum ImageType {
+ case avatar
+ case banner
+ }
+ private func createImageContextMenu(_ type: ImageType) -> UIMenu {
var children: [UIMenuElement] = []
let photoLibraryAction = UIAction(title: L10n.Scene.Compose.MediaSelection.photoLibrary, image: UIImage(systemName: "rectangle.on.rectangle"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .photoLibaray", ((#file as NSString).lastPathComponent), #line, #function)
+ self.currentImageType = type
self.present(self.imagePicker, animated: true, completion: nil)
}
children.append(photoLibraryAction)
@@ -197,6 +208,7 @@ extension ProfileHeaderViewController {
let cameraAction = UIAction(title: L10n.Scene.Compose.MediaSelection.camera, image: UIImage(systemName: "camera"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off, handler: { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .camera", ((#file as NSString).lastPathComponent), #line, #function)
+ self.currentImageType = type
self.present(self.imagePickerController, animated: true, completion: nil)
})
children.append(cameraAction)
@@ -204,6 +216,7 @@ extension ProfileHeaderViewController {
let browseAction = UIAction(title: L10n.Scene.Compose.MediaSelection.browse, image: UIImage(systemName: "ellipsis"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .browse", ((#file as NSString).lastPathComponent), #line, #function)
+ self.currentImageType = type
self.present(self.documentPickerController, animated: true, completion: nil)
}
children.append(browseAction)
@@ -215,7 +228,13 @@ extension ProfileHeaderViewController {
DispatchQueue.main.async {
let cropController = CropViewController(croppingStyle: .default, image: image)
cropController.delegate = self
- cropController.setAspectRatioPreset(.presetSquare, animated: true)
+ switch self.currentImageType {
+ case .banner:
+ cropController.customAspectRatio = CGSize(width: 3, height: 1)
+ cropController.setAspectRatioPreset(.presetCustom, animated: true)
+ case .avatar:
+ cropController.setAspectRatioPreset(.presetSquare, animated: true)
+ }
cropController.aspectRatioPickerButtonHidden = true
cropController.aspectRatioLockEnabled = true
pickerViewController.dismiss(animated: true, completion: {
@@ -443,7 +462,12 @@ extension ProfileHeaderViewController: UIDocumentPickerDelegate {
// MARK: - CropViewControllerDelegate
extension ProfileHeaderViewController: CropViewControllerDelegate {
public func cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
- viewModel.profileInfoEditing.avatar = image
+ switch currentImageType {
+ case .banner:
+ viewModel.profileInfoEditing.header = image
+ case .avatar:
+ viewModel.profileInfoEditing.avatar = image
+ }
cropViewController.dismiss(animated: true, completion: nil)
}
}
diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
index 65f15efa7..c66789cca 100644
--- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
+++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
@@ -18,6 +18,7 @@ import MastodonUI
final class ProfileHeaderViewModel {
static let avatarImageMaxSizeInPixel = CGSize(width: 400, height: 400)
+ static let bannerImageMaxSizeInPixel = CGSize(width: 1500, height: 500)
static let maxProfileFieldCount = 4
var disposeBag = Set()
@@ -52,6 +53,9 @@ final class ProfileHeaderViewModel {
.sink { [weak self] account in
guard let self = self else { return }
guard let account = account else { return }
+ // banner
+ self.profileInfo.header = nil
+ self.profileInfoEditing.header = nil
// avatar
self.profileInfo.avatar = nil
self.profileInfoEditing.avatar = nil
@@ -72,6 +76,7 @@ final class ProfileHeaderViewModel {
extension ProfileHeaderViewModel {
class ProfileInfo {
// input
+ @Published var header: UIImage?
@Published var avatar: UIImage?
@Published var name: String?
@Published var note: String?
@@ -99,6 +104,7 @@ extension ProfileHeaderViewModel: ProfileViewModelEditable {
var isEdited: Bool {
guard isEditing else { return false }
+ guard profileInfoEditing.header == nil else { return true }
guard profileInfoEditing.avatar == nil else { return true }
guard profileInfo.name == profileInfoEditing.name else { return true }
guard profileInfo.note == profileInfoEditing.note else { return true }
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift
index c51ccfab3..5095d7ac0 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift
@@ -28,6 +28,7 @@ extension ProfileHeaderView {
@Published var emojiMeta: MastodonContent.Emojis = [:]
@Published var headerImageURL: URL?
+ @Published var headerImageEditing: UIImage?
@Published var avatarImageURL: URL?
@Published var avatarImageEditing: UIImage?
@@ -61,14 +62,19 @@ extension ProfileHeaderView.ViewModel {
func bind(view: ProfileHeaderView) {
// header
- Publishers.CombineLatest(
+ Publishers.CombineLatest4(
$headerImageURL,
+ $headerImageEditing,
+ $isEditing,
viewDidAppear
)
- .sink { headerImageURL, _ in
+ .sink { headerImageURL, headerImageEditing, isEditing, _ in
view.bannerImageView.af.cancelImageRequest()
- let placeholder = UIImage.placeholder(color: ProfileHeaderView.bannerImageViewPlaceholderColor)
- guard let bannerImageURL = headerImageURL else {
+ let defaultPlaceholder = UIImage.placeholder(color: ProfileHeaderView.bannerImageViewPlaceholderColor)
+ let placeholder = isEditing ? (headerImageEditing ?? defaultPlaceholder) : defaultPlaceholder
+ guard let bannerImageURL = headerImageURL,
+ !isEditing || headerImageEditing == nil
+ else {
view.bannerImageView.image = placeholder
return
}
@@ -262,22 +268,29 @@ extension ProfileHeaderView {
animator.addAnimations {
self.bannerImageViewOverlayVisualEffectView.backgroundColor = ProfileHeaderView.bannerImageViewOverlayViewBackgroundNormalColor
self.nameTextFieldBackgroundView.backgroundColor = .clear
+ self.editBannerButton.alpha = 0
self.editAvatarBackgroundView.alpha = 0
}
animator.addCompletion { _ in
+ self.editBannerButton.isHidden = true
self.editAvatarBackgroundView.isHidden = true
+ self.bannerImageViewSingleTapGestureRecognizer.isEnabled = true
}
case .editing:
nameMetaText.textView.alpha = 0
nameTextField.isEnabled = true
nameTextField.alpha = 1
+ editBannerButton.isHidden = false
+ editBannerButton.alpha = 0
editAvatarBackgroundView.isHidden = false
editAvatarBackgroundView.alpha = 0
bioMetaText.textView.backgroundColor = .clear
+ bannerImageViewSingleTapGestureRecognizer.isEnabled = false
animator.addAnimations {
self.bannerImageViewOverlayVisualEffectView.backgroundColor = ProfileHeaderView.bannerImageViewOverlayViewBackgroundEditingColor
self.nameTextFieldBackgroundView.backgroundColor = Asset.Scene.Profile.Banner.nameEditBackgroundGray.color
+ self.editBannerButton.alpha = 1
self.editAvatarBackgroundView.alpha = 1
self.bioMetaText.textView.backgroundColor = Asset.Scene.Profile.Banner.bioEditBackgroundGray.color
}
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
index a2194758b..cf2443552 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
@@ -50,6 +50,7 @@ final class ProfileHeaderView: UIView {
return viewModel
}()
+ let bannerImageViewSingleTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
let bannerContainerView = UIView()
let bannerImageView: UIImageView = {
let imageView = UIImageView()
@@ -101,7 +102,9 @@ final class ProfileHeaderView: UIView {
return button
}()
- func setupAvatarOverlayViews() {
+ func setupImageOverlayViews() {
+ editBannerButton.tintColor = .white
+
editAvatarBackgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
editAvatarButtonOverlayIndicatorView.tintColor = .white
}
@@ -113,6 +116,13 @@ final class ProfileHeaderView: UIView {
return visualEffectView
}()
+ let editBannerButton: HighlightDimmableButton = {
+ let button = HighlightDimmableButton()
+ button.setImage(UIImage(systemName: "photo", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28)), for: .normal)
+ button.tintColor = .clear
+ return button
+ }()
+
let editAvatarBackgroundView: UIView = {
let view = UIView()
view.backgroundColor = .clear // set value after view appeared
@@ -265,13 +275,13 @@ extension ProfileHeaderView {
bannerImageViewOverlayVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
bannerImageView.addSubview(bannerImageViewOverlayVisualEffectView)
- NSLayoutConstraint.activate([
- bannerImageViewOverlayVisualEffectView.topAnchor.constraint(equalTo: bannerImageView.topAnchor),
- bannerImageViewOverlayVisualEffectView.leadingAnchor.constraint(equalTo: bannerImageView.leadingAnchor),
- bannerImageViewOverlayVisualEffectView.trailingAnchor.constraint(equalTo: bannerImageView.trailingAnchor),
- bannerImageViewOverlayVisualEffectView.bottomAnchor.constraint(equalTo: bannerImageView.bottomAnchor),
- ])
-
+ bannerImageViewOverlayVisualEffectView.pinToParent()
+
+ editBannerButton.translatesAutoresizingMaskIntoConstraints = false
+ bannerContainerView.addSubview(editBannerButton)
+ editBannerButton.pinTo(to: bannerImageView)
+ bannerContainerView.isUserInteractionEnabled = true
+
// follows you
followsYouBlurEffectView.translatesAutoresizingMaskIntoConstraints = false
addSubview(followsYouBlurEffectView)
@@ -286,12 +296,7 @@ extension ProfileHeaderView {
followsYouVibrantEffectView.translatesAutoresizingMaskIntoConstraints = false
followsYouBlurEffectView.contentView.addSubview(followsYouVibrantEffectView)
- NSLayoutConstraint.activate([
- followsYouVibrantEffectView.topAnchor.constraint(equalTo: followsYouBlurEffectView.topAnchor),
- followsYouVibrantEffectView.leadingAnchor.constraint(equalTo: followsYouBlurEffectView.leadingAnchor),
- followsYouVibrantEffectView.trailingAnchor.constraint(equalTo: followsYouBlurEffectView.trailingAnchor),
- followsYouVibrantEffectView.bottomAnchor.constraint(equalTo: followsYouBlurEffectView.bottomAnchor),
- ])
+ followsYouVibrantEffectView.pinTo(to: followsYouBlurEffectView)
followsYouLabel.translatesAutoresizingMaskIntoConstraints = false
followsYouVibrantEffectView.contentView.addSubview(followsYouLabel)
@@ -327,30 +332,15 @@ extension ProfileHeaderView {
avatarImageViewOverlayVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
avatarImageViewBackgroundView.addSubview(avatarImageViewOverlayVisualEffectView)
- NSLayoutConstraint.activate([
- avatarImageViewOverlayVisualEffectView.topAnchor.constraint(equalTo: avatarImageViewBackgroundView.topAnchor),
- avatarImageViewOverlayVisualEffectView.leadingAnchor.constraint(equalTo: avatarImageViewBackgroundView.leadingAnchor),
- avatarImageViewOverlayVisualEffectView.trailingAnchor.constraint(equalTo: avatarImageViewBackgroundView.trailingAnchor),
- avatarImageViewOverlayVisualEffectView.bottomAnchor.constraint(equalTo: avatarImageViewBackgroundView.bottomAnchor),
- ])
+ avatarImageViewOverlayVisualEffectView.pinToParent()
editAvatarBackgroundView.translatesAutoresizingMaskIntoConstraints = false
avatarButton.addSubview(editAvatarBackgroundView)
- NSLayoutConstraint.activate([
- editAvatarBackgroundView.topAnchor.constraint(equalTo: avatarButton.topAnchor),
- editAvatarBackgroundView.leadingAnchor.constraint(equalTo: avatarButton.leadingAnchor),
- editAvatarBackgroundView.trailingAnchor.constraint(equalTo: avatarButton.trailingAnchor),
- editAvatarBackgroundView.bottomAnchor.constraint(equalTo: avatarButton.bottomAnchor),
- ])
+ editAvatarBackgroundView.pinToParent()
editAvatarButtonOverlayIndicatorView.translatesAutoresizingMaskIntoConstraints = false
editAvatarBackgroundView.addSubview(editAvatarButtonOverlayIndicatorView)
- NSLayoutConstraint.activate([
- editAvatarButtonOverlayIndicatorView.topAnchor.constraint(equalTo: editAvatarBackgroundView.topAnchor),
- editAvatarButtonOverlayIndicatorView.leadingAnchor.constraint(equalTo: editAvatarBackgroundView.leadingAnchor),
- editAvatarButtonOverlayIndicatorView.trailingAnchor.constraint(equalTo: editAvatarBackgroundView.trailingAnchor),
- editAvatarButtonOverlayIndicatorView.bottomAnchor.constraint(equalTo: editAvatarBackgroundView.bottomAnchor),
- ])
+ editAvatarButtonOverlayIndicatorView.pinToParent()
editAvatarBackgroundView.isUserInteractionEnabled = true
avatarButton.isUserInteractionEnabled = true
@@ -436,11 +426,8 @@ extension ProfileHeaderView {
relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false
relationshipActionButtonShadowContainer.addSubview(relationshipActionButton)
+ relationshipActionButton.pinToParent()
NSLayoutConstraint.activate([
- relationshipActionButton.topAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.topAnchor),
- relationshipActionButton.leadingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.leadingAnchor),
- relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor),
- relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor),
relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileHeaderView.friendshipActionButtonSize.width).priority(.required - 1),
relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileHeaderView.friendshipActionButtonSize.height).priority(.defaultHigh),
])
@@ -455,8 +442,7 @@ extension ProfileHeaderView {
statusDashboardView.delegate = self
bioMetaText.textView.delegate = self
bioMetaText.textView.linkDelegate = self
-
- let bannerImageViewSingleTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
+
bannerImageView.addGestureRecognizer(bannerImageViewSingleTapGestureRecognizer)
bannerImageViewSingleTapGestureRecognizer.addTarget(self, action: #selector(ProfileHeaderView.bannerImageViewDidPressed(_:)))
diff --git a/Mastodon/Scene/Profile/Paging/ProfilePagingViewController.swift b/Mastodon/Scene/Profile/Paging/ProfilePagingViewController.swift
index db92617b7..27c539d18 100644
--- a/Mastodon/Scene/Profile/Paging/ProfilePagingViewController.swift
+++ b/Mastodon/Scene/Profile/Paging/ProfilePagingViewController.swift
@@ -99,12 +99,7 @@ extension ProfilePagingViewController {
if let buttonBarView = self.buttonBarView {
buttonBarShadowView.translatesAutoresizingMaskIntoConstraints = false
view.insertSubview(buttonBarShadowView, belowSubview: buttonBarView)
- NSLayoutConstraint.activate([
- buttonBarShadowView.topAnchor.constraint(equalTo: buttonBarView.topAnchor),
- buttonBarShadowView.leadingAnchor.constraint(equalTo: buttonBarView.leadingAnchor),
- buttonBarShadowView.trailingAnchor.constraint(equalTo: buttonBarView.trailingAnchor),
- buttonBarShadowView.bottomAnchor.constraint(equalTo: buttonBarView.bottomAnchor),
- ])
+ buttonBarShadowView.pinTo(to: buttonBarView)
viewModel.$needsSetupBottomShadow
.receive(on: DispatchQueue.main)
diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift
index 8749bae9c..15548a5fc 100644
--- a/Mastodon/Scene/Profile/ProfileViewController.swift
+++ b/Mastodon/Scene/Profile/ProfileViewController.swift
@@ -105,8 +105,8 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi
return barButtonItem
}()
- let refreshControl: UIRefreshControl = {
- let refreshControl = UIRefreshControl()
+ let refreshControl: RefreshControl = {
+ let refreshControl = RefreshControl()
refreshControl.tintColor = .white
return refreshControl
}()
@@ -259,12 +259,7 @@ extension ProfileViewController {
tabBarPagerController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tabBarPagerController.view)
tabBarPagerController.didMove(toParent: self)
- NSLayoutConstraint.activate([
- tabBarPagerController.view.topAnchor.constraint(equalTo: view.topAnchor),
- tabBarPagerController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tabBarPagerController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tabBarPagerController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tabBarPagerController.view.pinToParent()
tabBarPagerController.delegate = self
tabBarPagerController.dataSource = self
@@ -503,7 +498,7 @@ extension ProfileViewController {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
guard let setting = context.settingService.currentSetting.value else { return }
let settingsViewModel = SettingsViewModel(context: context, authContext: viewModel.authContext, setting: setting)
- coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
+ _ = coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
@objc private func shareBarButtonItemPressed(_ sender: UIBarButtonItem) {
@@ -551,7 +546,7 @@ extension ProfileViewController {
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil))
}
- @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
+ @objc private func refreshControlValueChanged(_ sender: RefreshControl) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
if let userTimelineViewController = profilePagingViewController.currentViewController as? UserTimelineViewController {
diff --git a/Mastodon/Scene/Profile/ProfileViewModel.swift b/Mastodon/Scene/Profile/ProfileViewModel.swift
index e23b465d4..5c81c7920 100644
--- a/Mastodon/Scene/Profile/ProfileViewModel.swift
+++ b/Mastodon/Scene/Profile/ProfileViewModel.swift
@@ -215,8 +215,17 @@ extension ProfileViewModel {
let authenticationBox = authContext.mastodonAuthenticationBox
let domain = authenticationBox.domain
let authorization = authenticationBox.userAuthorization
-
- let _image: UIImage? = {
+
+ // TODO: constrain size?
+ let _header: UIImage? = {
+ guard let image = headerProfileInfo.header else { return nil }
+ guard image.size.width <= ProfileHeaderViewModel.bannerImageMaxSizeInPixel.width else {
+ return image.af.imageScaled(to: ProfileHeaderViewModel.bannerImageMaxSizeInPixel)
+ }
+ return image
+ }()
+
+ let _avatar: UIImage? = {
guard let image = headerProfileInfo.avatar else { return nil }
guard image.size.width <= ProfileHeaderViewModel.avatarImageMaxSizeInPixel.width else {
return image.af.imageScaled(to: ProfileHeaderViewModel.avatarImageMaxSizeInPixel)
@@ -233,8 +242,8 @@ extension ProfileViewModel {
bot: nil,
displayName: headerProfileInfo.name,
note: headerProfileInfo.note,
- avatar: _image.flatMap { Mastodon.Query.MediaAttachment.png($0.pngData()) },
- header: nil,
+ avatar: _avatar.flatMap { Mastodon.Query.MediaAttachment.png($0.pngData()) },
+ header: _header.flatMap { Mastodon.Query.MediaAttachment.png($0.pngData()) },
locked: nil,
source: nil,
fieldsAttributes: fieldsAttributes
diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift
index 8a983da33..6cdd6a594 100644
--- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift
+++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift
@@ -60,12 +60,7 @@ extension UserTimelineViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift
index ebce374e7..07316cd3d 100644
--- a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift
+++ b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController.swift
@@ -61,12 +61,7 @@ extension FavoritedByViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift
index 0688bcccb..a45c491fc 100644
--- a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift
+++ b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController.swift
@@ -61,12 +61,7 @@ extension RebloggedByViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift
index c7b3e20cd..d0f7feb88 100644
--- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift
+++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift
@@ -134,7 +134,7 @@ extension UserListViewModel.State {
maxID = nil
}
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let viewModel = viewModel else { return }
let maxID = self.maxID
diff --git a/Mastodon/Scene/Report/Report/ReportViewController.swift b/Mastodon/Scene/Report/Report/ReportViewController.swift
index f1418c5a1..fb0417a7f 100644
--- a/Mastodon/Scene/Report/Report/ReportViewController.swift
+++ b/Mastodon/Scene/Report/Report/ReportViewController.swift
@@ -61,12 +61,7 @@ extension ReportViewController {
reportReasonViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(reportReasonViewController.view)
reportReasonViewController.didMove(toParent: self)
- NSLayoutConstraint.activate([
- reportReasonViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- reportReasonViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- reportReasonViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- reportReasonViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ reportReasonViewController.view.pinToParent()
}
}
@@ -126,7 +121,7 @@ extension ReportViewController: ReportServerRulesViewControllerDelegate {
return
}
- coordinator.present(
+ _ = coordinator.present(
scene: .reportStatus(viewModel: viewModel.reportStatusViewModel),
from: self,
transition: .show
diff --git a/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift b/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift
index 2e8e53d18..517873abe 100644
--- a/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift
+++ b/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift
@@ -57,12 +57,7 @@ extension ReportReasonViewController {
addChild(hostingViewController)
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingViewController.view)
- NSLayoutConstraint.activate([
- hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ hostingViewController.view.pinToParent()
navigationActionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navigationActionView)
diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift
index 10dcdf373..1d67ad6c3 100644
--- a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift
+++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift
@@ -60,12 +60,7 @@ extension ReportResultViewController {
addChild(hostingViewController)
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingViewController.view)
- NSLayoutConstraint.activate([
- hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ hostingViewController.view.pinToParent()
navigationActionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navigationActionView)
diff --git a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift
index 3f1cdf331..00be4d800 100644
--- a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift
+++ b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift
@@ -63,12 +63,7 @@ extension ReportServerRulesViewController {
addChild(hostingViewController)
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingViewController.view)
- NSLayoutConstraint.activate([
- hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ hostingViewController.view.pinToParent()
navigationActionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navigationActionView)
diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift
index d45c196cd..6f934e13d 100644
--- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift
+++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift
@@ -80,12 +80,7 @@ extension ReportStatusViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift
index 01e8715d1..79807cf0f 100644
--- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift
+++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift
@@ -75,7 +75,7 @@ extension ReportStatusViewModel.State {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
- guard let viewModel = viewModel, let stateMachine = stateMachine else { return }
+ guard let viewModel else { return }
let maxID = viewModel.statusFetchedResultsController.statusIDs.last
diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift
index e644c29ea..76f312273 100644
--- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift
+++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift
@@ -93,12 +93,7 @@ extension ReportSupplementaryViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift b/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift
index d735a094c..ad6ce252a 100644
--- a/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift
+++ b/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift
@@ -74,11 +74,8 @@ extension ReportCommentTableViewCell {
commentTextView.translatesAutoresizingMaskIntoConstraints = false
commentTextViewShadowBackgroundContainer.addSubview(commentTextView)
+ commentTextView.pinToParent()
NSLayoutConstraint.activate([
- commentTextView.topAnchor.constraint(equalTo: commentTextViewShadowBackgroundContainer.topAnchor),
- commentTextView.leadingAnchor.constraint(equalTo: commentTextViewShadowBackgroundContainer.leadingAnchor),
- commentTextView.trailingAnchor.constraint(equalTo: commentTextViewShadowBackgroundContainer.trailingAnchor),
- commentTextView.bottomAnchor.constraint(equalTo: commentTextViewShadowBackgroundContainer.bottomAnchor),
commentTextView.heightAnchor.constraint(greaterThanOrEqualToConstant: 100).priority(.defaultHigh),
])
}
diff --git a/Mastodon/Scene/Report/Share/Cell/ReportResultActionTableViewCell.swift b/Mastodon/Scene/Report/Share/Cell/ReportResultActionTableViewCell.swift
index 9b605a0c7..1828035a6 100644
--- a/Mastodon/Scene/Report/Share/Cell/ReportResultActionTableViewCell.swift
+++ b/Mastodon/Scene/Report/Share/Cell/ReportResultActionTableViewCell.swift
@@ -103,12 +103,7 @@ extension ReportResultActionTableViewCell {
reportBannerLabel.translatesAutoresizingMaskIntoConstraints = false
reportBannerShadowContainer.addSubview(reportBannerLabel)
- NSLayoutConstraint.activate([
- reportBannerLabel.topAnchor.constraint(equalTo: reportBannerShadowContainer.topAnchor),
- reportBannerLabel.leadingAnchor.constraint(equalTo: reportBannerShadowContainer.leadingAnchor),
- reportBannerLabel.trailingAnchor.constraint(equalTo: reportBannerShadowContainer.trailingAnchor),
- reportBannerLabel.bottomAnchor.constraint(equalTo: reportBannerShadowContainer.bottomAnchor),
- ])
+ reportBannerLabel.pinToParent()
}
diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift
index 3f4758e8e..a10f0ed9b 100644
--- a/Mastodon/Scene/Root/ContentSplitViewController.swift
+++ b/Mastodon/Scene/Root/ContentSplitViewController.swift
@@ -124,4 +124,17 @@ extension ContentSplitViewController: SidebarViewControllerDelegate {
accountListViewController.preferredContentSize = CGSize(width: 375, height: 400)
}
+ func sidebarViewController(_ sidebarViewController: SidebarViewController, didDoubleTapItem item: SidebarViewModel.Item, sourceView: UIView) {
+ guard case let .tab(tab) = item, tab == .me else { return }
+ guard let authContext = authContext else { return }
+ assert(Thread.isMainThread)
+
+ guard let nextAccount = context.nextAccount(in: authContext) else { return }
+
+ Task { @MainActor in
+ let isActive = try await context.authenticationService.activeMastodonUser(domain: nextAccount.domain, userID: nextAccount.userID)
+ guard isActive else { return }
+ self.coordinator.setup()
+ }
+ }
}
diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift
index ca301a535..2e5d5ae58 100644
--- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift
+++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift
@@ -8,6 +8,7 @@
import os.log
import UIKit
import Combine
+import CoreDataStack
import SafariServices
import MastodonAsset
import MastodonCore
@@ -42,6 +43,7 @@ class MainTabBarController: UITabBarController {
static let avatarButtonSize = CGSize(width: 25, height: 25)
let avatarButton = CircleAvatarButton()
+ let accountSwitcherChevron = UIImageView(image: .chevronUpChevronDown)
@Published var currentTab: Tab = .home
@@ -218,7 +220,7 @@ extension MainTabBarController {
let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
- coordinator.present(
+ _ = coordinator.present(
scene: .alertController(alertController: alertController),
from: nil,
transition: .alertController(animated: true, completion: nil)
@@ -306,12 +308,11 @@ extension MainTabBarController {
guard user.managedObjectContext != nil else { return }
self.avatarURL = user.avatarImageURL()
}
-
+
// a11y
let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag }
guard let profileTabItem = _profileTabItem else { return }
- let currentUserDisplayName = user.displayNameWithFallback ?? "no user"
- profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName)
+ profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(user.displayNameWithFallback)
context.authenticationService.updateActiveUserAccountPublisher
.sink { [weak self] in
@@ -325,7 +326,14 @@ extension MainTabBarController {
let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer()
tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:)))
tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer)
-
+
+ // todo: reconsider the "double tap to change account" feature -> https://github.com/mastodon/mastodon-ios/issues/628
+// let tabBarDoubleTapGestureRecognizer = UITapGestureRecognizer()
+// tabBarDoubleTapGestureRecognizer.numberOfTapsRequired = 2
+// tabBarDoubleTapGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarDoubleTapGestureRecognizerHandler(_:)))
+// tabBarDoubleTapGestureRecognizer.delaysTouchesEnded = false
+// tabBar.addGestureRecognizer(tabBarDoubleTapGestureRecognizer)
+
self.isReadyForWizardAvatarButton = authContext != nil
$currentTab
@@ -376,9 +384,7 @@ extension MainTabBarController {
_ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
}
- @objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) {
- guard sender.state == .began else { return }
-
+ private func touchedTab(by sender: UIGestureRecognizer) -> Tab? {
var _tab: Tab?
let location = sender.location(in: tabBar)
for item in tabBar.items ?? [] {
@@ -390,7 +396,34 @@ extension MainTabBarController {
break
}
- guard let tab = _tab else { return }
+ return _tab
+ }
+
+ @objc private func tabBarDoubleTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
+ guard sender.state == .ended else { return }
+ guard let tab = touchedTab(by: sender) else { return }
+ logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): double tap \(tab.title) tab")
+
+ switch tab {
+ case .me:
+ guard let authContext = authContext else { return }
+ assert(Thread.isMainThread)
+
+ guard let nextAccount = context.nextAccount(in: authContext) else { return }
+
+ Task { @MainActor in
+ let isActive = try await context.authenticationService.activeMastodonUser(domain: nextAccount.domain, userID: nextAccount.userID)
+ guard isActive else { return }
+ self.coordinator.setup()
+ }
+ default:
+ break
+ }
+ }
+
+ @objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) {
+ guard sender.state == .began else { return }
+ guard let tab = touchedTab(by: sender) else { return }
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): long press \(tab.title) tab")
switch tab {
@@ -443,12 +476,7 @@ extension MainTabBarController {
composeButton.translatesAutoresizingMaskIntoConstraints = false
composeButttonShadowBackgroundContainer.addSubview(composeButton)
- NSLayoutConstraint.activate([
- composeButton.topAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.topAnchor),
- composeButton.leadingAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.leadingAnchor),
- composeButton.trailingAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.trailingAnchor),
- composeButton.bottomAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.bottomAnchor),
- ])
+ composeButton.pinToParent()
composeButton.setContentHuggingPriority(.required - 1, for: .horizontal)
composeButton.setContentHuggingPriority(.required - 1, for: .vertical)
}
@@ -474,13 +502,20 @@ extension MainTabBarController {
}
anchorImageView.alpha = 0
+ accountSwitcherChevron.translatesAutoresizingMaskIntoConstraints = false
+ view.addSubview(accountSwitcherChevron)
+
self.avatarButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(self.avatarButton)
NSLayoutConstraint.activate([
- self.avatarButton.centerXAnchor.constraint(equalTo: anchorImageView.centerXAnchor),
+ self.avatarButton.centerXAnchor.constraint(equalTo: anchorImageView.centerXAnchor, constant: -16),
self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor),
self.avatarButton.widthAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.width).priority(.required - 1),
self.avatarButton.heightAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.height).priority(.required - 1),
+ accountSwitcherChevron.widthAnchor.constraint(equalToConstant: 10),
+ accountSwitcherChevron.heightAnchor.constraint(equalToConstant: 18),
+ accountSwitcherChevron.leadingAnchor.constraint(equalTo: avatarButton.trailingAnchor, constant: 8),
+ accountSwitcherChevron.centerYAnchor.constraint(equalTo: avatarButton.centerYAnchor)
])
self.avatarButton.setContentHuggingPriority(.required - 1, for: .horizontal)
self.avatarButton.setContentHuggingPriority(.required - 1, for: .vertical)
@@ -488,6 +523,7 @@ extension MainTabBarController {
}
private func updateAvatarButtonAppearance() {
+ accountSwitcherChevron.tintColor = currentTab == .me ? .label : .secondaryLabel
avatarButton.borderColor = currentTab == .me ? .label : .systemFill
avatarButton.setNeedsLayout()
}
diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
index 70e1239b6..7c76585a6 100644
--- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
+++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift
@@ -15,6 +15,7 @@ import MastodonUI
protocol SidebarViewControllerDelegate: AnyObject {
func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab)
func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView)
+ func sidebarViewController(_ sidebarViewController: SidebarViewController, didDoubleTapItem item: SidebarViewModel.Item, sourceView: UIView)
}
final class SidebarViewController: UIViewController, NeedsDependency {
@@ -101,12 +102,7 @@ extension SidebarViewController {
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
- NSLayoutConstraint.activate([
- collectionView.topAnchor.constraint(equalTo: view.topAnchor),
- collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ collectionView.pinToParent()
secondaryCollectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(secondaryCollectionView)
@@ -143,6 +139,15 @@ extension SidebarViewController {
let sidebarLongPressGestureRecognizer = UILongPressGestureRecognizer()
sidebarLongPressGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarLongPressGestureRecognizerHandler(_:)))
collectionView.addGestureRecognizer(sidebarLongPressGestureRecognizer)
+
+ // todo: reconsider the "double tap to change account" feature -> https://github.com/mastodon/mastodon-ios/issues/628
+// let sidebarDoubleTapGestureRecognizer = UITapGestureRecognizer()
+// sidebarDoubleTapGestureRecognizer.numberOfTapsRequired = 2
+// sidebarDoubleTapGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarDoubleTapGestureRecognizerHandler(_:)))
+// sidebarDoubleTapGestureRecognizer.delaysTouchesEnded = false
+// sidebarDoubleTapGestureRecognizer.cancelsTouchesInView = true
+// collectionView.addGestureRecognizer(sidebarDoubleTapGestureRecognizer)
+
}
private func setupBackground(theme: Theme) {
@@ -176,6 +181,20 @@ extension SidebarViewController {
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
delegate?.sidebarViewController(self, didLongPressItem: item, sourceView: cell)
}
+
+ @objc private func sidebarDoubleTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
+ guard sender.state == .ended else { return }
+
+ logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
+ assert(sender.view === collectionView)
+
+ let position = sender.location(in: collectionView)
+ guard let indexPath = collectionView.indexPathForItem(at: position) else { return }
+ guard let diffableDataSource = viewModel.diffableDataSource else { return }
+ guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
+ guard let cell = collectionView.cellForItem(at: indexPath) else { return }
+ delegate?.sidebarViewController(self, didDoubleTapItem: item, sourceView: cell)
+ }
}
diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift
index 7c323bbca..f6e90dcd9 100644
--- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift
+++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift
@@ -16,7 +16,6 @@ import MastodonCore
import MastodonLocalization
final class SidebarViewModel {
-
var disposeBag = Set()
// input
@@ -80,6 +79,7 @@ extension SidebarViewModel {
}()
cell.item = SidebarListContentView.Item(
isActive: false,
+ accessoryImage: item == .me ? .chevronUpChevronDown : nil,
title: item.title,
image: item.image,
activeImage: item.selectedImage,
@@ -166,6 +166,7 @@ extension SidebarViewModel {
case .compose:
let item = SidebarListContentView.Item(
isActive: false,
+ accessoryImage: self.currentTab == .me ? .chevronUpChevronDown : nil,
title: L10n.Common.Controls.Actions.compose,
image: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate),
activeImage: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate),
diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift
index 515988405..c2aa1a4f5 100644
--- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift
+++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift
@@ -23,7 +23,8 @@ final class SidebarListContentView: UIView, UIContentView {
button.borderColor = UIColor.label
return button
}()
-
+ private let accessoryImageView = UIImageView(image: nil)
+
private var currentConfiguration: ContentConfiguration!
var configuration: UIContentConfiguration {
get {
@@ -60,6 +61,9 @@ extension SidebarListContentView {
imageView.widthAnchor.constraint(equalToConstant: 40).priority(.required - 1),
imageView.heightAnchor.constraint(equalToConstant: 40).priority(.required - 1),
])
+
+ accessoryImageView.translatesAutoresizingMaskIntoConstraints = false
+ addSubview(accessoryImageView)
avatarButton.translatesAutoresizingMaskIntoConstraints = false
addSubview(avatarButton)
@@ -68,6 +72,10 @@ extension SidebarListContentView {
avatarButton.centerYAnchor.constraint(equalTo: imageView.centerYAnchor),
avatarButton.widthAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1.0).priority(.required - 2),
avatarButton.heightAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: 1.0).priority(.required - 2),
+ accessoryImageView.widthAnchor.constraint(equalToConstant: 12),
+ accessoryImageView.heightAnchor.constraint(equalToConstant: 22),
+ accessoryImageView.leadingAnchor.constraint(equalTo: avatarButton.trailingAnchor, constant: 4),
+ accessoryImageView.centerYAnchor.constraint(equalTo: avatarButton.centerYAnchor)
])
avatarButton.setContentHuggingPriority(.defaultLow - 10, for: .vertical)
avatarButton.setContentHuggingPriority(.defaultLow - 10, for: .horizontal)
@@ -96,6 +104,9 @@ extension SidebarListContentView {
imageView.isHidden = item.imageURL != nil
avatarButton.isHidden = item.imageURL == nil
imageView.image = item.isActive ? item.activeImage.withRenderingMode(.alwaysTemplate) : item.image.withRenderingMode(.alwaysTemplate)
+ accessoryImageView.image = item.accessoryImage
+ accessoryImageView.isHidden = item.accessoryImage == nil
+ accessoryImageView.tintColor = item.isActive ? .label : .secondaryLabel
avatarButton.avatarImageView.setImage(
url: item.imageURL,
placeholder: avatarButton.avatarImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink
@@ -112,7 +123,8 @@ extension SidebarListContentView {
var isSelected: Bool = false
var isHighlighted: Bool = false
var isActive: Bool
-
+ var accessoryImage: UIImage? = nil
+
// model
let title: String
var image: UIImage
@@ -124,6 +136,7 @@ extension SidebarListContentView {
return lhs.isSelected == rhs.isSelected
&& lhs.isHighlighted == rhs.isHighlighted
&& lhs.isActive == rhs.isActive
+ && lhs.accessoryImage == rhs.accessoryImage
&& lhs.title == rhs.title
&& lhs.image == rhs.image
&& lhs.activeImage == rhs.activeImage
@@ -134,6 +147,7 @@ extension SidebarListContentView {
hasher.combine(isSelected)
hasher.combine(isHighlighted)
hasher.combine(isActive)
+ hasher.combine(accessoryImage)
hasher.combine(title)
hasher.combine(image)
hasher.combine(activeImage)
diff --git a/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift b/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift
index 30f618625..4436459fb 100644
--- a/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift
+++ b/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift
@@ -48,12 +48,7 @@ extension TrendCollectionViewCell {
trendView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(trendView)
- NSLayoutConstraint.activate([
- trendView.topAnchor.constraint(equalTo: contentView.topAnchor),
- trendView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
- trendView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
- trendView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
- ])
+ trendView.pinToParent()
}
override func updateConfiguration(using state: UICellConfigurationState) {
diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift
index 7efef2c00..c190a1a4c 100644
--- a/Mastodon/Scene/Search/Search/SearchViewController.swift
+++ b/Mastodon/Scene/Search/Search/SearchViewController.swift
@@ -23,15 +23,15 @@ final class HeightFixedSearchBar: UISearchBar {
final class SearchViewController: UIViewController, NeedsDependency {
let logger = Logger(subsystem: "SearchViewController", category: "ViewController")
-
+
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
var searchTransitionController = SearchTransitionController()
-
+
var disposeBag = Set()
var viewModel: SearchViewModel!
-
+
// use AutoLayout could set search bar margin automatically to
// layout alongside with split mode button (on iPad)
let titleViewContainer = UIView()
@@ -73,19 +73,19 @@ extension SearchViewController {
override func viewDidLoad() {
super.viewDidLoad()
- setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
+ setupAppearance(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
- self.setupBackgroundColor(theme: theme)
+ self.setupAppearance(theme: theme)
}
.store(in: &disposeBag)
title = L10n.Scene.Search.title
setupSearchBar()
-
+
// collectionView.translatesAutoresizingMaskIntoConstraints = false
// view.addSubview(collectionView)
// NSLayoutConstraint.activate([
@@ -101,25 +101,21 @@ extension SearchViewController {
// )
guard let discoveryViewController = self.discoveryViewController else { return }
-
+
addChild(discoveryViewController)
discoveryViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(discoveryViewController.view)
- NSLayoutConstraint.activate([
- discoveryViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- discoveryViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- discoveryViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- discoveryViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
-
+ discoveryViewController.view.pinToParent()
+
// discoveryViewController.view.isHidden = true
+
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
viewModel.viewDidAppeared.send()
-
+
// note:
// need set alpha because (maybe) SDK forget set alpha back
titleViewContainer.alpha = 1
@@ -127,8 +123,22 @@ extension SearchViewController {
}
extension SearchViewController {
- private func setupBackgroundColor(theme: Theme) {
+ private func setupAppearance(theme: Theme) {
view.backgroundColor = theme.systemGroupedBackgroundColor
+
+ // Match the DiscoveryViewController tab color and remove the double separator.
+ let navigationBarAppearance = UINavigationBarAppearance()
+ navigationBarAppearance.configureWithOpaqueBackground()
+ navigationBarAppearance.backgroundColor = theme.systemBackgroundColor
+ navigationBarAppearance.shadowColor = nil
+
+ navigationItem.standardAppearance = navigationBarAppearance
+ navigationItem.scrollEdgeAppearance = navigationBarAppearance
+ navigationItem.compactAppearance = navigationBarAppearance
+
+ if #available(iOS 15, *) {
+ navigationItem.compactScrollEdgeAppearance = navigationBarAppearance
+ }
}
private func setupSearchBar() {
@@ -136,12 +146,7 @@ extension SearchViewController {
searchBar.delegate = self
searchBar.translatesAutoresizingMaskIntoConstraints = false
titleViewContainer.addSubview(searchBar)
- NSLayoutConstraint.activate([
- searchBar.topAnchor.constraint(equalTo: titleViewContainer.topAnchor),
- searchBar.leadingAnchor.constraint(equalTo: titleViewContainer.leadingAnchor),
- searchBar.trailingAnchor.constraint(equalTo: titleViewContainer.trailingAnchor),
- searchBar.bottomAnchor.constraint(equalTo: titleViewContainer.bottomAnchor),
- ])
+ searchBar.pinToParent()
searchBar.setContentHuggingPriority(.required, for: .horizontal)
searchBar.setContentHuggingPriority(.required, for: .vertical)
navigationItem.titleView = titleViewContainer
@@ -159,7 +164,7 @@ extension SearchViewController {
// FIXME:
// use `.customPush(animated: false)` false to disable navigation bar animation for searchBar layout
// but that should be a fade transition whe fixed size searchBar
- self.coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .customPush(animated: false))
+ _ = self.coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .customPush(animated: false))
}
.store(in: &disposeBag)
}
diff --git a/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift b/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift
index 1d4788ac8..0a65c6a25 100644
--- a/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift
+++ b/Mastodon/Scene/Search/Search/View/SearchRecommendCollectionHeader.swift
@@ -62,12 +62,7 @@ extension SearchRecommendCollectionHeader {
containerStackView.isLayoutMarginsRelativeArrangement = true
containerStackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(containerStackView)
- NSLayoutConstraint.activate([
- containerStackView.topAnchor.constraint(equalTo: topAnchor),
- containerStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
- containerStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
- containerStackView.trailingAnchor.constraint(equalTo: trailingAnchor)
- ])
+ containerStackView.pinToParent()
let horizontalStackView = UIStackView()
horizontalStackView.spacing = 8
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift
index 62dd1a2cc..4ec9bce31 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift
@@ -60,7 +60,7 @@ final class SearchDetailViewController: PageboyViewController, NeedsDependency {
let searchController: CustomSearchController = {
let searchController = CustomSearchController()
searchController.automaticallyShowsScopeBar = false
- searchController.dimsBackgroundDuringPresentation = false
+ searchController.obscuresBackgroundDuringPresentation = false
return searchController
}()
private(set) lazy var searchBar: UISearchBar = {
@@ -116,12 +116,7 @@ extension SearchDetailViewController {
searchHistoryViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
} else {
- NSLayoutConstraint.activate([
- searchHistoryViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
- searchHistoryViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- searchHistoryViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- searchHistoryViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ searchHistoryViewController.view.pinToParent()
}
transition = Transition(style: .fade, duration: 0.1)
@@ -289,12 +284,7 @@ extension SearchDetailViewController {
navigationBarVisualEffectBackgroundView.translatesAutoresizingMaskIntoConstraints = false
view.insertSubview(navigationBarVisualEffectBackgroundView, belowSubview: navigationBarBackgroundView)
- NSLayoutConstraint.activate([
- navigationBarVisualEffectBackgroundView.topAnchor.constraint(equalTo: navigationBarBackgroundView.topAnchor),
- navigationBarVisualEffectBackgroundView.leadingAnchor.constraint(equalTo: navigationBarBackgroundView.leadingAnchor),
- navigationBarVisualEffectBackgroundView.trailingAnchor.constraint(equalTo: navigationBarBackgroundView.trailingAnchor),
- navigationBarVisualEffectBackgroundView.bottomAnchor.constraint(equalTo: navigationBarBackgroundView.bottomAnchor),
- ])
+ navigationBarVisualEffectBackgroundView.pinTo(to: navigationBarBackgroundView)
} else {
navigationItem.setHidesBackButton(true, animated: false)
navigationItem.titleView = nil
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift
index 52d0ffb9c..ac08e7906 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController.swift
@@ -47,12 +47,7 @@ extension SearchHistoryViewController {
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
- NSLayoutConstraint.activate([
- collectionView.topAnchor.constraint(equalTo: view.topAnchor),
- collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ collectionView.pinToParent()
collectionView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift
index 67de62bf3..6a840f9b5 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController.swift
@@ -49,12 +49,7 @@ extension SearchResultViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
// tableView.prefetchDataSource = self
diff --git a/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift b/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift
index 44b6b39c3..efad9693d 100644
--- a/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift
+++ b/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift
@@ -101,12 +101,7 @@ extension SettingsAppearanceTableViewCell {
stackView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(stackView)
- NSLayoutConstraint.activate([
- stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
- stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
- stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
- stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
- ])
+ stackView.pinToParent()
stackView.addArrangedSubview(systemAppearanceView)
stackView.addArrangedSubview(darkAppearanceView)
diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift
index 53a856fd0..fa6948ced 100644
--- a/Mastodon/Scene/Settings/SettingsViewController.swift
+++ b/Mastodon/Scene/Settings/SettingsViewController.swift
@@ -225,12 +225,7 @@ extension SettingsViewController {
setupNavigation()
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
setupTableView()
updateSectionHeaderStackViewLayout()
@@ -401,7 +396,7 @@ extension SettingsViewController: UITableViewDelegate {
)
let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil)
alertController.addAction(okAction)
- self.coordinator.present(scene: .alertController(alertController: alertController), from: nil, transition: .alertController(animated: true, completion: nil))
+ _ = self.coordinator.present(scene: .alertController(alertController: alertController), from: nil, transition: .alertController(animated: true, completion: nil))
}
.store(in: &disposeBag)
case .signOut:
@@ -549,7 +544,7 @@ extension SettingsViewController: MetaLabelDelegate {
switch meta {
case .url(_, _, let url, _):
guard let url = URL(string: url) else { return }
- coordinator.present(scene: .safari(url: url), from: self, transition: .safariPresent(animated: true, completion: nil))
+ _ = coordinator.present(scene: .safari(url: url), from: self, transition: .safariPresent(animated: true, completion: nil))
default:
assertionFailure()
}
diff --git a/Mastodon/Scene/Settings/View/AppearanceView.swift b/Mastodon/Scene/Settings/View/AppearanceView.swift
index cdc29100b..a09401537 100644
--- a/Mastodon/Scene/Settings/View/AppearanceView.swift
+++ b/Mastodon/Scene/Settings/View/AppearanceView.swift
@@ -85,12 +85,7 @@ extension AppearanceView {
private func setupUI() {
imageView.translatesAutoresizingMaskIntoConstraints = false
imageViewShadowBackgroundContainer.addSubview(imageView)
- NSLayoutConstraint.activate([
- imageView.topAnchor.constraint(equalTo: imageViewShadowBackgroundContainer.topAnchor),
- imageView.leadingAnchor.constraint(equalTo: imageViewShadowBackgroundContainer.leadingAnchor),
- imageView.trailingAnchor.constraint(equalTo: imageViewShadowBackgroundContainer.trailingAnchor),
- imageView.bottomAnchor.constraint(equalTo: imageViewShadowBackgroundContainer.bottomAnchor),
- ])
+ imageView.pinToParent()
imageViewShadowBackgroundContainer.cornerRadius = 4
stackView.addArrangedSubview(imageViewShadowBackgroundContainer)
@@ -100,11 +95,8 @@ extension AppearanceView {
addSubview(stackView)
translatesAutoresizingMaskIntoConstraints = false
stackView.translatesAutoresizingMaskIntoConstraints = false
+ stackView.pinToParent()
NSLayoutConstraint.activate([
- stackView.topAnchor.constraint(equalTo: self.topAnchor),
- stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
- stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
- stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 121.0 / 100.0), // height / width
])
}
diff --git a/Mastodon/Scene/Share/ContextMenu/ImagePreview/ContextMenuImagePreviewViewController.swift b/Mastodon/Scene/Share/ContextMenu/ImagePreview/ContextMenuImagePreviewViewController.swift
index 0d3c4f574..12820e627 100644
--- a/Mastodon/Scene/Share/ContextMenu/ImagePreview/ContextMenuImagePreviewViewController.swift
+++ b/Mastodon/Scene/Share/ContextMenu/ImagePreview/ContextMenuImagePreviewViewController.swift
@@ -31,12 +31,7 @@ extension ContextMenuImagePreviewViewController {
imageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
- NSLayoutConstraint.activate([
- imageView.topAnchor.constraint(equalTo: view.topAnchor),
- imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ imageView.pinToParent()
imageView.image = viewModel.thumbnail
diff --git a/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift b/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift
index ca46193b6..eb55dc575 100644
--- a/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift
+++ b/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift
@@ -93,12 +93,7 @@ extension ContentWarningOverlayView {
vibrancyVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
blurVisualEffectView.contentView.addSubview(vibrancyVisualEffectView)
- NSLayoutConstraint.activate([
- vibrancyVisualEffectView.topAnchor.constraint(equalTo: blurVisualEffectView.topAnchor),
- vibrancyVisualEffectView.leadingAnchor.constraint(equalTo: blurVisualEffectView.leadingAnchor),
- vibrancyVisualEffectView.trailingAnchor.constraint(equalTo: blurVisualEffectView.trailingAnchor),
- vibrancyVisualEffectView.bottomAnchor.constraint(equalTo: blurVisualEffectView.bottomAnchor),
- ])
+ vibrancyVisualEffectView.pinTo(to: blurVisualEffectView)
vibrancyContentWarningLabel.translatesAutoresizingMaskIntoConstraints = false
vibrancyVisualEffectView.contentView.addSubview(vibrancyContentWarningLabel)
@@ -110,12 +105,7 @@ extension ContentWarningOverlayView {
blurVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
addSubview(blurVisualEffectView)
- NSLayoutConstraint.activate([
- blurVisualEffectView.topAnchor.constraint(equalTo: topAnchor),
- blurVisualEffectView.leadingAnchor.constraint(equalTo: leadingAnchor),
- blurVisualEffectView.trailingAnchor.constraint(equalTo: trailingAnchor),
- blurVisualEffectView.bottomAnchor.constraint(equalTo: bottomAnchor),
- ])
+ blurVisualEffectView.pinToParent()
// blur image style
contentOverlayView.translatesAutoresizingMaskIntoConstraints = false
@@ -134,12 +124,7 @@ extension ContentWarningOverlayView {
blurContentWarningLabelContainer.translatesAutoresizingMaskIntoConstraints = false
contentOverlayView.addSubview(blurContentWarningLabelContainer)
- NSLayoutConstraint.activate([
- blurContentWarningLabelContainer.topAnchor.constraint(equalTo: topAnchor),
- blurContentWarningLabelContainer.leadingAnchor.constraint(equalTo: leadingAnchor),
- blurContentWarningLabelContainer.trailingAnchor.constraint(equalTo: trailingAnchor),
- blurContentWarningLabelContainer.bottomAnchor.constraint(equalTo: bottomAnchor),
- ])
+ blurContentWarningLabelContainer.pinTo(to: self)
let topPaddingView = UIView()
let bottomPaddingView = UIView()
diff --git a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift
index 6734b7b77..f5ac0f8ec 100644
--- a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift
+++ b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift
@@ -47,12 +47,7 @@ extension DoubleTitleLabelNavigationBarTitleView {
containerView.distribution = .fill
containerView.translatesAutoresizingMaskIntoConstraints = false
addSubview(containerView)
- NSLayoutConstraint.activate([
- containerView.topAnchor.constraint(equalTo: topAnchor),
- containerView.leadingAnchor.constraint(equalTo: leadingAnchor),
- containerView.trailingAnchor.constraint(equalTo: trailingAnchor),
- containerView.bottomAnchor.constraint(equalTo: bottomAnchor),
- ])
+ containerView.pinToParent()
containerView.addArrangedSubview(titleLabel)
containerView.addArrangedSubview(subtitleLabel)
diff --git a/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift b/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift
index daa37a93b..018628473 100644
--- a/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift
+++ b/Mastodon/Scene/Share/View/Content/NotificationView+Configuration.swift
@@ -155,7 +155,7 @@ extension NotificationView {
)
case .status:
self.viewModel.notificationIndicatorText = createMetaContent(
- text: L10n.Scene.Notification.NotificationDescription.mentionedYou,
+ text: .empty,
emojis: emojis.asDictionary
)
case ._other:
diff --git a/Mastodon/Scene/Share/View/Control/RefreshControl.swift b/Mastodon/Scene/Share/View/Control/RefreshControl.swift
new file mode 100644
index 000000000..afac5a1a1
--- /dev/null
+++ b/Mastodon/Scene/Share/View/Control/RefreshControl.swift
@@ -0,0 +1,28 @@
+//
+// RefreshControl.swift
+// Mastodon
+//
+// Created by Kyle Bashour on 11/14/22.
+//
+
+import UIKit
+
+/// RefreshControl subclass that properly displays itself behind table view contents.
+class RefreshControl: UIRefreshControl {
+ override init() {
+ super.init()
+ }
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ }
+
+ override func didMoveToSuperview() {
+ super.didMoveToSuperview()
+ layer.zPosition = -1
+ }
+}
diff --git a/Mastodon/Scene/Share/Webview/WebViewController.swift b/Mastodon/Scene/Share/Webview/WebViewController.swift
index cb690de93..209ee483d 100644
--- a/Mastodon/Scene/Share/Webview/WebViewController.swift
+++ b/Mastodon/Scene/Share/Webview/WebViewController.swift
@@ -49,12 +49,7 @@ extension WebViewController {
webView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(webView)
- NSLayoutConstraint.activate([
- webView.topAnchor.constraint(equalTo: view.topAnchor),
- webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ webView.pinToParent()
let request = URLRequest(url: viewModel.url)
webView.load(request)
diff --git a/Mastodon/Scene/SuggestionAccount/CollectionViewCell/SuggestionAccountCollectionViewCell.swift b/Mastodon/Scene/SuggestionAccount/CollectionViewCell/SuggestionAccountCollectionViewCell.swift
index 2fb467fbd..296935521 100644
--- a/Mastodon/Scene/SuggestionAccount/CollectionViewCell/SuggestionAccountCollectionViewCell.swift
+++ b/Mastodon/Scene/SuggestionAccount/CollectionViewCell/SuggestionAccountCollectionViewCell.swift
@@ -53,11 +53,6 @@ extension SuggestionAccountCollectionViewCell {
private func configure() {
contentView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
- imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
- imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
- imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
- ])
+ imageView.pinToParent()
}
}
diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift
index 13c8311c7..7eacdc205 100644
--- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift
+++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift
@@ -161,7 +161,7 @@ extension SuggestionAccountViewController: UITableViewDelegate {
case .account(let record):
guard let account = record.object(in: context.managedObjectContext) else { return }
let cachedProfileViewModel = CachedProfileViewModel(context: context, authContext: viewModel.authContext, mastodonUser: account)
- coordinator.present(
+ _ = coordinator.present(
scene: .profile(viewModel: cachedProfileViewModel),
from: self,
transition: .show
diff --git a/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift b/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift
index 47bd9d6b3..d259ebed4 100644
--- a/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift
+++ b/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift
@@ -97,12 +97,7 @@ extension SuggestionAccountTableViewCell {
containerStackView.isLayoutMarginsRelativeArrangement = true
containerStackView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(containerStackView)
- NSLayoutConstraint.activate([
- containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor),
- containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
- containerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
- containerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
- ])
+ containerStackView.pinToParent()
avatarButton.translatesAutoresizingMaskIntoConstraints = false
containerStackView.addArrangedSubview(avatarButton)
diff --git a/Mastodon/Scene/Thread/ThreadViewController.swift b/Mastodon/Scene/Thread/ThreadViewController.swift
index 5dee182c6..e8e6ce130 100644
--- a/Mastodon/Scene/Thread/ThreadViewController.swift
+++ b/Mastodon/Scene/Thread/ThreadViewController.swift
@@ -87,12 +87,7 @@ extension ThreadViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.topAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- ])
+ tableView.pinToParent()
tableView.delegate = self
viewModel.setupDiffableDataSource(
diff --git a/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift b/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift
index 050670be7..1c6c40190 100644
--- a/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift
+++ b/Mastodon/Scene/Thread/ThreadViewModel+LoadThreadState.swift
@@ -92,19 +92,27 @@ extension ThreadViewModel.LoadThreadState {
from: response.value.ancestors
)
)
+ // deprecated: Tree mode replies
+ // viewModel.mastodonStatusThreadViewModel.appendDescendant(
+ // domain: threadContext.domain,
+ // nodes: MastodonStatusThreadViewModel.Node.children(
+ // of: threadContext.statusID,
+ // from: response.value.descendants
+ // )
+ // )
+
+ // new: the same order from API
viewModel.mastodonStatusThreadViewModel.appendDescendant(
domain: threadContext.domain,
- nodes: MastodonStatusThreadViewModel.Node.children(
- of: threadContext.statusID,
- from: response.value.descendants
- )
+ nodes: response.value.descendants.map { status in
+ return .init(statusID: status.id, children: [])
+ }
)
} catch {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch status context for \(threadContext.statusID) fail: \(error.localizedDescription)")
await enter(state: Fail.self)
}
-
- }
+ } // end Task
}
}
diff --git a/Mastodon/Scene/Thread/ThreadViewModel.swift b/Mastodon/Scene/Thread/ThreadViewModel.swift
index 735d85cd4..c845ce64c 100644
--- a/Mastodon/Scene/Thread/ThreadViewModel.swift
+++ b/Mastodon/Scene/Thread/ThreadViewModel.swift
@@ -28,12 +28,6 @@ class ThreadViewModel {
let context: AppContext
let authContext: AuthContext
let mastodonStatusThreadViewModel: MastodonStatusThreadViewModel
-
-// let cellFrameCache = NSCache()
-// let existStatusFetchedResultsController: StatusFetchedResultsController
-
-// weak var contentOffsetAdjustableTimelineViewControllerDelegate: ContentOffsetAdjustableTimelineViewControllerDelegate?
-// weak var tableView: UITableView?
// output
var diffableDataSource: UITableViewDiffableDataSource?
@@ -62,12 +56,6 @@ class ThreadViewModel {
self.authContext = authContext
self.root = optionalRoot
self.mastodonStatusThreadViewModel = MastodonStatusThreadViewModel(context: context)
-// self.rootNode = CurrentValueSubject(optionalStatus.flatMap { RootNode(domain: $0.domain, statusID: $0.id, replyToID: $0.inReplyToID) })
-// self.rootItem = CurrentValueSubject(optionalStatus.flatMap { Item.root(statusObjectID: $0.objectID, attribute: Item.StatusAttribute()) })
-// self.existStatusFetchedResultsController = StatusFetchedResultsController(managedObjectContext: context.managedObjectContext, domain: nil, additionalTweetPredicate: nil)
-// self.navigationBarTitle = CurrentValueSubject(
-// optionalStatus.flatMap { L10n.Scene.Thread.title($0.author.displayNameWithFallback) })
-// self.navigationBarTitleEmojiMeta = CurrentValueSubject(optionalStatus.flatMap { $0.author.emojis.asDictionary } ?? [:])
// end init
ManagedObjectObserver.observe(context: context.managedObjectContext)
@@ -85,24 +73,6 @@ class ThreadViewModel {
})
.store(in: &disposeBag)
-// // bind fetcher domain
-// context.authenticationService.activeMastodonAuthenticationBox
-// .receive(on: RunLoop.main)
-// .sink { [weak self] box in
-// guard let self = self else { return }
-// self.existStatusFetchedResultsController.domain.value = box?.domain
-// }
-// .store(in: &disposeBag)
-//
-// rootNode
-// .receive(on: DispatchQueue.main)
-// .sink { [weak self] rootNode in
-// guard let self = self else { return }
-// guard rootNode != nil else { return }
-// self.loadThreadStateMachine.enter(LoadThreadState.Loading.self)
-// }
-// .store(in: &disposeBag)
-
$root
.receive(on: DispatchQueue.main)
.sink { [weak self] root in
@@ -125,102 +95,6 @@ class ThreadViewModel {
}()
}
.store(in: &disposeBag)
-
-// rootItem
-// .receive(on: DispatchQueue.main)
-// .sink { [weak self] rootItem in
-// guard let self = self else { return }
-// guard case let .root(objectID, _) = rootItem else { return }
-// self.context.managedObjectContext.perform {
-// guard let status = self.context.managedObjectContext.object(with: objectID) as? Status else {
-// return
-// }
-// self.rootItemObserver = ManagedObjectObserver.observe(object: status)
-// .receive(on: DispatchQueue.main)
-// .sink(receiveCompletion: { _ in
-// // do nothing
-// }, receiveValue: { [weak self] change in
-// guard let self = self else { return }
-// switch change.changeType {
-// case .delete:
-// self.rootItem.value = nil
-// default:
-// break
-// }
-// })
-// }
-// }
-// .store(in: &disposeBag)
-//
-// ancestorNodes
-// .receive(on: DispatchQueue.main)
-// .compactMap { [weak self] nodes -> [Item]? in
-// guard let self = self else { return nil }
-// guard !nodes.isEmpty else { return [] }
-//
-// guard let diffableDataSource = self.diffableDataSource else { return nil }
-// let oldSnapshot = diffableDataSource.snapshot()
-// var oldSnapshotAttributeDict: [NSManagedObjectID : Item.StatusAttribute] = [:]
-// for item in oldSnapshot.itemIdentifiers {
-// switch item {
-// case .reply(let objectID, let attribute):
-// oldSnapshotAttributeDict[objectID] = attribute
-// default:
-// break
-// }
-// }
-//
-// var items: [Item] = []
-// for node in nodes {
-// let attribute = oldSnapshotAttributeDict[node.statusObjectID] ?? Item.StatusAttribute()
-// items.append(Item.reply(statusObjectID: node.statusObjectID, attribute: attribute))
-// }
-//
-// return items.reversed()
-// }
-// .assign(to: \.value, on: ancestorItems)
-// .store(in: &disposeBag)
-//
-// descendantNodes
-// .receive(on: DispatchQueue.main)
-// .compactMap { [weak self] nodes -> [Item]? in
-// guard let self = self else { return nil }
-// guard !nodes.isEmpty else { return [] }
-//
-// guard let diffableDataSource = self.diffableDataSource else { return nil }
-// let oldSnapshot = diffableDataSource.snapshot()
-// var oldSnapshotAttributeDict: [NSManagedObjectID : Item.StatusAttribute] = [:]
-// for item in oldSnapshot.itemIdentifiers {
-// switch item {
-// case .leaf(let objectID, let attribute):
-// oldSnapshotAttributeDict[objectID] = attribute
-// default:
-// break
-// }
-// }
-//
-// var items: [Item] = []
-//
-// func buildThread(node: LeafNode) {
-// let attribute = oldSnapshotAttributeDict[node.objectID] ?? Item.StatusAttribute()
-// items.append(Item.leaf(statusObjectID: node.objectID, attribute: attribute))
-// // only expand the first child
-// if let firstChild = node.children.first {
-// if !node.isChildrenExpanded {
-// items.append(Item.leafBottomLoader(statusObjectID: node.objectID))
-// } else {
-// buildThread(node: firstChild)
-// }
-// }
-// }
-//
-// for node in nodes {
-// buildThread(node: node)
-// }
-// return items
-// }
-// .assign(to: \.value, on: descendantItems)
-// .store(in: &disposeBag)
}
deinit {
diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift
index 5381feb0d..8219859a2 100644
--- a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift
+++ b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift
@@ -263,7 +263,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning {
}()
// FIXME:
- let maskLayerToFinalPath = maskLayerToFinalRect.flatMap { UIBezierPath(rect: $0) }?.cgPath
+ _ = maskLayerToFinalRect.flatMap { UIBezierPath(rect: $0) }?.cgPath
if let maskLayerToPath = maskLayerToPath {
maskLayer.path = maskLayerToPath
diff --git a/Mastodon/Supporting Files/AppDelegate.swift b/Mastodon/Supporting Files/AppDelegate.swift
index 3bf38f6da..84b819a5c 100644
--- a/Mastodon/Supporting Files/AppDelegate.swift
+++ b/Mastodon/Supporting Files/AppDelegate.swift
@@ -65,11 +65,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
extension AppDelegate {
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
- #if DEBUG
- return .all
- #else
return UIDevice.current.userInterfaceIdiom == .phone ? .portrait : .all
- #endif
}
}
diff --git a/MastodonIntent/cs.lproj/Intents.strings b/MastodonIntent/cs.lproj/Intents.strings
new file mode 100644
index 000000000..6f29830a1
--- /dev/null
+++ b/MastodonIntent/cs.lproj/Intents.strings
@@ -0,0 +1,51 @@
+"16wxgf" = "Příspěvek na Mastodon";
+
+"751xkl" = "Textový obsah";
+
+"CsR7G2" = "Příspěvek na Mastodon";
+
+"HZSGTr" = "Jaký obsah se má přidat?";
+
+"HdGikU" = "Odeslání se nezdařilo";
+
+"KDNTJ4" = "Důvod selhání";
+
+"RHxKOw" = "Odeslat příspěvek s textovým obsahem";
+
+"RxSqsb" = "Příspěvek";
+
+"WCIR3D" = "Zveřejnit ${content} na Mastodon";
+
+"ZKJSNu" = "Příspěvek";
+
+"ZS1XaK" = "${content}";
+
+"ZbSjzC" = "Viditelnost";
+
+"Zo4jgJ" = "Viditelnost příspěvku";
+
+"apSxMG-dYQ5NN" = "Existuje ${count} možností odpovídajících 'Veřejný'.";
+
+"apSxMG-ehFLjY" = "Existuje ${count} možností, které odpovídají „jen sledujícím“.";
+
+"ayoYEb-dYQ5NN" = "${content}, veřejné";
+
+"ayoYEb-ehFLjY" = "${content}, pouze sledující";
+
+"dUyuGg" = "Příspěvek na Mastodon";
+
+"dYQ5NN" = "Veřejný";
+
+"ehFLjY" = "Pouze sledující";
+
+"gfePDu" = "Odeslání se nezdařilo. ${failureReason}";
+
+"k7dbKQ" = "Příspěvek byl úspěšně odeslán.";
+
+"oGiqmY-dYQ5NN" = "Jen pro kontrolu, chtěli jste „Veřejný“?";
+
+"oGiqmY-ehFLjY" = "Jen pro kontrolu, chtěli jste „Pouze sledující“?";
+
+"rM6dvp" = "URL";
+
+"ryJLwG" = "Příspěvek byl úspěšně odeslán. ";
diff --git a/MastodonIntent/cs.lproj/Intents.stringsdict b/MastodonIntent/cs.lproj/Intents.stringsdict
new file mode 100644
index 000000000..5a39d5e64
--- /dev/null
+++ b/MastodonIntent/cs.lproj/Intents.stringsdict
@@ -0,0 +1,54 @@
+
+
+
+
+ There are ${count} options matching ‘${content}’. - 2
+
+ NSStringLocalizedFormatKey
+ There are %#@count_option@ matching ‘${content}’.
+ count_option
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ %ld
+ zero
+ 0 options
+ one
+ 1 option
+ two
+ 2 options
+ few
+ %ld options
+ many
+ %ld options
+ other
+ %ld options
+
+
+ There are ${count} options matching ‘${visibility}’.
+
+ NSStringLocalizedFormatKey
+ There are %#@count_option@ matching ‘${visibility}’.
+ count_option
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ %ld
+ zero
+ 0 options
+ one
+ 1 option
+ two
+ 2 options
+ few
+ %ld options
+ many
+ %ld options
+ other
+ %ld options
+
+
+
+
diff --git a/MastodonIntent/sl.lproj/Intents.strings b/MastodonIntent/sl.lproj/Intents.strings
new file mode 100644
index 000000000..72de87df2
--- /dev/null
+++ b/MastodonIntent/sl.lproj/Intents.strings
@@ -0,0 +1,51 @@
+"16wxgf" = "Objavi na Mastodonu";
+
+"751xkl" = "besedilo";
+
+"CsR7G2" = "Objavi na Mastodonu";
+
+"HZSGTr" = "Kakšno vsebino želite objaviti?";
+
+"HdGikU" = "Objava ni uspela";
+
+"KDNTJ4" = "Vzrok za neuspeh";
+
+"RHxKOw" = "Pošlji objavo z besedilom";
+
+"RxSqsb" = "Objavi";
+
+"WCIR3D" = "Objavite ${content} na Mastodonu";
+
+"ZKJSNu" = "Objavi";
+
+"ZS1XaK" = "${content}";
+
+"ZbSjzC" = "Vidnost";
+
+"Zo4jgJ" = "Vidnost objave";
+
+"apSxMG-dYQ5NN" = "Z \"Javno\" se ujema ${count} možnosti.";
+
+"apSxMG-ehFLjY" = "S \"Samo sledilci\" se ujema ${count} možnosti.";
+
+"ayoYEb-dYQ5NN" = "${content}, javno";
+
+"ayoYEb-ehFLjY" = "${content}, samo sledilci";
+
+"dUyuGg" = "Objavi na Mastodonu";
+
+"dYQ5NN" = "Javno";
+
+"ehFLjY" = "Samo sledilci";
+
+"gfePDu" = "Objava je spodletela. ${failureReason}";
+
+"k7dbKQ" = "Uspešno poslana objava.";
+
+"oGiqmY-dYQ5NN" = "Da ne bo nesporazuma - želeli ste \"Javno\"?";
+
+"oGiqmY-ehFLjY" = "Da ne bo nesporazuma - želeli ste \"Samo sledilci\"?";
+
+"rM6dvp" = "URL";
+
+"ryJLwG" = "Uspešno poslana objava. ";
diff --git a/MastodonIntent/sl.lproj/Intents.stringsdict b/MastodonIntent/sl.lproj/Intents.stringsdict
new file mode 100644
index 000000000..5a39d5e64
--- /dev/null
+++ b/MastodonIntent/sl.lproj/Intents.stringsdict
@@ -0,0 +1,54 @@
+
+
+
+
+ There are ${count} options matching ‘${content}’. - 2
+
+ NSStringLocalizedFormatKey
+ There are %#@count_option@ matching ‘${content}’.
+ count_option
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ %ld
+ zero
+ 0 options
+ one
+ 1 option
+ two
+ 2 options
+ few
+ %ld options
+ many
+ %ld options
+ other
+ %ld options
+
+
+ There are ${count} options matching ‘${visibility}’.
+
+ NSStringLocalizedFormatKey
+ There are %#@count_option@ matching ‘${visibility}’.
+ count_option
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ %ld
+ zero
+ 0 options
+ one
+ 1 option
+ two
+ 2 options
+ few
+ %ld options
+ many
+ %ld options
+ other
+ %ld options
+
+
+
+
diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift
index 7a4201894..1ac22e6a7 100644
--- a/MastodonSDK/Package.swift
+++ b/MastodonSDK/Package.swift
@@ -32,7 +32,6 @@ let package = Package(
.package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.1.0"),
.package(url: "https://github.com/apple/swift-collections.git", from: "1.0.3"),
.package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"),
- .package(url: "https://github.com/cezheng/Fuzi.git", from: "3.1.3"),
.package(url: "https://github.com/Flipboard/FLAnimatedImage.git", from: "1.0.0"),
.package(url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"),
.package(url: "https://github.com/kean/Nuke.git", from: "10.3.1"),
diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.imageset/Contents.json
deleted file mode 100644
index 3018f4b9a..000000000
--- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.imageset/Contents.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "images" : [
- {
- "filename" : "mastodon.logo.black.pdf",
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.imageset/mastodon.logo.black.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.imageset/mastodon.logo.black.pdf
deleted file mode 100644
index 773ed5e77..000000000
--- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.imageset/mastodon.logo.black.pdf
+++ /dev/null
@@ -1,339 +0,0 @@
-%PDF-1.7
-
-1 0 obj
- << /BBox [ 0.000000 0.000000 480.000000 119.097778 ]
- /Resources << >>
- /Subtype /Form
- /Length 2 0 R
- /Group << /Type /Group
- /S /Transparency
- >>
- /Type /XObject
- >>
-stream
-/DeviceRGB CS
-/DeviceRGB cs
-q
-1.000000 0.000000 -0.000000 1.000000 0.001709 -0.290527 cm
-0.188235 0.533333 0.831373 scn
-107.682541 47.532677 m
-106.063889 39.212074 93.195923 30.106506 78.416977 28.341690 c
-70.709908 27.421394 63.121937 26.576881 55.030510 26.946808 c
-41.798027 27.553123 31.357124 30.104706 31.357124 30.104706 c
-31.357124 28.818085 31.436523 27.591019 31.595320 26.443352 c
-33.315022 13.385902 44.544495 12.602745 55.180283 12.238235 c
-65.917122 11.870117 75.475624 14.885460 75.475624 14.885460 c
-75.917725 5.177185 l
-75.917725 5.177185 68.407349 1.147720 55.030510 0.406067 c
-47.655472 0.000053 38.495773 0.590118 27.827501 3.414185 c
-4.693666 9.538696 0.712913 34.197334 0.106597 59.224106 c
--0.079267 66.653275 0.034417 73.660202 0.034417 79.517647 c
-0.034417 105.105621 16.798328 112.606972 16.798328 112.606972 c
-25.250660 116.488472 39.757122 118.121559 54.837425 118.244263 c
-55.207348 118.244263 l
-70.287651 118.121559 84.801338 116.488472 93.255470 112.606972 c
-93.255470 112.606972 110.019386 105.105621 110.019386 79.517647 c
-110.019386 79.517647 110.230507 60.638844 107.682541 47.532677 c
-h
-f
-n
-Q
-q
-1.000000 0.000000 -0.000000 1.000000 23.245789 45.780518 cm
-0.121569 0.137255 0.168627 scn
-0.000000 39.648720 m
-0.000000 43.373230 3.018947 46.392181 6.743458 46.392181 c
-10.467969 46.392181 13.486919 43.373230 13.486919 39.648720 c
-13.486919 35.924210 10.467969 32.905262 6.743458 32.905262 c
-3.018947 32.905262 0.000000 35.924210 0.000000 39.648720 c
-h
-96.718201 31.461655 m
-96.718201 0.478188 l
-84.443916 0.478188 l
-84.443916 30.553986 l
-84.443916 36.893234 81.776840 40.110676 76.440903 40.110676 c
-70.541954 40.110676 67.586166 36.292332 67.586166 28.745865 c
-67.586166 12.286915 l
-55.384064 12.286915 l
-55.384064 28.745865 l
-55.384064 36.294136 52.426468 40.110676 46.529324 40.110676 c
-41.193382 40.110676 38.524509 36.893234 38.524509 30.553986 c
-38.524509 0.481804 l
-26.252031 0.481804 l
-26.252031 31.465263 l
-26.252031 37.795486 27.865263 42.828270 31.104361 46.550980 c
-34.442707 50.273685 38.816845 52.181053 44.246616 52.181053 c
-50.526318 52.181053 55.284817 49.768425 58.430077 44.939552 c
-61.486919 39.814735 l
-64.543762 44.939552 l
-67.689026 49.768425 72.445709 52.182858 78.727219 52.182858 c
-84.156990 52.182858 88.529327 50.273685 91.869476 46.552784 c
-95.108574 42.828270 96.720009 37.795490 96.720009 31.463459 c
-96.718201 31.461655 l
-h
-139.005112 16.060150 m
-141.536835 18.736240 142.758499 22.105263 142.758499 26.170826 c
-142.758499 30.236389 141.536835 33.605415 139.005112 36.184063 c
-136.565414 38.860153 133.468872 40.148571 129.715500 40.148571 c
-125.962112 40.148571 122.867371 38.860153 120.427673 36.184063 c
-117.987968 33.605415 116.768120 30.236389 116.768120 26.170826 c
-116.768120 22.107067 117.987968 18.736240 120.427673 16.060150 c
-122.867371 13.483311 125.962112 12.194881 129.715500 12.194881 c
-133.468872 12.194881 136.565414 13.483311 139.005112 16.060150 c
-139.005112 16.060150 l
-h
-142.758499 50.953987 m
-154.859543 50.953987 l
-154.859543 1.389473 l
-142.754898 1.389473 l
-142.754898 7.236088 l
-139.097153 2.378342 134.030075 -0.000008 127.463463 -0.000008 c
-121.176544 -0.000008 115.827965 2.477585 111.323906 7.533829 c
-106.915489 12.590069 104.665268 18.835487 104.665268 26.169022 c
-104.665268 33.405113 106.915489 39.650528 111.323906 44.706768 c
-115.827965 49.763008 121.176544 52.339851 127.463463 52.339851 c
-134.030075 52.339851 139.097153 49.959702 142.754898 45.103760 c
-142.754898 50.950378 l
-142.758499 50.953987 l
-h
-195.581955 27.062256 m
-199.147659 24.387970 200.930527 20.620148 200.836685 15.863457 c
-200.836685 10.807217 199.053848 6.840900 195.394302 4.065559 c
-191.734756 1.389473 187.326309 0.001801 181.977737 0.001801 c
-172.314575 0.001801 165.746170 3.966316 162.274292 11.797894 c
-172.783768 18.041504 l
-174.191299 13.781052 177.286011 11.599396 181.977737 11.599396 c
-186.294128 11.599396 188.452347 12.988873 188.452347 15.863457 c
-188.452347 17.944057 185.637283 19.827969 179.913376 21.313084 c
-177.755188 21.908573 175.972336 22.504059 174.566620 23.000301 c
-172.596085 23.792480 170.907074 24.685715 169.499557 25.775639 c
-166.027664 28.451729 164.246628 32.019249 164.246628 36.579250 c
-164.246628 41.436996 165.933823 45.302254 169.311874 48.079399 c
-172.783752 50.953987 177.004501 52.341656 182.071579 52.341656 c
-190.141342 52.341656 196.051117 48.871578 199.898331 41.833984 c
-189.578354 35.886318 l
-188.076996 39.255341 185.543457 40.940754 182.071579 40.940754 c
-178.412018 40.940754 176.630966 39.553085 176.630966 36.876991 c
-176.630966 34.796391 179.444214 32.912483 185.168121 31.425564 c
-189.578339 30.433083 193.048416 28.947971 195.581955 27.064060 c
-195.581955 27.062256 l
-h
-234.052322 38.661655 m
-223.449036 38.661655 l
-223.449036 18.043308 l
-223.449036 15.563908 224.389175 14.078796 226.170227 13.384060 c
-227.483917 12.887817 230.111267 12.788570 234.052322 12.987068 c
-234.052322 1.389473 l
-225.890518 0.396988 219.978958 1.190971 216.507080 3.868866 c
-213.037003 6.445709 211.346176 11.202404 211.346176 18.043308 c
-211.346176 38.661655 l
-203.184372 38.661655 l
-203.184372 50.953987 l
-211.346176 50.953987 l
-211.346176 60.965416 l
-223.449036 64.830681 l
-223.449036 50.953987 l
-234.052322 50.953987 l
-234.052322 38.661655 l
-234.052322 38.661655 l
-h
-272.614716 16.357895 m
-275.054413 18.936543 276.274261 22.208122 276.274261 26.172634 c
-276.274261 30.137146 275.054413 33.408722 272.614716 35.985565 c
-270.176819 38.562408 267.174133 39.850830 263.514587 39.850830 c
-259.855011 39.850830 256.854126 38.562408 254.414429 35.985565 c
-252.068558 33.309475 250.848709 30.037895 250.848709 26.172634 c
-250.848709 22.305565 252.068558 19.033985 254.414429 16.357895 c
-256.854126 13.781052 259.855011 12.492626 263.514587 12.492626 c
-267.174133 12.492626 270.176819 13.781052 272.614716 16.357895 c
-h
-245.875488 7.535637 m
-241.091721 12.590076 238.745850 18.736240 238.745850 26.172634 c
-238.745850 33.507973 241.091721 39.652328 245.875488 44.708572 c
-250.661057 49.763008 256.570801 52.341656 263.514587 52.341656 c
-270.458344 52.341656 276.368134 49.763008 281.153687 44.708572 c
-285.939240 39.652328 288.377136 33.408722 288.377136 26.172634 c
-288.377136 18.835491 285.939240 12.590076 281.153687 7.535637 c
-276.368134 2.479401 270.552155 0.001801 263.514587 0.001801 c
-256.476990 0.001801 250.661057 2.479401 245.875488 7.535637 c
-h
-328.818054 16.060150 m
-331.257751 18.736240 332.475769 22.105263 332.475769 26.170826 c
-332.475769 30.236389 331.257751 33.605415 328.818054 36.184063 c
-326.378357 38.860153 323.281799 40.148571 319.528412 40.148571 c
-315.775024 40.148571 312.680298 38.860153 310.146759 36.184063 c
-307.708893 33.605415 306.487213 30.236389 306.487213 26.170826 c
-306.487213 22.107067 307.708893 18.736240 310.146759 16.060150 c
-312.680298 13.483311 315.870667 12.194881 319.528412 12.194881 c
-323.281799 12.194881 326.378357 13.483311 328.818054 16.060150 c
-328.818054 16.060150 l
-h
-332.475769 70.780151 m
-344.580475 70.780151 l
-344.580475 1.389473 l
-332.475769 1.389473 l
-332.475769 7.236088 l
-328.911865 2.378342 323.844818 -0.000008 317.278198 -0.000008 c
-310.991272 -0.000008 305.550690 2.477585 301.046631 7.533829 c
-296.636414 12.590069 294.384369 18.835487 294.384369 26.169022 c
-294.384369 33.405113 296.636414 39.650528 301.046631 44.706768 c
-305.550690 49.763008 310.991272 52.339851 317.278198 52.339851 c
-323.844818 52.339851 328.911865 49.959702 332.475769 45.103760 c
-332.475769 70.780151 l
-332.475769 70.780151 l
-h
-387.083923 16.357895 m
-389.523621 18.936543 390.743469 22.208122 390.743469 26.172634 c
-390.743469 30.137146 389.523621 33.408722 387.083923 35.985565 c
-384.644226 38.562408 381.643311 39.850830 377.983765 39.850830 c
-374.324219 39.850830 371.321503 38.562408 368.881805 35.985565 c
-366.535950 33.309475 365.316101 30.037895 365.316101 26.172634 c
-365.316101 22.305565 366.535950 19.033985 368.881805 16.357895 c
-371.321503 13.781052 374.324219 12.492626 377.983765 12.492626 c
-381.643311 12.492626 384.644226 13.781052 387.083923 16.357895 c
-387.083923 16.357895 l
-h
-360.344666 7.535637 m
-355.559082 12.590076 353.215027 18.736240 353.215027 26.172634 c
-353.215027 33.507973 355.559082 39.652328 360.344666 44.708572 c
-365.130219 49.763008 371.040009 52.341656 377.983765 52.341656 c
-384.925720 52.341656 390.837280 49.763008 395.622864 44.708572 c
-400.408417 39.652328 402.846313 33.408722 402.846313 26.172634 c
-402.846313 18.835491 400.408417 12.590076 395.622864 7.535637 c
-390.837280 2.479401 385.019562 0.001801 377.983765 0.001801 c
-370.946167 0.001801 365.130219 2.479401 360.344666 7.535637 c
-360.344666 7.535637 l
-h
-455.202423 31.822556 m
-455.202423 1.389473 l
-443.097748 1.389473 l
-443.097748 30.236389 l
-443.097748 33.507969 442.255035 35.985565 440.566010 37.869476 c
-438.970825 39.553085 436.718811 40.446320 433.809937 40.446320 c
-426.960022 40.446320 423.489929 36.382557 423.489929 28.153984 c
-423.489929 1.389473 l
-411.387054 1.389473 l
-411.387054 50.953987 l
-423.489929 50.953987 l
-423.489929 45.403309 l
-426.398773 50.060753 430.994904 52.341656 437.469482 52.341656 c
-442.630371 52.341656 446.851135 50.556992 450.135345 46.888420 c
-453.513397 43.221657 455.202423 38.264664 455.202423 31.820751 c
-455.202423 31.822556 l
-h
-f
-n
-Q
-
-endstream
-endobj
-
-2 0 obj
- 9224
-endobj
-
-3 0 obj
- << /BBox [ 0.000000 0.000000 480.000000 119.097778 ]
- /Resources << >>
- /Subtype /Form
- /Length 4 0 R
- /Group << /Type /Group
- /S /Transparency
- >>
- /Type /XObject
- >>
-stream
-/DeviceRGB CS
-/DeviceRGB cs
-q
-1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
-0.000000 0.000000 0.000000 scn
-0.000000 119.097778 m
-480.000000 119.097778 l
-480.000000 0.000031 l
-0.000000 0.000031 l
-0.000000 119.097778 l
-h
-f
-n
-Q
-
-endstream
-endobj
-
-4 0 obj
- 237
-endobj
-
-5 0 obj
- << /XObject << /X1 1 0 R >>
- /ExtGState << /E1 << /SMask << /Type /Mask
- /G 3 0 R
- /S /Alpha
- >>
- /Type /ExtGState
- >> >>
- >>
-endobj
-
-6 0 obj
- << /Length 7 0 R >>
-stream
-/DeviceRGB CS
-/DeviceRGB cs
-q
-/E1 gs
-/X1 Do
-Q
-
-endstream
-endobj
-
-7 0 obj
- 46
-endobj
-
-8 0 obj
- << /Annots []
- /Type /Page
- /MediaBox [ 0.000000 0.000000 480.000000 119.097778 ]
- /Resources 5 0 R
- /Contents 6 0 R
- /Parent 9 0 R
- >>
-endobj
-
-9 0 obj
- << /Kids [ 8 0 R ]
- /Count 1
- /Type /Pages
- >>
-endobj
-
-10 0 obj
- << /Type /Catalog
- /Pages 9 0 R
- >>
-endobj
-
-xref
-0 11
-0000000000 65535 f
-0000000010 00000 n
-0000009484 00000 n
-0000009507 00000 n
-0000009994 00000 n
-0000010016 00000 n
-0000010314 00000 n
-0000010416 00000 n
-0000010437 00000 n
-0000010612 00000 n
-0000010686 00000 n
-trailer
-<< /ID [ (some) (id) ]
- /Root 10 0 R
- /Size 11
->>
-startxref
-10746
-%%EOF
\ No newline at end of file
diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.large.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.large.imageset/Contents.json
deleted file mode 100644
index fefc19832..000000000
--- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.large.imageset/Contents.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "images" : [
- {
- "filename" : "mastodon.logo.black.large.pdf",
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.large.imageset/mastodon.logo.black.large.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.large.imageset/mastodon.logo.black.large.pdf
deleted file mode 100644
index b6244d04e..000000000
--- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.black.large.imageset/mastodon.logo.black.large.pdf
+++ /dev/null
@@ -1,339 +0,0 @@
-%PDF-1.7
-
-1 0 obj
- << /BBox [ 0.000000 0.000000 960.000000 238.195496 ]
- /Resources << >>
- /Subtype /Form
- /Length 2 0 R
- /Group << /Type /Group
- /S /Transparency
- >>
- /Type /XObject
- >>
-stream
-/DeviceRGB CS
-/DeviceRGB cs
-q
-1.000000 0.000000 -0.000000 1.000000 0.003357 -0.580933 cm
-0.188235 0.533333 0.831373 scn
-215.365082 95.065247 m
-212.127777 78.424042 186.391846 60.212906 156.833954 56.683273 c
-141.419815 54.842682 126.243874 53.153656 110.061020 53.893509 c
-83.596054 55.106140 62.714249 60.209290 62.714249 60.209290 c
-62.714249 57.636063 62.873047 55.181931 63.190639 52.886597 c
-66.630043 26.771698 89.088989 25.205383 110.360565 24.476364 c
-131.834244 23.740112 150.951248 29.770813 150.951248 29.770813 c
-151.835449 10.354263 l
-151.835449 10.354263 136.814697 2.295334 110.061020 0.812027 c
-95.310944 0.000000 76.991547 1.180130 55.655003 6.828262 c
-9.387332 19.077271 1.425826 68.394562 0.213194 118.448097 c
--0.158535 133.306442 0.068834 147.320282 0.068834 159.035172 c
-0.068834 210.211121 33.596657 225.213821 33.596657 225.213821 c
-50.501320 232.976822 79.514244 236.242996 109.674850 236.488403 c
-110.414696 236.488403 l
-140.575302 236.242996 169.602676 232.976822 186.510941 225.213821 c
-186.510941 225.213821 220.038773 210.211121 220.038773 159.035172 c
-220.038773 159.035172 220.461014 121.277573 215.365082 95.065247 c
-h
-f
-n
-Q
-q
-1.000000 0.000000 -0.000000 1.000000 46.491440 91.561096 cm
-0.121569 0.137255 0.168627 scn
-0.000000 79.297432 m
-0.000000 86.746460 6.037893 92.784363 13.486916 92.784363 c
-20.935938 92.784363 26.973839 86.746460 26.973839 79.297432 c
-26.973839 71.848412 20.935938 65.810516 13.486916 65.810516 c
-6.037893 65.810516 0.000000 71.848412 0.000000 79.297432 c
-h
-193.436401 62.923302 m
-193.436401 0.956360 l
-168.887833 0.956360 l
-168.887833 61.107964 l
-168.887833 73.786461 163.553680 80.221344 152.881805 80.221344 c
-141.083908 80.221344 135.172333 72.584648 135.172333 57.491714 c
-135.172333 24.573814 l
-110.768127 24.573814 l
-110.768127 57.491714 l
-110.768127 72.588257 104.852936 80.221344 93.058647 80.221344 c
-82.386765 80.221344 77.049019 73.786461 77.049019 61.107964 c
-77.049019 0.963593 l
-52.504063 0.963593 l
-52.504063 62.930511 l
-52.504063 75.590965 55.730526 85.656540 62.208721 93.101944 c
-68.885414 100.547363 77.633690 104.362106 88.493233 104.362106 c
-101.052635 104.362106 110.569633 99.536835 116.860153 89.879089 c
-122.973839 79.629471 l
-129.087524 89.879089 l
-135.378052 99.536835 144.891418 104.365707 157.454437 104.365707 c
-168.313980 104.365707 177.058655 100.547363 183.738953 93.105560 c
-190.217148 85.656540 193.440018 75.590973 193.440018 62.926910 c
-193.436401 62.923302 l
-h
-278.010223 32.120285 m
-283.073669 37.472473 285.516998 44.210510 285.516998 52.341637 c
-285.516998 60.472771 283.073669 67.210823 278.010223 72.368118 c
-273.130829 77.720299 266.937744 80.297134 259.431000 80.297134 c
-251.924225 80.297134 245.734741 77.720299 240.855347 72.368118 c
-235.975937 67.210823 233.536240 60.472771 233.536240 52.341637 c
-233.536240 44.214119 235.975937 37.472473 240.855347 32.120285 c
-245.734741 26.966606 251.924225 24.389748 259.431000 24.389748 c
-266.937744 24.389748 273.130829 26.966606 278.010223 32.120285 c
-278.010223 32.120285 l
-h
-285.516998 101.907967 m
-309.719086 101.907967 l
-309.719086 2.778915 l
-285.509796 2.778915 l
-285.509796 14.472160 l
-278.194305 4.756668 268.060150 -0.000031 254.926926 -0.000031 c
-242.353088 -0.000031 231.655930 4.955154 222.647812 15.067642 c
-213.830978 25.180122 209.330536 37.670959 209.330536 52.338036 c
-209.330536 66.810219 213.830978 79.301048 222.647812 89.413528 c
-231.655930 99.526016 242.353088 104.679695 254.926926 104.679695 c
-268.060150 104.679695 278.194305 99.919395 285.509796 90.207512 c
-285.509796 101.900742 l
-285.516998 101.907967 l
-h
-391.163910 54.124504 m
-398.295319 48.775932 401.861053 41.240288 401.673370 31.726898 c
-401.673370 21.614418 398.107697 13.681786 390.788605 8.131104 c
-383.469513 2.778931 374.652618 0.003571 363.955475 0.003571 c
-344.629150 0.003571 331.492340 7.932617 324.548584 23.595772 c
-345.567535 36.082993 l
-348.382599 27.562088 354.572021 23.198776 363.955475 23.198776 c
-372.588257 23.198776 376.904694 25.977730 376.904694 31.726898 c
-376.904694 35.888107 371.274567 39.655930 359.826752 42.626152 c
-355.510376 43.817131 351.944672 45.008102 349.133240 46.000587 c
-345.192169 47.584946 341.814148 49.371414 338.999115 51.551262 c
-332.055328 56.903450 328.493256 64.038490 328.493256 73.158493 c
-328.493256 82.873978 331.867645 90.604507 338.623749 96.158791 c
-345.567505 101.907967 354.009003 104.683304 364.143158 104.683304 c
-380.282684 104.683304 392.102234 97.743149 399.796661 83.667961 c
-379.156708 71.772621 l
-376.153992 78.510666 371.086914 81.881500 364.143158 81.881500 c
-356.824036 81.881500 353.261932 79.106155 353.261932 73.753975 c
-353.261932 69.592773 358.888428 65.824951 370.336243 62.851120 c
-379.156677 60.866158 386.096832 57.895927 391.163910 54.128113 c
-391.163910 54.124504 l
-h
-468.104645 77.323303 m
-446.898071 77.323303 l
-446.898071 36.086601 l
-446.898071 31.127808 448.778351 28.157578 452.340454 26.768105 c
-454.967834 25.775620 460.222534 25.577126 468.104645 25.974121 c
-468.104645 2.778915 l
-451.781036 0.793961 439.957916 2.381927 433.014160 7.737717 c
-426.074005 12.891403 422.692352 22.404793 422.692352 36.086601 c
-422.692352 77.323303 l
-406.368744 77.323303 l
-406.368744 101.907967 l
-422.692352 101.907967 l
-422.692352 121.930832 l
-446.898071 129.661346 l
-446.898071 101.907967 l
-468.104645 101.907967 l
-468.104645 77.323303 l
-468.104645 77.323303 l
-h
-545.229431 32.715775 m
-550.108826 37.873070 552.548523 44.416229 552.548523 52.345253 c
-552.548523 60.274277 550.108826 66.817436 545.229431 71.971123 c
-540.353638 77.124809 534.348267 79.701645 527.029175 79.701645 c
-519.710022 79.701645 513.708252 77.124809 508.828857 71.971123 c
-504.137115 66.618942 501.697418 60.075783 501.697418 52.345253 c
-501.697418 44.611115 504.137115 38.067955 508.828857 32.715775 c
-513.708252 27.562088 519.710022 24.985237 527.029175 24.985237 c
-534.348267 24.985237 540.353638 27.562088 545.229431 32.715775 c
-h
-491.750977 15.071259 m
-482.183441 25.180138 477.491699 37.472473 477.491699 52.345253 c
-477.491699 67.015930 482.183441 79.304657 491.750977 89.417137 c
-501.322113 99.526016 513.141602 104.683304 527.029175 104.683304 c
-540.916687 104.683304 552.736267 99.526016 562.307373 89.417137 c
-571.878479 79.304657 576.754272 66.817436 576.754272 52.345253 c
-576.754272 37.670967 571.878479 25.180138 562.307373 15.071259 c
-552.736267 4.958771 541.104309 0.003571 527.029175 0.003571 c
-512.953979 0.003571 501.322113 4.958771 491.750977 15.071259 c
-h
-657.636108 32.120285 m
-662.515503 37.472473 664.951538 44.210510 664.951538 52.341637 c
-664.951538 60.472771 662.515503 67.210823 657.636108 72.368118 c
-652.756714 77.720299 646.563599 80.297134 639.056824 80.297134 c
-631.550049 80.297134 625.360596 77.720299 620.293518 72.368118 c
-615.417786 67.210823 612.974426 60.472771 612.974426 52.341637 c
-612.974426 44.214119 615.417786 37.472473 620.293518 32.120285 c
-625.360596 26.966606 631.741333 24.389748 639.056824 24.389748 c
-646.563599 24.389748 652.756714 26.966606 657.636108 32.120285 c
-657.636108 32.120285 l
-h
-664.951538 141.560303 m
-689.160950 141.560303 l
-689.160950 2.778915 l
-664.951538 2.778915 l
-664.951538 14.472160 l
-657.823730 4.756668 647.689636 -0.000031 634.556396 -0.000031 c
-621.982544 -0.000031 611.101379 4.955154 602.093262 15.067642 c
-593.272827 25.180122 588.768738 37.670959 588.768738 52.338036 c
-588.768738 66.810219 593.272827 79.301048 602.093262 89.413528 c
-611.101379 99.526016 621.982544 104.679695 634.556396 104.679695 c
-647.689636 104.679695 657.823730 99.919395 664.951538 90.207512 c
-664.951538 141.560303 l
-664.951538 141.560303 l
-h
-774.167847 32.715775 m
-779.047241 37.873070 781.486938 44.416229 781.486938 52.345253 c
-781.486938 60.274277 779.047241 66.817436 774.167847 71.971123 c
-769.288452 77.124809 763.286621 79.701645 755.967529 79.701645 c
-748.648438 79.701645 742.643005 77.124809 737.763611 71.971123 c
-733.071899 66.618942 730.632202 60.075783 730.632202 52.345253 c
-730.632202 44.611115 733.071899 38.067955 737.763611 32.715775 c
-742.643005 27.562088 748.648438 24.985237 755.967529 24.985237 c
-763.286621 24.985237 769.288452 27.562088 774.167847 32.715775 c
-774.167847 32.715775 l
-h
-720.689331 15.071259 m
-711.118164 25.180138 706.430054 37.472473 706.430054 52.345253 c
-706.430054 67.015930 711.118164 79.304657 720.689331 89.417137 c
-730.260437 99.526016 742.080017 104.683304 755.967529 104.683304 c
-769.851440 104.683304 781.674561 99.526016 791.245728 89.417137 c
-800.816833 79.304657 805.692627 66.817436 805.692627 52.345253 c
-805.692627 37.670967 800.816833 25.180138 791.245728 15.071259 c
-781.674561 4.958771 770.039124 0.003571 755.967529 0.003571 c
-741.892334 0.003571 730.260437 4.958771 720.689331 15.071259 c
-720.689331 15.071259 l
-h
-910.404846 63.645103 m
-910.404846 2.778915 l
-886.195496 2.778915 l
-886.195496 60.472771 l
-886.195496 67.015930 884.510071 71.971123 881.132019 75.738945 c
-877.941650 79.106163 873.437622 80.892624 867.619873 80.892624 c
-853.920044 80.892624 846.979858 72.765106 846.979858 56.307961 c
-846.979858 2.778915 l
-822.774109 2.778915 l
-822.774109 101.907967 l
-846.979858 101.907967 l
-846.979858 90.806610 l
-852.797546 100.121506 861.989807 104.683304 874.938965 104.683304 c
-885.260742 104.683304 893.702271 101.113983 900.270691 93.776840 c
-907.026794 86.443298 910.404846 76.529312 910.404846 63.641495 c
-910.404846 63.645103 l
-h
-f
-n
-Q
-
-endstream
-endobj
-
-2 0 obj
- 9343
-endobj
-
-3 0 obj
- << /BBox [ 0.000000 0.000000 960.000000 238.195496 ]
- /Resources << >>
- /Subtype /Form
- /Length 4 0 R
- /Group << /Type /Group
- /S /Transparency
- >>
- /Type /XObject
- >>
-stream
-/DeviceRGB CS
-/DeviceRGB cs
-q
-1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
-0.000000 0.000000 0.000000 scn
-0.000000 238.195496 m
-960.000000 238.195496 l
-960.000000 0.000000 l
-0.000000 0.000000 l
-0.000000 238.195496 l
-h
-f
-n
-Q
-
-endstream
-endobj
-
-4 0 obj
- 237
-endobj
-
-5 0 obj
- << /XObject << /X1 1 0 R >>
- /ExtGState << /E1 << /SMask << /Type /Mask
- /G 3 0 R
- /S /Alpha
- >>
- /Type /ExtGState
- >> >>
- >>
-endobj
-
-6 0 obj
- << /Length 7 0 R >>
-stream
-/DeviceRGB CS
-/DeviceRGB cs
-q
-/E1 gs
-/X1 Do
-Q
-
-endstream
-endobj
-
-7 0 obj
- 46
-endobj
-
-8 0 obj
- << /Annots []
- /Type /Page
- /MediaBox [ 0.000000 0.000000 960.000000 238.195496 ]
- /Resources 5 0 R
- /Contents 6 0 R
- /Parent 9 0 R
- >>
-endobj
-
-9 0 obj
- << /Kids [ 8 0 R ]
- /Count 1
- /Type /Pages
- >>
-endobj
-
-10 0 obj
- << /Type /Catalog
- /Pages 9 0 R
- >>
-endobj
-
-xref
-0 11
-0000000000 65535 f
-0000000010 00000 n
-0000009603 00000 n
-0000009626 00000 n
-0000010113 00000 n
-0000010135 00000 n
-0000010433 00000 n
-0000010535 00000 n
-0000010556 00000 n
-0000010731 00000 n
-0000010805 00000 n
-trailer
-<< /ID [ (some) (id) ]
- /Root 10 0 R
- /Size 11
->>
-startxref
-10865
-%%EOF
\ No newline at end of file
diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json
index 6a0bfc87a..76d42c15e 100644
--- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json
+++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json
@@ -1,7 +1,7 @@
{
"images" : [
{
- "filename" : "logotypeFull1.pdf",
+ "filename" : "logo.small.pdf",
"idiom" : "universal"
}
],
diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/logo.small.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/logo.small.pdf
new file mode 100644
index 000000000..581801f38
--- /dev/null
+++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/logo.small.pdf
@@ -0,0 +1,648 @@
+%PDF-1.7
+
+1 0 obj
+ << /Type /XObject
+ /Length 2 0 R
+ /Group << /Type /Group
+ /S /Transparency
+ >>
+ /Subtype /Form
+ /Resources << >>
+ /BBox [ 0.000000 0.000000 269.000000 75.000000 ]
+ >>
+stream
+/DeviceRGB CS
+/DeviceRGB cs
+q
+1.000000 0.000000 -0.000000 1.000000 4.000000 4.000000 cm
+0.000000 0.000000 0.000000 scn
+0.000000 67.000000 m
+261.000000 67.000000 l
+261.000000 0.000000 l
+0.000000 0.000000 l
+0.000000 67.000000 l
+h
+f
+n
+Q
+
+endstream
+endobj
+
+2 0 obj
+ 234
+endobj
+
+3 0 obj
+ << /Length 4 0 R
+ /Range [ 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000 ]
+ /Domain [ 0.000000 1.000000 ]
+ /FunctionType 4
+ >>
+stream
+{ 0.388235 exch 0.392157 exch 1.000000 exch dup 0.000000 gt { exch pop exch pop exch pop dup 0.000000 sub -0.050980 mul 0.388235 add exch dup 0.000000 sub -0.164706 mul 0.392157 add exch dup 0.000000 sub -0.200000 mul 1.000000 add exch } if dup 1.000000 gt { exch pop exch pop exch pop 0.337255 exch 0.227451 exch 0.800000 exch } if pop }
+endstream
+endobj
+
+4 0 obj
+ 339
+endobj
+
+5 0 obj
+ << /Type /XObject
+ /Length 6 0 R
+ /Group << /Type /Group
+ /S /Transparency
+ >>
+ /Subtype /Form
+ /Resources << /Pattern << /P1 << /Matrix [ 0.000000 -65.993195 65.993195 0.000000 -61.993195 70.224548 ]
+ /Shading << /Coords [ 0.000000 0.000000 1.000000 0.000000 ]
+ /ColorSpace /DeviceRGB
+ /Function 3 0 R
+ /Domain [ 0.000000 1.000000 ]
+ /ShadingType 2
+ /Extend [ true true ]
+ >>
+ /PatternType 2
+ /Type /Pattern
+ >> >> >>
+ /BBox [ 0.000000 0.000000 269.000000 75.000000 ]
+ >>
+stream
+/DeviceRGB CS
+/DeviceRGB cs
+q
+1.000000 0.000000 -0.000000 1.000000 4.000000 3.632446 cm
+/Pattern cs
+/P1 scn
+60.826767 51.982300 m
+59.885666 59.068882 53.787518 64.663071 46.568073 65.739265 c
+45.346546 65.922020 40.730431 66.592102 30.036348 66.592102 c
+29.956215 66.592102 l
+19.252211 66.592102 16.959164 65.922020 15.737550 65.739265 c
+8.708311 64.683380 2.299911 59.667900 0.737860 52.489872 c
+-0.003115 48.956699 -0.083220 45.037697 0.056964 41.443653 c
+0.257227 36.286026 0.297280 31.148746 0.757885 26.011383 c
+1.078305 22.600037 1.629032 19.219128 2.420071 15.889084 c
+3.902017 9.736488 9.889900 4.619389 15.757648 2.538147 c
+22.035824 0.365425 28.794806 0.000015 35.263187 1.492470 c
+35.974140 1.665001 36.675091 1.857872 37.376038 2.081261 c
+38.948124 2.588921 40.790466 3.157455 42.152252 4.152424 c
+42.172348 4.162594 42.182354 4.182858 42.192364 4.203201 c
+42.202370 4.223465 42.212376 4.243816 42.212376 4.274334 c
+42.212376 9.249176 l
+42.212376 9.249176 42.212376 9.289791 42.192364 9.310051 c
+42.192364 9.330315 42.172348 9.350658 42.152252 9.360832 c
+42.132240 9.370922 42.112228 9.381180 42.092300 9.391270 c
+42.072121 9.391270 42.052189 9.391270 42.032177 9.391270 c
+37.886612 8.386127 33.631145 7.878468 29.375511 7.888641 c
+22.035824 7.888641 20.063231 11.421898 19.502539 12.883831 c
+19.051918 14.152893 18.761566 15.482990 18.641405 16.823097 c
+18.641405 16.843441 18.641405 16.863705 18.651411 16.884052 c
+18.651411 16.904316 18.671425 16.924664 18.691521 16.934837 c
+18.711451 16.944927 18.731462 16.955097 18.751476 16.965271 c
+18.821604 16.965271 l
+22.896957 15.970303 27.082464 15.462643 31.277977 15.462643 c
+32.289371 15.462643 33.290596 15.462646 34.301991 15.493084 c
+38.517517 15.614994 42.963440 15.828209 47.118843 16.650486 c
+47.218906 16.670830 47.329144 16.691097 47.419201 16.711441 c
+53.967884 17.990677 60.196030 21.990898 60.826767 32.123367 c
+60.846947 32.519287 60.906982 36.306290 60.906982 36.712379 c
+60.906982 38.123699 61.357521 46.692589 60.836857 51.961868 c
+60.826767 51.982300 l
+h
+f
+n
+Q
+q
+1.000000 0.000000 -0.000000 1.000000 16.353134 47.918640 cm
+1.000000 1.000000 1.000000 scn
+0.000000 3.736245 m
+0.000000 5.807401 1.632209 7.472382 3.654834 7.472382 c
+5.677542 7.472382 7.309585 5.797228 7.309585 3.736245 c
+7.309585 1.675262 5.677542 0.000028 3.654834 0.000028 c
+1.632209 0.000028 0.000000 1.675262 0.000000 3.736245 c
+h
+f
+n
+Q
+q
+1.000000 0.000000 -0.000000 1.000000 32.524460 30.973694 cm
+1.000000 1.000000 1.000000 scn
+38.200230 17.462723 m
+38.200230 0.284256 l
+31.541471 0.284256 l
+31.541471 16.955149 l
+31.541471 20.467976 30.099640 22.244776 27.205791 22.244776 c
+24.011585 22.244776 22.399469 20.122755 22.399469 15.950090 c
+22.399469 6.822678 l
+15.790834 6.822678 l
+15.790834 15.950090 l
+15.790834 20.143185 14.198734 22.244776 10.984432 22.244776 c
+8.100758 22.244776 6.648746 20.467976 6.648746 16.955149 c
+6.648746 0.294346 l
+0.000000 0.294346 l
+0.000000 17.462723 l
+0.000000 20.965542 0.871139 23.757576 2.623425 25.828648 c
+4.435832 27.899887 6.808930 28.945639 9.742804 28.945639 c
+13.147311 28.945639 15.730712 27.605450 17.432966 24.925154 c
+19.095194 22.082256 l
+20.757338 24.925154 l
+22.459507 27.595276 25.032986 28.945639 28.447416 28.945639 c
+31.381290 28.945639 33.754387 27.889629 35.566792 25.828648 c
+37.319077 23.757576 38.190220 20.985806 38.190220 17.462723 c
+38.200230 17.462723 l
+h
+61.110268 8.924355 m
+62.491982 10.416807 63.143234 12.264570 63.143234 14.518509 c
+63.143234 16.772449 62.481976 18.640476 61.110268 20.061882 c
+59.788589 21.554337 58.106689 22.265121 56.073723 22.265121 c
+54.041008 22.265121 52.368858 21.554337 51.037174 20.061882 c
+49.715416 18.640476 49.054577 16.772449 49.054577 14.518509 c
+49.054577 12.264570 49.715416 10.396461 51.037174 8.924355 c
+52.358852 7.502947 54.041008 6.781986 56.073723 6.781986 c
+58.106689 6.781986 59.778584 7.492773 61.110268 8.924355 c
+h
+63.143234 28.255198 m
+69.701591 28.255198 l
+69.701591 0.781738 l
+63.143234 0.781738 l
+63.143234 4.020473 l
+61.160301 1.330006 58.416882 -0.000011 54.852188 -0.000011 c
+51.287495 -0.000011 48.543831 1.370613 46.110611 4.172821 c
+43.717499 6.974941 42.505974 10.437069 42.505974 14.498163 c
+42.505974 18.559340 43.727505 21.970684 46.110611 24.772808 c
+48.553837 27.574930 51.457687 28.996338 54.852188 28.996338 c
+58.246773 28.996338 61.160301 27.676495 63.143234 24.996117 c
+63.143234 28.234852 l
+63.143234 28.255198 l
+h
+91.770676 15.036257 m
+93.703575 13.543886 94.665031 11.462475 94.615005 8.832880 c
+94.615005 6.030758 93.653549 3.827599 91.670616 2.304710 c
+89.688515 0.812176 87.294495 0.050774 84.390968 0.050774 c
+79.154297 0.050774 75.599525 2.253845 73.716660 6.579025 c
+79.405289 10.041067 l
+80.164940 7.685646 81.837677 6.467285 84.390968 6.467285 c
+86.734138 6.467285 87.895714 7.228771 87.895714 8.822790 c
+87.895714 9.980196 86.373070 11.025948 83.269424 11.838133 c
+82.097839 12.163090 81.127220 12.498138 80.375908 12.772230 c
+79.303558 13.208757 78.392975 13.706240 77.631653 14.315380 c
+75.749619 15.807833 74.789009 17.777590 74.789009 20.305622 c
+74.789009 22.996006 75.699593 25.138290 77.531593 26.681526 c
+79.415298 28.275459 81.706749 29.037029 84.451004 29.037029 c
+88.826294 29.037029 92.020851 27.118137 94.113853 23.219398 c
+88.526115 19.929964 l
+87.715591 21.798073 86.333038 22.732088 84.451004 22.732088 c
+82.468071 22.732088 81.506630 21.970686 81.506630 20.478231 c
+81.506630 19.320744 83.029274 18.274992 86.132919 17.462723 c
+88.526115 16.914539 90.408142 16.092180 91.770676 15.036257 c
+91.780693 15.036257 l
+91.770676 15.036257 l
+h
+112.618164 21.452854 m
+106.870323 21.452854 l
+106.870323 10.020803 l
+106.870323 8.650179 107.381485 7.817646 108.352104 7.441906 c
+109.063393 7.167816 110.485130 7.117115 112.628166 7.218597 c
+112.628166 0.791912 l
+108.212013 0.243645 105.008308 0.690430 103.126274 2.162537 c
+101.243401 3.583942 100.331985 6.233803 100.331985 10.010632 c
+100.331985 21.452854 l
+95.915833 21.452854 l
+95.915833 28.265369 l
+100.331985 28.265369 l
+100.331985 33.808784 l
+106.890335 35.951027 l
+106.890335 28.255198 l
+112.638176 28.255198 l
+112.638176 21.442680 l
+112.628166 21.442680 l
+112.618164 21.452854 l
+h
+133.525681 9.086706 m
+134.847351 10.508114 135.507782 12.325527 135.507782 14.528599 c
+135.507782 16.731840 134.847351 18.528820 133.525681 19.970573 c
+132.193161 21.391897 130.571289 22.112776 128.589188 22.112776 c
+126.606262 22.112776 124.984390 21.402071 123.651871 19.970573 c
+122.381058 18.478121 121.719803 16.680973 121.719803 14.528599 c
+121.719803 12.376308 122.381058 10.579159 123.651871 9.086706 c
+124.974380 7.665382 126.606262 6.944508 128.589188 6.944508 c
+130.571289 6.944508 132.193161 7.655127 133.525681 9.086706 c
+h
+119.037262 4.203255 m
+116.443100 7.005379 115.171455 10.406551 115.171455 14.528599 c
+115.171455 18.650732 116.443100 22.001038 119.037262 24.803242 c
+121.629745 27.605450 124.834297 29.026855 128.589188 29.026855 c
+132.343262 29.026855 135.558640 27.605450 138.141953 24.803242 c
+140.725266 22.001038 142.056961 18.538994 142.056961 14.528599 c
+142.056961 10.518290 140.725266 7.005379 138.141953 4.203255 c
+135.547806 1.401051 132.394119 0.030510 128.589188 0.030510 c
+124.784264 0.030510 121.619743 1.401051 119.037262 4.203255 c
+h
+163.985123 8.934444 m
+165.306808 10.426897 165.968063 12.274660 165.968063 14.528599 c
+165.968063 16.782539 165.306808 18.650732 163.985123 20.072056 c
+162.664291 21.564592 160.982376 22.275211 158.948578 22.275211 c
+156.916458 22.275211 155.233719 21.564592 153.862839 20.072056 c
+152.540329 18.650732 151.879898 16.782539 151.879898 14.528599 c
+151.879898 12.274660 152.540329 10.406551 153.862839 8.934444 c
+155.243713 7.513037 156.966492 6.792244 158.948578 6.792244 c
+160.932358 6.792244 162.654282 7.502947 163.985123 8.934444 c
+h
+165.968063 39.260834 m
+172.526413 39.260834 l
+172.526413 0.791912 l
+165.968063 0.791912 l
+165.968063 4.030647 l
+164.035995 1.340179 161.291748 0.010162 157.727798 0.010162 c
+154.163025 0.010162 151.379578 1.380703 148.925522 4.182991 c
+146.532318 6.985115 145.321548 10.447161 145.321548 14.508337 c
+145.321548 18.569429 146.542328 21.980774 148.925522 24.782898 c
+151.358734 27.585186 154.312286 29.006512 157.727798 29.006512 c
+161.141647 29.006512 164.035995 27.686666 165.968063 25.006289 c
+165.968063 39.250683 l
+165.968063 39.260834 l
+h
+195.566971 9.117228 m
+196.888641 10.538635 197.549896 12.355879 197.549896 14.559118 c
+197.549896 16.762192 196.888641 18.559340 195.566971 20.001011 c
+194.245285 21.422335 192.623413 22.143211 190.630478 22.143211 c
+188.638367 22.143211 187.026520 21.432508 185.694000 20.001011 c
+184.422363 18.508474 183.761093 16.711493 183.761093 14.559118 c
+183.761093 12.406662 184.422363 10.609680 185.694000 9.117228 c
+187.016510 7.695736 188.648376 6.974945 190.630478 6.974945 c
+192.613403 6.974945 194.235291 7.685648 195.566971 9.117228 c
+h
+181.077713 4.233692 m
+178.495224 7.035900 177.212753 10.437071 177.212753 14.559118 c
+177.212753 18.681084 178.485229 22.031557 181.077713 24.833679 c
+183.671036 27.635885 186.875580 29.057293 190.630478 29.057293 c
+194.385376 29.057293 197.599915 27.635885 200.183228 24.833679 c
+202.775726 22.031557 204.098236 18.569429 204.098236 14.559118 c
+204.098236 10.548725 202.775726 7.035900 200.183228 4.233692 c
+197.589905 1.431572 194.435410 0.060863 190.630478 0.060863 c
+186.825546 0.060863 183.661026 1.431572 181.077713 4.233692 c
+h
+232.475540 17.696289 m
+232.475540 0.822433 l
+225.917206 0.822433 l
+225.917206 16.812975 l
+225.917206 18.630386 225.466064 20.001011 224.535477 21.036505 c
+223.674088 21.970686 222.452469 22.457994 220.879807 22.457994 c
+217.175766 22.457994 215.292923 20.204056 215.292923 15.645479 c
+215.292923 0.812172 l
+208.734528 0.812172 l
+208.734528 28.265369 l
+215.292923 28.265369 l
+215.292923 25.178900 l
+216.864761 27.757797 219.367996 29.026855 222.862732 29.026855 c
+225.656174 29.026855 227.949310 28.041977 229.732117 26.011431 c
+231.564957 23.980885 232.475540 21.229462 232.475540 17.665854 c
+f
+n
+Q
+
+endstream
+endobj
+
+6 0 obj
+ 9965
+endobj
+
+7 0 obj
+ << /Type /XObject
+ /Subtype /Image
+ /BitsPerComponent 8
+ /Length 8 0 R
+ /Height 148
+ /Width 538
+ /ColorSpace /DeviceGray
+ /Filter [ /FlateDecode ]
+ >>
+stream
+xC#[ֆ;ݍ;$$@pwwwwww~wW̽LPU[}ӿ>_a?CL]0qoAtUǏ>QoN|ȥ\Q;iϢАPCa6OP8u!!\@?Qw
3̡̞ǯIL 4DFFDEECQ11(66&6oGEGErN 5?%fSHlDEEBDDd$6vdq.11!!!>..N0
<~ՑqDdt\BfіkΗ` .dNMMK@^×E/zҠTt$;2)1!.&:2tpP;?G&:4&1͕+J
O!1q IvGM3|9yy~*r ?//77';;+3ӗ e6~ }gsz|yy>k-$ŧEL|-gfWVVUT։E7TWUUVVfefx)(A+(iчq6WFnQyUM]mUyqn_ PZϖddWU646wtvwYo~0/Mu:bPLf|1$<:˯klb"~).z";pxdtl|brrjjzzzffv2 LOMMMNLtu46TWfz]ShW"#P@K2"cщɉс<#."XCqI73pdlbjfn~~qiyeuu
ZX:0?7;=59>:4TWU
+6#|@sI9bxbDdZ~Jp:VV:|΄пMfv.ovAiuckW*@;888<<:<:::X萓{{;;[dianzbd('HD02X0s4xkY>|
+Jtg5O.mn.M
gѼ` 8['odrf~emc{wJtͷ!>\svvzrrrR @(!6/
M0X'B DucKͫ<`F;sla1Ca1Ԍ殁sp}ss'7B
X&gLJkKC=exEaEF&$=wпn~
+{
+j'wOnNV&k_CfhB#cS<9EUMKG'gW7@Woo|0Ĺ/ϟ??~6`gcynb8ۓ+@a˲Mz}YDbS 1Hw>ڽ뇗,t{ˇsb¢bmΌÓ˛ϰ~,?'tpngd@{}Y7%)NRE£ѠiB"6eYH5! }2f6XNW3
E_7awgV6u
O-n]b4 O?!.7(pwceA+)6ׯ0nT pgW5( &eO1!cvl}Q=6,/odjXT=5wlnm\FPi?}Ï!_<^͍TZ֠)1n ݙm==y丈пo& q2$332^eԶL.n\ DAHx^lLJ˓Bb|#bəARB!3&&B
ذ)!SrRK:Wvϯ%.`%?E rws~4eKx7o|vy}}ea`Bb_@B2a!HO`KD-5cxfuᵼy;h{Y(HID!JQ\DWficp[eaE?GdFQ2mſUY~Wd
+o>c]YhgvO.Ӣ|gh@/J(Jɷ't5q8P(?5&º뛫=:\]D*El\կ*M u_ 3eFQd+ϙ&T
+hUP G9c*haNеO~e^ Eg`ڐZi(r%My9x8h9c,S)2S r#sf4 /o 3yNT ˹BGk*VVK_giӧPDY(