From 15c352b06bd572c5ed4ae48530b58d9a75534c1c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:12 +0200 Subject: [PATCH 001/392] New translations Localizable.stringsdict (French) --- .../input/fr_FR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index d6fb911f3..eb1fec6a9 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -50,6 +50,22 @@ publications + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From e213b60875108ab772708f244fff2a151bc36020 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:13 +0200 Subject: [PATCH 002/392] New translations Localizable.stringsdict (Catalan) --- .../input/ca_ES/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict index b76b0a921..0b6c7b256 100644 --- a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict @@ -50,6 +50,22 @@ publicacions + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Opció 1 + other + Opció %ld %ld + + plural.count.post NSStringLocalizedFormatKey From dff0c793eabaef51c778f7a4f3e5a8f877ffe1d1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:14 +0200 Subject: [PATCH 003/392] New translations Localizable.stringsdict (Swedish) --- .../input/sv_SE/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict index 30533a5eb..9e04cf4d5 100644 --- a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict @@ -50,6 +50,22 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From ca437c709cffa4ba97f17c383c6461305ce728e8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:15 +0200 Subject: [PATCH 004/392] New translations Localizable.stringsdict (Indonesian) --- .../input/id_ID/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict index 718723849..986044443 100644 --- a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict @@ -44,6 +44,20 @@ postingan + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 63e1776449a9fc96e776ff7fe452763815b03d72 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:16 +0200 Subject: [PATCH 005/392] New translations Localizable.stringsdict (Danish) --- .../input/da_DK/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict index c7c84d074..c08619745 100644 --- a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict @@ -50,6 +50,22 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From db667141c0e879bb19bd42aaf3e38a998400ee5c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:17 +0200 Subject: [PATCH 006/392] New translations Localizable.stringsdict (Thai) --- .../input/th_TH/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict index dc114db41..fbee3d86f 100644 --- a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict @@ -44,6 +44,20 @@ โพสต์ + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 008591ca7908773aa83a0ded858a5a2ea5df4f98 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:18 +0200 Subject: [PATCH 007/392] New translations Localizable.stringsdict (Dutch) --- .../input/nl_NL/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict index 1726606b4..66cb5eb9a 100644 --- a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict @@ -50,6 +50,22 @@ berichten + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 61c027c5d4ad2a310851e3365282eb2581dc0e06 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:19 +0200 Subject: [PATCH 008/392] New translations Localizable.stringsdict (Chinese Traditional) --- .../input/zh_TW/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict index bebde18a5..15b58c271 100644 --- a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict @@ -44,6 +44,20 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From d41f7feda97503c1283902895d0bb5fdbed2aac9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:20 +0200 Subject: [PATCH 009/392] New translations Localizable.stringsdict (English) --- .../input/en_US/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict index c7c84d074..c08619745 100644 --- a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict @@ -50,6 +50,22 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 3b76f8725acdd5c22f4f5d6c0b9646b7b13842d6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:21 +0200 Subject: [PATCH 010/392] New translations Localizable.stringsdict (Scottish Gaelic) --- .../input/gd_GB/Localizable.stringsdict | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict index 63a998c6e..1079bd488 100644 --- a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict @@ -62,6 +62,26 @@ post + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + two + Option %ld %ld + few + Option %ld %ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From a9a80be47366b878db6be0ae57d752fe0b054b3d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:22 +0200 Subject: [PATCH 011/392] New translations Localizable.stringsdict (Romanian) --- .../input/ro_RO/Localizable.stringsdict | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict index f623187e7..bffced074 100644 --- a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict @@ -56,6 +56,24 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + few + Option %ld %ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 66763ff764c0fdb2fbd1a5e54de4a7271ebba11b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:23 +0200 Subject: [PATCH 012/392] New translations Localizable.stringsdict (Korean) --- .../input/ko_KR/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict index 4b19bab17..0ec6c1e70 100644 --- a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict @@ -44,6 +44,20 @@ 게시물 + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 0a458418879f61ee11357cd83d51e534765923ff Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:24 +0200 Subject: [PATCH 013/392] New translations Localizable.stringsdict (Spanish) --- .../input/es_ES/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict index bf493c1e8..1c285df42 100644 --- a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict @@ -50,6 +50,22 @@ publicaciones + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From e77f3d8d6d6cc51bbcb4c96835ab0313cc92ef58 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:25 +0200 Subject: [PATCH 014/392] New translations Localizable.stringsdict (Welsh) --- .../input/cy_GB/Localizable.stringsdict | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict index 537064efb..d69978fb3 100644 --- a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict @@ -74,6 +74,30 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + Option %ld %ld + one + Option 1 + two + Option %ld %ld + few + Option %ld %ld + many + Option %ld %ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From c21750eddeddeb00ec31cd3c9c31cb3196f99dc8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:26 +0200 Subject: [PATCH 015/392] New translations Localizable.stringsdict (Hindi) --- .../input/hi_IN/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict index c7c84d074..c08619745 100644 --- a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict @@ -50,6 +50,22 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 4ca53b11230b69dcad2c928509e5524090f44b81 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:28 +0200 Subject: [PATCH 016/392] New translations Localizable.stringsdict (Spanish, Argentina) --- .../input/es_AR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict index f98962ccb..037b17216 100644 --- a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict @@ -50,6 +50,22 @@ mensajes + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 8ee0470517421521ebbbeb5be86b354bfdf9faf7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:29 +0200 Subject: [PATCH 017/392] New translations Localizable.stringsdict (Portuguese, Brazilian) --- .../input/pt_BR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict index c7c84d074..c08619745 100644 --- a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict @@ -50,6 +50,22 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 6d73e8908cf6754565345428f2d7f4ce8e5f3901 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:30 +0200 Subject: [PATCH 018/392] New translations Localizable.stringsdict (Chinese Simplified) --- .../input/zh_CN/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict index c28637620..2d7c64488 100644 --- a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict @@ -44,6 +44,20 @@ 个帖子 + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 5d9752901e2cbe562912eaed6c94be45cd3dc7d3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:31 +0200 Subject: [PATCH 019/392] New translations Localizable.stringsdict (Russian) --- .../input/ru_RU/Localizable.stringsdict | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict index 1a9a44a0f..7b6831575 100644 --- a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict @@ -62,6 +62,26 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + few + Option %ld %ld + many + Option %ld %ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From bbee4b8ace94e8145ed8aca51386083a736faa34 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:32 +0200 Subject: [PATCH 020/392] New translations Localizable.stringsdict (Portuguese) --- .../input/pt_PT/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict index c7c84d074..c08619745 100644 --- a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict @@ -50,6 +50,22 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 80830538323c5a23479d69b92aa4b04f4fa9df5e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:33 +0200 Subject: [PATCH 021/392] New translations Localizable.stringsdict (Japanese) --- .../input/ja_JP/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict index ac37d9a39..0684a041f 100644 --- a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict @@ -44,6 +44,20 @@ 投稿 + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 890d773022fd7ab46ab3c084eb189068d16dbc26 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:34 +0200 Subject: [PATCH 022/392] New translations Localizable.stringsdict (German) --- .../input/de_DE/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict index e89bdb074..e6cc9a52a 100644 --- a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict @@ -50,6 +50,22 @@ Beiträge + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From a5d3776ba79018f782c4629d2886b36989e1b0c5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:35 +0200 Subject: [PATCH 023/392] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index 537064efb..d69978fb3 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -74,6 +74,30 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + Option %ld %ld + one + Option 1 + two + Option %ld %ld + few + Option %ld %ld + many + Option %ld %ld + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From 0cd6f1a92ed512db99a1b3d45d5b00d8ab0145e5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 10:40:36 +0200 Subject: [PATCH 024/392] New translations Localizable.stringsdict (Swedish, Finland) --- .../input/sv_FI/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict index 30533a5eb..9e04cf4d5 100644 --- a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict @@ -50,6 +50,22 @@ posts + plural.number.poll_option + + NSStringLocalizedFormatKey + %#@number_poll_option@ + number_poll_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Option 1 + other + Option %ld %ld + + plural.count.post NSStringLocalizedFormatKey From afdef9f2b4106a8a5230153a6dd13c20a04d49f1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 11:44:42 +0200 Subject: [PATCH 025/392] New translations Localizable.stringsdict (Spanish) --- .../StringsConvertor/input/es_ES/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict index 1c285df42..c07e85b24 100644 --- a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - Option 1 + Opción 1 other - Option %ld %ld + Opción %ld %ld plural.count.post From a0eab2770d1a896dea5815207f607b006a00596c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 16 Aug 2021 16:39:51 +0200 Subject: [PATCH 026/392] New translations Localizable.stringsdict (Spanish, Argentina) --- .../StringsConvertor/input/es_AR/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict index 037b17216..882a85ecc 100644 --- a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - Option 1 + Opción 1 other - Option %ld %ld + Opción %ld %ld plural.count.post From 05806b8d53d46344ae345a148842e9a9bbd6d83a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 17 Aug 2021 09:02:05 +0200 Subject: [PATCH 027/392] New translations Localizable.stringsdict (Russian) --- .../StringsConvertor/input/ru_RU/Localizable.stringsdict | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict index 7b6831575..e7207794e 100644 --- a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict @@ -73,13 +73,13 @@ NSStringFormatValueTypeKey ld one - Option 1 + Опция %ld %ld few - Option %ld %ld + Опции %ld %ld many - Option %ld %ld + Опции %ld %ld other - Option %ld %ld + Опции %ld %ld plural.count.post From be79f0aad094e189071b1e0c4b2bfad57c4af3f4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 17 Aug 2021 09:02:06 +0200 Subject: [PATCH 028/392] New translations Intents.stringsdict (Scottish Gaelic) --- .../Intents/input/gd_GB/Intents.stringsdict | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/gd_GB/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/gd_GB/Intents.stringsdict index 9a4c7df17..4b93628d7 100644 --- a/Localization/StringsConvertor/Intents/input/gd_GB/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/gd_GB/Intents.stringsdict @@ -13,11 +13,11 @@ NSStringFormatValueTypeKey %ld one - 1 option + %ld roghainn two - %ld options + %ld roghainn few - %ld options + %ld roghainnean other %ld roghainn @@ -33,11 +33,11 @@ NSStringFormatValueTypeKey %ld one - 1 option + %ld roghainn two - %ld options + %ld roghainn few - %ld options + %ld roghainnean other %ld roghainn From 74e62678a038d30067652077bd50455fd646475a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 09:40:32 +0200 Subject: [PATCH 029/392] New translations Intents.strings (Scottish Gaelic) --- .../StringsConvertor/Intents/input/gd_GB/Intents.strings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/gd_GB/Intents.strings b/Localization/StringsConvertor/Intents/input/gd_GB/Intents.strings index 0f8ef5edc..526defecd 100644 --- a/Localization/StringsConvertor/Intents/input/gd_GB/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/gd_GB/Intents.strings @@ -24,9 +24,9 @@ "Zo4jgJ" = "Faicsinneachd a’ phuist"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Tha ${count} roghainn(ean) dha “Poblach” ann."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Tha ${count} roghainn(ean) dha “Luchd-leantainn a-mhàin” ann."; "ayoYEb-dYQ5NN" = "${content}, poblach"; From d1357e5f9071ea1363636d3f470a7933e08cfe36 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 16:10:26 +0200 Subject: [PATCH 030/392] New translations ios-infoPlist.json (Russian) --- Localization/StringsConvertor/input/ru_RU/ios-infoPlist.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/ru_RU/ios-infoPlist.json b/Localization/StringsConvertor/input/ru_RU/ios-infoPlist.json index c6db73de0..3dabe4322 100644 --- a/Localization/StringsConvertor/input/ru_RU/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/ru_RU/ios-infoPlist.json @@ -2,5 +2,5 @@ "NSCameraUsageDescription": "Used to take photo for post status", "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", "NewPostShortcutItemTitle": "New Post", - "SearchShortcutItemTitle": "Search" + "SearchShortcutItemTitle": "Поиск" } From c1a2c9c00848fba7cd169138cc7418ef13826a38 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 16:10:27 +0200 Subject: [PATCH 031/392] New translations Localizable.stringsdict (Russian) --- .../input/ru_RU/Localizable.stringsdict | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict index e7207794e..16918d75a 100644 --- a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict @@ -5,7 +5,7 @@ a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Превышающих лимит символов: %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -13,19 +13,19 @@ NSStringFormatValueTypeKey ld one - 1 character + %ld символ few - %ld characters + %ld символа many - %ld characters + %ld символов other - %ld characters + %ld символа a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Символов осталось: %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -33,13 +33,13 @@ NSStringFormatValueTypeKey ld one - 1 character + %ld символ few - %ld characters + %ld символа many - %ld characters + %ld символов other - %ld characters + %ld символов plural.count.metric_formatted.post @@ -53,13 +53,13 @@ NSStringFormatValueTypeKey ld one - post + пост few - posts + поста many - posts + постов other - posts + поста plural.number.poll_option @@ -153,13 +153,13 @@ NSStringFormatValueTypeKey ld one - 1 vote + %ld голос few - %ld votes + %ld голоса many - %ld votes + %ld голосов other - %ld votes + %ld голоса plural.count.voter From c82385ccdf242b81693482e54e83a6d708bec540 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 17:19:27 +0200 Subject: [PATCH 032/392] New translations Localizable.stringsdict (Russian) --- .../input/ru_RU/Localizable.stringsdict | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict index 16918d75a..635e478b5 100644 --- a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict @@ -5,7 +5,7 @@ a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Превышающих лимит символов: %#@character_count@ + Лимит превышен на %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -25,7 +25,7 @@ a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Символов осталось: %#@character_count@ + %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -33,13 +33,13 @@ NSStringFormatValueTypeKey ld one - %ld символ + %ld символ остался few - %ld символа + %ld символа осталось many - %ld символов + %ld символов осталось other - %ld символов + %ld символа осталось plural.count.metric_formatted.post From 030cb86f4c7d7f8188c3441c733733e5e8670f59 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 20:26:16 +0200 Subject: [PATCH 033/392] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index 1a73b068e..a82899fd9 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -454,10 +454,10 @@ "Everything": "Tout", "Mentions": "Mentions" }, - "user_followed_you": "%s followed you", + "user_followed_you": "%s vous suit", "user_favorited your post": "%s favorited your post", "user_reblogged_your_post": "%s reblogged your post", - "user_mentioned_you": "%s mentioned you", + "user_mentioned_you": "%s vous a mentionné", "user_requested_to_follow_you": "%s requested to follow you", "user_your_poll_has_ended": "%s Your poll has ended", "keyobard": { From b0f32f51daed585ed7080e52e0b59a0e9d409a18 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 20:26:17 +0200 Subject: [PATCH 034/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index ba15760fb..99c4d685a 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -13,7 +13,7 @@ }, "vote_failure": { "title": "فشل التصويت", - "poll_ended": "The poll has ended" + "poll_ended": "انتهى استطلاع الرأي" }, "discard_post_content": { "title": "تجاهل المسودة", @@ -129,24 +129,24 @@ "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", "poll": { - "vote": "Vote", - "closed": "Closed" + "vote": "صَوّت", + "closed": "انتهى" }, "actions": { - "reply": "Reply", - "reblog": "Reblog", - "unreblog": "Undo reblog", - "favorite": "Favorite", - "unfavorite": "Unfavorite", - "menu": "Menu" + "reply": "رد", + "reblog": "إعادة النشر", + "unreblog": "تراجع عن إعادة النشر", + "favorite": "إضافة إلى المفضلة", + "unfavorite": "إزالة من المفضلة", + "menu": "القائمة" }, "tag": { - "url": "URL", - "mention": "Mention", - "link": "Link", - "hashtag": "Hashtag", + "url": "عنوان URL", + "mention": "أشر إلى", + "link": "الرابط", + "hashtag": "الوسم", "email": "البريد الإلكتروني", - "emoji": "Emoji" + "emoji": "إيموجي" } }, "friendship": { From b9ac2fb850a54c59891c3d4f3e52bc001dd0ae7d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 20:26:18 +0200 Subject: [PATCH 035/392] New translations Localizable.stringsdict (French) --- .../input/fr_FR/Localizable.stringsdict | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index eb1fec6a9..2cc6797b6 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 caractère other - %ld characters + %ld caractères a11y.plural.count.input_limit_remains @@ -29,9 +29,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 caractère other - %ld characters + %ld caractères plural.count.metric_formatted.post @@ -365,9 +365,9 @@ NSStringFormatValueTypeKey ld one - 1m ago + Il y a 1 m other - %ldm ago + il y a %ld m date.second.ago.abbr @@ -381,9 +381,9 @@ NSStringFormatValueTypeKey ld one - 1s ago + Il y a 1 s other - %lds ago + il y a %ld s From 795adad96b8ce847bba85c72c18363df5bdd003a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 20:26:19 +0200 Subject: [PATCH 036/392] New translations Intents.strings (French) --- .../Intents/input/fr_FR/Intents.strings | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings index 6877490ba..27e03b7cc 100644 --- a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings @@ -1,10 +1,10 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Publier sur Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Contenu textuel"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Publier sur Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Quel contenu à publier ?"; "HdGikU" = "Posting failed"; @@ -14,15 +14,15 @@ "RxSqsb" = "Post"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Publier du ${content} sur Mastodon"; "ZKJSNu" = "Post"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Visibilité"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Visibilité de la publication"; "apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; @@ -32,11 +32,11 @@ "ayoYEb-ehFLjY" = "${content}, Followers Only"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Publier sur Mastodon"; "dYQ5NN" = "Public"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Abonné·e·s seulement"; "gfePDu" = "Posting failed. ${failureReason}"; @@ -48,4 +48,4 @@ "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "La publication a été envoyée avec succès. "; From 5fde6becceadf6d5d137b89d3ca5ce8fedad5981 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 20:26:20 +0200 Subject: [PATCH 037/392] New translations Intents.stringsdict (French) --- .../StringsConvertor/Intents/input/fr_FR/Intents.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict index 18422c772..6b51359f4 100644 --- a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Il y a %#@count_option@ correspondant à « ${content} ». count_option NSStringFormatSpecTypeKey From a8c041c0d7f199636ce8d3ed8adb9cf1e8c767ca Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 21:26:26 +0200 Subject: [PATCH 038/392] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 99c4d685a..50f6c9e01 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -150,8 +150,8 @@ } }, "friendship": { - "follow": "Follow", - "following": "Following", + "follow": "اتبع", + "following": "مُتابَع", "request": "Request", "pending": "Pending", "block": "Block", @@ -454,11 +454,11 @@ "Everything": "Everything", "Mentions": "Mentions" }, - "user_followed_you": "%s followed you", + "user_followed_you": "يتابعك %s", "user_favorited your post": "%s favorited your post", "user_reblogged_your_post": "%s reblogged your post", "user_mentioned_you": "%s mentioned you", - "user_requested_to_follow_you": "%s requested to follow you", + "user_requested_to_follow_you": "طلب %s متابعتك", "user_your_poll_has_ended": "%s Your poll has ended", "keyobard": { "show_everything": "Show Everything", @@ -481,12 +481,12 @@ "notifications": { "title": "الإشعارات", "favorites": "Favorites my post", - "follows": "Follows me", + "follows": "يتابعني", "boosts": "Reblogs my post", "mentions": "Mentions me", "trigger": { "anyone": "anyone", - "follower": "a follower", + "follower": "مشترِك", "follow": "anyone I follow", "noone": "no one", "title": "Notify me when" From ed043f21a89f5c9a27be92422ff53408d895c68a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 23 Aug 2021 21:26:28 +0200 Subject: [PATCH 039/392] New translations Intents.strings (Arabic) --- .../StringsConvertor/Intents/input/ar_SA/Intents.strings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings index 6877490ba..d5a4cf82b 100644 --- a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings @@ -46,6 +46,6 @@ "oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; -"rM6dvp" = "URL"; +"rM6dvp" = "عنوان URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "تم إرسال المنشور بنجاح. "; From 869d8168741148f880087938c1997891278eec1b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Aug 2021 10:55:37 +0200 Subject: [PATCH 040/392] New translations app.json (French) --- .../StringsConvertor/input/fr_FR/app.json | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index a82899fd9..5d75ab25e 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -105,10 +105,10 @@ "open_settings": "Ouvrir les paramètres" }, "timeline": { - "previous_status": "Article précédent", - "next_status": "Article suivant", + "previous_status": "Publication précédente", + "next_status": "Publication suivante", "open_status": "Ouvrir la publication", - "open_author_profile": "Ouvrir le profil de l'auteur", + "open_author_profile": "Ouvrir le profil de l’auteur·rice", "open_reblogger_profile": "Ouvrir le profil du rebloggeur", "reply_status": "Répondre à la publication", "toggle_reblog": "Basculer le reblogue lors de la publication", @@ -122,10 +122,10 @@ } }, "status": { - "user_reblogged": "%s à reblogué", + "user_reblogged": "%s a reblogué", "user_replied_to": "À répondu à %s", "show_post": "Montrer la publication", - "show_user_profile": "Montrer le profil de l’utilisateur", + "show_user_profile": "Montrer le profil de l’utilisateur·rice", "content_warning": "Avertissement de contenu", "media_content_warning": "Tapotez n’importe où pour révéler la publication", "poll": { @@ -180,9 +180,9 @@ "header": { "no_status_found": "Aucune publication trouvée", "blocking_warning": "Vous ne pouvez pas voir le profil de cet utilisateur\n tant que vous ne l’avez pas débloqué\nVotre profil ressemble à ça pour lui.", - "user_blocking_warning": "Vous ne pouvez pas voir le profil de %s tant que vous ne l’avez pas débloqué\nVotre profil ressemble à ça pour lui.", + "user_blocking_warning": "Vous ne pouvez pas voir le profil de %s\ntant que vous ne l’avez pas débloqué\nVotre profil ressemble à ça pour lui.", "blocked_warning": "Vous ne pouvez pas voir le profil de cet utilisateur\n tant qu'il ne vous aura pas débloqué.", - "user_blocked_warning": "Vous ne pouvez pas voir le profil de %s\n tant qu'il ne vous aura pas débloqué.", + "user_blocked_warning": "Vous ne pouvez pas voir le profil de %s\ntant qu’il ne vous aura pas débloqué.", "suspended_warning": "Cet utilisateur a été suspendu.", "user_suspended_warning": "Le compte de %s à été suspendu." } @@ -217,7 +217,7 @@ }, "label": { "language": "LANGUE", - "users": "UTILISATEURS", + "users": "UTILISATEUR·RICE·S", "category": "CATÉGORIE" }, "input": { @@ -255,7 +255,7 @@ }, "error": { "item": { - "username": "Nom d'utilisateur", + "username": "Nom d’utilisateur", "email": "Courriel", "password": "Mot de passe", "agreement": "Accord", @@ -370,7 +370,7 @@ "append_attachment": "Joindre un document", "append_poll": "Ajouter un Sondage", "remove_poll": "Retirer le sondage", - "custom_emoji_picker": "Sélecteur d’émojis personnalisé", + "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" @@ -405,7 +405,7 @@ "relationship_action_alert": { "confirm_unmute_user": { "title": "Ne plus mettre en sourdine ce compte", - "message": "Êtes-vous sûr de vouloir mettre en sourdine %s" + "message": "Êtes-vous sûr de vouloir désactiver la sourdine de %s" }, "confirm_unblock_usre": { "title": "Débloquer le compte", @@ -454,12 +454,12 @@ "Everything": "Tout", "Mentions": "Mentions" }, - "user_followed_you": "%s vous suit", + "user_followed_you": "%s s’est abonné à vous", "user_favorited your post": "%s favorited your post", - "user_reblogged_your_post": "%s reblogged your post", + "user_reblogged_your_post": "%s a partagé votre publication", "user_mentioned_you": "%s vous a mentionné", - "user_requested_to_follow_you": "%s requested to follow you", - "user_your_poll_has_ended": "%s Your poll has ended", + "user_requested_to_follow_you": "%s a demandé à vous suivre", + "user_your_poll_has_ended": "%s votre sondage est terminé", "keyobard": { "show_everything": "Tout Afficher", "show_mentions": "Afficher les mentions" @@ -496,7 +496,7 @@ "title": "Préférences", "true_black_dark_mode": "Vrai mode sombre", "disable_avatar_animation": "Désactiver les avatars animés", - "disable_emoji_animation": "Désactiver les émoticônes animées", + "disable_emoji_animation": "Désactiver les émojis animées", "using_default_browser": "Utiliser le navigateur par défaut pour ouvrir les liens" }, "boring_zone": { From 6ddf04ba67248f777eea11eeb1fd10675472a0b2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Aug 2021 11:57:29 +0200 Subject: [PATCH 041/392] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index 5d75ab25e..b665ce196 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -455,7 +455,7 @@ "Mentions": "Mentions" }, "user_followed_you": "%s s’est abonné à vous", - "user_favorited your post": "%s favorited your post", + "user_favorited your post": "%s a mis votre pouet en favori", "user_reblogged_your_post": "%s a partagé votre publication", "user_mentioned_you": "%s vous a mentionné", "user_requested_to_follow_you": "%s a demandé à vous suivre", From c2284b2bdc1629d80bbb21cb5587016bf7b477de Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Aug 2021 13:07:22 +0200 Subject: [PATCH 042/392] New translations Localizable.stringsdict (French) --- .../input/fr_FR/Localizable.stringsdict | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index 2cc6797b6..3164d3032 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -77,9 +77,9 @@ NSStringFormatValueTypeKey ld one - 1 post + 1 publication other - %ld posts + %ld publications plural.count.favorite @@ -173,9 +173,9 @@ NSStringFormatValueTypeKey ld one - 1 following + 1 abonnement other - %ld following + %ld abonnements plural.count.follower @@ -189,9 +189,9 @@ NSStringFormatValueTypeKey ld one - 1 follower + 1 abonné·e other - %ld followers + %ld abonné·e·s date.year.left @@ -205,9 +205,9 @@ NSStringFormatValueTypeKey ld one - 1 year left + Il reste 1 an other - %ld years left + %ld ans restants date.month.left @@ -221,9 +221,9 @@ NSStringFormatValueTypeKey ld one - 1 months left + 1 mois restant other - %ld months left + %ld mois restants date.day.left @@ -237,9 +237,9 @@ NSStringFormatValueTypeKey ld one - 1 day left + Il reste 1 jour other - %ld days left + il reste %ld jours date.hour.left @@ -253,9 +253,9 @@ NSStringFormatValueTypeKey ld one - 1 hour left + 1 heure restante other - %ld hours left + %ld heures restantes date.minute.left @@ -269,9 +269,9 @@ NSStringFormatValueTypeKey ld one - 1 minute left + 1 minute restante other - %ld minutes left + %ld minutes restantes date.second.left @@ -285,9 +285,9 @@ NSStringFormatValueTypeKey ld one - 1 second left + Il reste 1 seconde other - %ld seconds left + %ld secondes restantes date.year.ago.abbr @@ -301,9 +301,9 @@ NSStringFormatValueTypeKey ld one - 1y ago + il y a 1 année other - %ldy ago + il y a %ld ans date.month.ago.abbr @@ -317,9 +317,9 @@ NSStringFormatValueTypeKey ld one - 1M ago + il y a 1 mois other - %ldM ago + il y a %ld mois date.day.ago.abbr @@ -333,9 +333,9 @@ NSStringFormatValueTypeKey ld one - 1d ago + il y a 1j other - %ldd ago + il y a %ldj date.hour.ago.abbr @@ -349,9 +349,9 @@ NSStringFormatValueTypeKey ld one - 1h ago + il y a 1h other - %ldh ago + il y a %ldh date.minute.ago.abbr From 0b8426e8f2396453e5a4a57e16d7f8165c0c5c5a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Aug 2021 13:07:22 +0200 Subject: [PATCH 043/392] New translations Intents.strings (French) --- .../StringsConvertor/Intents/input/fr_FR/Intents.strings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings index 27e03b7cc..e5955cbba 100644 --- a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings @@ -8,15 +8,15 @@ "HdGikU" = "Posting failed"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Raison de l’échec"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Envoyer une publication avec du contenu texte"; "RxSqsb" = "Post"; "WCIR3D" = "Publier du ${content} sur Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Publication"; "ZS1XaK" = "${content}"; @@ -30,7 +30,7 @@ "ayoYEb-dYQ5NN" = "${content}, Public"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, abonné·e·s seulement"; "dUyuGg" = "Publier sur Mastodon"; From e510ae734ec6f3f363d29d6158370575e901383c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Aug 2021 13:07:24 +0200 Subject: [PATCH 044/392] New translations Intents.stringsdict (French) --- .../StringsConvertor/Intents/input/fr_FR/Intents.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict index 6b51359f4..53d39da2e 100644 --- a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.stringsdict @@ -21,7 +21,7 @@ There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Il y a %#@count_option@ correspondant à « ${visibility} ». count_option NSStringFormatSpecTypeKey From 205cc917d48ee4ac14c918e58088ec27093f0d0d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 28 Aug 2021 09:09:13 +0200 Subject: [PATCH 045/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 50f6c9e01..f98fcb416 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -123,10 +123,10 @@ }, "status": { "user_reblogged": "%s reblogged", - "user_replied_to": "Replied to %s", - "show_post": "Show Post", - "show_user_profile": "Show user profile", - "content_warning": "Content Warning", + "user_replied_to": "رد على %s", + "show_post": "اظهر المنشور", + "show_user_profile": "اظهر الملف التعريفي للمستخدم", + "content_warning": "تحذير عن المحتوى", "media_content_warning": "Tap anywhere to reveal", "poll": { "vote": "صَوّت", @@ -154,12 +154,12 @@ "following": "مُتابَع", "request": "Request", "pending": "Pending", - "block": "Block", - "block_user": "Block %s", - "block_domain": "Block %s", - "unblock": "Unblock", - "unblock_user": "Unblock %s", - "blocked": "Blocked", + "block": "حظر", + "block_user": "حظر %s", + "block_domain": "حظر %s", + "unblock": "إلغاء الحَظر", + "unblock_user": "إلغاء حظر %s", + "blocked": "محظور", "mute": "أكتم", "mute_user": "أكتم %s", "unmute": "إلغاء الكتم", @@ -316,12 +316,12 @@ "navigation_bar_state": { "offline": "غير متصل", "new_posts": "See new posts", - "published": "Published!", - "Publishing": "Publishing post..." + "published": "تم نشره!", + "Publishing": "جارٍ نشر المشاركة…" } }, "suggestion_account": { - "title": "Find People to Follow", + "title": "ابحث عن أشخاص لمتابعتهم", "follow_explain": "When you follow someone, you’ll see their posts in your home feed." }, "compose": { @@ -345,23 +345,23 @@ "description_video": "Describe the video for the visually-impaired..." }, "poll": { - "duration_time": "Duration: %s", + "duration_time": "المدة: %s", "thirty_minutes": "30 دقيقة", "one_hour": "ساعة واحدة", "six_hours": "6 ساعات", "one_day": "يوم واحد", "three_days": "3 أيام", "seven_days": "7 أيام", - "option_number": "Option %ld" + "option_number": "الخيار %ld" }, "content_warning": { "placeholder": "Write an accurate warning here..." }, "visibility": { - "public": "Public", - "unlisted": "Unlisted", - "private": "Followers only", - "direct": "Only people I mention" + "public": "للعامة", + "unlisted": "غير مُدرَج", + "private": "لمتابعيك فقط", + "direct": "ففط للأشخاص المشار إليهم" }, "auto_complete": { "space_to_add": "Space to add" @@ -440,24 +440,24 @@ "posts": "المنشورات" }, "empty_state": { - "no_results": "No results" + "no_results": "ليس هناك أية نتيجة" }, - "recent_search": "Recent searches", - "clear": "Clear" + "recent_search": "عمليات البحث الأخيرة", + "clear": "امسح" } }, "favorite": { - "title": "Your Favorites" + "title": "مفضلتك" }, "notification": { "title": { - "Everything": "Everything", - "Mentions": "Mentions" + "Everything": "الكل", + "Mentions": "الإشارات" }, "user_followed_you": "يتابعك %s", - "user_favorited your post": "%s favorited your post", - "user_reblogged_your_post": "%s reblogged your post", - "user_mentioned_you": "%s mentioned you", + "user_favorited your post": "أضاف %s منشورك إلى مفضلته", + "user_reblogged_your_post": "أعاد %s تدوين مشاركتك", + "user_mentioned_you": "أشار إليك %s", "user_requested_to_follow_you": "طلب %s متابعتك", "user_your_poll_has_ended": "%s Your poll has ended", "keyobard": { From 041f66a4211f4adf4c5af6c97fac21bce0c8ae82 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 28 Aug 2021 09:09:14 +0200 Subject: [PATCH 046/392] New translations Intents.strings (Arabic) --- .../Intents/input/ar_SA/Intents.strings | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings index d5a4cf82b..c129b706f 100644 --- a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings @@ -20,9 +20,9 @@ "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "مدى الظهور"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "مدى ظهور المنشور"; "apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; @@ -32,11 +32,11 @@ "ayoYEb-ehFLjY" = "${content}, Followers Only"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "النشر على ماستدون"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "للعامة"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "لمتابعيك فقط"; "gfePDu" = "Posting failed. ${failureReason}"; From 4521e78eeb6ef829dd8cc4122f4960156d9f89cb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 28 Aug 2021 09:09:15 +0200 Subject: [PATCH 047/392] New translations ios-infoPlist.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json b/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json index 932ac804a..54fb1aacc 100644 --- a/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json @@ -1,6 +1,6 @@ { "NSCameraUsageDescription": "Used to take photo for post status", "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", - "NewPostShortcutItemTitle": "New Post", + "NewPostShortcutItemTitle": "منشور جديد", "SearchShortcutItemTitle": "البحث" } From d3bbe77f162baff649193ce46696d1e2053363d2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 28 Aug 2021 16:46:47 +0200 Subject: [PATCH 048/392] New translations Intents.strings (French) --- .../StringsConvertor/Intents/input/fr_FR/Intents.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings index e5955cbba..628f794c9 100644 --- a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings @@ -38,7 +38,7 @@ "ehFLjY" = "Abonné·e·s seulement"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Échec lors de la publication. ${failureReason}"; "k7dbKQ" = "Post was sent successfully."; From 289a70899ad68215e9aed751122cbd5a26bb3b5f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 29 Aug 2021 11:46:20 +0200 Subject: [PATCH 049/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index f98fcb416..acd5fda4d 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -29,7 +29,7 @@ }, "edit_profile_failure": { "title": "Edit Profile Error", - "message": "Cannot edit profile. Please try again." + "message": "لا يمكن تعديل الملف الشخصي. الرجاء المحاولة مرة أخرى." }, "sign_out": { "title": "تسجيل الخروج", @@ -268,23 +268,23 @@ "taken": "%s is already in use", "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", + "blank": "%s مطلوب", + "invalid": "%s غير صالح", + "too_long": "%s طويل جداً", + "too_short": "%s قصير جدا", "inclusion": "%s is not a supported value" }, "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)" + "email_invalid": "هذا عنوان بريد إلكتروني غير صالح", + "password_too_short": "كلمة المرور قصيرة جداً (يجب أن تكون 8 أحرف على الأقل)" } } }, "server_rules": { - "title": "Some ground rules.", - "subtitle": "These rules are set by the admins of %s.", + "title": "بعض القواعد الأساسية.", + "subtitle": "تم سنّ هذه القواعد من قبل مشرفي %s.", "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.", "terms_of_service": "شروط الخدمة", "privacy_policy": "سياسة الخصوصية", From e9b048870a71210432900f88e395e30861c0150c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 29 Aug 2021 12:44:37 +0200 Subject: [PATCH 050/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index acd5fda4d..48cc380b0 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -285,7 +285,7 @@ "server_rules": { "title": "بعض القواعد الأساسية.", "subtitle": "تم سنّ هذه القواعد من قبل مشرفي %s.", - "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.", + "prompt": "إن اخترت المواصلة، فإنك تخضع لشروط الخدمة وسياسة الخصوصية لـ %s.", "terms_of_service": "شروط الخدمة", "privacy_policy": "سياسة الخصوصية", "button": { @@ -294,13 +294,13 @@ }, "confirm_email": { "title": "شيء واحد أخير.", - "subtitle": "We just sent an email to %s,\ntap the link to confirm your account.", + "subtitle": "لقد أرسلنا للتو رسالة بريد إلكتروني إلى %s،\nاضغط على الرابط لتأكيد حسابك.", "button": { - "open_email_app": "Open Email App", - "dont_receive_email": "I never got an email" + "open_email_app": "افتح تطبيق البريد الإلكتروني", + "dont_receive_email": "لم أستلم أبدًا بريدا إلكترونيا" }, "dont_receive_email": { - "title": "Check your email", + "title": "تحقق من بريدك الإلكتروني", "description": "Check if your email address is correct as well as your junk folder if you haven’t.", "resend_email": "Resend Email" }, @@ -381,7 +381,7 @@ "toggle_poll": "Toggle Poll", "toggle_content_warning": "Toggle Content Warning", "append_attachment_entry": "Add Attachment - %s", - "select_visibility_entry": "Select Visibility - %s" + "select_visibility_entry": "اختر مدى الظهور - %s" } }, "profile": { @@ -427,8 +427,8 @@ "people_talking": "%s people are talking" }, "accounts": { - "title": "Accounts you might like", - "description": "You may like to follow these accounts", + "title": "حسابات قد تعجبك", + "description": "قد ترغب في متابعة هذه الحسابات", "follow": "تابع" } }, @@ -461,7 +461,7 @@ "user_requested_to_follow_you": "طلب %s متابعتك", "user_your_poll_has_ended": "%s Your poll has ended", "keyobard": { - "show_everything": "Show Everything", + "show_everything": "إظهار كل شيء", "show_mentions": "Show Mentions" } }, @@ -500,14 +500,14 @@ "using_default_browser": "Use default browser to open links" }, "boring_zone": { - "title": "The Boring Zone", + "title": "المنطقة المملة", "account_settings": "إعدادات الحساب", "terms": "شروط الخدمة", "privacy": "سياسة الخصوصية" }, "spicy_zone": { - "title": "The Spicy Zone", - "clear": "Clear Media Cache", + "title": "المنطقة الحارة", + "clear": "مسح ذاكرة التخزين المؤقت للوسائط", "signout": "تسجيل الخروج" } }, @@ -524,8 +524,8 @@ "step2": "الخطوة 2 من 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?", - "send": "Send Report", - "skip_to_send": "Send without comment", + "send": "ارسل الشكوى", + "skip_to_send": "إرسال بدون تعليق", "text_placeholder": "Type or paste additional comments" }, "preview": { From b16d4760c6c864bafa4003d6adfd9701b3a21a89 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 29 Aug 2021 12:44:38 +0200 Subject: [PATCH 051/392] New translations Intents.strings (Arabic) --- .../StringsConvertor/Intents/input/ar_SA/Intents.strings | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings index c129b706f..bf3e77ed2 100644 --- a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings @@ -1,14 +1,14 @@ "16wxgf" = "Post on Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "محتوى نصي"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "انشر على ماستدون"; "HZSGTr" = "What content to post?"; "HdGikU" = "Posting failed"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "سبب الإخفاق"; "RHxKOw" = "Send Post with text content"; From 91e16349e71774a95830eea3bfcf7f6c4d194e01 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 2 Sep 2021 10:01:29 +0200 Subject: [PATCH 052/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 318d05391..a91336657 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -179,10 +179,10 @@ }, "header": { "no_status_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.", + "blocking_warning": "คุณไม่สามารถดูโปรไฟล์ของผู้ใช้นี้\nจนกว่าคุณจะเลิกปิดกั้นผู้ใช้นี้\nผู้ใช้นี้เห็นโปรไฟล์ของคุณเหมือนกับที่คุณเห็น", + "user_blocking_warning": "คุณไม่สามารถดูโปรไฟล์ของ %s\nจนกว่าคุณจะเลิกปิดกั้นผู้ใช้นี้\nผู้ใช้นี้เห็นโปรไฟล์ของคุณเหมือนกับที่คุณเห็น", + "blocked_warning": "คุณไม่สามารถดูโปรไฟล์ของผู้ใช้นี้\nจนกว่าผู้ใช้นี้จะเลิกปิดกั้นคุณ", + "user_blocked_warning": "คุณไม่สามารถดูโปรไฟล์ของ %s\nจนกว่าผู้ใช้นี้จะเลิกปิดกั้นคุณ", "suspended_warning": "ผู้ใช้นี้ถูกระงับการใช้งาน", "user_suspended_warning": "บัญชีของ %s ถูกระงับการใช้งาน" } @@ -285,7 +285,7 @@ "server_rules": { "title": "กฎพื้นฐานบางประการ", "subtitle": "กฎเหล่านี้ถูกตั้งโดยผู้ดูแลของ %s", - "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.", + "prompt": "เมื่อคุณดำเนินการต่อ คุณอยู่ภายใต้เงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัวสำหรับ %s", "terms_of_service": "เงื่อนไขการให้บริการ", "privacy_policy": "นโยบายความเป็นส่วนตัว", "button": { From 1a95ca57171e445ed976ccbe2336680996b304b4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 2 Sep 2021 13:56:16 +0200 Subject: [PATCH 053/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index a91336657..c3a002db8 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -210,7 +210,7 @@ "regional": "ภูมิภาค", "art": "ศิลปะ", "music": "ดนตรี", - "tech": "tech" + "tech": "เทคโนโลยี" }, "see_less": "ดูน้อยลง", "see_more": "ดูเพิ่มเติม" From c09b2d55820576e895385a85c344ba81c1a6d09b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:43:56 +0200 Subject: [PATCH 054/392] New translations Localizable.stringsdict (Romanian) --- .../input/ro_RO/Localizable.stringsdict | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict index bffced074..f623187e7 100644 --- a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict @@ -56,24 +56,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - few - Option %ld %ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From ac010607f993e59512082c80ce21d702a2a10694 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:43:57 +0200 Subject: [PATCH 055/392] New translations Localizable.stringsdict (Chinese Simplified) --- .../input/zh_CN/Localizable.stringsdict | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict index 2d7c64488..c28637620 100644 --- a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict @@ -44,20 +44,6 @@ 个帖子 - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 3e4f3178f3257d5010d6ef5a4abc0015ee2e6dc7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:43:58 +0200 Subject: [PATCH 056/392] New translations Localizable.stringsdict (Scottish Gaelic) --- .../input/gd_GB/Localizable.stringsdict | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict index 1079bd488..63a998c6e 100644 --- a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict @@ -62,26 +62,6 @@ post - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - two - Option %ld %ld - few - Option %ld %ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 44700253c972190df01db42f9ae2b1d5e7769b49 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:43:59 +0200 Subject: [PATCH 057/392] New translations Localizable.stringsdict (Welsh) --- .../input/cy_GB/Localizable.stringsdict | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict index d69978fb3..537064efb 100644 --- a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict @@ -74,30 +74,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - zero - Option %ld %ld - one - Option 1 - two - Option %ld %ld - few - Option %ld %ld - many - Option %ld %ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 1ecb6f56e094a1508b6aae7111b43e374b238eeb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:00 +0200 Subject: [PATCH 058/392] New translations Localizable.stringsdict (Hindi) --- .../input/hi_IN/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict index c08619745..c7c84d074 100644 --- a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict @@ -50,22 +50,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From fcbffa76551e94bf3dff14c67de4bfbee1524cf2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:01 +0200 Subject: [PATCH 059/392] New translations Localizable.stringsdict (Thai) --- .../input/th_TH/Localizable.stringsdict | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict index fbee3d86f..dc114db41 100644 --- a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict @@ -44,20 +44,6 @@ โพสต์ - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From bedb288320fac33883bfc5da7a84589f7bc1dba5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:02 +0200 Subject: [PATCH 060/392] New translations Localizable.stringsdict (Spanish, Argentina) --- .../input/es_AR/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict index 882a85ecc..f98962ccb 100644 --- a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict @@ -50,22 +50,6 @@ mensajes - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Opción 1 - other - Opción %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 5c1a674cfeabef5568ae1932e79707318547f884 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:03 +0200 Subject: [PATCH 061/392] New translations Localizable.stringsdict (Indonesian) --- .../input/id_ID/Localizable.stringsdict | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict index 986044443..718723849 100644 --- a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict @@ -44,20 +44,6 @@ postingan - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From de4071aa00d11aa194571dd67a2c3605e4217543 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:04 +0200 Subject: [PATCH 062/392] New translations Localizable.stringsdict (Portuguese, Brazilian) --- .../input/pt_BR/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict index c08619745..c7c84d074 100644 --- a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict @@ -50,22 +50,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From b4985c6682fd39705b795608b5d1b27df130c479 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:05 +0200 Subject: [PATCH 063/392] New translations Localizable.stringsdict (English) --- .../input/en_US/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict index c08619745..c7c84d074 100644 --- a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict @@ -50,22 +50,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 4cfde0cca99eebf877ddb08b061a17228e89158a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:06 +0200 Subject: [PATCH 064/392] New translations Localizable.stringsdict (Chinese Traditional) --- .../input/zh_TW/Localizable.stringsdict | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict index 15b58c271..bebde18a5 100644 --- a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict @@ -44,20 +44,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 8bec52904fb2dea0fe2a28f0b73ba4bb9327329f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:06 +0200 Subject: [PATCH 065/392] New translations Localizable.stringsdict (Swedish) --- .../input/sv_SE/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict index 9e04cf4d5..30533a5eb 100644 --- a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict @@ -50,22 +50,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 465bf3ca369a4b4aa5980c363aa0e5879ad07b31 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:07 +0200 Subject: [PATCH 066/392] New translations Localizable.stringsdict (French) --- .../input/fr_FR/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index 3164d3032..f95f4ee16 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -50,22 +50,6 @@ publications - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 08e6490f72ef9fcd3cda78f3d647a809e0724376 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:08 +0200 Subject: [PATCH 067/392] New translations Localizable.stringsdict (Russian) --- .../input/ru_RU/Localizable.stringsdict | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict index 635e478b5..2fe378b55 100644 --- a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict @@ -62,26 +62,6 @@ поста - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Опция %ld %ld - few - Опции %ld %ld - many - Опции %ld %ld - other - Опции %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 3188223b26b960e4cb7cdf050dbf552808f871ac Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:09 +0200 Subject: [PATCH 068/392] New translations Localizable.stringsdict (Portuguese) --- .../input/pt_PT/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict index c08619745..c7c84d074 100644 --- a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict @@ -50,22 +50,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From faa9db27c2b408424d4aecd37be74810ac785d1b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:10 +0200 Subject: [PATCH 069/392] New translations Localizable.stringsdict (Dutch) --- .../input/nl_NL/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict index 66cb5eb9a..1726606b4 100644 --- a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict @@ -50,22 +50,6 @@ berichten - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 55bfbcd1ecc9f2b92d005ca0ba03f50ce264b42a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:11 +0200 Subject: [PATCH 070/392] New translations Localizable.stringsdict (Korean) --- .../input/ko_KR/Localizable.stringsdict | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict index 0ec6c1e70..4b19bab17 100644 --- a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict @@ -44,20 +44,6 @@ 게시물 - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 511392e1972b5a883b3ba508b95529341ce59107 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:12 +0200 Subject: [PATCH 071/392] New translations Localizable.stringsdict (Japanese) --- .../input/ja_JP/Localizable.stringsdict | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict index 0684a041f..ac37d9a39 100644 --- a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict @@ -44,20 +44,6 @@ 投稿 - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From eebf9ae31132b497fc37325926c4b042cc3bdd54 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:13 +0200 Subject: [PATCH 072/392] New translations Localizable.stringsdict (German) --- .../input/de_DE/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict index e6cc9a52a..e89bdb074 100644 --- a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict @@ -50,22 +50,6 @@ Beiträge - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 92970049385b41c67e19cdfd4e3f573372f56124 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:14 +0200 Subject: [PATCH 073/392] New translations Localizable.stringsdict (Danish) --- .../input/da_DK/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict index c08619745..c7c84d074 100644 --- a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict @@ -50,22 +50,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From cce58da5e56ea224baff57cac8326be33892aad1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:15 +0200 Subject: [PATCH 074/392] New translations Localizable.stringsdict (Catalan) --- .../input/ca_ES/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict index 0b6c7b256..b76b0a921 100644 --- a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict @@ -50,22 +50,6 @@ publicacions - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Opció 1 - other - Opció %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 51e762ccf2e297ae1fda13e4bf9c4346a5495d26 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:16 +0200 Subject: [PATCH 075/392] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index d69978fb3..537064efb 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -74,30 +74,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - zero - Option %ld %ld - one - Option 1 - two - Option %ld %ld - few - Option %ld %ld - many - Option %ld %ld - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 5a10f62ff58f1592824db54752f484d5fd6657ff Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:17 +0200 Subject: [PATCH 076/392] New translations Localizable.stringsdict (Spanish) --- .../input/es_ES/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict index c07e85b24..bf493c1e8 100644 --- a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict @@ -50,22 +50,6 @@ publicaciones - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Opción 1 - other - Opción %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 679d53854982182e9812a76441b88412e02ca49e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Sep 2021 04:44:18 +0200 Subject: [PATCH 077/392] New translations Localizable.stringsdict (Swedish, Finland) --- .../input/sv_FI/Localizable.stringsdict | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict index 9e04cf4d5..30533a5eb 100644 --- a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict @@ -50,22 +50,6 @@ posts - plural.number.poll_option - - NSStringLocalizedFormatKey - %#@number_poll_option@ - number_poll_option - - NSStringFormatSpecTypeKey - NSStringPluralRuleType - NSStringFormatValueTypeKey - ld - one - Option 1 - other - Option %ld %ld - - plural.count.post NSStringLocalizedFormatKey From 66af30da2a3ea4fd28c02fe14d103abb3a2b79de Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 13 Sep 2021 19:14:26 +0800 Subject: [PATCH 078/392] feat: [WIP] add account list for multiple account switch --- Mastodon.xcodeproj/project.pbxproj | 20 ++++ .../xcschemes/xcschememanagement.plist | 14 +-- .../xcshareddata/swiftpm/Package.resolved | 4 +- Mastodon/Coordinator/SceneCoordinator.swift | 4 + .../Account/AccountListTableViewCell.swift | 34 +++++++ .../Scene/Account/AccountListViewModel.swift | 80 +++++++++++++++ .../Scene/Account/AccountViewController.swift | 98 +++++++++++++++++++ ...meTimelineViewController+DebugAction.swift | 68 ++++++++----- .../MastodonPickServerViewController.swift | 3 +- Podfile.lock | 2 +- 10 files changed, 292 insertions(+), 35 deletions(-) create mode 100644 Mastodon/Scene/Account/AccountListTableViewCell.swift create mode 100644 Mastodon/Scene/Account/AccountListViewModel.swift create mode 100644 Mastodon/Scene/Account/AccountViewController.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index c935acb21..fac9174ca 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -415,6 +415,9 @@ DB9D6C3825E508BE0051B173 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C3725E508BE0051B173 /* Attachment.swift */; }; DB9D7C21269824B80054B3DF /* APIService+Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D7C20269824B80054B3DF /* APIService+Filter.swift */; }; DB9E0D6F25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */; }; + DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */; }; + DB9F58EF26EF491E00E7BBE9 /* AccountListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */; }; + DB9F58F126EF512300E7BBE9 /* AccountListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */; }; DBA088DF26958164003EB4B2 /* UserFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA088DE26958164003EB4B2 /* UserFetchedResultsController.swift */; }; DBA0A11325FB3FC10079C110 /* ComposeToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */; }; DBA1DB80268F84F80052DB59 /* NotificationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA1DB7F268F84F80052DB59 /* NotificationType.swift */; }; @@ -1184,6 +1187,9 @@ DB9D6C3725E508BE0051B173 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; DB9D7C20269824B80054B3DF /* APIService+Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Filter.swift"; sourceTree = ""; }; DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIInterpolatingMotionEffect.swift; sourceTree = ""; }; + DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountViewController.swift; sourceTree = ""; }; + DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountListViewModel.swift; sourceTree = ""; }; + DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountListTableViewCell.swift; sourceTree = ""; }; DBA088DE26958164003EB4B2 /* UserFetchedResultsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserFetchedResultsController.swift; sourceTree = ""; }; DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbarView.swift; sourceTree = ""; }; DBA1DB7F268F84F80052DB59 /* NotificationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationType.swift; sourceTree = ""; }; @@ -2601,6 +2607,7 @@ DB6180E426391A500018D199 /* Transition */, DB8AF54E25C13703002E6C99 /* MainTab */, DB01409B25C40BB600F9F3CF /* Onboarding */, + DB9F58ED26EF435800E7BBE9 /* Account */, 2D38F1D325CD463600561493 /* HomeTimeline */, 2D76316325C14BAC00929FB9 /* PublicTimeline */, 5B24BBD6262DB14800A9381B /* Report */, @@ -2775,6 +2782,16 @@ path = ViewModel; sourceTree = ""; }; + DB9F58ED26EF435800E7BBE9 /* Account */ = { + isa = PBXGroup; + children = ( + DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */, + DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */, + DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */, + ); + path = Account; + sourceTree = ""; + }; DBA5E7A6263BD298004598BB /* ContextMenu */ = { isa = PBXGroup; children = ( @@ -3960,6 +3977,7 @@ 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, DB4F096C269EFA2000D62E92 /* SearchResultViewController+StatusProvider.swift in Sources */, DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */, + DB9F58EF26EF491E00E7BBE9 /* AccountListViewModel.swift in Sources */, DB6D9F7D26358ED4008423CD /* SettingsSection.swift in Sources */, DB0E91EA26A9675100BD2ACC /* MetaLabel.swift in Sources */, DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */, @@ -4017,6 +4035,7 @@ DB938F1526241FDF00E5B6C1 /* APIService+Thread.swift in Sources */, DB482A45261335BA008AE74C /* UserTimelineViewController+Provider.swift in Sources */, 2D206B8625F5FB0900143C56 /* Double.swift in Sources */, + DB9F58F126EF512300E7BBE9 /* AccountListTableViewCell.swift in Sources */, 2D76319F25C1521200929FB9 /* StatusSection.swift in Sources */, DB35FC252612FD7A006193C9 /* ProfileFieldView.swift in Sources */, DB938F0326240EA300E5B6C1 /* CachedThreadViewModel.swift in Sources */, @@ -4105,6 +4124,7 @@ 2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */, DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */, DBB525302611EBF3002F1F29 /* ProfilePagingViewModel.swift in Sources */, + DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */, DBCBCC0B2680B03F000F5B51 /* AsyncHomeTimelineViewModel+LoadOldestState.swift in Sources */, 2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */, DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 9d41c6857..62193f0d7 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,17 +7,17 @@ AppShared.xcscheme_^#shared#^_ orderHint - 60 + 24 CoreDataStack.xcscheme_^#shared#^_ orderHint - 62 + 23 Mastodon - ASDK.xcscheme_^#shared#^_ orderHint - 11 + 2 Mastodon - RTL.xcscheme_^#shared#^_ @@ -27,7 +27,7 @@ Mastodon - Release.xcscheme_^#shared#^_ orderHint - 10 + 1 Mastodon - ar.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 56 + 25 MastodonIntents.xcscheme_^#shared#^_ @@ -112,12 +112,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 13 + 3 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 58 + 22 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0dc724ded..5d8511197 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -141,8 +141,8 @@ "repositoryURL": "https://github.com/apple/swift-collections.git", "state": { "branch": null, - "revision": "0959ba76a1d4a98fd11163aa83fd49c25b93bfae", - "version": "0.0.5" + "revision": "9d8719c8bebdc79740b6969c912ac706eb721d7a", + "version": "0.0.7" } }, { diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 04804dde3..43a51fcda 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -87,6 +87,7 @@ extension SceneCoordinator { case activityViewController(activityViewController: UIActivityViewController, sourceView: UIView?, barButtonItem: UIBarButtonItem?) #if DEBUG + case accountList case publicTimeline #endif @@ -321,6 +322,9 @@ private extension SceneCoordinator { _viewController.viewModel = viewModel viewController = _viewController #if DEBUG + case .accountList: + let _viewController = AccountListViewController() + viewController = _viewController case .publicTimeline: let _viewController = PublicTimelineViewController() _viewController.viewModel = PublicTimelineViewModel(context: appContext) diff --git a/Mastodon/Scene/Account/AccountListTableViewCell.swift b/Mastodon/Scene/Account/AccountListTableViewCell.swift new file mode 100644 index 000000000..c98e94ec1 --- /dev/null +++ b/Mastodon/Scene/Account/AccountListTableViewCell.swift @@ -0,0 +1,34 @@ +// +// AccountListTableViewCell.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-13. +// + + +#if DEBUG +import UIKit + +final class AccountListTableViewCell: UITableViewCell { + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension AccountListTableViewCell { + + private func _init() { + + } + +} + +#endif diff --git a/Mastodon/Scene/Account/AccountListViewModel.swift b/Mastodon/Scene/Account/AccountListViewModel.swift new file mode 100644 index 000000000..3f56134b0 --- /dev/null +++ b/Mastodon/Scene/Account/AccountListViewModel.swift @@ -0,0 +1,80 @@ +// +// AccountListViewModel.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-13. +// + +#if DEBUG +import UIKit +import Combine +import CoreData +import CoreDataStack + +final class AccountListViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + + // output + let authentications = CurrentValueSubject<[Item], Never>([]) + var diffableDataSource: UITableViewDiffableDataSource! + + init(context: AppContext) { + self.context = context + + context.authenticationService.mastodonAuthentications + .map { authentications in + return authentications.map { + Item.authentication(objectID: $0.objectID) + } + } + .assign(to: \.value, on: authentications) + .store(in: &disposeBag) + + authentications + .receive(on: DispatchQueue.main) + .sink { [weak self] authentications in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + snapshot.appendItems(authentications, toSection: .main) + + diffableDataSource.apply(snapshot) + } + .store(in: &disposeBag) + } + +} + +extension AccountListViewModel { + enum Section: Hashable { + case main + } + + enum Item: Hashable { + case authentication(objectID: NSManagedObjectID) + } + + func setupDiffableDataSource( + tableView: UITableView, + managedObjectContext: NSManagedObjectContext + ) { + diffableDataSource = UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in + switch item { + case .authentication(let objectID): + let authentication = managedObjectContext.object(with: objectID) as! MastodonAuthentication + let user = authentication.user + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AccountListTableViewCell.self), for: indexPath) as! AccountListTableViewCell + cell.textLabel?.text = user.acctWithDomain + return cell + } + } + } +} + +#endif diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift new file mode 100644 index 000000000..65c41620d --- /dev/null +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -0,0 +1,98 @@ +// +// AccountViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-13. +// + +#if DEBUG + +import os.log +import UIKit +import Combine +import CoreDataStack + +final class AccountListViewController: UIViewController, NeedsDependency { + + let logger = Logger(subsystem: "AccountListViewController", category: "UI") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + private(set) lazy var viewModel = AccountListViewModel(context: context) + + private(set) lazy var addBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem( + image: UIImage(systemName: "plus"), + style: .plain, + target: self, + action: #selector(AccountListViewController.addBarButtonItem(_:)) + ) + return barButtonItem + }() + + private(set) lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.register(AccountListTableViewCell.self, forCellReuseIdentifier: String(describing: AccountListTableViewCell.self)) + return tableView + }() + +} + +extension AccountListViewController { + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemBackground + navigationItem.rightBarButtonItem = addBarButtonItem + + 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.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView, + managedObjectContext: context.managedObjectContext + ) + } +} + +extension AccountListViewController { + + @objc private func addBarButtonItem(_ sender: UIBarButtonItem) { + 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)) + } + +} + +// MARK: - UITableViewDelegate +extension AccountListViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard case let .authentication(objectID) = diffableDataSource.itemIdentifier(for: indexPath) else { return } + assert(Thread.isMainThread) + + let authentication = context.managedObjectContext.object(with: objectID) as! MastodonAuthentication + context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID) + .receive(on: DispatchQueue.main) + .sink { [weak self] result in + guard let self = self else { return } + self.coordinator.setup() + } + .store(in: &disposeBag) + + } +} + + +#endif diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index a55f1ebf6..4d9bb470f 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -23,20 +23,9 @@ extension HomeTimelineViewController { identifier: nil, options: .displayInline, children: [ - UIAction(title: "Show FLEX", image: nil, attributes: [], handler: { [weak self] action in - guard let self = self else { return } - self.showFLEXAction(action) - }), + showMenu, moveMenu, dropMenu, - UIAction(title: "Show Welcome", image: UIImage(systemName: "figure.walk"), attributes: []) { [weak self] action in - guard let self = self else { return } - self.showWelcomeAction(action) - }, - UIAction(title: "Show Confirm Email", image: UIImage(systemName: "envelope"), attributes: []) { [weak self] action in - guard let self = self else { return } - self.showConfirmEmail(action) - }, UIAction(title: "Toggle EmptyView", image: UIImage(systemName: "clear"), attributes: []) { [weak self] action in guard let self = self else { return } if self.emptyView.superview != nil { @@ -45,18 +34,6 @@ extension HomeTimelineViewController { self.showEmptyView() } }, - UIAction(title: "Show Public Timeline", image: UIImage(systemName: "list.dash"), attributes: []) { [weak self] action in - guard let self = self else { return } - self.showPublicTimelineAction(action) - }, - UIAction(title: "Show Profile", image: UIImage(systemName: "person.crop.circle"), attributes: []) { [weak self] action in - guard let self = self else { return } - self.showProfileAction(action) - }, - UIAction(title: "Show Thread", image: UIImage(systemName: "bubble.left.and.bubble.right"), attributes: []) { [weak self] action in - guard let self = self else { return } - self.showThreadAction(action) - }, UIAction(title: "Settings", image: UIImage(systemName: "gear"), attributes: []) { [weak self] action in guard let self = self else { return } self.showSettings(action) @@ -69,6 +46,45 @@ extension HomeTimelineViewController { ) return menu } + + var showMenu: UIMenu { + return UIMenu( + title: "Show…", + image: UIImage(systemName: "plus.rectangle.on.rectangle"), + identifier: nil, + options: [], + children: [ + UIAction(title: "FLEX", image: nil, attributes: [], handler: { [weak self] action in + guard let self = self else { return } + self.showFLEXAction(action) + }), + UIAction(title: "Welcome", image: UIImage(systemName: "figure.walk"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showWelcomeAction(action) + }, + UIAction(title: "Confirm Email", image: UIImage(systemName: "envelope"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showConfirmEmail(action) + }, + UIAction(title: "Account List", image: UIImage(systemName: "person"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showAccountList(action) + }, + UIAction(title: "Public Timeline", image: UIImage(systemName: "list.dash"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showPublicTimelineAction(action) + }, + UIAction(title: "Profile", image: UIImage(systemName: "person.crop.circle"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showProfileAction(action) + }, + UIAction(title: "Thread", image: UIImage(systemName: "bubble.left.and.bubble.right"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showThreadAction(action) + }, + ] + ) + } var moveMenu: UIMenu { return UIMenu( @@ -321,6 +337,10 @@ extension HomeTimelineViewController { let mastodonConfirmEmailViewModel = MastodonConfirmEmailViewModel() coordinator.present(scene: .mastodonConfirmEmail(viewModel: mastodonConfirmEmailViewModel), from: nil, transition: .modal(animated: true, completion: nil)) } + + @objc private func showAccountList(_ sender: UIAction) { + coordinator.present(scene: .accountList, from: self, transition: .modal(animated: true, completion: nil)) + } @objc private func showPublicTimelineAction(_ sender: UIAction) { coordinator.present(scene: .publicTimeline, from: self, transition: .show) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index 70c1067f9..604e23825 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -222,7 +222,8 @@ extension MastodonPickServerViewController { assertionFailure(error.localizedDescription) case .success(let isActived): assert(isActived) - self.dismiss(animated: true, completion: nil) + // self.dismiss(animated: true, completion: nil) + self.coordinator.setup() } } .store(in: &disposeBag) diff --git a/Podfile.lock b/Podfile.lock index b2c540abf..7c64e59b9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -80,4 +80,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4db0bdf969729c5758bd923e33d9e097cb892086 -COCOAPODS: 1.10.2 +COCOAPODS: 1.11.0 From 46ebdd80596035e44ac82984a730f54953d040fd Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 14 Sep 2021 18:21:15 +0800 Subject: [PATCH 079/392] feat: update account list UI --- Localization/app.json | 5 +- Mastodon.xcodeproj/project.pbxproj | 43 ++++++++- .../xcschemes/xcschememanagement.plist | 8 +- .../xcshareddata/swiftpm/Package.resolved | 9 ++ Mastodon/Coordinator/SceneCoordinator.swift | 21 ++-- Mastodon/Extension/MetaLabel.swift | 8 ++ .../Account/AccountListTableViewCell.swift | 34 ------- .../Scene/Account/AccountListViewModel.swift | 36 ++++++- .../Scene/Account/AccountViewController.swift | 78 +++++++++++---- .../Cell/AccountListTableViewCell.swift | 95 +++++++++++++++++++ .../Cell/AddAccountTableViewCell.swift | 75 +++++++++++++++ .../Account/View/DragIndicatorView.swift | 55 +++++++++++ .../Scene/MainTab/MainTabBarController.swift | 38 ++++++++ README.md | 1 + 14 files changed, 438 insertions(+), 68 deletions(-) delete mode 100644 Mastodon/Scene/Account/AccountListTableViewCell.swift create mode 100644 Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift create mode 100644 Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift create mode 100644 Mastodon/Scene/Account/View/DragIndicatorView.swift diff --git a/Localization/app.json b/Localization/app.json index b60ade9c1..ae1593940 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -534,6 +534,9 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "account_list": { + "add_account": "Add Account" } } -} \ No newline at end of file +} diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index fac9174ca..6e0980275 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -425,6 +425,9 @@ DBA465952696E387002B41DB /* AppPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA465942696E387002B41DB /* AppPreference.swift */; }; DBA4B0F626C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; }; DBA4B0F726C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; }; + DBA5A52F26F07ED800CACBAA /* PanModal in Frameworks */ = {isa = PBXBuildFile; productRef = DBA5A52E26F07ED800CACBAA /* PanModal */; }; + DBA5A53126F08EF000CACBAA /* DragIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */; }; + DBA5A53526F0A36A00CACBAA /* AddAccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5A53426F0A36A00CACBAA /* AddAccountTableViewCell.swift */; }; DBA5E7A3263AD0A3004598BB /* PhotoLibraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */; }; DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */; }; DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */; }; @@ -1225,6 +1228,8 @@ DBA4B0EF26C153B20077136E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = ""; }; DBA4B0F526C2621D0077136E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = ""; }; DBA4B0F826C269880077136E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Intents.stringsdict; sourceTree = ""; }; + DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DragIndicatorView.swift; sourceTree = ""; }; + DBA5A53426F0A36A00CACBAA /* AddAccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountTableViewCell.swift; sourceTree = ""; }; DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryService.swift; sourceTree = ""; }; DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewModel.swift; sourceTree = ""; }; DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewController.swift; sourceTree = ""; }; @@ -1387,6 +1392,7 @@ 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */, DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */, DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */, + DBA5A52F26F07ED800CACBAA /* PanModal in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2785,13 +2791,31 @@ DB9F58ED26EF435800E7BBE9 /* Account */ = { isa = PBXGroup; children = ( + DBA5A53226F08EF300CACBAA /* View */, + DBA5A53326F0932E00CACBAA /* Cell */, DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */, DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */, - DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */, ); path = Account; sourceTree = ""; }; + DBA5A53226F08EF300CACBAA /* View */ = { + isa = PBXGroup; + children = ( + DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */, + ); + path = View; + sourceTree = ""; + }; + DBA5A53326F0932E00CACBAA /* Cell */ = { + isa = PBXGroup; + children = ( + DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */, + DBA5A53426F0A36A00CACBAA /* AddAccountTableViewCell.swift */, + ); + path = Cell; + sourceTree = ""; + }; DBA5E7A6263BD298004598BB /* ContextMenu */ = { isa = PBXGroup; children = ( @@ -3161,6 +3185,7 @@ DB01E23226A98F0900C3965B /* MastodonMeta */, DB01E23426A98F0900C3965B /* MetaTextKit */, DB552D4E26BBD10C00E481F6 /* OrderedCollections */, + DBA5A52E26F07ED800CACBAA /* PanModal */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -3420,6 +3445,7 @@ DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */, DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */, DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */, + DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */, ); productRefGroup = DB427DD325BAA00100D1B89D /* Products */; projectDirPath = ""; @@ -3773,6 +3799,7 @@ 2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */, DB6180EF26391CA50018D199 /* MediaPreviewImageViewController.swift in Sources */, DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */, + DBA5A53126F08EF000CACBAA /* DragIndicatorView.swift in Sources */, DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */, DB6180F626391D580018D199 /* MediaPreviewableViewController.swift in Sources */, 2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */, @@ -4042,6 +4069,7 @@ DB6D9F6326357848008423CD /* SettingService.swift in Sources */, 2D650FAB25ECDC9300851B58 /* Mastodon+Entity+Error+Detail.swift in Sources */, 2D24E12D2626FD2E00A59D4F /* NotificationViewModel+LoadOldestState.swift in Sources */, + DBA5A53526F0A36A00CACBAA /* AddAccountTableViewCell.swift in Sources */, 2DB72C8C262D764300CE6173 /* Mastodon+Entity+Notification+Type.swift in Sources */, 2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */, DB084B5725CBC56C00F898ED /* Status.swift in Sources */, @@ -5845,6 +5873,14 @@ minimumVersion = 1.4.1; }; }; + DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/slackhq/PanModal.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.2.7; + }; + }; DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ra1028/DifferenceKit.git"; @@ -5957,6 +5993,11 @@ package = DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */; productName = "UITextView+Placeholder"; }; + DBA5A52E26F07ED800CACBAA /* PanModal */ = { + isa = XCSwiftPackageProductDependency; + package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */; + productName = PanModal; + }; DBAC6482267D0B21007FE9FD /* DifferenceKit */ = { isa = XCSwiftPackageProductDependency; package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 62193f0d7..0db21afd2 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 24 + 22 CoreDataStack.xcscheme_^#shared#^_ orderHint - 23 + 24 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 25 + 26 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 23 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5d8511197..c6a659bd5 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -127,6 +127,15 @@ "version": "3.6.2" } }, + { + "package": "PanModal", + "repositoryURL": "https://github.com/slackhq/PanModal.git", + "state": { + "branch": null, + "revision": "b012aecb6b67a8e46369227f893c12544846613f", + "version": "1.2.7" + } + }, { "package": "SDWebImage", "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 43a51fcda..f604ef546 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -7,6 +7,7 @@ import UIKit import SafariServices import CoreDataStack +import PanModal final public class SceneCoordinator { @@ -31,6 +32,7 @@ extension SceneCoordinator { case show // push case showDetail // replace case modal(animated: Bool, completion: (() -> Void)? = nil) + case panModal case custom(transitioningDelegate: UIViewControllerTransitioningDelegate) case customPush case safariPresent(animated: Bool, completion: (() -> Void)? = nil) @@ -66,9 +68,10 @@ extension SceneCoordinator { case hashtagTimeline(viewModel: HashtagTimelineViewModel) // profile + case accountList case profile(viewModel: ProfileViewModel) case favorite(viewModel: FavoriteViewModel) - + // setting case settings(viewModel: SettingsViewModel) @@ -87,7 +90,6 @@ extension SceneCoordinator { case activityViewController(activityViewController: UIActivityViewController, sourceView: UIView?, barButtonItem: UIBarButtonItem?) #if DEBUG - case accountList case publicTimeline #endif @@ -184,7 +186,14 @@ extension SceneCoordinator { modalNavigationController.presentationController?.delegate = adaptivePresentationControllerDelegate } presentingViewController.present(modalNavigationController, animated: animated, completion: completion) - + + case .panModal: + guard let panModalPresentable = viewController as? PanModalPresentable & UIViewController else { + assertionFailure() + return nil + } + presentingViewController.presentPanModal(panModalPresentable) + case .custom(let transitioningDelegate): viewController.modalPresentationStyle = .custom viewController.transitioningDelegate = transitioningDelegate @@ -274,6 +283,9 @@ private extension SceneCoordinator { let _viewController = HashtagTimelineViewController() _viewController.viewModel = viewModel viewController = _viewController + case .accountList: + let _viewController = AccountListViewController() + viewController = _viewController case .profile(let viewModel): let _viewController = ProfileViewController() _viewController.viewModel = viewModel @@ -322,9 +334,6 @@ private extension SceneCoordinator { _viewController.viewModel = viewModel viewController = _viewController #if DEBUG - case .accountList: - let _viewController = AccountListViewController() - viewController = _viewController case .publicTimeline: let _viewController = PublicTimelineViewController() _viewController.viewModel = PublicTimelineViewModel(context: appContext) diff --git a/Mastodon/Extension/MetaLabel.swift b/Mastodon/Extension/MetaLabel.swift index 9e7920a8e..a9696892a 100644 --- a/Mastodon/Extension/MetaLabel.swift +++ b/Mastodon/Extension/MetaLabel.swift @@ -20,6 +20,8 @@ extension MetaLabel { case titleView case settingTableFooter case autoCompletion + case accountListName + case accountListUsername } convenience init(style: Style) { @@ -74,6 +76,12 @@ extension MetaLabel { case .autoCompletion: font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 22) textColor = Asset.Colors.brandBlue.color + case .accountListName: + font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22) + textColor = Asset.Colors.Label.primary.color + case .accountListUsername: + font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20) + textColor = Asset.Colors.Label.secondary.color } self.font = font diff --git a/Mastodon/Scene/Account/AccountListTableViewCell.swift b/Mastodon/Scene/Account/AccountListTableViewCell.swift deleted file mode 100644 index c98e94ec1..000000000 --- a/Mastodon/Scene/Account/AccountListTableViewCell.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// AccountListTableViewCell.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021-9-13. -// - - -#if DEBUG -import UIKit - -final class AccountListTableViewCell: UITableViewCell { - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - _init() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - _init() - } - -} - -extension AccountListTableViewCell { - - private func _init() { - - } - -} - -#endif diff --git a/Mastodon/Scene/Account/AccountListViewModel.swift b/Mastodon/Scene/Account/AccountListViewModel.swift index 3f56134b0..6842806e2 100644 --- a/Mastodon/Scene/Account/AccountListViewModel.swift +++ b/Mastodon/Scene/Account/AccountListViewModel.swift @@ -5,11 +5,11 @@ // Created by Cirno MainasuK on 2021-9-13. // -#if DEBUG import UIKit import Combine import CoreData import CoreDataStack +import MastodonMeta final class AccountListViewModel { @@ -43,6 +43,7 @@ final class AccountListViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems(authentications, toSection: .main) + snapshot.appendItems([.addAccount], toSection: .main) diffableDataSource.apply(snapshot) } @@ -58,6 +59,7 @@ extension AccountListViewModel { enum Item: Hashable { case authentication(objectID: NSManagedObjectID) + case addAccount } func setupDiffableDataSource( @@ -70,11 +72,37 @@ extension AccountListViewModel { let authentication = managedObjectContext.object(with: objectID) as! MastodonAuthentication let user = authentication.user let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AccountListTableViewCell.self), for: indexPath) as! AccountListTableViewCell - cell.textLabel?.text = user.acctWithDomain + AccountListViewModel.configure(cell: cell, user: user) + return cell + case .addAccount: + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AddAccountTableViewCell.self), for: indexPath) as! AddAccountTableViewCell return cell } } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + diffableDataSource?.apply(snapshot) + } + + static func configure( + cell: AccountListTableViewCell, + user: MastodonUser + ) { + // avatar + cell.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: user.avatarImageURL())) + + // name + do { + let content = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojiMeta) + let metaContent = try MastodonMetaContent.convert(document: content) + cell.nameLabel.configure(content: metaContent) + } catch { + assertionFailure() + cell.nameLabel.configure(content: PlaintextMetaContent(string: user.displayNameWithFallback)) + } + + // username + cell.usernameLabel.configure(content: PlaintextMetaContent(string: user.acctWithDomain)) } } - -#endif diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index 65c41620d..28ee88c95 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -5,12 +5,11 @@ // Created by Cirno MainasuK on 2021-9-13. // -#if DEBUG - import os.log import UIKit import Combine import CoreDataStack +import PanModal final class AccountListViewController: UIViewController, NeedsDependency { @@ -32,25 +31,61 @@ final class AccountListViewController: UIViewController, NeedsDependency { return barButtonItem }() + let dragIndicatorView = DragIndicatorView() + private(set) lazy var tableView: UITableView = { let tableView = UITableView() tableView.register(AccountListTableViewCell.self, forCellReuseIdentifier: String(describing: AccountListTableViewCell.self)) + tableView.register(AddAccountTableViewCell.self, forCellReuseIdentifier: String(describing: AddAccountTableViewCell.self)) + tableView.backgroundColor = .clear + tableView.tableFooterView = UIView() + tableView.separatorStyle = .none return tableView }() } +// MARK: - PanModalPresentable +extension AccountListViewController: PanModalPresentable { + var panScrollable: UIScrollView? { tableView } + var showDragIndicator: Bool { false } + + var shortFormHeight: PanModalHeight { + return .contentHeight(300) + } + + var longFormHeight: PanModalHeight { + return .maxHeightWithTopInset(40) + } +} + extension AccountListViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemBackground + view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor.withAlphaComponent(0.9) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupBackgroundColor(theme: theme) + } + .store(in: &disposeBag) navigationItem.rightBarButtonItem = addBarButtonItem + dragIndicatorView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(dragIndicatorView) + NSLayoutConstraint.activate([ + dragIndicatorView.topAnchor.constraint(equalTo: view.topAnchor), + dragIndicatorView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + dragIndicatorView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + dragIndicatorView.heightAnchor.constraint(equalToConstant: DragIndicatorView.height).priority(.required - 1), + ]) + tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.topAnchor.constraint(equalTo: dragIndicatorView.bottomAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), @@ -62,6 +97,11 @@ extension AccountListViewController { managedObjectContext: context.managedObjectContext ) } + + private func setupBackgroundColor(theme: Theme) { + view.backgroundColor = theme.systemBackgroundColor.withAlphaComponent(0.9) + } + } extension AccountListViewController { @@ -79,20 +119,22 @@ extension AccountListViewController: UITableViewDelegate { tableView.deselectRow(at: indexPath, animated: true) guard let diffableDataSource = viewModel.diffableDataSource else { return } - guard case let .authentication(objectID) = diffableDataSource.itemIdentifier(for: indexPath) else { return } - assert(Thread.isMainThread) - - let authentication = context.managedObjectContext.object(with: objectID) as! MastodonAuthentication - context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID) - .receive(on: DispatchQueue.main) - .sink { [weak self] result in - guard let self = self else { return } - self.coordinator.setup() - } - .store(in: &disposeBag) + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } + switch item { + case .authentication(let objectID): + assert(Thread.isMainThread) + let authentication = context.managedObjectContext.object(with: objectID) as! MastodonAuthentication + context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID) + .receive(on: DispatchQueue.main) + .sink { [weak self] result in + guard let self = self else { return } + self.coordinator.setup() + } + .store(in: &disposeBag) + case .addAccount: + // TODO: add dismiss entry for welcome scene + coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil)) + } } } - - -#endif diff --git a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift new file mode 100644 index 000000000..9125923a1 --- /dev/null +++ b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift @@ -0,0 +1,95 @@ +// +// AccountListTableViewCell.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-13. +// + +import UIKit +import FLAnimatedImage +import MetaTextKit + +final class CircleAvatarButton: AvatarButton { + override func layoutSubviews() { + super.layoutSubviews() + + layer.masksToBounds = true + layer.cornerRadius = frame.width * 0.5 + layer.borderColor = UIColor.systemFill.cgColor + layer.borderWidth = 1 + } +} + +final class AccountListTableViewCell: UITableViewCell { + + let avatarButton = CircleAvatarButton() + let nameLabel = MetaLabel(style: .accountListName) + let usernameLabel = MetaLabel(style: .accountListUsername) + let separatorLine = UIView.separatorLine + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension AccountListTableViewCell { + + private func _init() { + avatarButton.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(avatarButton) + NSLayoutConstraint.activate([ + avatarButton.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + avatarButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + avatarButton.heightAnchor.constraint(equalTo: avatarButton.widthAnchor, multiplier: 1.0).priority(.required - 1), + avatarButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).priority(.required - 1), + ]) + avatarButton.setContentHuggingPriority(.defaultLow, for: .horizontal) + avatarButton.setContentHuggingPriority(.defaultLow, for: .vertical) + + let labelContainerStackView = UIStackView() + labelContainerStackView.axis = .vertical + labelContainerStackView.distribution = .equalCentering + labelContainerStackView.spacing = 2 + labelContainerStackView.distribution = .fillProportionally + labelContainerStackView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(labelContainerStackView) + NSLayoutConstraint.activate([ + labelContainerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), + labelContainerStackView.leadingAnchor.constraint(equalTo: avatarButton.trailingAnchor, constant: 10), + contentView.bottomAnchor.constraint(equalTo: labelContainerStackView.bottomAnchor, constant: 10), + avatarButton.heightAnchor.constraint(equalTo: labelContainerStackView.heightAnchor, multiplier: 0.8).priority(.required - 10), + labelContainerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + ]) + + labelContainerStackView.addArrangedSubview(nameLabel) + labelContainerStackView.addArrangedSubview(usernameLabel) + + avatarButton.isUserInteractionEnabled = false + nameLabel.isUserInteractionEnabled = false + usernameLabel.isUserInteractionEnabled = false + + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + } + +} + +// MARK: - AvatarConfigurableView +extension AccountListTableViewCell: AvatarConfigurableView { + static var configurableAvatarImageSize: CGSize { CGSize(width: 30, height: 30) } + static var configurableAvatarImageCornerRadius: CGFloat { 0 } + var configurableAvatarImageView: FLAnimatedImageView? { avatarButton.avatarImageView } +} diff --git a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift new file mode 100644 index 000000000..0ac022c5d --- /dev/null +++ b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift @@ -0,0 +1,75 @@ +// +// AddAccountTableViewCell.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-14. +// + +import UIKit +import MetaTextKit + +final class AddAccountTableViewCell: UITableViewCell { + + let iconImageView: UIImageView = { + let image = UIImage(systemName: "plus.circle.fill")! + let imageView = UIImageView(image: image) + imageView.tintColor = Asset.Colors.Label.primary.color + return imageView + }() + let titleLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22) + label.textColor = Asset.Colors.Label.primary.color + label.text = "Add Account" // TODO: i18n + return label + }() + let usernameLabel = MetaLabel(style: .accountListUsername) + let separatorLine = UIView.separatorLine + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension AddAccountTableViewCell { + + private func _init() { + iconImageView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(iconImageView) + NSLayoutConstraint.activate([ + iconImageView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + iconImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + iconImageView.heightAnchor.constraint(equalTo: iconImageView.widthAnchor, multiplier: 1.0).priority(.required - 1), + iconImageView.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).priority(.required - 1), + ]) + iconImageView.setContentHuggingPriority(.defaultLow, for: .horizontal) + iconImageView.setContentHuggingPriority(.defaultLow, for: .vertical) + + titleLabel.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(titleLabel) + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 19), + titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 10), + contentView.bottomAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 19), + iconImageView.heightAnchor.constraint(equalTo: titleLabel.heightAnchor, multiplier: 1.0).priority(.required - 10), + titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + ]) + + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + } + +} diff --git a/Mastodon/Scene/Account/View/DragIndicatorView.swift b/Mastodon/Scene/Account/View/DragIndicatorView.swift new file mode 100644 index 000000000..5efa141bc --- /dev/null +++ b/Mastodon/Scene/Account/View/DragIndicatorView.swift @@ -0,0 +1,55 @@ +// +// DragIndicatorView.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-14. +// + +import UIKit + +final class DragIndicatorView: UIView { + + static let height: CGFloat = 38 + + let barView = UIView() + let separatorLine = UIView.separatorLine + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension DragIndicatorView { + + private func _init() { + barView.backgroundColor = Asset.Colors.Label.secondary.color + barView.layer.masksToBounds = true + barView.layer.cornerRadius = 2.5 + + barView.translatesAutoresizingMaskIntoConstraints = false + addSubview(barView) + NSLayoutConstraint.activate([ + barView.centerXAnchor.constraint(equalTo: centerXAnchor), + barView.centerYAnchor.constraint(equalTo: centerYAnchor), + barView.heightAnchor.constraint(equalToConstant: 5).priority(.required - 1), + barView.widthAnchor.constraint(equalToConstant: 36).priority(.required - 1), + ]) + + separatorLine.translatesAutoresizingMaskIntoConstraints = false + addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: self)), + ]) + } + +} diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index 1f9bcb578..8e6edd2aa 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -11,6 +11,8 @@ import Combine import SafariServices class MainTabBarController: UITabBarController { + + let logger = Logger(subsystem: "MainTabBarController", category: "UI") var disposeBag = Set() @@ -24,6 +26,10 @@ class MainTabBarController: UITabBarController { case search case notification case me + + var tag: Int { + return rawValue + } var title: String { switch self { @@ -121,6 +127,7 @@ extension MainTabBarController { let tabs = Tab.allCases let viewControllers: [UIViewController] = tabs.map { tab in let viewController = tab.viewController(context: context, coordinator: coordinator) + viewController.tabBarItem.tag = tab.tag viewController.tabBarItem.title = tab.title viewController.tabBarItem.image = tab.image viewController.tabBarItem.accessibilityLabel = tab.title @@ -204,6 +211,10 @@ extension MainTabBarController { } .store(in: &disposeBag) + let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer() + tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:))) + tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer) + #if DEBUG // selectedIndex = 1 #endif @@ -211,6 +222,33 @@ extension MainTabBarController { } +extension MainTabBarController { + @objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) { + guard sender.state == .began else { return } + + var _tab: Tab? + let location = sender.location(in: tabBar) + for item in tabBar.items ?? [] { + guard let tab = Tab(rawValue: item.tag) else { continue } + guard let view = item.value(forKey: "view") as? UIView else { continue } + guard view.frame.contains(location) else { continue} + + _tab = tab + break + } + + guard let tab = _tab else { return } + logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): long press \(tab.title) tab") + + switch tab { + case .me: + coordinator.present(scene: .accountList, from: nil, transition: .panModal) + default: + break + } + } +} + extension MainTabBarController { var notificationViewController: NotificationViewController? { diff --git a/README.md b/README.md index e31c4879b..08c87e558 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ The app is compatible with [toot-relay](https://github.com/DagAgren/toot-relay) - [Nuke-FLAnimatedImage-Plugin](https://github.com/kean/Nuke-FLAnimatedImage-Plugin) - [Nuke](https://github.com/kean/Nuke) - [Pageboy](https://github.com/uias/Pageboy#the-basics) +- [PanModal](https://github.com/slackhq/PanModal.git) - [SDWebImage](https://github.com/SDWebImage/SDWebImage) - [swift-collections](https://github.com/apple/swift-collections) - [swift-nio](https://github.com/apple/swift-nio) From 016d7b987dd50757ae86ea7000977a91dd789754 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 15 Sep 2021 20:18:19 +0800 Subject: [PATCH 080/392] feat: add wizard for multiple account entry --- Localization/app.json | 9 +- Mastodon.xcodeproj/project.pbxproj | 20 +++ .../xcschemes/xcschememanagement.plist | 38 +++--- .../TableNodeDiffableDataSource.swift | 2 +- Mastodon/Preference/WizardPreference.swift | 15 +++ .../Scene/Account/AccountListViewModel.swift | 47 +++++-- .../Scene/Account/AccountViewController.swift | 13 ++ .../Cell/AccountListTableViewCell.swift | 24 ++-- .../MainTab/MainTabBarController+Wizard.swift | 124 ++++++++++++++++++ .../Scene/MainTab/MainTabBarController.swift | 115 ++++++++++++++++ .../Welcome/View/WizardCardView.swift | 110 ++++++++++++++++ .../Welcome/WelcomeViewController.swift | 19 +++ .../Onboarding/Welcome/WelcomeViewModel.swift | 30 +++++ .../Share/View/Button/AvatarButton.swift | 1 + .../View/Button/CircleAvatarButton.swift | 20 +++ .../Share/View/Node/Status/StatusNode.swift | 2 +- 16 files changed, 544 insertions(+), 45 deletions(-) create mode 100644 Mastodon/Preference/WizardPreference.swift create mode 100644 Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift create mode 100644 Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift create mode 100644 Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift create mode 100644 Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift diff --git a/Localization/app.json b/Localization/app.json index ae1593940..ce307a2e0 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -536,7 +536,12 @@ } }, "account_list": { - "add_account": "Add Account" + "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", + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button." } } -} +} \ No newline at end of file diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 6e0980275..504a29ea1 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -202,6 +202,7 @@ DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift */; }; DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */; }; DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D186B25EF5BA7003F1F23 /* PollTableView.swift */; }; + DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D61CE26F1B33600DA8662 /* WelcomeViewModel.swift */; }; DB1D842C26551A1C000346B3 /* StatusProvider+StatusTableViewKeyCommandNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D842B26551A1C000346B3 /* StatusProvider+StatusTableViewKeyCommandNavigateable.swift */; }; DB1D842E26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D842D26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift */; }; DB1D843026566512000346B3 /* KeyboardPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D842F26566512000346B3 /* KeyboardPreference.swift */; }; @@ -262,6 +263,8 @@ DB482A45261335BA008AE74C /* UserTimelineViewController+Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB482A44261335BA008AE74C /* UserTimelineViewController+Provider.swift */; }; DB482A4B261340A7008AE74C /* APIService+UserTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB482A4A261340A7008AE74C /* APIService+UserTimeline.swift */; }; DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4924E126312AB200E9DB22 /* NotificationService.swift */; }; + DB4932B126F1FB5300EF46D4 /* WizardCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */; }; + DB4932B326F2054200EF46D4 /* CircleAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4932B226F2054200EF46D4 /* CircleAvatarButton.swift */; }; DB49A61425FF2C5600B98345 /* EmojiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A61325FF2C5600B98345 /* EmojiService.swift */; }; DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift */; }; DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A62425FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift */; }; @@ -301,6 +304,8 @@ DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180F726391D660018D199 /* MediaPreviewingViewController.swift */; }; DB6180FA26391F2E0018D199 /* MediaPreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180F926391F2E0018D199 /* MediaPreviewViewModel.swift */; }; DB63BE7F268DD1070011D3F9 /* NotificationViewController+StatusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63BE7E268DD1070011D3F9 /* NotificationViewController+StatusProvider.swift */; }; + DB647C5726F1E97300F7F82C /* MainTabBarController+Wizard.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB647C5626F1E97300F7F82C /* MainTabBarController+Wizard.swift */; }; + DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB647C5826F1EA2700F7F82C /* WizardPreference.swift */; }; DB66728C25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66728B25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift */; }; DB66729625F9F91600D60309 /* ComposeStatusSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729525F9F91600D60309 /* ComposeStatusSection.swift */; }; DB66729C25F9F91F00D60309 /* ComposeStatusItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */; }; @@ -949,6 +954,7 @@ DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerLoaderTableViewCell.swift; sourceTree = ""; }; DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; DB1D186B25EF5BA7003F1F23 /* PollTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollTableView.swift; sourceTree = ""; }; + DB1D61CE26F1B33600DA8662 /* WelcomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewModel.swift; sourceTree = ""; }; DB1D842B26551A1C000346B3 /* StatusProvider+StatusTableViewKeyCommandNavigateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusProvider+StatusTableViewKeyCommandNavigateable.swift"; sourceTree = ""; }; DB1D842D26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewControllerNavigateable.swift; sourceTree = ""; }; DB1D842F26566512000346B3 /* KeyboardPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPreference.swift; sourceTree = ""; }; @@ -1016,6 +1022,8 @@ DB482A44261335BA008AE74C /* UserTimelineViewController+Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserTimelineViewController+Provider.swift"; sourceTree = ""; }; DB482A4A261340A7008AE74C /* APIService+UserTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+UserTimeline.swift"; sourceTree = ""; }; DB4924E126312AB200E9DB22 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; + DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardCardView.swift; sourceTree = ""; }; + DB4932B226F2054200EF46D4 /* CircleAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleAvatarButton.swift; sourceTree = ""; }; DB49A61325FF2C5600B98345 /* EmojiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiService.swift; sourceTree = ""; }; DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmojiViewModel.swift"; sourceTree = ""; }; DB49A62425FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmojiViewModel+LoadState.swift"; sourceTree = ""; }; @@ -1079,6 +1087,8 @@ DB6180F726391D660018D199 /* MediaPreviewingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewingViewController.swift; sourceTree = ""; }; DB6180F926391F2E0018D199 /* MediaPreviewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewViewModel.swift; sourceTree = ""; }; DB63BE7E268DD1070011D3F9 /* NotificationViewController+StatusProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationViewController+StatusProvider.swift"; sourceTree = ""; }; + DB647C5626F1E97300F7F82C /* MainTabBarController+Wizard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainTabBarController+Wizard.swift"; sourceTree = ""; }; + DB647C5826F1EA2700F7F82C /* WizardPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardPreference.swift; sourceTree = ""; }; DB66728B25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ComposeViewModel+DataSource.swift"; sourceTree = ""; }; DB66729525F9F91600D60309 /* ComposeStatusSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusSection.swift; sourceTree = ""; }; DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusItem.swift; sourceTree = ""; }; @@ -1499,6 +1509,7 @@ children = ( DBABE3F125ECAC4E00879EE5 /* View */, 0FAA0FDE25E0B57E0017CCDE /* WelcomeViewController.swift */, + DB1D61CE26F1B33600DA8662 /* WelcomeViewModel.swift */, ); path = Welcome; sourceTree = ""; @@ -1676,6 +1687,7 @@ isa = PBXGroup; children = ( DB0C947126A7D2D70088FB11 /* AvatarButton.swift */, + DB4932B226F2054200EF46D4 /* CircleAvatarButton.swift */, DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */, 2D42FF8425C8224F004A627A /* HitTestExpandedButton.swift */, 0FAA101125E105390017CCDE /* PrimaryActionButton.swift */, @@ -2322,6 +2334,7 @@ isa = PBXGroup; children = ( DBA465942696E387002B41DB /* AppPreference.swift */, + DB647C5826F1EA2700F7F82C /* WizardPreference.swift */, DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */, DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */, DB1D842F26566512000346B3 /* KeyboardPreference.swift */, @@ -2602,6 +2615,7 @@ isa = PBXGroup; children = ( DB8AF54F25C13703002E6C99 /* MainTabBarController.swift */, + DB647C5626F1E97300F7F82C /* MainTabBarController+Wizard.swift */, ); path = MainTab; sourceTree = ""; @@ -2847,6 +2861,7 @@ isa = PBXGroup; children = ( DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */, + DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */, ); path = View; sourceTree = ""; @@ -3966,10 +3981,12 @@ 2D45E5BF25C9549700A6D639 /* PublicTimelineViewModel+State.swift in Sources */, DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */, + DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */, 2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */, 5DDDF1992617447F00311060 /* Mastodon+Entity+Tag.swift in Sources */, 5B90C45F262599800002E742 /* SettingsToggleTableViewCell.swift in Sources */, 2D694A7425F9EB4E0038ADDC /* ContentWarningOverlayView.swift in Sources */, + DB4932B126F1FB5300EF46D4 /* WizardCardView.swift in Sources */, DBAE3F682615DD60004B8251 /* UserProvider.swift in Sources */, DBAC6488267D388B007FE9FD /* ASTableNode.swift in Sources */, DB6D9F76263587C7008423CD /* SettingFetchedResultController.swift in Sources */, @@ -4122,6 +4139,7 @@ DB9D6C3825E508BE0051B173 /* Attachment.swift in Sources */, 5DFC35DF262068D20045711D /* SearchViewController+Follow.swift in Sources */, DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */, + DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */, 2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */, DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */, DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */, @@ -4158,9 +4176,11 @@ DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */, DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */, DB6D9F6F2635807F008423CD /* Setting.swift in Sources */, + DB647C5726F1E97300F7F82C /* MainTabBarController+Wizard.swift in Sources */, DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */, DBB525412611ED54002F1F29 /* ProfileHeaderViewController.swift in Sources */, DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */, + DB4932B326F2054200EF46D4 /* CircleAvatarButton.swift in Sources */, 0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */, 2D4AD8A226316CD200613EFC /* SelectedAccountSection.swift in Sources */, DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 0db21afd2..2fec1c757 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,42 +7,42 @@ AppShared.xcscheme_^#shared#^_ orderHint - 22 + 38 CoreDataStack.xcscheme_^#shared#^_ orderHint - 24 + 35 Mastodon - ASDK.xcscheme_^#shared#^_ orderHint - 2 + 3 Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 12 + 13 Mastodon - Release.xcscheme_^#shared#^_ orderHint - 1 + 2 Mastodon - ar.xcscheme_^#shared#^_ orderHint - 7 + 10 Mastodon - ca.xcscheme_^#shared#^_ orderHint - 32 + 16 Mastodon - de.xcscheme_^#shared#^_ orderHint - 8 + 11 Mastodon - en.xcscheme_^#shared#^_ @@ -52,42 +52,42 @@ Mastodon - es-419.xcscheme_^#shared#^_ orderHint - 5 + 8 Mastodon - es.xcscheme_^#shared#^_ orderHint - 4 + 7 Mastodon - fr.xcscheme_^#shared#^_ orderHint - 6 + 9 Mastodon - jp.xcscheme_^#shared#^_ orderHint - 27 + 14 Mastodon - nl.xcscheme_^#shared#^_ orderHint - 9 + 12 Mastodon - ru.xcscheme_^#shared#^_ orderHint - 2 + 4 Mastodon - th.xcscheme_^#shared#^_ orderHint - 3 + 5 Mastodon - zh_Hans.xcscheme_^#shared#^_ orderHint - 30 + 15 Mastodon.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 26 + 36 MastodonIntents.xcscheme_^#shared#^_ @@ -112,12 +112,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 3 + 6 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 23 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Diffiable/DataSource/TableNodeDiffableDataSource.swift b/Mastodon/Diffiable/DataSource/TableNodeDiffableDataSource.swift index 155c8d8af..54ab22a4c 100644 --- a/Mastodon/Diffiable/DataSource/TableNodeDiffableDataSource.swift +++ b/Mastodon/Diffiable/DataSource/TableNodeDiffableDataSource.swift @@ -32,7 +32,7 @@ open class TableNodeDiffableDataSource([]) + let activeUserID = CurrentValueSubject(nil) var diffableDataSource: UITableViewDiffableDataSource! init(context: AppContext) { self.context = context - context.authenticationService.mastodonAuthentications - .map { authentications in - return authentications.map { - Item.authentication(objectID: $0.objectID) + Publishers.CombineLatest( + context.authenticationService.mastodonAuthentications, + context.authenticationService.activeMastodonAuthentication + ) + .sink { [weak self] authentications, activeAuthentication in + guard let self = self else { return } + var items: [Item] = [] + var activeUserID: Mastodon.Entity.Account.ID? + for authentication in authentications { + let item = Item.authentication(objectID: authentication.objectID) + items.append(item) + if authentication === activeAuthentication { + activeUserID = authentication.userID } } - .assign(to: \.value, on: authentications) - .store(in: &disposeBag) + self.authentications.value = items + self.activeUserID.value = activeUserID + } + .store(in: &disposeBag) authentications .receive(on: DispatchQueue.main) @@ -72,7 +85,11 @@ extension AccountListViewModel { let authentication = managedObjectContext.object(with: objectID) as! MastodonAuthentication let user = authentication.user let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AccountListTableViewCell.self), for: indexPath) as! AccountListTableViewCell - AccountListViewModel.configure(cell: cell, user: user) + AccountListViewModel.configure( + cell: cell, + user: user, + activeUserID: self.activeUserID.eraseToAnyPublisher() + ) return cell case .addAccount: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AddAccountTableViewCell.self), for: indexPath) as! AddAccountTableViewCell @@ -87,7 +104,8 @@ extension AccountListViewModel { static func configure( cell: AccountListTableViewCell, - user: MastodonUser + user: MastodonUser, + activeUserID: AnyPublisher ) { // avatar cell.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: user.avatarImageURL())) @@ -103,6 +121,17 @@ extension AccountListViewModel { } // username - cell.usernameLabel.configure(content: PlaintextMetaContent(string: user.acctWithDomain)) + let usernameMetaContent = PlaintextMetaContent(string: "@" + user.acctWithDomain) + cell.usernameLabel.configure(content: usernameMetaContent) + + // checkmark + activeUserID + .receive(on: DispatchQueue.main) + .sink { userID in + let isCurrentUser = user.id == userID + cell.tintColor = .label + cell.accessoryType = isCurrentUser ? .checkmark : .none + } + .store(in: &cell.disposeBag) } } diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index 28ee88c95..3e913da4e 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -96,6 +96,14 @@ extension AccountListViewController { tableView: tableView, managedObjectContext: context.managedObjectContext ) + + if UIAccessibility.isVoiceOverRunning { + let dragIndicatorTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer + dragIndicatorView.addGestureRecognizer(dragIndicatorTapGestureRecognizer) + dragIndicatorTapGestureRecognizer.addTarget(self, action: #selector(AccountListViewController.dragIndicatorTapGestureRecognizerHandler(_:))) + dragIndicatorView.isAccessibilityElement = true + dragIndicatorView.accessibilityLabel = "Dismiss Account Switcher" + } } private func setupBackgroundColor(theme: Theme) { @@ -110,6 +118,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) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + dismiss(animated: true, completion: nil) + } } diff --git a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift index 9125923a1..aec182798 100644 --- a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift @@ -6,26 +6,24 @@ // import UIKit +import Combine import FLAnimatedImage import MetaTextKit -final class CircleAvatarButton: AvatarButton { - override func layoutSubviews() { - super.layoutSubviews() - - layer.masksToBounds = true - layer.cornerRadius = frame.width * 0.5 - layer.borderColor = UIColor.systemFill.cgColor - layer.borderWidth = 1 - } -} - final class AccountListTableViewCell: UITableViewCell { + + var disposeBag = Set() - let avatarButton = CircleAvatarButton() + let avatarButton = CircleAvatarButton(frame: .zero) let nameLabel = MetaLabel(style: .accountListName) let usernameLabel = MetaLabel(style: .accountListUsername) let separatorLine = UIView.separatorLine + + override func prepareForReuse() { + super.prepareForReuse() + + disposeBag.removeAll() + } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -79,7 +77,7 @@ extension AccountListTableViewCell { contentView.addSubview(separatorLine) NSLayoutConstraint.activate([ separatorLine.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), - separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: trailingAnchor), // needs align to edge separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), ]) diff --git a/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift b/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift new file mode 100644 index 000000000..803cc6d3f --- /dev/null +++ b/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift @@ -0,0 +1,124 @@ +// +// MainTabBarController+Wizard.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-15. +// + +import os.log +import UIKit + +protocol WizardDelegate: AnyObject { + func spotlight(item: MainTabBarController.Wizard.Item) -> UIBezierPath + func layoutWizardCard(_ wizard: MainTabBarController.Wizard, item: MainTabBarController.Wizard.Item) +} + +extension MainTabBarController { + class Wizard { + + let logger = Logger(subsystem: "Wizard", category: "UI") + + weak var delegate: WizardDelegate? + + private(set) var items: [Item] + + let backgroundView: UIView = { + let view = UIView() + view.backgroundColor = UIColor.black.withAlphaComponent(0.7) + return view + }() + + init() { + var items: [Item] = [] + if !UserDefaults.shared.didShowMultipleAccountSwitchWizard { + items.append(.multipleAccountSwitch) + } + self.items = items + + let backgroundTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer + backgroundTapGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.Wizard.backgroundTapGestureRecognizerHandler(_:))) + backgroundView.addGestureRecognizer(backgroundTapGestureRecognizer) + } + } +} + +extension MainTabBarController.Wizard { + enum Item { + case multipleAccountSwitch + + var title: String { + return "New in Mastodon" + } + + var description: String { + switch self { + case .multipleAccountSwitch: + return "Switch between multiple accounts by holding the profile button." + } + } + } +} + +extension MainTabBarController.Wizard { + + func setup(in view: UIView) { + assert(delegate != nil, "need set delegate before use") + backgroundView.frame = view.bounds + backgroundView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(backgroundView) + NSLayoutConstraint.activate([ + backgroundView.topAnchor.constraint(equalTo: view.topAnchor), + backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + } + + func consume() { + guard !items.isEmpty else { + backgroundView.removeFromSuperview() + return + } + let item = items.removeFirst() + perform(item: item) + } + + private func perform(item: Item) { + guard let delegate = delegate else { + assertionFailure() + return + } + + prepareForReuse() + + // add spotlight + let spotlight = delegate.spotlight(item: item) + let maskLayer = CAShapeLayer() + let path = UIBezierPath(rect: backgroundView.bounds) + path.append(spotlight) + maskLayer.fillRule = .evenOdd + maskLayer.path = path.cgPath + backgroundView.layer.mask = maskLayer + + // layout wizard card + delegate.layoutWizardCard(self, item: item) + } + + private func prepareForReuse() { + backgroundView.subviews.forEach { subview in + subview.removeFromSuperview() + } + backgroundView.mask = nil + backgroundView.layer.mask = nil + } + +} + +extension MainTabBarController.Wizard { + @objc private func backgroundTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + // TODO: toggle current item preference flag + consume() + } +} diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index 8e6edd2aa..7ff6c1be1 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -18,7 +18,12 @@ class MainTabBarController: UITabBarController { weak var context: AppContext! weak var coordinator: SceneCoordinator! + + static let avatarButtonSize = CGSize(width: 28, height: 28) + let avatarButton = CircleAvatarButton() + let wizard = Wizard() + var currentTab = Tab.home enum Tab: Int, CaseIterable { @@ -210,6 +215,31 @@ extension MainTabBarController { self.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show) } .store(in: &disposeBag) + + layoutAvatarButton() + context.authenticationService.activeMastodonAuthentication + .receive(on: DispatchQueue.main) + .sink { [weak self] activeMastodonAuthentication in + guard let self = self else { return } + + let avatarImageURL = activeMastodonAuthentication?.user.avatarImageURL() + self.avatarButton.avatarImageView.setImage( + url: avatarImageURL, + placeholder: .placeholder(color: .systemFill), + scaleToSize: MainTabBarController.avatarButtonSize + ) + + // a11y + let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag } + guard let profileTabItem = _profileTabItem else { return } + + let currentUserDisplayName = activeMastodonAuthentication?.user.displayNameWithFallback ?? "no user" + profileTabItem.accessibilityHint = "Current selected profile: \(currentUserDisplayName). Double tap then hold to show account switcher" + } + .store(in: &disposeBag) + + wizard.delegate = self + wizard.setup(in: view) let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer() tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:))) @@ -219,6 +249,12 @@ extension MainTabBarController { // selectedIndex = 1 #endif } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + wizard.consume() + } } @@ -249,6 +285,38 @@ extension MainTabBarController { } } +extension MainTabBarController { + private func layoutAvatarButton() { + guard avatarButton.superview == nil else { return } + + let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag } + guard let profileTabItem = _profileTabItem else { return } + guard let view = profileTabItem.value(forKey: "view") as? UIView else { + return + } + + let _anchorImageView = view.subviews.first { subview in subview is UIImageView } as? UIImageView + guard let anchorImageView = _anchorImageView else { + assertionFailure() + return + } + anchorImageView.alpha = 0 + + self.avatarButton.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(self.avatarButton) + NSLayoutConstraint.activate([ + self.avatarButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + 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), + ]) + self.avatarButton.setContentHuggingPriority(.required - 1, for: .horizontal) + self.avatarButton.setContentHuggingPriority(.required - 1, for: .vertical) + self.avatarButton.isUserInteractionEnabled = false + } + +} + extension MainTabBarController { var notificationViewController: NotificationViewController? { @@ -277,6 +345,53 @@ extension MainTabBarController: UITabBarControllerDelegate { } } +// MARK: - WizardDataSource +extension MainTabBarController: WizardDelegate { + func spotlight(item: Wizard.Item) -> UIBezierPath { + switch item { + case .multipleAccountSwitch: + guard let avatarButtonFrameInView = avatarButtonFrameInView() else { + return UIBezierPath() + } + return UIBezierPath(ovalIn: avatarButtonFrameInView) + + } + } + + func layoutWizardCard(_ wizard: MainTabBarController.Wizard, item: Wizard.Item) { + switch item { + case .multipleAccountSwitch: + guard let avatarButtonFrameInView = avatarButtonFrameInView() else { + return + } + let anchorView = UIView() + anchorView.frame = avatarButtonFrameInView + wizard.backgroundView.addSubview(anchorView) + + let wizardCardView = WizardCardView() + wizardCardView.arrowRectCorner = view.traitCollection.layoutDirection == .leftToRight ? .bottomRight : .bottomLeft + wizardCardView.titleLabel.text = item.title + wizardCardView.descriptionLabel.text = item.description + + wizardCardView.translatesAutoresizingMaskIntoConstraints = false + wizard.backgroundView.addSubview(wizardCardView) + NSLayoutConstraint.activate([ + anchorView.topAnchor.constraint(equalTo: wizardCardView.bottomAnchor, constant: 13), // 13pt spacing + wizardCardView.trailingAnchor.constraint(equalTo: anchorView.centerXAnchor), + wizardCardView.widthAnchor.constraint(equalTo: wizard.backgroundView.widthAnchor, multiplier: 2.0/3.0).priority(.required - 1), + ]) + wizardCardView.setContentHuggingPriority(.defaultLow, for: .vertical) + } + } + + private func avatarButtonFrameInView() -> CGRect? { + guard let superview = avatarButton.superview else { + assertionFailure() + return nil + } + return superview.convert(avatarButton.frame, to: view) + } +} // HIG: keyboard UX // https://developer.apple.com/design/human-interface-guidelines/macos/user-interaction/keyboard/ diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift new file mode 100644 index 000000000..7855d76d6 --- /dev/null +++ b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift @@ -0,0 +1,110 @@ +// +// WizardCardView.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-15. +// + +import UIKit + +final class WizardCardView: UIView { + + static let bubbleArrowHeight: CGFloat = 17 + static let bubbleArrowWidth: CGFloat = 20 + + let contentView = UIView() + + let backgroundShapeLayer = CAShapeLayer() + var arrowRectCorner: UIRectCorner = .bottomRight + + let titleLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) + label.textColor = .black + return label + }() + + let descriptionLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) + label.textColor = .black + label.numberOfLines = 0 + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension WizardCardView { + private func _init() { + layer.masksToBounds = false + layer.addSublayer(backgroundShapeLayer) + + contentView.translatesAutoresizingMaskIntoConstraints = false + addSubview(contentView) + NSLayoutConstraint.activate([ + contentView.topAnchor.constraint(equalTo: topAnchor, constant: WizardCardView.bubbleArrowHeight), + contentView.leadingAnchor.constraint(equalTo: leadingAnchor), + trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: WizardCardView.bubbleArrowHeight), + ]) + + let containerStackView = UIStackView() + containerStackView.axis = .vertical + containerStackView.spacing = 2 + containerStackView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(containerStackView) + NSLayoutConstraint.activate([ + containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5), + containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 7), + contentView.trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor, constant: 24), + contentView.bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 5), + ]) + + containerStackView.addArrangedSubview(titleLabel) + containerStackView.addArrangedSubview(descriptionLabel) + } + + override func layoutSubviews() { + super.layoutSubviews() + + let radius: CGFloat = 5 + let rect = contentView.frame + let path = UIBezierPath() + + switch arrowRectCorner { + case .bottomRight: + path.move(to: CGPoint(x: rect.maxX - WizardCardView.bubbleArrowWidth, y: rect.maxY + radius)) + path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.maxY), radius: radius, startAngle: .pi / 2, endAngle: .pi, clockwise: true) + path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: .pi, endAngle: .pi / 2 * 3, clockwise: true) + path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.minY), radius: radius, startAngle: .pi / 2 * 3, endAngle: .pi * 2, clockwise: true) + path.addLine(to: CGPoint(x: rect.maxX + radius, y: rect.maxY + radius + WizardCardView.bubbleArrowHeight)) + path.close() + case .bottomLeft: + path.move(to: CGPoint(x: rect.minX + WizardCardView.bubbleArrowWidth, y: rect.maxY + radius)) + path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.maxY), radius: radius, startAngle: .pi / 2, endAngle: 0, clockwise: false) + path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.minY), radius: radius, startAngle: 0, endAngle: -.pi / 2, clockwise: false) + path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: -.pi / 2, endAngle: -.pi, clockwise: false) + path.addLine(to: CGPoint(x: rect.minX - radius, y: rect.maxY + radius + WizardCardView.bubbleArrowHeight)) + path.close() + default: + assertionFailure("FIXME") + } + + backgroundShapeLayer.lineCap = .round + backgroundShapeLayer.lineJoin = .round + backgroundShapeLayer.lineWidth = 3 + backgroundShapeLayer.strokeColor = UIColor.white.cgColor + backgroundShapeLayer.fillColor = UIColor.white.cgColor + backgroundShapeLayer.path = path.cgPath + } +} diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index 8dba6d700..e424d350a 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -7,15 +7,21 @@ import os.log import UIKit +import Combine final class WelcomeViewController: UIViewController, NeedsDependency { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + var disposeBag = Set() + private(set) lazy var viewModel = WelcomeViewModel(context: context) + let welcomeIllustrationView = WelcomeIllustrationView() var welcomeIllustrationViewBottomAnchorLayoutConstraint: NSLayoutConstraint? + private(set) lazy var dismissBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(WelcomeViewController.dismissBarButtonItemDidPressed(_:))) + private(set) lazy var logoImageView: UIImageView = { let image = view.traitCollection.userInterfaceIdiom == .phone ? Asset.Scene.Welcome.mastodonLogo.image : Asset.Scene.Welcome.mastodonLogoBlackLarge.image let imageView = UIImageView(image: image) @@ -90,6 +96,14 @@ extension WelcomeViewController { signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside) signInButton.addTarget(self, action: #selector(signInButtonDidClicked(_:)), for: .touchUpInside) + + viewModel.needsShowDismissEntry + .receive(on: DispatchQueue.main) + .sink { [weak self] needsShowDismissEntry in + guard let self = self else { return } + self.navigationItem.leftBarButtonItem = needsShowDismissEntry ? self.dismissBarButtonItem : nil + } + .store(in: &disposeBag) } override func viewSafeAreaInsetsDidChange() { @@ -213,6 +227,11 @@ extension WelcomeViewController { private func signInButtonDidClicked(_ sender: UIButton) { coordinator.present(scene: .mastodonPickServer(viewMode: MastodonPickServerViewModel(context: context, mode: .signIn)), from: self, transition: .show) } + + @objc + private func dismissBarButtonItemDidPressed(_ sender: UIButton) { + dismiss(animated: true, completion: nil) + } } // MARK: - OnboardingViewControllerAppearance diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift new file mode 100644 index 000000000..74b13b1a8 --- /dev/null +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewModel.swift @@ -0,0 +1,30 @@ +// +// WelcomeViewModel.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-15. +// + +import Foundation +import Combine + +final class WelcomeViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + + // output + let needsShowDismissEntry = CurrentValueSubject(false) + + init(context: AppContext) { + self.context = context + + context.authenticationService.mastodonAuthentications + .map { !$0.isEmpty } + .assign(to: \.value, on: needsShowDismissEntry) + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Share/View/Button/AvatarButton.swift b/Mastodon/Scene/Share/View/Button/AvatarButton.swift index a8f7212ae..9bc87a053 100644 --- a/Mastodon/Scene/Share/View/Button/AvatarButton.swift +++ b/Mastodon/Scene/Share/View/Button/AvatarButton.swift @@ -28,6 +28,7 @@ class AvatarButton: UIControl { } func _init() { + avatarImageView.frame = bounds avatarImageView.translatesAutoresizingMaskIntoConstraints = false addSubview(avatarImageView) NSLayoutConstraint.activate([ diff --git a/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift b/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift new file mode 100644 index 000000000..40272d290 --- /dev/null +++ b/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift @@ -0,0 +1,20 @@ +// +// CircleAvatarButton.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-15. +// + +import UIKit + +final class CircleAvatarButton: AvatarButton { + + override func layoutSubviews() { + super.layoutSubviews() + + layer.masksToBounds = true + layer.cornerRadius = frame.width * 0.5 + layer.borderColor = UIColor.systemFill.cgColor + layer.borderWidth = 1 + } +} diff --git a/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift b/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift index 2f640a140..170543482 100644 --- a/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift +++ b/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift @@ -121,7 +121,7 @@ final class StatusNode: ASCellNode { // } for imageNode in mediaMultiplexImageNodes { - imageNode.dataSource = self + imageNode.delegate = self } } From 1d554a3d9e93f478ab66299df64d2e4ac2fa4c39 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 15 Sep 2021 20:26:45 +0800 Subject: [PATCH 081/392] chore: update version to 1.1.0 (61) --- AppShared/Info.plist | 4 +- CoreDataStack/Info.plist | 4 +- CoreDataStackTests/Info.plist | 4 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++++++++--------------- Mastodon/Info.plist | 4 +- MastodonIntent/Info.plist | 4 +- MastodonTests/Info.plist | 4 +- MastodonUITests/Info.plist | 4 +- NotificationService/Info.plist | 4 +- ShareActionExtension/Info.plist | 4 +- 10 files changed, 50 insertions(+), 50 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 889a6a010..f7c58d0a7 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 889a6a010..f7c58d0a7 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 889a6a010..f7c58d0a7 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 504a29ea1..28d55c93f 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4691,7 +4691,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4719,7 +4719,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4826,11 +4826,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4857,11 +4857,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4886,11 +4886,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4916,11 +4916,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4983,7 +4983,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5008,7 +5008,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5033,7 +5033,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5058,7 +5058,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5083,7 +5083,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5108,7 +5108,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5133,7 +5133,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5158,7 +5158,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5249,7 +5249,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5315,11 +5315,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5364,7 +5364,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5389,11 +5389,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5485,7 +5485,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5551,11 +5551,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5600,7 +5600,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5625,11 +5625,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 60; + DYLIB_CURRENT_VERSION = 61; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5655,7 +5655,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5679,7 +5679,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 60; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 8190cdbbe..59c8b7297 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleURLTypes @@ -28,7 +28,7 @@ CFBundleVersion - 60 + 61 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index cfc2744b7..9d54c3878 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 889a6a010..f7c58d0a7 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 889a6a010..f7c58d0a7 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index cd6753939..c457414df 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 7cfb6436e..190dddeb8 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.8 + 1.1.0 CFBundleVersion - 60 + 61 NSExtension NSExtensionAttributes From 76efa7162e15542567e662ca289351402676c55b Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 11:41:56 +0800 Subject: [PATCH 082/392] chore: update avatar icon UI --- Mastodon/Scene/MainTab/MainTabBarController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index 7ff6c1be1..ca978a5a2 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -306,7 +306,7 @@ extension MainTabBarController { view.addSubview(self.avatarButton) NSLayoutConstraint.activate([ self.avatarButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor), + self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor, constant: 1), // 1pt offset self.avatarButton.widthAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.width).priority(.required - 1), self.avatarButton.heightAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.height).priority(.required - 1), ]) From 7dea01da1e0e5fbeaff974b9a1fec1eb32a7c5ed Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 12:23:47 +0800 Subject: [PATCH 083/392] fix: checkmark display logic and account list not scrollable in PanModal issue --- .../Scene/Account/AccountListViewModel.swift | 23 +++++++++++-------- .../Scene/Account/AccountViewController.swift | 10 +++++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Mastodon/Scene/Account/AccountListViewModel.swift b/Mastodon/Scene/Account/AccountListViewModel.swift index 09d3d53d4..a70209eeb 100644 --- a/Mastodon/Scene/Account/AccountListViewModel.swift +++ b/Mastodon/Scene/Account/AccountListViewModel.swift @@ -21,7 +21,8 @@ final class AccountListViewModel { // output let authentications = CurrentValueSubject<[Item], Never>([]) - let activeUserID = CurrentValueSubject(nil) + let activeMastodonUserObjectID = CurrentValueSubject(nil) + let dataSourceDidUpdate = PassthroughSubject() var diffableDataSource: UITableViewDiffableDataSource! init(context: AppContext) { @@ -34,16 +35,16 @@ final class AccountListViewModel { .sink { [weak self] authentications, activeAuthentication in guard let self = self else { return } var items: [Item] = [] - var activeUserID: Mastodon.Entity.Account.ID? + var activeMastodonUserObjectID: NSManagedObjectID? for authentication in authentications { let item = Item.authentication(objectID: authentication.objectID) items.append(item) if authentication === activeAuthentication { - activeUserID = authentication.userID + activeMastodonUserObjectID = authentication.user.objectID } } self.authentications.value = items - self.activeUserID.value = activeUserID + self.activeMastodonUserObjectID.value = activeMastodonUserObjectID } .store(in: &disposeBag) @@ -58,7 +59,9 @@ final class AccountListViewModel { snapshot.appendItems(authentications, toSection: .main) snapshot.appendItems([.addAccount], toSection: .main) - diffableDataSource.apply(snapshot) + diffableDataSource.apply(snapshot) { + self.dataSourceDidUpdate.send() + } } .store(in: &disposeBag) } @@ -88,7 +91,7 @@ extension AccountListViewModel { AccountListViewModel.configure( cell: cell, user: user, - activeUserID: self.activeUserID.eraseToAnyPublisher() + activeMastodonUserObjectID: self.activeMastodonUserObjectID.eraseToAnyPublisher() ) return cell case .addAccount: @@ -105,7 +108,7 @@ extension AccountListViewModel { static func configure( cell: AccountListTableViewCell, user: MastodonUser, - activeUserID: AnyPublisher + activeMastodonUserObjectID: AnyPublisher ) { // avatar cell.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: user.avatarImageURL())) @@ -125,10 +128,10 @@ extension AccountListViewModel { cell.usernameLabel.configure(content: usernameMetaContent) // checkmark - activeUserID + activeMastodonUserObjectID .receive(on: DispatchQueue.main) - .sink { userID in - let isCurrentUser = user.id == userID + .sink { objectID in + let isCurrentUser = user.objectID == objectID cell.tintColor = .label cell.accessoryType = isCurrentUser ? .checkmark : .none } diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index 3e913da4e..a7a0992e1 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -38,8 +38,8 @@ final class AccountListViewController: UIViewController, NeedsDependency { tableView.register(AccountListTableViewCell.self, forCellReuseIdentifier: String(describing: AccountListTableViewCell.self)) tableView.register(AddAccountTableViewCell.self, forCellReuseIdentifier: String(describing: AddAccountTableViewCell.self)) tableView.backgroundColor = .clear - tableView.tableFooterView = UIView() tableView.separatorStyle = .none + tableView.tableFooterView = UIView() return tableView }() @@ -97,6 +97,14 @@ extension AccountListViewController { managedObjectContext: context.managedObjectContext ) + viewModel.dataSourceDidUpdate + .receive(on: DispatchQueue.main) + .sink { [weak self] in + guard let self = self else { return } + self.panModalSetNeedsLayoutUpdate() + } + .store(in: &disposeBag) + if UIAccessibility.isVoiceOverRunning { let dragIndicatorTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer dragIndicatorView.addGestureRecognizer(dragIndicatorTapGestureRecognizer) From 5a746ef8818c710d8b45b459d38139883c24cbff Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 16:30:21 +0800 Subject: [PATCH 084/392] feat: add notification badge in AccountList scene --- AppShared/UserDefaults.swift | 32 +++++++++++++ Localization/app.json | 3 +- Mastodon.xcodeproj/project.pbxproj | 6 +++ Mastodon/Generated/Assets.swift | 1 + .../badge.background.colorset/Contents.json | 20 ++++++++ .../Colors/danger.colorset/Contents.json | 18 ++++---- .../Scene/Account/AccountListViewModel.swift | 27 +++++++++-- .../Cell/AccountListTableViewCell.swift | 32 ++++++++++++- Mastodon/Scene/Account/View/BadgeButton.swift | 46 +++++++++++++++++++ ...meTimelineViewController+DebugAction.swift | 42 +++++++++++++---- .../Scene/MainTab/MainTabBarController.swift | 30 +++++++----- .../NotificationViewController.swift | 10 ++++ ...otificationViewModel+LoadLatestState.swift | 2 - .../Welcome/View/WizardCardView.swift | 24 ++++++++++ Mastodon/Service/NotificationService.swift | 38 ++++++++++++++- Mastodon/Supporting Files/AppDelegate.swift | 5 ++ Mastodon/Supporting Files/SceneDelegate.swift | 5 +- NotificationService/NotificationService.swift | 3 ++ 18 files changed, 302 insertions(+), 42 deletions(-) create mode 100644 Mastodon/Resources/Assets.xcassets/Colors/badge.background.colorset/Contents.json create mode 100644 Mastodon/Scene/Account/View/BadgeButton.swift diff --git a/AppShared/UserDefaults.swift b/AppShared/UserDefaults.swift index 9cecdcf60..67a3cf685 100644 --- a/AppShared/UserDefaults.swift +++ b/AppShared/UserDefaults.swift @@ -6,7 +6,39 @@ // import UIKit +import CryptoKit extension UserDefaults { public static let shared = UserDefaults(suiteName: AppName.groupID)! } + +extension UserDefaults { + // always use hash value (SHA256) from accessToken as key + private static func deriveKey(from accessToken: String, prefix: String) -> String { + let digest = SHA256.hash(data: Data(accessToken.utf8)) + let bytes = [UInt8](digest) + let hex = bytes.toHexString() + let key = prefix + "@" + hex + return key + } + + private static let notificationCountKeyPrefix = "notification_count" + + public func getNotificationCountWithAccessToken(accessToken: String) -> Int { + let prefix = UserDefaults.notificationCountKeyPrefix + let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix) + return integer(forKey: key) + } + + public func setNotificationCountWithAccessToken(accessToken: String, value: Int) { + let prefix = UserDefaults.notificationCountKeyPrefix + let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix) + setValue(value, forKey: key) + } + + public func increaseNotificationCount(accessToken: String) { + let count = getNotificationCountWithAccessToken(accessToken: accessToken) + setNotificationCountWithAccessToken(accessToken: accessToken, value: count + 1) + } + +} diff --git a/Localization/app.json b/Localization/app.json index ce307a2e0..f4c3ffb5a 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -541,7 +541,8 @@ "add_account": "Add Account", }, "wizard": { - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button." + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 28d55c93f..c67b879ea 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -265,6 +265,8 @@ DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4924E126312AB200E9DB22 /* NotificationService.swift */; }; DB4932B126F1FB5300EF46D4 /* WizardCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */; }; DB4932B326F2054200EF46D4 /* CircleAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4932B226F2054200EF46D4 /* CircleAvatarButton.swift */; }; + DB4932B726F30F0700EF46D4 /* Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F20223826146553000C64BF /* Array.swift */; }; + DB4932B926F31AD300EF46D4 /* BadgeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4932B826F31AD300EF46D4 /* BadgeButton.swift */; }; DB49A61425FF2C5600B98345 /* EmojiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A61325FF2C5600B98345 /* EmojiService.swift */; }; DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift */; }; DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB49A62425FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift */; }; @@ -1024,6 +1026,7 @@ DB4924E126312AB200E9DB22 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardCardView.swift; sourceTree = ""; }; DB4932B226F2054200EF46D4 /* CircleAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleAvatarButton.swift; sourceTree = ""; }; + DB4932B826F31AD300EF46D4 /* BadgeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeButton.swift; sourceTree = ""; }; DB49A61325FF2C5600B98345 /* EmojiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiService.swift; sourceTree = ""; }; DB49A61E25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmojiViewModel.swift"; sourceTree = ""; }; DB49A62425FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EmojiService+CustomEmojiViewModel+LoadState.swift"; sourceTree = ""; }; @@ -2817,6 +2820,7 @@ isa = PBXGroup; children = ( DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */, + DB4932B826F31AD300EF46D4 /* BadgeButton.swift */, ); path = View; sourceTree = ""; @@ -4155,6 +4159,7 @@ 2D69CFF425CA9E2200C3A1B2 /* LoadMoreConfigurableTableViewContainer.swift in Sources */, DB482A4B261340A7008AE74C /* APIService+UserTimeline.swift in Sources */, DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */, + DB4932B926F31AD300EF46D4 /* BadgeButton.swift in Sources */, 0F2021FB2613262F000C64BF /* HashtagTimelineViewController.swift in Sources */, DBCC3B30261440A50045B23D /* UITabBarController.swift in Sources */, DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */, @@ -4236,6 +4241,7 @@ buildActionMask = 2147483647; files = ( DB6804D12637CE4700430867 /* UserDefaults.swift in Sources */, + DB4932B726F30F0700EF46D4 /* Array.swift in Sources */, DB6804922637CD8700430867 /* AppName.swift in Sources */, DB6804FD2637CFEC00430867 /* AppSecret.swift in Sources */, ); diff --git a/Mastodon/Generated/Assets.swift b/Mastodon/Generated/Assets.swift index f3ef1088e..36edb7bcd 100644 --- a/Mastodon/Generated/Assets.swift +++ b/Mastodon/Generated/Assets.swift @@ -70,6 +70,7 @@ internal enum Asset { internal static let valid = ColorAsset(name: "Colors/TextField/valid") } internal static let alertYellow = ColorAsset(name: "Colors/alert.yellow") + internal static let badgeBackground = ColorAsset(name: "Colors/badge.background") internal static let battleshipGrey = ColorAsset(name: "Colors/battleshipGrey") internal static let brandBlue = ColorAsset(name: "Colors/brand.blue") internal static let brandBlueDarken20 = ColorAsset(name: "Colors/brand.blue.darken.20") diff --git a/Mastodon/Resources/Assets.xcassets/Colors/badge.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/badge.background.colorset/Contents.json new file mode 100644 index 000000000..f58a604a1 --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Colors/badge.background.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "48", + "green" : "59", + "red" : "255" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Colors/danger.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/danger.colorset/Contents.json index 8ea3105e6..b77cb3c75 100644 --- a/Mastodon/Resources/Assets.xcassets/Colors/danger.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Colors/danger.colorset/Contents.json @@ -1,20 +1,20 @@ { - "info" : { - "version" : 1, - "author" : "xcode" - }, "colors" : [ { "color" : { "color-space" : "srgb", "components" : { "alpha" : "1.000", - "red" : "0.875", - "blue" : "0.353", - "green" : "0.251" + "blue" : "90", + "green" : "64", + "red" : "223" } }, "idiom" : "universal" } - ] -} \ No newline at end of file + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Scene/Account/AccountListViewModel.swift b/Mastodon/Scene/Account/AccountListViewModel.swift index a70209eeb..1977b90ec 100644 --- a/Mastodon/Scene/Account/AccountListViewModel.swift +++ b/Mastodon/Scene/Account/AccountListViewModel.swift @@ -86,11 +86,10 @@ extension AccountListViewModel { switch item { case .authentication(let objectID): let authentication = managedObjectContext.object(with: objectID) as! MastodonAuthentication - let user = authentication.user let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: AccountListTableViewCell.self), for: indexPath) as! AccountListTableViewCell AccountListViewModel.configure( cell: cell, - user: user, + authentication: authentication, activeMastodonUserObjectID: self.activeMastodonUserObjectID.eraseToAnyPublisher() ) return cell @@ -107,9 +106,11 @@ extension AccountListViewModel { static func configure( cell: AccountListTableViewCell, - user: MastodonUser, + authentication: MastodonAuthentication, activeMastodonUserObjectID: AnyPublisher ) { + let user = authentication.user + // avatar cell.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: user.avatarImageURL())) @@ -127,14 +128,32 @@ extension AccountListViewModel { let usernameMetaContent = PlaintextMetaContent(string: "@" + user.acctWithDomain) cell.usernameLabel.configure(content: usernameMetaContent) + // badge + let accessToken = authentication.userAccessToken + let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken) + cell.badgeButton.setBadge(number: count) + // checkmark activeMastodonUserObjectID .receive(on: DispatchQueue.main) .sink { objectID in let isCurrentUser = user.objectID == objectID cell.tintColor = .label - cell.accessoryType = isCurrentUser ? .checkmark : .none + cell.checkmarkImageView.isHidden = !isCurrentUser + if isCurrentUser { + cell.accessibilityTraits.insert(.selected) + } else { + cell.accessibilityTraits.remove(.selected) + } } .store(in: &cell.disposeBag) + + cell.accessibilityLabel = [ + cell.nameLabel.text, + cell.usernameLabel.text, + cell.badgeButton.accessibilityLabel + ] + .compactMap { $0 } + .joined(separator: " ") } } diff --git a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift index aec182798..4c9977f37 100644 --- a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift @@ -17,6 +17,13 @@ final class AccountListTableViewCell: UITableViewCell { let avatarButton = CircleAvatarButton(frame: .zero) let nameLabel = MetaLabel(style: .accountListName) let usernameLabel = MetaLabel(style: .accountListUsername) + let badgeButton = BadgeButton() + let checkmarkImageView: UIImageView = { + let image = UIImage(systemName: "checkmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .semibold)) + let imageView = UIImageView(image: image) + imageView.tintColor = .label + return imageView + }() let separatorLine = UIView.separatorLine override func prepareForReuse() { @@ -63,15 +70,36 @@ extension AccountListTableViewCell { labelContainerStackView.leadingAnchor.constraint(equalTo: avatarButton.trailingAnchor, constant: 10), contentView.bottomAnchor.constraint(equalTo: labelContainerStackView.bottomAnchor, constant: 10), avatarButton.heightAnchor.constraint(equalTo: labelContainerStackView.heightAnchor, multiplier: 0.8).priority(.required - 10), - labelContainerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), ]) labelContainerStackView.addArrangedSubview(nameLabel) labelContainerStackView.addArrangedSubview(usernameLabel) - + + badgeButton.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(badgeButton) + NSLayoutConstraint.activate([ + badgeButton.leadingAnchor.constraint(equalTo: labelContainerStackView.trailingAnchor, constant: 4), + badgeButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + badgeButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 16).priority(.required - 1), + badgeButton.widthAnchor.constraint(equalTo: badgeButton.heightAnchor, multiplier: 1.0).priority(.required - 1), + ]) + badgeButton.setContentHuggingPriority(.required - 10, for: .horizontal) + badgeButton.setContentCompressionResistancePriority(.required - 10, for: .horizontal) + + checkmarkImageView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(checkmarkImageView) + NSLayoutConstraint.activate([ + checkmarkImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + checkmarkImageView.leadingAnchor.constraint(equalTo: badgeButton.trailingAnchor, constant: 12), + checkmarkImageView.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), + ]) + checkmarkImageView.setContentHuggingPriority(.required - 9, for: .horizontal) + checkmarkImageView.setContentCompressionResistancePriority(.required - 9, for: .horizontal) + avatarButton.isUserInteractionEnabled = false nameLabel.isUserInteractionEnabled = false usernameLabel.isUserInteractionEnabled = false + badgeButton.isUserInteractionEnabled = false separatorLine.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(separatorLine) diff --git a/Mastodon/Scene/Account/View/BadgeButton.swift b/Mastodon/Scene/Account/View/BadgeButton.swift new file mode 100644 index 000000000..c55448ae4 --- /dev/null +++ b/Mastodon/Scene/Account/View/BadgeButton.swift @@ -0,0 +1,46 @@ +// +// BadgeButton.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-16. +// + +import UIKit + +final class BadgeButton: UIButton { + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension BadgeButton { + private func _init() { + titleLabel?.font = UIFontMetrics(forTextStyle: .caption1).scaledFont(for: .systemFont(ofSize: 13, weight: .medium)) + setBackgroundColor(Asset.Colors.badgeBackground.color, for: .normal) + setTitleColor(.white, for: .normal) + + contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) + } + + override func layoutSubviews() { + super.layoutSubviews() + + layer.masksToBounds = true + layer.cornerRadius = frame.height * 0.5 + } + + func setBadge(number: Int) { + let number = min(99, max(0, number)) + setTitle("\(number)", for: .normal) + self.isHidden = number == 0 + accessibilityLabel = "\(number) unread notification" + } +} diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index 4d9bb470f..b0fddb445 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -26,14 +26,7 @@ extension HomeTimelineViewController { showMenu, moveMenu, dropMenu, - UIAction(title: "Toggle EmptyView", image: UIImage(systemName: "clear"), attributes: []) { [weak self] action in - guard let self = self else { return } - if self.emptyView.superview != nil { - self.emptyView.removeFromSuperview() - } else { - self.showEmptyView() - } - }, + miscMenu, UIAction(title: "Settings", image: UIImage(systemName: "gear"), attributes: []) { [weak self] action in guard let self = self else { return } self.showSettings(action) @@ -139,6 +132,39 @@ extension HomeTimelineViewController { } ) } + + var miscMenu: UIMenu { + return UIMenu( + title: "Debug…", + image: UIImage(systemName: "switch.2"), + identifier: nil, + options: [], + children: [ + UIAction(title: "Toggle EmptyView", image: UIImage(systemName: "clear"), attributes: []) { [weak self] action in + guard let self = self else { return } + if self.emptyView.superview != nil { + self.emptyView.removeFromSuperview() + } else { + self.showEmptyView() + } + }, + UIAction( + title: "notification badge +1", + image: UIImage(systemName: "1.circle.fill"), + identifier: nil, + attributes: [], + state: .off, + handler: { [weak self] _ in + guard let self = self else { return } + guard let accessToken = self.context.authenticationService.activeMastodonAuthentication.value?.userAccessToken else { return } + UserDefaults.shared.increaseNotificationCount(accessToken: accessToken) + self.context.notificationService.applicationIconBadgeNeedsUpdate.send() + } + ) + ] + ) + } + } extension HomeTimelineViewController { diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index ca978a5a2..f07a1f905 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -194,17 +194,25 @@ extension MainTabBarController { .store(in: &disposeBag) // handle push notification. toggle entry when finish fetch latest notification - context.notificationService.hasUnreadPushNotification - .receive(on: DispatchQueue.main) - .sink { [weak self] hasUnreadPushNotification in - guard let self = self else { return } - guard let notificationViewController = self.notificationViewController else { return } - - let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge.fill")! : UIImage(systemName: "bell.fill")! - notificationViewController.tabBarItem.image = image - notificationViewController.navigationController?.tabBarItem.image = image - } - .store(in: &disposeBag) + Publishers.CombineLatest( + context.authenticationService.activeMastodonAuthentication, + context.notificationService.unreadNotificationCountDidUpdate + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] authentication, _ in + guard let self = self else { return } + guard let notificationViewController = self.notificationViewController else { return } + + let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in + let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken) + return count > 0 + } ?? false + + let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge.fill")! : UIImage(systemName: "bell.fill")! + notificationViewController.tabBarItem.image = image + notificationViewController.navigationController?.tabBarItem.image = image + } + .store(in: &disposeBag) context.notificationService.requestRevealNotificationPublisher .receive(on: DispatchQueue.main) diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift index 100cd3d82..e00749657 100644 --- a/Mastodon/Scene/Notification/NotificationViewController.swift +++ b/Mastodon/Scene/Notification/NotificationViewController.swift @@ -166,6 +166,16 @@ extension NotificationViewController { self.viewModel.loadLatestStateMachine.enter(NotificationViewModel.LoadLatestState.Loading.self) } } + + // reset notification count + context.notificationService.clearNotificationCountForActiveUser() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + // reset notification count + context.notificationService.clearNotificationCountForActiveUser() } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { diff --git a/Mastodon/Scene/Notification/NotificationViewModel+LoadLatestState.swift b/Mastodon/Scene/Notification/NotificationViewModel+LoadLatestState.swift index 04d33202f..dac7bb7d3 100644 --- a/Mastodon/Scene/Notification/NotificationViewModel+LoadLatestState.swift +++ b/Mastodon/Scene/Notification/NotificationViewModel+LoadLatestState.swift @@ -67,8 +67,6 @@ extension NotificationViewModel.LoadLatestState { viewModel.isFetchingLatestNotification.value = false os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch notification failed. %s", (#file as NSString).lastPathComponent, #line, #function, error.localizedDescription) case .finished: - // toggle unread state - viewModel.context.notificationService.hasUnreadPushNotification.value = false // handle isFetchingLatestTimeline in fetch controller delegate break } diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift index 7855d76d6..defe6f4ee 100644 --- a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift +++ b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift @@ -107,4 +107,28 @@ extension WizardCardView { backgroundShapeLayer.fillColor = UIColor.white.cgColor backgroundShapeLayer.path = path.cgPath } + + override var isAccessibilityElement: Bool { + get { true } + set { } + } + + override var accessibilityLabel: String? { + get { + return [ + titleLabel.text, + descriptionLabel.text + ] + .compactMap { $0 } + .joined(separator: " ") + } + set { } + } + + override var accessibilityHint: String? { + get { + return "Wizard for account switcher on the Profile tab. Double tap to dismiss this wizard" + } + set { } + } } diff --git a/Mastodon/Service/NotificationService.swift b/Mastodon/Service/NotificationService.swift index ffe4c9916..6437e1b66 100644 --- a/Mastodon/Service/NotificationService.swift +++ b/Mastodon/Service/NotificationService.swift @@ -24,11 +24,12 @@ final class NotificationService { weak var authenticationService: AuthenticationService? let isNotificationPermissionGranted = CurrentValueSubject(false) let deviceToken = CurrentValueSubject(nil) + let applicationIconBadgeNeedsUpdate = CurrentValueSubject(Void()) // output /// [Token: UserID] let notificationSubscriptionDict: [String: NotificationViewModel] = [:] - let hasUnreadPushNotification = CurrentValueSubject(false) + let unreadNotificationCountDidUpdate = CurrentValueSubject(Void()) let requestRevealNotificationPublisher = PassthroughSubject() init( @@ -57,6 +58,26 @@ final class NotificationService { os_log(.info, log: .api, "%{public}s[%{public}ld], %{public}s: deviceToken: %s", ((#file as NSString).lastPathComponent), #line, #function, token) } .store(in: &disposeBag) + + Publishers.CombineLatest( + authenticationService.mastodonAuthentications, + applicationIconBadgeNeedsUpdate + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] mastodonAuthentications, _ in + guard let self = self else { return } + + var count = 0 + for authentication in mastodonAuthentications { + count += UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken) + } + + UserDefaults.shared.notificationBadgeCount = count + UIApplication.shared.applicationIconBadgeNumber = count + + self.unreadNotificationCountDidUpdate.send() + } + .store(in: &disposeBag) } } @@ -101,7 +122,9 @@ extension NotificationService { } func handle(mastodonPushNotification: MastodonPushNotification) { - hasUnreadPushNotification.value = true + defer { + unreadNotificationCountDidUpdate.send() + } // Subscription maybe failed to cancel when sign-out // Try cancel again if receive that kind push notification @@ -154,6 +177,17 @@ extension NotificationService { } +extension NotificationService { + func clearNotificationCountForActiveUser() { + guard let authenticationService = self.authenticationService else { return } + if let accessToken = authenticationService.activeMastodonAuthentication.value?.userAccessToken { + UserDefaults.shared.setNotificationCountWithAccessToken(accessToken: accessToken, value: 0) + } + + applicationIconBadgeNeedsUpdate.send() + } +} + // MARK: - NotificationViewModel extension NotificationService { diff --git a/Mastodon/Supporting Files/AppDelegate.swift b/Mastodon/Supporting Files/AppDelegate.swift index 56382babf..192f201d1 100644 --- a/Mastodon/Supporting Files/AppDelegate.swift +++ b/Mastodon/Supporting Files/AppDelegate.swift @@ -100,6 +100,11 @@ extension AppDelegate: UNUserNotificationCenterDelegate { let notificationID = String(mastodonPushNotification.notificationID) os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Push Notification] notification %s", ((#file as NSString).lastPathComponent), #line, #function, notificationID) + + let accessToken = mastodonPushNotification.accessToken + UserDefaults.shared.increaseNotificationCount(accessToken: accessToken) + appContext.notificationService.applicationIconBadgeNeedsUpdate.send() + appContext.notificationService.handle(mastodonPushNotification: mastodonPushNotification) completionHandler([.sound]) } diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift index d0067129b..f5cc269b0 100644 --- a/Mastodon/Supporting Files/SceneDelegate.swift +++ b/Mastodon/Supporting Files/SceneDelegate.swift @@ -87,9 +87,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - // reset notification badge - UserDefaults.shared.notificationBadgeCount = 0 - UIApplication.shared.applicationIconBadgeNumber = 0 + // update application badge + AppContext.shared.notificationService.applicationIconBadgeNeedsUpdate.send() // trigger status filter update AppContext.shared.statusFilterService.filterUpdatePublisher.send() diff --git a/NotificationService/NotificationService.swift b/NotificationService/NotificationService.swift index e65ea9aca..c3d02933b 100644 --- a/NotificationService/NotificationService.swift +++ b/NotificationService/NotificationService.swift @@ -60,6 +60,9 @@ class NotificationService: UNNotificationServiceExtension { bestAttemptContent.sound = UNNotificationSound.init(named: UNNotificationSoundName(rawValue: "BoopSound.caf")) bestAttemptContent.userInfo["plaintext"] = plaintextData + let accessToken = notification.accessToken + UserDefaults.shared.increaseNotificationCount(accessToken: accessToken) + UserDefaults.shared.notificationBadgeCount += 1 bestAttemptContent.badge = NSNumber(integerLiteral: UserDefaults.shared.notificationBadgeCount) From 2fdd5e23c700b02c07b4ec50d81822f4b096c18b Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 16:58:29 +0800 Subject: [PATCH 085/392] fix: add new account via register entry not trigger app state update issue --- .../MastodonConfirmEmailViewController.swift | 3 ++- .../Settings/SettingsViewController.swift | 27 +++---------------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift index 9e9235baf..1abb35617 100644 --- a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift +++ b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift @@ -131,7 +131,8 @@ extension MastodonConfirmEmailViewController { } } receiveValue: { response in os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: user %s's email confirmed", ((#file as NSString).lastPathComponent), #line, #function, response.value.username) - self.dismiss(animated: true, completion: nil) + self.coordinator.setup() + // self.dismiss(animated: true, completion: nil) } .store(in: &self.disposeBag) } diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index e93668801..7804a70de 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -189,7 +189,7 @@ class SettingsViewController: UIViewController, NeedsDependency { if let activeSubscription = setting.activeSubscription { self.whoButton.setTitle(activeSubscription.policy.title, for: .normal) } else { - assertionFailure() + // assertionFailure() } } } @@ -199,27 +199,6 @@ class SettingsViewController: UIViewController, NeedsDependency { let footer = "Mastodon v\(UIApplication.appVersion()) (\(UIApplication.appBuild()))" let metaContent = PlaintextMetaContent(string: footer) tableFooterLabel.configure(content: metaContent) - - // FIXME: - // needs a workaround for GitHub link -// viewModel.currentInstance -// .receive(on: RunLoop.main) -// .sink { [weak self] instance in -// guard let self = self else { return } -// let version = instance?.version ?? "-" -// let link = #"mastodon/mastodon"# -// let content = L10n.Scene.Settings.Footer.mastodonDescription(link, version) -// let mastodonContent = MastodonContent(content: content, emojis: [:]) -// do { -// let metaContent = try MastodonMetaContent.convert(document: mastodonContent) -// self.tableFooterLabel.configure(content: metaContent) -// } catch { -// let metaContent = PlaintextMetaContent(string: "") -// self.tableFooterLabel.configure(content: metaContent) -// assertionFailure() -// } -// } -// .store(in: &disposeBag) } private func setupView() { @@ -276,7 +255,7 @@ class SettingsViewController: UIViewController, NeedsDependency { tableView.tableFooterView = tableFooterView } - func alertToSignout() { + func alertToSignOut() { let alertController = UIAlertController( title: L10n.Common.Alerts.SignOut.title, message: L10n.Common.Alerts.SignOut.message, @@ -423,7 +402,7 @@ extension SettingsViewController: UITableViewDelegate { .store(in: &disposeBag) case .signOut: feedbackGenerator.impactOccurred() - alertToSignout() + alertToSignOut() } } } From f3789a525c646edc876755ca6b407ee0eade2157 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 17:03:24 +0800 Subject: [PATCH 086/392] chore: set wizard not display after read --- .../Scene/MainTab/MainTabBarController+Wizard.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift b/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift index 803cc6d3f..0f143a98e 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift @@ -56,6 +56,13 @@ extension MainTabBarController.Wizard { return "Switch between multiple accounts by holding the profile button." } } + + func markAsRead() { + switch self { + case .multipleAccountSwitch: + UserDefaults.shared.didShowMultipleAccountSwitchWizard = true + } + } } } @@ -89,8 +96,12 @@ extension MainTabBarController.Wizard { return } + // prepare for reuse prepareForReuse() + // set wizard item read + item.markAsRead() + // add spotlight let spotlight = delegate.spotlight(item: item) let maskLayer = CAShapeLayer() @@ -118,7 +129,6 @@ extension MainTabBarController.Wizard { @objc private func backgroundTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") - // TODO: toggle current item preference flag consume() } } From 171b2412f95c9057393fe245bb5d1754c081f478 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:23:22 +0200 Subject: [PATCH 087/392] New translations app.json (Swedish, Finland) --- Localization/StringsConvertor/input/sv_FI/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/sv_FI/app.json b/Localization/StringsConvertor/input/sv_FI/app.json index b7eb3b167..978d6719c 100644 --- a/Localization/StringsConvertor/input/sv_FI/app.json +++ b/Localization/StringsConvertor/input/sv_FI/app.json @@ -454,12 +454,12 @@ "Everything": "Everything", "Mentions": "Mentions" }, - "user_followed_you": "%s followed you", + "user_followed_you": "%s följde dig", "user_favorited your post": "%s favorited your post", "user_reblogged_your_post": "%s reblogged your post", - "user_mentioned_you": "%s mentioned you", - "user_requested_to_follow_you": "%s requested to follow you", - "user_your_poll_has_ended": "%s Your poll has ended", + "user_mentioned_you": "%s nämnde dig", + "user_requested_to_follow_you": "%s har begärt att följa dig", + "user_your_poll_has_ended": "%s Omröstningen har avslutats", "keyobard": { "show_everything": "Show Everything", "show_mentions": "Show Mentions" From 1e2be1417c3460276e1275aca2c3a6b5d68a11d7 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 17:27:08 +0800 Subject: [PATCH 088/392] chore: fix i18n template --- Localization/app.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index ce307a2e0..f5d806a0e 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -538,10 +538,11 @@ "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", + "add_account": "Add Account" }, "wizard": { - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button." + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 7ef2692afa0cd4c917585dbf3519f76990d6dff6 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 17:33:57 +0800 Subject: [PATCH 089/392] chore: add unread notification i18n string --- Localization/Localizable.stringsdict | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Localization/Localizable.stringsdict b/Localization/Localizable.stringsdict index 44fb608bc..ce358b439 100644 --- a/Localization/Localizable.stringsdict +++ b/Localization/Localizable.stringsdict @@ -2,6 +2,28 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + no unread notification + one + 1 unread notification + few + %ld unread notifications + many + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 4919570fa76751391154cc285952295ae35c21f6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:34:39 +0200 Subject: [PATCH 090/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index c3a002db8..94c5a49b0 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -534,6 +534,15 @@ "show_next": "แสดงถัดไป", "show_previous": "แสดงก่อนหน้า" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 84cddf32b846d77df1689417c7183673251b8ee1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:08 +0200 Subject: [PATCH 091/392] New translations Localizable.stringsdict (Romanian) --- .../input/ro_RO/Localizable.stringsdict | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict index f623187e7..8cda4bbd7 100644 --- a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict @@ -2,6 +2,24 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + few + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From df498abea00693c9b48c9e41f32754a7a6cf9071 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:10 +0200 Subject: [PATCH 092/392] New translations Localizable.stringsdict (Chinese Traditional) --- .../input/zh_TW/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict index bebde18a5..dafab129d 100644 --- a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 721d1dab1ac3a0d8dda0e048648a38e0ec47c21b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:11 +0200 Subject: [PATCH 093/392] New translations app.json (Spanish) --- Localization/StringsConvertor/input/es_ES/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/es_ES/app.json b/Localization/StringsConvertor/input/es_ES/app.json index 5151137d7..88a4acb3c 100644 --- a/Localization/StringsConvertor/input/es_ES/app.json +++ b/Localization/StringsConvertor/input/es_ES/app.json @@ -534,6 +534,15 @@ "show_next": "Mostrar Siguiente", "show_previous": "Mostrar 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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From f6e098e3f8c33b80d9be968d7d2754a426e98f0a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:12 +0200 Subject: [PATCH 094/392] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index b665ce196..bc8486232 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -534,6 +534,15 @@ "show_next": "Afficher le suivant", "show_previous": "Afficher le précédent" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 1e05ddd709c576d7bf432773e0fd69a53d7a9578 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:13 +0200 Subject: [PATCH 095/392] New translations app.json (Romanian) --- Localization/StringsConvertor/input/ro_RO/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/ro_RO/app.json b/Localization/StringsConvertor/input/ro_RO/app.json index f4f7a91ec..1442fb31f 100644 --- a/Localization/StringsConvertor/input/ro_RO/app.json +++ b/Localization/StringsConvertor/input/ro_RO/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 35deaefec3aa60a87168f8892c6b0bc65ec53409 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:14 +0200 Subject: [PATCH 096/392] New translations Localizable.stringsdict (Swedish, Finland) --- .../input/sv_FI/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict index 30533a5eb..65316e3d0 100644 --- a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 3824e74e8ad2cd3c295f4b927528e193b9610765 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:15 +0200 Subject: [PATCH 097/392] New translations Localizable.stringsdict (Scottish Gaelic) --- .../input/gd_GB/Localizable.stringsdict | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict index 63a998c6e..41e592a5e 100644 --- a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict @@ -2,6 +2,26 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + two + %ld unread notification + few + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From add099755cbe997cb152f8a5f9574da8b7a09c2a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:16 +0200 Subject: [PATCH 098/392] New translations Localizable.stringsdict (Welsh) --- .../input/cy_GB/Localizable.stringsdict | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict index 537064efb..e6b0d5f95 100644 --- a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict @@ -2,6 +2,30 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + %ld unread notification + one + 1 unread notification + two + %ld unread notification + few + %ld unread notification + many + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 27fd8294ca933b3cf3bf635ddb913955acfabad2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:17 +0200 Subject: [PATCH 099/392] New translations Localizable.stringsdict (Hindi) --- .../input/hi_IN/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict index c7c84d074..730e2902a 100644 --- a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From f5b2117fbcff20e0d8c835d61f5c572b5244eead Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:18 +0200 Subject: [PATCH 100/392] New translations Localizable.stringsdict (Thai) --- .../input/th_TH/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict index dc114db41..1d6ff10bc 100644 --- a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 7eac7563b8a7929e51aa716ed63108241c1ded66 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:19 +0200 Subject: [PATCH 101/392] New translations Localizable.stringsdict (Spanish, Argentina) --- .../input/es_AR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict index f98962ccb..dbbd363fa 100644 --- a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 07acc8c0fc3afaf384857c83d89d79053edff357 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:20 +0200 Subject: [PATCH 102/392] New translations Localizable.stringsdict (Indonesian) --- .../input/id_ID/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict index 718723849..5cd02115d 100644 --- a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From ef707b5da8aa786f17d4ab150d093baa677055f1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:21 +0200 Subject: [PATCH 103/392] New translations Localizable.stringsdict (Portuguese, Brazilian) --- .../input/pt_BR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict index c7c84d074..730e2902a 100644 --- a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 6b1aebf219b93538a2aa101a9938102bbc4a296e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:22 +0200 Subject: [PATCH 104/392] New translations Localizable.stringsdict (English) --- .../input/en_US/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict index c7c84d074..730e2902a 100644 --- a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From e0f06fb2e766352f7d04366f5e3da3cc2baa3ab2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:23 +0200 Subject: [PATCH 105/392] New translations Localizable.stringsdict (Chinese Simplified) --- .../input/zh_CN/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict index c28637620..7d99f7fa5 100644 --- a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From edc705d623b359491213a116518afdf4ea6386dd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:24 +0200 Subject: [PATCH 106/392] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index 19ff88b46..b98367f54 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -534,6 +534,15 @@ "show_next": "Mostrar Següent", "show_previous": "Mostrar 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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 2de8d33aef0fc52e414f4513a0f23e746e2cde1b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:25 +0200 Subject: [PATCH 107/392] New translations Localizable.stringsdict (Swedish) --- .../input/sv_SE/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict index 30533a5eb..65316e3d0 100644 --- a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 97f93808d07ed3dc157c06cd8dad43c9bb116539 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:26 +0200 Subject: [PATCH 108/392] New translations Localizable.stringsdict (Russian) --- .../input/ru_RU/Localizable.stringsdict | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict index 2fe378b55..96afce4ed 100644 --- a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict @@ -2,6 +2,26 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + few + %ld unread notification + many + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 650e3b2612879ee5876c2c9495fdbac2aac08a0f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:27 +0200 Subject: [PATCH 109/392] New translations Localizable.stringsdict (Portuguese) --- .../input/pt_PT/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict index c7c84d074..730e2902a 100644 --- a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 0fdf9c6377419f04836995324d8c3814c43bbf38 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:28 +0200 Subject: [PATCH 110/392] New translations Localizable.stringsdict (Dutch) --- .../input/nl_NL/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict index 1726606b4..8b6ab05ca 100644 --- a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From efffe5f0bf410eba93d2945d31e0115ed92f2a0d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:30 +0200 Subject: [PATCH 111/392] New translations Localizable.stringsdict (Korean) --- .../input/ko_KR/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict index 4b19bab17..7c990671b 100644 --- a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 2435a4f12ea54530c3aa2e9fc37825d9a4bcb039 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:31 +0200 Subject: [PATCH 112/392] New translations Localizable.stringsdict (Japanese) --- .../input/ja_JP/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict index ac37d9a39..0300d9dc3 100644 --- a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 1e58b36cea38df43a43b8fc2a7c929ee970230fc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:32 +0200 Subject: [PATCH 113/392] New translations Localizable.stringsdict (German) --- .../input/de_DE/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict index e89bdb074..c868bdc0f 100644 --- a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 992d0bf11e9b6a6d614ee5347eaf5214333a55d4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:33 +0200 Subject: [PATCH 114/392] New translations Localizable.stringsdict (Danish) --- .../input/da_DK/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict index c7c84d074..730e2902a 100644 --- a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 85071fe2790215e1158a6ef28426e6652902fa28 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:34 +0200 Subject: [PATCH 115/392] New translations Localizable.stringsdict (Catalan) --- .../input/ca_ES/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict index b76b0a921..65a83d363 100644 --- a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From c41ee251fdcf3f52489900f59efcaeb60b481d77 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:35 +0200 Subject: [PATCH 116/392] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index 537064efb..e6b0d5f95 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -2,6 +2,30 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + %ld unread notification + one + 1 unread notification + two + %ld unread notification + few + %ld unread notification + many + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From dab8b8a1401cc72b8390485845e99f9a0d8d17be Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:36 +0200 Subject: [PATCH 117/392] New translations Localizable.stringsdict (Spanish) --- .../input/es_ES/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict index bf493c1e8..d31d8825b 100644 --- a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From 25dbd7c55032e5613e8f33a909e759314d5486d8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:37 +0200 Subject: [PATCH 118/392] New translations Localizable.stringsdict (French) --- .../input/fr_FR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index f95f4ee16..d512b204c 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey From ea9073dedd6a316048f771da1cd23ef8a34b57b2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:38 +0200 Subject: [PATCH 119/392] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 48cc380b0..3b950f10d 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -534,6 +534,15 @@ "show_next": "إظهار التالي", "show_previous": "إظهار السابق" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From f6607d03c5d4a21dd7c2e04aa44938ba757575ca Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:39 +0200 Subject: [PATCH 120/392] New translations app.json (Danish) --- Localization/StringsConvertor/input/da_DK/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/da_DK/app.json b/Localization/StringsConvertor/input/da_DK/app.json index b60ade9c1..f5d806a0e 100644 --- a/Localization/StringsConvertor/input/da_DK/app.json +++ b/Localization/StringsConvertor/input/da_DK/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From e9c29a2057a8b5394a7423dd57fff157662e4f65 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:40 +0200 Subject: [PATCH 121/392] New translations app.json (Scottish Gaelic) --- Localization/StringsConvertor/input/gd_GB/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index 89ca12e3a..e592063a6 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -534,6 +534,15 @@ "show_next": "Air adhart", "show_previous": "Air ais" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From f4c44f0af8060c46a971d53756e292c019596996 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:46 +0200 Subject: [PATCH 122/392] New translations app.json (Swedish, Finland) --- Localization/StringsConvertor/input/sv_FI/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_FI/app.json b/Localization/StringsConvertor/input/sv_FI/app.json index 978d6719c..61dd43507 100644 --- a/Localization/StringsConvertor/input/sv_FI/app.json +++ b/Localization/StringsConvertor/input/sv_FI/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 5d9151b29dfd69f301512d019fc2b4b3d60494f3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:47 +0200 Subject: [PATCH 123/392] New translations app.json (Welsh) --- Localization/StringsConvertor/input/cy_GB/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/cy_GB/app.json b/Localization/StringsConvertor/input/cy_GB/app.json index b60ade9c1..f5d806a0e 100644 --- a/Localization/StringsConvertor/input/cy_GB/app.json +++ b/Localization/StringsConvertor/input/cy_GB/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 9b92a6a2fea997531b16f5a00eb6e15971af529b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:48 +0200 Subject: [PATCH 124/392] New translations app.json (German) --- Localization/StringsConvertor/input/de_DE/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/de_DE/app.json b/Localization/StringsConvertor/input/de_DE/app.json index ecfe841eb..a4c423c25 100644 --- a/Localization/StringsConvertor/input/de_DE/app.json +++ b/Localization/StringsConvertor/input/de_DE/app.json @@ -534,6 +534,15 @@ "show_next": "Nächstes anzeigen", "show_previous": "Vorheriges anzeigen" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 54698a4199f19635595b07763a1c50f118738e64 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:49 +0200 Subject: [PATCH 125/392] New translations app.json (Hindi) --- Localization/StringsConvertor/input/hi_IN/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/hi_IN/app.json b/Localization/StringsConvertor/input/hi_IN/app.json index b60ade9c1..f5d806a0e 100644 --- a/Localization/StringsConvertor/input/hi_IN/app.json +++ b/Localization/StringsConvertor/input/hi_IN/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 0a6329eeea0761cba39a92738a6cc1b167136dde Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:50 +0200 Subject: [PATCH 126/392] New translations app.json (Spanish, Argentina) --- Localization/StringsConvertor/input/es_AR/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index 301cec40e..bd01ea80b 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -534,6 +534,15 @@ "show_next": "Mostrar siguiente", "show_previous": "Mostrar 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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 96c7f24acf9f359a430a98384a94ecffe7ece77b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:51 +0200 Subject: [PATCH 127/392] New translations app.json (Indonesian) --- Localization/StringsConvertor/input/id_ID/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/id_ID/app.json b/Localization/StringsConvertor/input/id_ID/app.json index cf4beced4..24233e34e 100644 --- a/Localization/StringsConvertor/input/id_ID/app.json +++ b/Localization/StringsConvertor/input/id_ID/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 25535971c6e1188179664b4e2258ce2a9339fc5e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:53 +0200 Subject: [PATCH 128/392] New translations app.json (Portuguese, Brazilian) --- Localization/StringsConvertor/input/pt_BR/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_BR/app.json b/Localization/StringsConvertor/input/pt_BR/app.json index b60ade9c1..f5d806a0e 100644 --- a/Localization/StringsConvertor/input/pt_BR/app.json +++ b/Localization/StringsConvertor/input/pt_BR/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 2405650445bf405b3dcea853341340246b706edb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:54 +0200 Subject: [PATCH 129/392] New translations app.json (English) --- Localization/StringsConvertor/input/en_US/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/en_US/app.json b/Localization/StringsConvertor/input/en_US/app.json index b60ade9c1..f5d806a0e 100644 --- a/Localization/StringsConvertor/input/en_US/app.json +++ b/Localization/StringsConvertor/input/en_US/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 2118c447202d3ac0fac543190497eba2ab6d9413 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:55 +0200 Subject: [PATCH 130/392] New translations app.json (Chinese Traditional) --- Localization/StringsConvertor/input/zh_TW/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_TW/app.json b/Localization/StringsConvertor/input/zh_TW/app.json index b60ade9c1..f5d806a0e 100644 --- a/Localization/StringsConvertor/input/zh_TW/app.json +++ b/Localization/StringsConvertor/input/zh_TW/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From dc40363a92234b0546475471d18326d80115c316 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:56 +0200 Subject: [PATCH 131/392] New translations app.json (Chinese Simplified) --- Localization/StringsConvertor/input/zh_CN/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index 25a8f13a7..956ef8925 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -534,6 +534,15 @@ "show_next": "显示下一个", "show_previous": "显示前一个" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 5f4ee3f1f1b122b89af2dc61944cbefb29c600b5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:57 +0200 Subject: [PATCH 132/392] New translations app.json (Swedish) --- Localization/StringsConvertor/input/sv_SE/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_SE/app.json b/Localization/StringsConvertor/input/sv_SE/app.json index 978d6719c..61dd43507 100644 --- a/Localization/StringsConvertor/input/sv_SE/app.json +++ b/Localization/StringsConvertor/input/sv_SE/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 8c772402c936574218bc9b570f309aea1e2d2ba5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:58 +0200 Subject: [PATCH 133/392] New translations app.json (Russian) --- Localization/StringsConvertor/input/ru_RU/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/ru_RU/app.json b/Localization/StringsConvertor/input/ru_RU/app.json index f357a60b4..103e46482 100644 --- a/Localization/StringsConvertor/input/ru_RU/app.json +++ b/Localization/StringsConvertor/input/ru_RU/app.json @@ -534,6 +534,15 @@ "show_next": "Следующее изображение", "show_previous": "Предыдущее изображение" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From aa2e769578c1154f13e251ba8d547bcc76c73ee4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:35:59 +0200 Subject: [PATCH 134/392] New translations app.json (Portuguese) --- Localization/StringsConvertor/input/pt_PT/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_PT/app.json b/Localization/StringsConvertor/input/pt_PT/app.json index b60ade9c1..f5d806a0e 100644 --- a/Localization/StringsConvertor/input/pt_PT/app.json +++ b/Localization/StringsConvertor/input/pt_PT/app.json @@ -534,6 +534,15 @@ "show_next": "Show Next", "show_previous": "Show Previous" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 8ae60aad6df1d5639378c8534f39260c4f362da1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:36:00 +0200 Subject: [PATCH 135/392] New translations app.json (Dutch) --- Localization/StringsConvertor/input/nl_NL/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/nl_NL/app.json b/Localization/StringsConvertor/input/nl_NL/app.json index df20cab67..8f16d4a3c 100644 --- a/Localization/StringsConvertor/input/nl_NL/app.json +++ b/Localization/StringsConvertor/input/nl_NL/app.json @@ -534,6 +534,15 @@ "show_next": "Volgende", "show_previous": "Vorige" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 2c8a8930641ca184e64509fdc1cb04f47b7a550b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:36:01 +0200 Subject: [PATCH 136/392] New translations app.json (Korean) --- Localization/StringsConvertor/input/ko_KR/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/ko_KR/app.json b/Localization/StringsConvertor/input/ko_KR/app.json index 4cc299238..005361558 100644 --- a/Localization/StringsConvertor/input/ko_KR/app.json +++ b/Localization/StringsConvertor/input/ko_KR/app.json @@ -534,6 +534,15 @@ "show_next": "다음 보기", "show_previous": "이전 보기" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 8fe0eb7d757e5277c59b8ecceeaca18bd3132067 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 11:36:02 +0200 Subject: [PATCH 137/392] New translations app.json (Japanese) --- Localization/StringsConvertor/input/ja_JP/app.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Localization/StringsConvertor/input/ja_JP/app.json b/Localization/StringsConvertor/input/ja_JP/app.json index 3d05e62dc..eecccac3f 100644 --- a/Localization/StringsConvertor/input/ja_JP/app.json +++ b/Localization/StringsConvertor/input/ja_JP/app.json @@ -534,6 +534,15 @@ "show_next": "次を見る", "show_previous": "前を見る" } + }, + "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" + }, + "wizard": { + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" } } } \ No newline at end of file From 6851730dbc327635d87e9c658fcec6b964522c46 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 17:57:02 +0800 Subject: [PATCH 138/392] chore: add wizard reset debug action --- .../HomeTimelineViewController+DebugAction.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index b0fddb445..fbc221c7a 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -149,7 +149,7 @@ extension HomeTimelineViewController { } }, UIAction( - title: "notification badge +1", + title: "Notification badge +1", image: UIImage(systemName: "1.circle.fill"), identifier: nil, attributes: [], @@ -160,7 +160,17 @@ extension HomeTimelineViewController { UserDefaults.shared.increaseNotificationCount(accessToken: accessToken) self.context.notificationService.applicationIconBadgeNeedsUpdate.send() } - ) + ), + UIAction( + title: "Enable account switcher wizard", + image: UIImage(systemName: "square.stack.3d.down.forward.fill"), + identifier: nil, + attributes: [], + state: .off, + handler: { _ in + UserDefaults.shared.didShowMultipleAccountSwitchWizard = false + } + ), ] ) } From 0c01e53db9c252b96b9bfbb0c795b87ea2c1176a Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 17:58:46 +0800 Subject: [PATCH 139/392] chore: add wizard title i18n string --- Localization/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/app.json b/Localization/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From ed327b07728cfd651e62e97cc97c9b2251ada4d6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:07:19 +0200 Subject: [PATCH 140/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 94c5a49b0..707add6f7 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 5ba16349b4cc60b33859746477d38399e3736061 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:07:49 +0200 Subject: [PATCH 141/392] New translations app.json (Spanish) --- Localization/StringsConvertor/input/es_ES/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/es_ES/app.json b/Localization/StringsConvertor/input/es_ES/app.json index 88a4acb3c..5e96daff0 100644 --- a/Localization/StringsConvertor/input/es_ES/app.json +++ b/Localization/StringsConvertor/input/es_ES/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 9d74104fd220ef6d2ed2cbf6c2e18a64861ba8d7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:07:49 +0200 Subject: [PATCH 142/392] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index bc8486232..5c101dbe9 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From b40d761335d72553f42f005e7fb5965f7d860cac Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:07:50 +0200 Subject: [PATCH 143/392] New translations app.json (Romanian) --- Localization/StringsConvertor/input/ro_RO/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/ro_RO/app.json b/Localization/StringsConvertor/input/ro_RO/app.json index 1442fb31f..ef819f8e6 100644 --- a/Localization/StringsConvertor/input/ro_RO/app.json +++ b/Localization/StringsConvertor/input/ro_RO/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 696d1aabf8684302e218439e85f7f4484c957f55 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:07:56 +0200 Subject: [PATCH 144/392] New translations Localizable.stringsdict (Chinese Simplified) --- .../StringsConvertor/input/zh_CN/Localizable.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict index 7d99f7fa5..12b8b5f6e 100644 --- a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict @@ -13,7 +13,7 @@ NSStringFormatValueTypeKey ld other - %ld unread notification + %ld 条未读通知 a11y.plural.count.input_limit_exceeds From 5ff96bfe0841fa76b2df6babbcb02a9abf774626 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:07:57 +0200 Subject: [PATCH 145/392] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index b98367f54..99d0e97b5 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 58f9697f3003c3a76aacb344ed3a9b2fd2113251 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:03 +0200 Subject: [PATCH 146/392] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 3b950f10d..db8de394d 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 5e2be285033ca780ae87c78c869bf90f1a5ffa20 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:04 +0200 Subject: [PATCH 147/392] New translations app.json (Danish) --- Localization/StringsConvertor/input/da_DK/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/da_DK/app.json b/Localization/StringsConvertor/input/da_DK/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/StringsConvertor/input/da_DK/app.json +++ b/Localization/StringsConvertor/input/da_DK/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 2768c63e2659e1cc4ad3c0776d5fd4910ac2fdeb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:06 +0200 Subject: [PATCH 148/392] New translations app.json (Scottish Gaelic) --- Localization/StringsConvertor/input/gd_GB/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index e592063a6..35f551fea 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 9aa35ab4c818e7b59022ed5e64a40edd60efbeb5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:11 +0200 Subject: [PATCH 149/392] New translations app.json (Swedish, Finland) --- Localization/StringsConvertor/input/sv_FI/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/sv_FI/app.json b/Localization/StringsConvertor/input/sv_FI/app.json index 61dd43507..c5910c887 100644 --- a/Localization/StringsConvertor/input/sv_FI/app.json +++ b/Localization/StringsConvertor/input/sv_FI/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 473cd3c433ff0989dccc9f5d17c50bd256e3f382 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:12 +0200 Subject: [PATCH 150/392] New translations app.json (Welsh) --- Localization/StringsConvertor/input/cy_GB/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/cy_GB/app.json b/Localization/StringsConvertor/input/cy_GB/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/StringsConvertor/input/cy_GB/app.json +++ b/Localization/StringsConvertor/input/cy_GB/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 3219496c55d102f980ea5d37d565ca6b576543a2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:13 +0200 Subject: [PATCH 151/392] New translations app.json (German) --- Localization/StringsConvertor/input/de_DE/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/de_DE/app.json b/Localization/StringsConvertor/input/de_DE/app.json index a4c423c25..47e57498c 100644 --- a/Localization/StringsConvertor/input/de_DE/app.json +++ b/Localization/StringsConvertor/input/de_DE/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From eeb51fad5b410af7c8cbb6f6c476f03b8f21e7ef Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:14 +0200 Subject: [PATCH 152/392] New translations app.json (Hindi) --- Localization/StringsConvertor/input/hi_IN/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/hi_IN/app.json b/Localization/StringsConvertor/input/hi_IN/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/StringsConvertor/input/hi_IN/app.json +++ b/Localization/StringsConvertor/input/hi_IN/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From ce37e79503ab454de633d32e3ad8efff6d8ee819 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:15 +0200 Subject: [PATCH 153/392] New translations app.json (Spanish, Argentina) --- Localization/StringsConvertor/input/es_AR/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index bd01ea80b..302aab22c 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 964e6bf22e1b08b4313211ed05bd6c399b5defcb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:16 +0200 Subject: [PATCH 154/392] New translations app.json (Indonesian) --- Localization/StringsConvertor/input/id_ID/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/id_ID/app.json b/Localization/StringsConvertor/input/id_ID/app.json index 24233e34e..180c1356c 100644 --- a/Localization/StringsConvertor/input/id_ID/app.json +++ b/Localization/StringsConvertor/input/id_ID/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 78aa008673817a683961e0405f6c959953860fbc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:17 +0200 Subject: [PATCH 155/392] New translations app.json (Portuguese, Brazilian) --- Localization/StringsConvertor/input/pt_BR/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/pt_BR/app.json b/Localization/StringsConvertor/input/pt_BR/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/StringsConvertor/input/pt_BR/app.json +++ b/Localization/StringsConvertor/input/pt_BR/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 65b069be51750b0cc1d040b5a5b8eb8ab6d95111 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:18 +0200 Subject: [PATCH 156/392] New translations app.json (English) --- Localization/StringsConvertor/input/en_US/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/en_US/app.json b/Localization/StringsConvertor/input/en_US/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/StringsConvertor/input/en_US/app.json +++ b/Localization/StringsConvertor/input/en_US/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From c6a00a232971050733fd4af3d1a5976e7b41d519 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:19 +0200 Subject: [PATCH 157/392] New translations app.json (Chinese Traditional) --- Localization/StringsConvertor/input/zh_TW/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/zh_TW/app.json b/Localization/StringsConvertor/input/zh_TW/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/StringsConvertor/input/zh_TW/app.json +++ b/Localization/StringsConvertor/input/zh_TW/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 194a5ca85f93b6f626bdf003ce202bf1b4e30719 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:21 +0200 Subject: [PATCH 158/392] New translations app.json (Chinese Simplified) --- Localization/StringsConvertor/input/zh_CN/app.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index 956ef8925..a12c92bcb 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -536,13 +536,14 @@ } }, "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": "当前账户:%s。 双击并按住来打开账户切换页面", + "dismiss_account_switcher": "关闭账户切换页面", + "add_account": "添加账户" }, "wizard": { - "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": "New in Mastodon", + "multiple_account_switch_intro_description": "按住个人资料标签按钮,即可在多个账户之间进行切换。", + "accessibility_hint": "双击关闭此向导" } } } \ No newline at end of file From e8c260713f7f2a0cd6e8d4e8fd32f21101ae5ee2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:21 +0200 Subject: [PATCH 159/392] New translations app.json (Swedish) --- Localization/StringsConvertor/input/sv_SE/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/sv_SE/app.json b/Localization/StringsConvertor/input/sv_SE/app.json index 61dd43507..c5910c887 100644 --- a/Localization/StringsConvertor/input/sv_SE/app.json +++ b/Localization/StringsConvertor/input/sv_SE/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 7e7b9acde4ada004876fd65602864a1f41dec6de Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:22 +0200 Subject: [PATCH 160/392] New translations app.json (Russian) --- Localization/StringsConvertor/input/ru_RU/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/ru_RU/app.json b/Localization/StringsConvertor/input/ru_RU/app.json index 103e46482..a5c34023a 100644 --- a/Localization/StringsConvertor/input/ru_RU/app.json +++ b/Localization/StringsConvertor/input/ru_RU/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 72cf103aaf4a71fbd4069d28632b75c17426c30c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:23 +0200 Subject: [PATCH 161/392] New translations app.json (Portuguese) --- Localization/StringsConvertor/input/pt_PT/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/pt_PT/app.json b/Localization/StringsConvertor/input/pt_PT/app.json index f5d806a0e..3ec77cf10 100644 --- a/Localization/StringsConvertor/input/pt_PT/app.json +++ b/Localization/StringsConvertor/input/pt_PT/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From 3971b506c752ae565d247817e61a8bbaf4b4ac54 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:24 +0200 Subject: [PATCH 162/392] New translations app.json (Dutch) --- Localization/StringsConvertor/input/nl_NL/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/nl_NL/app.json b/Localization/StringsConvertor/input/nl_NL/app.json index 8f16d4a3c..d57a38ef2 100644 --- a/Localization/StringsConvertor/input/nl_NL/app.json +++ b/Localization/StringsConvertor/input/nl_NL/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From ad08a89530753c540bb47a92c379125c43e90342 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:25 +0200 Subject: [PATCH 163/392] New translations app.json (Korean) --- Localization/StringsConvertor/input/ko_KR/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/ko_KR/app.json b/Localization/StringsConvertor/input/ko_KR/app.json index 005361558..a9fb71ee8 100644 --- a/Localization/StringsConvertor/input/ko_KR/app.json +++ b/Localization/StringsConvertor/input/ko_KR/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From bad3b8626bcadab7710b073c6a595f91e6c89259 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:08:26 +0200 Subject: [PATCH 164/392] New translations app.json (Japanese) --- Localization/StringsConvertor/input/ja_JP/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/StringsConvertor/input/ja_JP/app.json b/Localization/StringsConvertor/input/ja_JP/app.json index eecccac3f..2f1aec4ec 100644 --- a/Localization/StringsConvertor/input/ja_JP/app.json +++ b/Localization/StringsConvertor/input/ja_JP/app.json @@ -541,6 +541,7 @@ "add_account": "Add Account" }, "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" } From e3060005115eb351f650161c6eea41a8158af3f5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 12:14:36 +0200 Subject: [PATCH 165/392] New translations app.json (Chinese Simplified) --- Localization/StringsConvertor/input/zh_CN/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index a12c92bcb..b7728b60c 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -541,7 +541,7 @@ "add_account": "添加账户" }, "wizard": { - "new_in_mastodon": "New in Mastodon", + "new_in_mastodon": "新功能", "multiple_account_switch_intro_description": "按住个人资料标签按钮,即可在多个账户之间进行切换。", "accessibility_hint": "双击关闭此向导" } From 99f15fafedf7e3292fd3e32f6ae895f6200d3b30 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 18:18:19 +0800 Subject: [PATCH 166/392] chore: update i18n resources --- Mastodon/Generated/Strings.swift | 24 +++ Mastodon/Resources/ar.lproj/InfoPlist.strings | 2 +- .../Resources/ar.lproj/Localizable.strings | 152 +++++++++--------- .../ar.lproj/Localizable.stringsdict | 24 +++ .../Resources/ca.lproj/Localizable.strings | 8 +- .../ca.lproj/Localizable.stringsdict | 16 ++ .../Resources/de.lproj/Localizable.strings | 8 +- .../de.lproj/Localizable.stringsdict | 16 ++ .../Resources/en.lproj/Localizable.strings | 8 +- .../en.lproj/Localizable.stringsdict | 16 ++ .../es-419.lproj/Localizable.strings | 8 +- .../es-419.lproj/Localizable.stringsdict | 16 ++ .../Resources/es.lproj/Localizable.strings | 8 +- .../es.lproj/Localizable.stringsdict | 16 ++ .../Resources/fr.lproj/Localizable.strings | 45 +++--- .../fr.lproj/Localizable.stringsdict | 84 ++++++---- .../Resources/gd-GB.lproj/Localizable.strings | 8 +- .../gd-GB.lproj/Localizable.stringsdict | 20 +++ .../Resources/ja.lproj/Localizable.strings | 8 +- .../ja.lproj/Localizable.stringsdict | 14 ++ .../Resources/nl.lproj/Localizable.strings | 8 +- .../nl.lproj/Localizable.stringsdict | 16 ++ Mastodon/Resources/ru.lproj/InfoPlist.strings | 2 +- .../Resources/ru.lproj/Localizable.strings | 8 +- .../ru.lproj/Localizable.stringsdict | 56 ++++--- .../Resources/th.lproj/Localizable.strings | 32 ++-- .../th.lproj/Localizable.stringsdict | 14 ++ .../zh-Hans.lproj/Localizable.strings | 8 +- .../zh-Hans.lproj/Localizable.stringsdict | 14 ++ MastodonIntent/ar.lproj/Intents.strings | 20 +-- MastodonIntent/fr.lproj/Intents.strings | 30 ++-- MastodonIntent/gd-GB.lproj/Intents.strings | 4 +- 32 files changed, 517 insertions(+), 196 deletions(-) diff --git a/Mastodon/Generated/Strings.swift b/Mastodon/Generated/Strings.swift index 86dc89025..93cc4ca38 100644 --- a/Mastodon/Generated/Strings.swift +++ b/Mastodon/Generated/Strings.swift @@ -365,6 +365,16 @@ internal enum L10n { } internal enum Scene { + internal enum AccountList { + /// Add Account + internal static let addAccount = L10n.tr("Localizable", "Scene.AccountList.AddAccount") + /// Dismiss Account Switcher + internal static let dismissAccountSwitcher = L10n.tr("Localizable", "Scene.AccountList.DismissAccountSwitcher") + /// Current selected profile: %@. Double tap then hold to show account switcher + internal static func tabBarHint(_ p1: Any) -> String { + return L10n.tr("Localizable", "Scene.AccountList.TabBarHint", String(describing: p1)) + } + } internal enum Compose { /// Publish internal static let composeAction = L10n.tr("Localizable", "Scene.Compose.ComposeAction") @@ -973,6 +983,14 @@ internal enum L10n { /// Social networking\nback in your hands. internal static let slogan = L10n.tr("Localizable", "Scene.Welcome.Slogan") } + internal enum Wizard { + /// Double tap to dismiss this wizard + internal static let accessibilityHint = L10n.tr("Localizable", "Scene.Wizard.AccessibilityHint") + /// Switch between multiple accounts by holding the profile button. + internal static let multipleAccountSwitchIntroDescription = L10n.tr("Localizable", "Scene.Wizard.MultipleAccountSwitchIntroDescription") + /// New in Mastodon + internal static let newInMastodon = L10n.tr("Localizable", "Scene.Wizard.NewInMastodon") + } } internal enum A11y { @@ -986,6 +1004,12 @@ internal enum L10n { internal static func inputLimitRemains(_ p1: Int) -> String { return L10n.tr("Localizable", "a11y.plural.count.input_limit_remains", p1) } + internal enum Unread { + /// Plural format key: "%#@notification_count_unread_notification@" + internal static func notification(_ p1: Int) -> String { + return L10n.tr("Localizable", "a11y.plural.count.unread.notification", p1) + } + } } } } diff --git a/Mastodon/Resources/ar.lproj/InfoPlist.strings b/Mastodon/Resources/ar.lproj/InfoPlist.strings index 2531bd454..5ced1e74f 100644 --- a/Mastodon/Resources/ar.lproj/InfoPlist.strings +++ b/Mastodon/Resources/ar.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"; +"NewPostShortcutItemTitle" = "منشور جديد"; "SearchShortcutItemTitle" = "البحث"; \ No newline at end of file diff --git a/Mastodon/Resources/ar.lproj/Localizable.strings b/Mastodon/Resources/ar.lproj/Localizable.strings index 475d27886..3dfe057ed 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.strings +++ b/Mastodon/Resources/ar.lproj/Localizable.strings @@ -8,7 +8,7 @@ "Common.Alerts.DeletePost.Title" = "هل أنت متأكد من أنك تريد حذف هذا المنشور؟"; "Common.Alerts.DiscardPostContent.Message" = "Confirm to discard composed post content."; "Common.Alerts.DiscardPostContent.Title" = "تجاهل المسودة"; -"Common.Alerts.EditProfileFailure.Message" = "Cannot edit profile. Please try again."; +"Common.Alerts.EditProfileFailure.Message" = "لا يمكن تعديل الملف الشخصي. الرجاء المحاولة مرة أخرى."; "Common.Alerts.EditProfileFailure.Title" = "Edit Profile Error"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images."; @@ -22,7 +22,7 @@ Please check your internet connection."; "Common.Alerts.SignOut.Message" = "هل أنت متأكد من أنك تريد تسجيل الخروج؟"; "Common.Alerts.SignOut.Title" = "تسجيل الخروج"; "Common.Alerts.SignUpFailure.Title" = "فشل التسجيل"; -"Common.Alerts.VoteFailure.PollEnded" = "The poll has ended"; +"Common.Alerts.VoteFailure.PollEnded" = "انتهى استطلاع الرأي"; "Common.Alerts.VoteFailure.Title" = "فشل التصويت"; "Common.Controls.Actions.Add" = "إضافة"; "Common.Controls.Actions.Back" = "العودة"; @@ -59,20 +59,20 @@ Please check your internet connection."; "Common.Controls.Actions.TakePhoto" = "التقط صورة"; "Common.Controls.Actions.TryAgain" = "حاول مرة أخرى"; "Common.Controls.Actions.UnblockDomain" = "إلغاء حظر %@"; -"Common.Controls.Friendship.Block" = "Block"; -"Common.Controls.Friendship.BlockDomain" = "Block %@"; -"Common.Controls.Friendship.BlockUser" = "Block %@"; -"Common.Controls.Friendship.Blocked" = "Blocked"; +"Common.Controls.Friendship.Block" = "حظر"; +"Common.Controls.Friendship.BlockDomain" = "حظر %@"; +"Common.Controls.Friendship.BlockUser" = "حظر %@"; +"Common.Controls.Friendship.Blocked" = "محظور"; "Common.Controls.Friendship.EditInfo" = "تعديل المعلومات"; -"Common.Controls.Friendship.Follow" = "Follow"; -"Common.Controls.Friendship.Following" = "Following"; +"Common.Controls.Friendship.Follow" = "اتبع"; +"Common.Controls.Friendship.Following" = "مُتابَع"; "Common.Controls.Friendship.Mute" = "أكتم"; "Common.Controls.Friendship.MuteUser" = "أكتم %@"; "Common.Controls.Friendship.Muted" = "مكتوم"; "Common.Controls.Friendship.Pending" = "Pending"; "Common.Controls.Friendship.Request" = "Request"; -"Common.Controls.Friendship.Unblock" = "Unblock"; -"Common.Controls.Friendship.UnblockUser" = "Unblock %@"; +"Common.Controls.Friendship.Unblock" = "إلغاء الحَظر"; +"Common.Controls.Friendship.UnblockUser" = "إلغاء حظر %@"; "Common.Controls.Friendship.Unmute" = "إلغاء الكتم"; "Common.Controls.Friendship.UnmuteUser" = "إلغاء كتم %@"; "Common.Controls.Keyboard.Common.ComposeNewPost" = "إنشاء منشور جديد"; @@ -91,26 +91,26 @@ Please check your internet connection."; "Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Toggle Content Warning"; "Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Toggle Favorite on Post"; "Common.Controls.Keyboard.Timeline.ToggleReblog" = "Toggle Reblog on Post"; -"Common.Controls.Status.Actions.Favorite" = "Favorite"; -"Common.Controls.Status.Actions.Menu" = "Menu"; -"Common.Controls.Status.Actions.Reblog" = "Reblog"; -"Common.Controls.Status.Actions.Reply" = "Reply"; -"Common.Controls.Status.Actions.Unfavorite" = "Unfavorite"; -"Common.Controls.Status.Actions.Unreblog" = "Undo reblog"; -"Common.Controls.Status.ContentWarning" = "Content Warning"; +"Common.Controls.Status.Actions.Favorite" = "إضافة إلى المفضلة"; +"Common.Controls.Status.Actions.Menu" = "القائمة"; +"Common.Controls.Status.Actions.Reblog" = "إعادة النشر"; +"Common.Controls.Status.Actions.Reply" = "رد"; +"Common.Controls.Status.Actions.Unfavorite" = "إزالة من المفضلة"; +"Common.Controls.Status.Actions.Unreblog" = "تراجع عن إعادة النشر"; +"Common.Controls.Status.ContentWarning" = "تحذير عن المحتوى"; "Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal"; -"Common.Controls.Status.Poll.Closed" = "Closed"; -"Common.Controls.Status.Poll.Vote" = "Vote"; -"Common.Controls.Status.ShowPost" = "Show Post"; -"Common.Controls.Status.ShowUserProfile" = "Show user profile"; +"Common.Controls.Status.Poll.Closed" = "انتهى"; +"Common.Controls.Status.Poll.Vote" = "صَوّت"; +"Common.Controls.Status.ShowPost" = "اظهر المنشور"; +"Common.Controls.Status.ShowUserProfile" = "اظهر الملف التعريفي للمستخدم"; "Common.Controls.Status.Tag.Email" = "البريد الإلكتروني"; -"Common.Controls.Status.Tag.Emoji" = "Emoji"; -"Common.Controls.Status.Tag.Hashtag" = "Hashtag"; -"Common.Controls.Status.Tag.Link" = "Link"; -"Common.Controls.Status.Tag.Mention" = "Mention"; -"Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.Tag.Emoji" = "إيموجي"; +"Common.Controls.Status.Tag.Hashtag" = "الوسم"; +"Common.Controls.Status.Tag.Link" = "الرابط"; +"Common.Controls.Status.Tag.Mention" = "أشر إلى"; +"Common.Controls.Status.Tag.Url" = "عنوان URL"; "Common.Controls.Status.UserReblogged" = "%@ reblogged"; -"Common.Controls.Status.UserRepliedTo" = "Replied to %@"; +"Common.Controls.Status.UserRepliedTo" = "رد على %@"; "Common.Controls.Tabs.Home" = "الخيط الرئيسي"; "Common.Controls.Tabs.Notification" = "الإشعارات"; "Common.Controls.Tabs.Profile" = "الملف التعريفي"; @@ -133,6 +133,9 @@ Your profile looks like this to them."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "تحميل المزيد من المنشورات..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "إظهار المزيد من الردود"; "Common.Controls.Timeline.Timestamp.Now" = "الأن"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Add Attachment"; "Scene.Compose.Accessibility.AppendPoll" = "اضافة استطلاع رأي"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "منتقي مخصص للإيموجي"; @@ -153,16 +156,16 @@ uploaded to Mastodon."; "Scene.Compose.Keyboard.AppendAttachmentEntry" = "Add Attachment - %@"; "Scene.Compose.Keyboard.DiscardPost" = "Discard Post"; "Scene.Compose.Keyboard.PublishPost" = "Publish Post"; -"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Select Visibility - %@"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "اختر مدى الظهور - %@"; "Scene.Compose.Keyboard.ToggleContentWarning" = "Toggle Content Warning"; "Scene.Compose.Keyboard.TogglePoll" = "Toggle Poll"; "Scene.Compose.MediaSelection.Browse" = "تصفح"; "Scene.Compose.MediaSelection.Camera" = "التقط صورة"; "Scene.Compose.MediaSelection.PhotoLibrary" = "مكتبة الصور"; -"Scene.Compose.Poll.DurationTime" = "Duration: %@"; +"Scene.Compose.Poll.DurationTime" = "المدة: %@"; "Scene.Compose.Poll.OneDay" = "يوم واحد"; "Scene.Compose.Poll.OneHour" = "ساعة واحدة"; -"Scene.Compose.Poll.OptionNumber" = "Option %ld"; +"Scene.Compose.Poll.OptionNumber" = "الخيار %ld"; "Scene.Compose.Poll.SevenDays" = "7 أيام"; "Scene.Compose.Poll.SixHours" = "6 ساعات"; "Scene.Compose.Poll.ThirtyMinutes" = "30 دقيقة"; @@ -170,37 +173,37 @@ uploaded to Mastodon."; "Scene.Compose.ReplyingToUser" = "رد على %@"; "Scene.Compose.Title.NewPost" = "منشور جديد"; "Scene.Compose.Title.NewReply" = "رد جديد"; -"Scene.Compose.Visibility.Direct" = "Only people I mention"; -"Scene.Compose.Visibility.Private" = "Followers only"; -"Scene.Compose.Visibility.Public" = "Public"; -"Scene.Compose.Visibility.Unlisted" = "Unlisted"; -"Scene.ConfirmEmail.Button.DontReceiveEmail" = "I never got an email"; -"Scene.ConfirmEmail.Button.OpenEmailApp" = "Open Email App"; +"Scene.Compose.Visibility.Direct" = "ففط للأشخاص المشار إليهم"; +"Scene.Compose.Visibility.Private" = "لمتابعيك فقط"; +"Scene.Compose.Visibility.Public" = "للعامة"; +"Scene.Compose.Visibility.Unlisted" = "غير مُدرَج"; +"Scene.ConfirmEmail.Button.DontReceiveEmail" = "لم أستلم أبدًا بريدا إلكترونيا"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "افتح تطبيق البريد الإلكتروني"; "Scene.ConfirmEmail.DontReceiveEmail.Description" = "Check if your email address is correct as well as your junk folder if you haven’t."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Resend Email"; -"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Check your email"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "تحقق من بريدك الإلكتروني"; "Scene.ConfirmEmail.OpenEmailApp.Description" = "We just sent you an email. Check your junk folder if you haven’t."; "Scene.ConfirmEmail.OpenEmailApp.Mail" = "البريد"; "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Open Email Client"; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; -"Scene.ConfirmEmail.Subtitle" = "We just sent an email to %@, -tap the link to confirm your account."; +"Scene.ConfirmEmail.Subtitle" = "لقد أرسلنا للتو رسالة بريد إلكتروني إلى %@، +اضغط على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيء واحد أخير."; -"Scene.Favorite.Title" = "Your Favorites"; +"Scene.Favorite.Title" = "مفضلتك"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; "Scene.HomeTimeline.NavigationBarState.Offline" = "غير متصل"; -"Scene.HomeTimeline.NavigationBarState.Published" = "Published!"; -"Scene.HomeTimeline.NavigationBarState.Publishing" = "Publishing post..."; +"Scene.HomeTimeline.NavigationBarState.Published" = "تم نشره!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "جارٍ نشر المشاركة…"; "Scene.HomeTimeline.Title" = "الخيط الرئيسي"; -"Scene.Notification.Keyobard.ShowEverything" = "Show Everything"; +"Scene.Notification.Keyobard.ShowEverything" = "إظهار كل شيء"; "Scene.Notification.Keyobard.ShowMentions" = "Show Mentions"; -"Scene.Notification.Title.Everything" = "Everything"; -"Scene.Notification.Title.Mentions" = "Mentions"; -"Scene.Notification.UserFavorited Your Post" = "%@ favorited your post"; -"Scene.Notification.UserFollowedYou" = "%@ followed you"; -"Scene.Notification.UserMentionedYou" = "%@ mentioned you"; -"Scene.Notification.UserRebloggedYourPost" = "%@ reblogged your post"; -"Scene.Notification.UserRequestedToFollowYou" = "%@ requested to follow you"; +"Scene.Notification.Title.Everything" = "الكل"; +"Scene.Notification.Title.Mentions" = "الإشارات"; +"Scene.Notification.UserFavorited Your Post" = "أضاف %@ منشورك إلى مفضلته"; +"Scene.Notification.UserFollowedYou" = "يتابعك %@"; +"Scene.Notification.UserMentionedYou" = "أشار إليك %@"; +"Scene.Notification.UserRebloggedYourPost" = "أعاد %@ تدوين مشاركتك"; +"Scene.Notification.UserRequestedToFollowYou" = "طلب %@ متابعتك"; "Scene.Notification.UserYourPollHasEnded" = "%@ Your poll has ended"; "Scene.Preview.Keyboard.ClosePreview" = "إغلاق المعاينة"; "Scene.Preview.Keyboard.ShowNext" = "إظهار التالي"; @@ -225,17 +228,17 @@ tap the link to confirm your account."; "Scene.Register.Error.Item.Reason" = "السبب"; "Scene.Register.Error.Item.Username" = "اسم المستخدم"; "Scene.Register.Error.Reason.Accepted" = "%@ must be accepted"; -"Scene.Register.Error.Reason.Blank" = "%@ is required"; +"Scene.Register.Error.Reason.Blank" = "%@ مطلوب"; "Scene.Register.Error.Reason.Blocked" = "%@ contains a disallowed email provider"; "Scene.Register.Error.Reason.Inclusion" = "%@ is not a supported value"; -"Scene.Register.Error.Reason.Invalid" = "%@ is invalid"; +"Scene.Register.Error.Reason.Invalid" = "%@ غير صالح"; "Scene.Register.Error.Reason.Reserved" = "%@ is a reserved keyword"; "Scene.Register.Error.Reason.Taken" = "%@ is already in use"; -"Scene.Register.Error.Reason.TooLong" = "%@ is too long"; -"Scene.Register.Error.Reason.TooShort" = "%@ is too short"; +"Scene.Register.Error.Reason.TooLong" = "%@ طويل جداً"; +"Scene.Register.Error.Reason.TooShort" = "%@ قصير جدا"; "Scene.Register.Error.Reason.Unreachable" = "%@ does not seem to exist"; -"Scene.Register.Error.Special.EmailInvalid" = "This is not a valid email address"; -"Scene.Register.Error.Special.PasswordTooShort" = "Password is too short (must be at least 8 characters)"; +"Scene.Register.Error.Special.EmailInvalid" = "هذا عنوان بريد إلكتروني غير صالح"; +"Scene.Register.Error.Special.PasswordTooShort" = "كلمة المرور قصيرة جداً (يجب أن تكون 8 أحرف على الأقل)"; "Scene.Register.Error.Special.UsernameInvalid" = "Username must only contain alphanumeric characters and underscores"; "Scene.Register.Error.Special.UsernameTooLong" = "Username is too long (can’t be longer than 30 characters)"; "Scene.Register.Input.Avatar.Delete" = "احذف"; @@ -249,24 +252,24 @@ tap the link to confirm your account."; "Scene.Register.Title" = "أخبرنا عنك."; "Scene.Report.Content1" = "Are there any other posts you’d like to add to the report?"; "Scene.Report.Content2" = "Is there anything the moderators should know about this report?"; -"Scene.Report.Send" = "Send Report"; -"Scene.Report.SkipToSend" = "Send without comment"; +"Scene.Report.Send" = "ارسل الشكوى"; +"Scene.Report.SkipToSend" = "إرسال بدون تعليق"; "Scene.Report.Step1" = "الخطوة 1 من 2"; "Scene.Report.Step2" = "الخطوة 2 من 2"; "Scene.Report.TextPlaceholder" = "Type or paste additional comments"; "Scene.Report.Title" = "ابلغ عن %@"; -"Scene.Search.Recommend.Accounts.Description" = "You may like to follow these accounts"; +"Scene.Search.Recommend.Accounts.Description" = "قد ترغب في متابعة هذه الحسابات"; "Scene.Search.Recommend.Accounts.Follow" = "تابع"; -"Scene.Search.Recommend.Accounts.Title" = "Accounts you might like"; +"Scene.Search.Recommend.Accounts.Title" = "حسابات قد تعجبك"; "Scene.Search.Recommend.ButtonText" = "طالع الكل"; "Scene.Search.Recommend.HashTag.Description" = "Hashtags that are getting quite a bit of attention"; "Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ people are talking"; "Scene.Search.Recommend.HashTag.Title" = "ذات شعبية على ماستدون"; "Scene.Search.SearchBar.Cancel" = "إلغاء"; "Scene.Search.SearchBar.Placeholder" = "البحث عن وسوم أو مستخدمين·ات"; -"Scene.Search.Searching.Clear" = "Clear"; -"Scene.Search.Searching.EmptyState.NoResults" = "No results"; -"Scene.Search.Searching.RecentSearch" = "Recent searches"; +"Scene.Search.Searching.Clear" = "امسح"; +"Scene.Search.Searching.EmptyState.NoResults" = "ليس هناك أية نتيجة"; +"Scene.Search.Searching.RecentSearch" = "عمليات البحث الأخيرة"; "Scene.Search.Searching.Segment.All" = "الكل"; "Scene.Search.Searching.Segment.Hashtags" = "الوسوم"; "Scene.Search.Searching.Segment.People" = "الأشخاص"; @@ -299,10 +302,10 @@ tap the link to confirm your account."; any server."; "Scene.ServerRules.Button.Confirm" = "انا أوافق"; "Scene.ServerRules.PrivacyPolicy" = "سياسة الخصوصية"; -"Scene.ServerRules.Prompt" = "By continuing, you’re subject to the terms of service and privacy policy for %@."; -"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@."; +"Scene.ServerRules.Prompt" = "إن اخترت المواصلة، فإنك تخضع لشروط الخدمة وسياسة الخصوصية لـ %@."; +"Scene.ServerRules.Subtitle" = "تم سنّ هذه القواعد من قبل مشرفي %@."; "Scene.ServerRules.TermsOfService" = "شروط الخدمة"; -"Scene.ServerRules.Title" = "Some ground rules."; +"Scene.ServerRules.Title" = "بعض القواعد الأساسية."; "Scene.Settings.Footer.MastodonDescription" = "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على غيت هب %@ (%@)"; "Scene.Settings.Keyboard.CloseSettingsWindow" = "إغلاق نافذة الإعدادات"; "Scene.Settings.Section.Appearance.Automatic" = "تلقائي"; @@ -312,15 +315,15 @@ any server."; "Scene.Settings.Section.BoringZone.AccountSettings" = "إعدادات الحساب"; "Scene.Settings.Section.BoringZone.Privacy" = "سياسة الخصوصية"; "Scene.Settings.Section.BoringZone.Terms" = "شروط الخدمة"; -"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone"; +"Scene.Settings.Section.BoringZone.Title" = "المنطقة المملة"; "Scene.Settings.Section.Notifications.Boosts" = "Reblogs my post"; "Scene.Settings.Section.Notifications.Favorites" = "Favorites my post"; -"Scene.Settings.Section.Notifications.Follows" = "Follows me"; +"Scene.Settings.Section.Notifications.Follows" = "يتابعني"; "Scene.Settings.Section.Notifications.Mentions" = "Mentions me"; "Scene.Settings.Section.Notifications.Title" = "الإشعارات"; "Scene.Settings.Section.Notifications.Trigger.Anyone" = "anyone"; "Scene.Settings.Section.Notifications.Trigger.Follow" = "anyone I follow"; -"Scene.Settings.Section.Notifications.Trigger.Follower" = "a follower"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "مشترِك"; "Scene.Settings.Section.Notifications.Trigger.Noone" = "no one"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars"; @@ -328,13 +331,16 @@ any server."; "Scene.Settings.Section.Preference.Title" = "التفضيلات"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links"; -"Scene.Settings.Section.SpicyZone.Clear" = "Clear Media Cache"; +"Scene.Settings.Section.SpicyZone.Clear" = "مسح ذاكرة التخزين المؤقت للوسائط"; "Scene.Settings.Section.SpicyZone.Signout" = "تسجيل الخروج"; -"Scene.Settings.Section.SpicyZone.Title" = "The Spicy Zone"; +"Scene.Settings.Section.SpicyZone.Title" = "المنطقة الحارة"; "Scene.Settings.Title" = "الإعدادات"; "Scene.SuggestionAccount.FollowExplain" = "When you follow someone, you’ll see their posts in your home feed."; -"Scene.SuggestionAccount.Title" = "Find People to Follow"; +"Scene.SuggestionAccount.Title" = "ابحث عن أشخاص لمتابعتهم"; "Scene.Thread.BackTitle" = "Post"; "Scene.Thread.Title" = "Post from %@"; "Scene.Welcome.Slogan" = "Social networking -back in your hands."; \ No newline at end of file +back in your hands."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/ar.lproj/Localizable.stringsdict b/Mastodon/Resources/ar.lproj/Localizable.stringsdict index 537064efb..e6b0d5f95 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ar.lproj/Localizable.stringsdict @@ -2,6 +2,30 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + %ld unread notification + one + 1 unread notification + two + %ld unread notification + few + %ld unread notification + many + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/ca.lproj/Localizable.strings b/Mastodon/Resources/ca.lproj/Localizable.strings index fc0168abc..f7492aa86 100644 --- a/Mastodon/Resources/ca.lproj/Localizable.strings +++ b/Mastodon/Resources/ca.lproj/Localizable.strings @@ -133,6 +133,9 @@ El teu perfil els sembla així."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions que falten..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostra més respostes"; "Common.Controls.Timeline.Timestamp.Now" = "Ara"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Afegeix Adjunt"; "Scene.Compose.Accessibility.AppendPoll" = "Afegir enquesta"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector d'Emoji Personalitzat"; @@ -337,4 +340,7 @@ qualsevol servidor."; "Scene.Thread.BackTitle" = "Publicació"; "Scene.Thread.Title" = "Publicació de %@"; "Scene.Welcome.Slogan" = "Xarxa social -de nou a les teves mans."; \ No newline at end of file +de nou a les teves mans."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/ca.lproj/Localizable.stringsdict b/Mastodon/Resources/ca.lproj/Localizable.stringsdict index b76b0a921..65a83d363 100644 --- a/Mastodon/Resources/ca.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ca.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/de.lproj/Localizable.strings b/Mastodon/Resources/de.lproj/Localizable.strings index 353cf1433..cc92b8e77 100644 --- a/Mastodon/Resources/de.lproj/Localizable.strings +++ b/Mastodon/Resources/de.lproj/Localizable.strings @@ -133,6 +133,9 @@ Dein Profil sieht für diesen Benutzer auch so aus."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Lade fehlende Beiträge..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Weitere Antworten anzeigen"; "Common.Controls.Timeline.Timestamp.Now" = "Gerade"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Anhang hinzufügen"; "Scene.Compose.Accessibility.AppendPoll" = "Umfrage hinzufügen"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Benutzerdefinierter Emojiwähler"; @@ -336,4 +339,7 @@ beliebigen Server."; "Scene.SuggestionAccount.Title" = "Finde Personen zum Folgen"; "Scene.Thread.BackTitle" = "Beitrag"; "Scene.Thread.Title" = "Beitrag von %@"; -"Scene.Welcome.Slogan" = "Soziale Netzwerke wieder in deinen Händen."; \ No newline at end of file +"Scene.Welcome.Slogan" = "Soziale Netzwerke wieder in deinen Händen."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/de.lproj/Localizable.stringsdict b/Mastodon/Resources/de.lproj/Localizable.stringsdict index e89bdb074..c868bdc0f 100644 --- a/Mastodon/Resources/de.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/de.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/en.lproj/Localizable.strings b/Mastodon/Resources/en.lproj/Localizable.strings index ff8bb12d8..a8852675c 100644 --- a/Mastodon/Resources/en.lproj/Localizable.strings +++ b/Mastodon/Resources/en.lproj/Localizable.strings @@ -133,6 +133,9 @@ Your profile looks like this to them."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Loading missing posts..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Show more replies"; "Common.Controls.Timeline.Timestamp.Now" = "Now"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Add Attachment"; "Scene.Compose.Accessibility.AppendPoll" = "Add Poll"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Custom Emoji Picker"; @@ -337,4 +340,7 @@ any server."; "Scene.Thread.BackTitle" = "Post"; "Scene.Thread.Title" = "Post from %@"; "Scene.Welcome.Slogan" = "Social networking -back in your hands."; \ No newline at end of file +back in your hands."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/en.lproj/Localizable.stringsdict b/Mastodon/Resources/en.lproj/Localizable.stringsdict index c7c84d074..730e2902a 100644 --- a/Mastodon/Resources/en.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/en.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/es-419.lproj/Localizable.strings b/Mastodon/Resources/es-419.lproj/Localizable.strings index 7189f282a..eda6b4efd 100644 --- a/Mastodon/Resources/es-419.lproj/Localizable.strings +++ b/Mastodon/Resources/es-419.lproj/Localizable.strings @@ -133,6 +133,9 @@ Tu perfil le aparece así a este usuario."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Cargando mensajes faltantes…"; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostrar más respuestas"; "Common.Controls.Timeline.Timestamp.Now" = "Ahora"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Agregar archivo adjunto"; "Scene.Compose.Accessibility.AppendPoll" = "Agregar encuesta"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector de emoji personalizado"; @@ -337,4 +340,7 @@ el que quieras."; "Scene.Thread.BackTitle" = "Mensaje"; "Scene.Thread.Title" = "Mensaje de %@"; "Scene.Welcome.Slogan" = "La red social, -nuevamente en tu poder."; \ No newline at end of file +nuevamente en tu poder."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/es-419.lproj/Localizable.stringsdict b/Mastodon/Resources/es-419.lproj/Localizable.stringsdict index f98962ccb..dbbd363fa 100644 --- a/Mastodon/Resources/es-419.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/es-419.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/es.lproj/Localizable.strings b/Mastodon/Resources/es.lproj/Localizable.strings index db1680d43..1fffc928a 100644 --- a/Mastodon/Resources/es.lproj/Localizable.strings +++ b/Mastodon/Resources/es.lproj/Localizable.strings @@ -133,6 +133,9 @@ Tu perfil se ve así para él."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Cargando publicaciones faltantes..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostrar más respuestas"; "Common.Controls.Timeline.Timestamp.Now" = "Ahora"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Añadir Adjunto"; "Scene.Compose.Accessibility.AppendPoll" = "Añadir Encuesta"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector de Emojis Personalizados"; @@ -337,4 +340,7 @@ cualquier servidor."; "Scene.Thread.BackTitle" = "Publicación"; "Scene.Thread.Title" = "Publicación de %@"; "Scene.Welcome.Slogan" = "Las redes sociales -de nuevo en tus manos."; \ No newline at end of file +de nuevo en tus manos."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/es.lproj/Localizable.stringsdict b/Mastodon/Resources/es.lproj/Localizable.stringsdict index bf493c1e8..d31d8825b 100644 --- a/Mastodon/Resources/es.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/es.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/fr.lproj/Localizable.strings b/Mastodon/Resources/fr.lproj/Localizable.strings index f7810e3fd..76df6b600 100644 --- a/Mastodon/Resources/fr.lproj/Localizable.strings +++ b/Mastodon/Resources/fr.lproj/Localizable.strings @@ -81,12 +81,12 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Keyboard.Common.SwitchToTab" = "Basculer vers %@"; "Common.Controls.Keyboard.SegmentedControl.NextSection" = "Prochaine section"; "Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Section précédente"; -"Common.Controls.Keyboard.Timeline.NextStatus" = "Article suivant"; -"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Ouvrir le profil de l'auteur"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "Publication suivante"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Ouvrir le profil de l’auteur·rice"; "Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Ouvrir le profil du rebloggeur"; "Common.Controls.Keyboard.Timeline.OpenStatus" = "Ouvrir la publication"; "Common.Controls.Keyboard.Timeline.PreviewImage" = "Prévisualiser l’image"; -"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Article précédent"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Publication précédente"; "Common.Controls.Keyboard.Timeline.ReplyStatus" = "Répondre à la publication"; "Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Basculer l’avertissement de contenu"; "Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Basculer le favori lors de la publication"; @@ -102,14 +102,14 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Poll.Closed" = "Fermé"; "Common.Controls.Status.Poll.Vote" = "Voter"; "Common.Controls.Status.ShowPost" = "Montrer la publication"; -"Common.Controls.Status.ShowUserProfile" = "Montrer le profil de l’utilisateur"; +"Common.Controls.Status.ShowUserProfile" = "Montrer le profil de l’utilisateur·rice"; "Common.Controls.Status.Tag.Email" = "Courriel"; "Common.Controls.Status.Tag.Emoji" = "Émoji"; "Common.Controls.Status.Tag.Hashtag" = "Hashtag"; "Common.Controls.Status.Tag.Link" = "Lien"; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.UserReblogged" = "%@ à reblogué"; +"Common.Controls.Status.UserReblogged" = "%@ a reblogué"; "Common.Controls.Status.UserRepliedTo" = "À répondu à %@"; "Common.Controls.Tabs.Home" = "Accueil"; "Common.Controls.Tabs.Notification" = "Notification"; @@ -124,17 +124,21 @@ Votre profil ressemble à ça pour lui."; "Common.Controls.Timeline.Header.NoStatusFound" = "Aucune publication trouvée"; "Common.Controls.Timeline.Header.SuspendedWarning" = "Cet utilisateur a été suspendu."; "Common.Controls.Timeline.Header.UserBlockedWarning" = "Vous ne pouvez pas voir le profil de %@ - tant qu'il ne vous aura pas débloqué."; -"Common.Controls.Timeline.Header.UserBlockingWarning" = "Vous ne pouvez pas voir le profil de %@ tant que vous ne l’avez pas débloqué +tant qu’il ne vous aura pas débloqué."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "Vous ne pouvez pas voir le profil de %@ +tant que vous ne l’avez pas débloqué Votre profil ressemble à ça pour lui."; "Common.Controls.Timeline.Header.UserSuspendedWarning" = "Le compte de %@ à été suspendu."; "Common.Controls.Timeline.Loader.LoadMissingPosts" = "Charger les messages manquants"; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Chargement des publications manquantes..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Charger plus de réponses"; "Common.Controls.Timeline.Timestamp.Now" = "À l’instant"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Joindre un document"; "Scene.Compose.Accessibility.AppendPoll" = "Ajouter un Sondage"; -"Scene.Compose.Accessibility.CustomEmojiPicker" = "Sélecteur d’émojis personnalisé"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Sélecteur d’émojis personnalisés"; "Scene.Compose.Accessibility.DisableContentWarning" = "Désactiver l'avertissement de contenu"; "Scene.Compose.Accessibility.EnableContentWarning" = "Basculer l’avertissement de contenu"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Menu de Visibilité de la publication"; @@ -195,12 +199,12 @@ tapotez le lien pour confirmer votre compte."; "Scene.Notification.Keyobard.ShowMentions" = "Afficher les mentions"; "Scene.Notification.Title.Everything" = "Tout"; "Scene.Notification.Title.Mentions" = "Mentions"; -"Scene.Notification.UserFavorited Your Post" = "%@ favorited your post"; -"Scene.Notification.UserFollowedYou" = "%@ followed you"; -"Scene.Notification.UserMentionedYou" = "%@ mentioned you"; -"Scene.Notification.UserRebloggedYourPost" = "%@ reblogged your post"; -"Scene.Notification.UserRequestedToFollowYou" = "%@ requested to follow you"; -"Scene.Notification.UserYourPollHasEnded" = "%@ Your poll has ended"; +"Scene.Notification.UserFavorited Your Post" = "%@ a mis votre pouet en favori"; +"Scene.Notification.UserFollowedYou" = "%@ s’est abonné à vous"; +"Scene.Notification.UserMentionedYou" = "%@ vous a mentionné"; +"Scene.Notification.UserRebloggedYourPost" = "%@ a partagé votre publication"; +"Scene.Notification.UserRequestedToFollowYou" = "%@ a demandé à vous suivre"; +"Scene.Notification.UserYourPollHasEnded" = "%@ votre sondage est terminé"; "Scene.Preview.Keyboard.ClosePreview" = "Fermer l'aperçu"; "Scene.Preview.Keyboard.ShowNext" = "Afficher le suivant"; "Scene.Preview.Keyboard.ShowPrevious" = "Afficher le précédent"; @@ -212,7 +216,7 @@ tapotez le lien pour confirmer votre compte."; "Scene.Profile.Fields.Placeholder.Label" = "Étiquette"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Message" = "Confirmer le déblocage de %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Title" = "Débloquer le compte"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Êtes-vous sûr de vouloir mettre en sourdine %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Êtes-vous sûr de vouloir désactiver la sourdine de %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Ne plus mettre en sourdine ce compte"; "Scene.Profile.SegmentedControl.Media" = "Média"; "Scene.Profile.SegmentedControl.Posts" = "Publications"; @@ -222,7 +226,7 @@ tapotez le lien pour confirmer votre compte."; "Scene.Register.Error.Item.Locale" = "Lieu"; "Scene.Register.Error.Item.Password" = "Mot de passe"; "Scene.Register.Error.Item.Reason" = "Raison"; -"Scene.Register.Error.Item.Username" = "Nom d'utilisateur"; +"Scene.Register.Error.Item.Username" = "Nom d’utilisateur"; "Scene.Register.Error.Reason.Accepted" = "%@ doit être accepté"; "Scene.Register.Error.Reason.Blank" = "%@ est requis"; "Scene.Register.Error.Reason.Blocked" = "%@ contient un fournisseur courriel proscrit"; @@ -293,7 +297,7 @@ tapotez le lien pour confirmer votre compte."; "Scene.ServerPicker.Input.Placeholder" = "Trouvez un serveur ou rejoignez le vôtre..."; "Scene.ServerPicker.Label.Category" = "CATÉGORIE"; "Scene.ServerPicker.Label.Language" = "LANGUE"; -"Scene.ServerPicker.Label.Users" = "UTILISATEURS"; +"Scene.ServerPicker.Label.Users" = "UTILISATEUR·RICE·S"; "Scene.ServerPicker.Title" = "Choisissez un serveur, n'importe quel serveur."; "Scene.ServerRules.Button.Confirm" = "J’accepte"; @@ -323,7 +327,7 @@ n'importe quel serveur."; "Scene.Settings.Section.Notifications.Trigger.Noone" = "personne"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Me notifier lorsque"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Désactiver les avatars animés"; -"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Désactiver les émoticônes animées"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Désactiver les émojis animées"; "Scene.Settings.Section.Preference.Title" = "Préférences"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Vrai mode sombre"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Utiliser le navigateur par défaut pour ouvrir les liens"; @@ -335,4 +339,7 @@ n'importe quel serveur."; "Scene.SuggestionAccount.Title" = "Trouver des personnes à suivre"; "Scene.Thread.BackTitle" = "Publication"; "Scene.Thread.Title" = "Publication de %@"; -"Scene.Welcome.Slogan" = "Le réseau social qui vous rend le contrôle."; \ No newline at end of file +"Scene.Welcome.Slogan" = "Le réseau social qui vous rend le contrôle."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/fr.lproj/Localizable.stringsdict b/Mastodon/Resources/fr.lproj/Localizable.stringsdict index d6fb911f3..d512b204c 100644 --- a/Mastodon/Resources/fr.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/fr.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey @@ -13,9 +29,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 caractère other - %ld characters + %ld caractères a11y.plural.count.input_limit_remains @@ -29,9 +45,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 caractère other - %ld characters + %ld caractères plural.count.metric_formatted.post @@ -61,9 +77,9 @@ NSStringFormatValueTypeKey ld one - 1 post + 1 publication other - %ld posts + %ld publications plural.count.favorite @@ -157,9 +173,9 @@ NSStringFormatValueTypeKey ld one - 1 following + 1 abonnement other - %ld following + %ld abonnements plural.count.follower @@ -173,9 +189,9 @@ NSStringFormatValueTypeKey ld one - 1 follower + 1 abonné·e other - %ld followers + %ld abonné·e·s date.year.left @@ -189,9 +205,9 @@ NSStringFormatValueTypeKey ld one - 1 year left + Il reste 1 an other - %ld years left + %ld ans restants date.month.left @@ -205,9 +221,9 @@ NSStringFormatValueTypeKey ld one - 1 months left + 1 mois restant other - %ld months left + %ld mois restants date.day.left @@ -221,9 +237,9 @@ NSStringFormatValueTypeKey ld one - 1 day left + Il reste 1 jour other - %ld days left + il reste %ld jours date.hour.left @@ -237,9 +253,9 @@ NSStringFormatValueTypeKey ld one - 1 hour left + 1 heure restante other - %ld hours left + %ld heures restantes date.minute.left @@ -253,9 +269,9 @@ NSStringFormatValueTypeKey ld one - 1 minute left + 1 minute restante other - %ld minutes left + %ld minutes restantes date.second.left @@ -269,9 +285,9 @@ NSStringFormatValueTypeKey ld one - 1 second left + Il reste 1 seconde other - %ld seconds left + %ld secondes restantes date.year.ago.abbr @@ -285,9 +301,9 @@ NSStringFormatValueTypeKey ld one - 1y ago + il y a 1 année other - %ldy ago + il y a %ld ans date.month.ago.abbr @@ -301,9 +317,9 @@ NSStringFormatValueTypeKey ld one - 1M ago + il y a 1 mois other - %ldM ago + il y a %ld mois date.day.ago.abbr @@ -317,9 +333,9 @@ NSStringFormatValueTypeKey ld one - 1d ago + il y a 1j other - %ldd ago + il y a %ldj date.hour.ago.abbr @@ -333,9 +349,9 @@ NSStringFormatValueTypeKey ld one - 1h ago + il y a 1h other - %ldh ago + il y a %ldh date.minute.ago.abbr @@ -349,9 +365,9 @@ NSStringFormatValueTypeKey ld one - 1m ago + Il y a 1 m other - %ldm ago + il y a %ld m date.second.ago.abbr @@ -365,9 +381,9 @@ NSStringFormatValueTypeKey ld one - 1s ago + Il y a 1 s other - %lds ago + il y a %ld s diff --git a/Mastodon/Resources/gd-GB.lproj/Localizable.strings b/Mastodon/Resources/gd-GB.lproj/Localizable.strings index 985819610..f24bd24e9 100644 --- a/Mastodon/Resources/gd-GB.lproj/Localizable.strings +++ b/Mastodon/Resources/gd-GB.lproj/Localizable.strings @@ -133,6 +133,9 @@ Seo an coltas a th’ air a’ phròifil agad dhaibh-san."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "A’ luchdadh nam post a tha a dhìth…"; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Seall barrachd freagairtean"; "Common.Controls.Timeline.Timestamp.Now" = "An-dràsta"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Cuir ceanglachan ris"; "Scene.Compose.Accessibility.AppendPoll" = "Cuir cunntas-bheachd ris"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Roghnaichear nan Emoji gnàthaichte"; @@ -336,4 +339,7 @@ thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.Thread.BackTitle" = "Post"; "Scene.Thread.Title" = "Post le %@"; "Scene.Welcome.Slogan" = "A’ cur nan lìonraidhean sòisealta -’nad làmhan fhèin."; \ No newline at end of file +’nad làmhan fhèin."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict b/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict index 63a998c6e..41e592a5e 100644 --- a/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict @@ -2,6 +2,26 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + two + %ld unread notification + few + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/ja.lproj/Localizable.strings b/Mastodon/Resources/ja.lproj/Localizable.strings index 681461212..e83278e34 100644 --- a/Mastodon/Resources/ja.lproj/Localizable.strings +++ b/Mastodon/Resources/ja.lproj/Localizable.strings @@ -129,6 +129,9 @@ "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "読込中..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "リプライをもっとみる"; "Common.Controls.Timeline.Timestamp.Now" = "今"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "アタッチメントの追加"; "Scene.Compose.Accessibility.AppendPoll" = "投票を追加"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "カスタム絵文字ピッカー"; @@ -330,4 +333,7 @@ "Scene.Thread.BackTitle" = "投稿"; "Scene.Thread.Title" = "%@の投稿"; "Scene.Welcome.Slogan" = "Social networking -back in your hands."; \ No newline at end of file +back in your hands."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/ja.lproj/Localizable.stringsdict b/Mastodon/Resources/ja.lproj/Localizable.stringsdict index ac37d9a39..0300d9dc3 100644 --- a/Mastodon/Resources/ja.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ja.lproj/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/nl.lproj/Localizable.strings b/Mastodon/Resources/nl.lproj/Localizable.strings index 6f4c33134..1ebda1172 100644 --- a/Mastodon/Resources/nl.lproj/Localizable.strings +++ b/Mastodon/Resources/nl.lproj/Localizable.strings @@ -128,6 +128,9 @@ Uw profiel ziet er zo uit voor hen."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Resterende berichten laden..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Toon meer reacties"; "Common.Controls.Timeline.Timestamp.Now" = "Nu"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Bijlage Toevoegen"; "Scene.Compose.Accessibility.AppendPoll" = "Peiling Toevoegen"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Eigen Emojikiezer"; @@ -329,4 +332,7 @@ klik op de link om uw account te bevestigen."; "Scene.SuggestionAccount.Title" = "Zoek Mensen om te Volgen"; "Scene.Thread.BackTitle" = "Bericht"; "Scene.Thread.Title" = "Bericht van %@"; -"Scene.Welcome.Slogan" = "Sociale media terug in uw handen."; \ No newline at end of file +"Scene.Welcome.Slogan" = "Sociale media terug in uw handen."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/nl.lproj/Localizable.stringsdict b/Mastodon/Resources/nl.lproj/Localizable.stringsdict index 1726606b4..8b6ab05ca 100644 --- a/Mastodon/Resources/nl.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/nl.lproj/Localizable.stringsdict @@ -2,6 +2,22 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/ru.lproj/InfoPlist.strings b/Mastodon/Resources/ru.lproj/InfoPlist.strings index 710865573..ccb7ca685 100644 --- a/Mastodon/Resources/ru.lproj/InfoPlist.strings +++ b/Mastodon/Resources/ru.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 +"SearchShortcutItemTitle" = "Поиск"; \ No newline at end of file diff --git a/Mastodon/Resources/ru.lproj/Localizable.strings b/Mastodon/Resources/ru.lproj/Localizable.strings index 4c0e5eafa..3a8adbbab 100644 --- a/Mastodon/Resources/ru.lproj/Localizable.strings +++ b/Mastodon/Resources/ru.lproj/Localizable.strings @@ -141,6 +141,9 @@ "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Загрузка недостающих постов..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Показать больше ответов"; "Common.Controls.Timeline.Timestamp.Now" = "Только что"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Прикрепить файл"; "Scene.Compose.Accessibility.AppendPoll" = "Добавить опрос"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Меню пользовательских эмодзи"; @@ -347,4 +350,7 @@ "Scene.Thread.BackTitle" = "Пост"; "Scene.Thread.Title" = "Пост %@"; "Scene.Welcome.Slogan" = "Социальная сеть -под вашим контролем."; \ No newline at end of file +под вашим контролем."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/ru.lproj/Localizable.stringsdict b/Mastodon/Resources/ru.lproj/Localizable.stringsdict index 1a9a44a0f..96afce4ed 100644 --- a/Mastodon/Resources/ru.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ru.lproj/Localizable.stringsdict @@ -2,10 +2,30 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + few + %ld unread notification + many + %ld unread notification + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Лимит превышен на %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -13,19 +33,19 @@ NSStringFormatValueTypeKey ld one - 1 character + %ld символ few - %ld characters + %ld символа many - %ld characters + %ld символов other - %ld characters + %ld символа a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -33,13 +53,13 @@ NSStringFormatValueTypeKey ld one - 1 character + %ld символ остался few - %ld characters + %ld символа осталось many - %ld characters + %ld символов осталось other - %ld characters + %ld символа осталось plural.count.metric_formatted.post @@ -53,13 +73,13 @@ NSStringFormatValueTypeKey ld one - post + пост few - posts + поста many - posts + постов other - posts + поста plural.count.post @@ -133,13 +153,13 @@ NSStringFormatValueTypeKey ld one - 1 vote + %ld голос few - %ld votes + %ld голоса many - %ld votes + %ld голосов other - %ld votes + %ld голоса plural.count.voter diff --git a/Mastodon/Resources/th.lproj/Localizable.strings b/Mastodon/Resources/th.lproj/Localizable.strings index e3afe433f..0c586cab3 100644 --- a/Mastodon/Resources/th.lproj/Localizable.strings +++ b/Mastodon/Resources/th.lproj/Localizable.strings @@ -116,23 +116,26 @@ "Common.Controls.Tabs.Profile" = "โปรไฟล์"; "Common.Controls.Tabs.Search" = "ค้นหา"; "Common.Controls.Timeline.Filtered" = "กรองอยู่"; -"Common.Controls.Timeline.Header.BlockedWarning" = "You can’t view this user’s profile -until they unblock you."; -"Common.Controls.Timeline.Header.BlockingWarning" = "You can’t view this user's profile -until you unblock them. -Your profile looks like this to them."; +"Common.Controls.Timeline.Header.BlockedWarning" = "คุณไม่สามารถดูโปรไฟล์ของผู้ใช้นี้ +จนกว่าผู้ใช้นี้จะเลิกปิดกั้นคุณ"; +"Common.Controls.Timeline.Header.BlockingWarning" = "คุณไม่สามารถดูโปรไฟล์ของผู้ใช้นี้ +จนกว่าคุณจะเลิกปิดกั้นผู้ใช้นี้ +ผู้ใช้นี้เห็นโปรไฟล์ของคุณเหมือนกับที่คุณเห็น"; "Common.Controls.Timeline.Header.NoStatusFound" = "ไม่พบโพสต์"; "Common.Controls.Timeline.Header.SuspendedWarning" = "ผู้ใช้นี้ถูกระงับการใช้งาน"; -"Common.Controls.Timeline.Header.UserBlockedWarning" = "You can’t view %@’s profile -until they unblock you."; -"Common.Controls.Timeline.Header.UserBlockingWarning" = "You can’t view %@’s profile -until you unblock them. -Your profile looks like this to them."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "คุณไม่สามารถดูโปรไฟล์ของ %@ +จนกว่าผู้ใช้นี้จะเลิกปิดกั้นคุณ"; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "คุณไม่สามารถดูโปรไฟล์ของ %@ +จนกว่าคุณจะเลิกปิดกั้นผู้ใช้นี้ +ผู้ใช้นี้เห็นโปรไฟล์ของคุณเหมือนกับที่คุณเห็น"; "Common.Controls.Timeline.Header.UserSuspendedWarning" = "บัญชีของ %@ ถูกระงับการใช้งาน"; "Common.Controls.Timeline.Loader.LoadMissingPosts" = "โหลดโพสต์ที่ขาดหายไป"; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "กำลังโหลดโพสต์ที่ขาดหายไป..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "แสดงการตอบกลับเพิ่มเติม"; "Common.Controls.Timeline.Timestamp.Now" = "ตอนนี้"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "เพิ่มไฟล์แนบ"; "Scene.Compose.Accessibility.AppendPoll" = "เพิ่มการสำรวจความคิดเห็น"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "ตัวเลือกอีโมจิที่กำหนดเอง"; @@ -285,7 +288,7 @@ Your profile looks like this to them."; "Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; "Scene.ServerPicker.Button.Category.Music" = "ดนตรี"; "Scene.ServerPicker.Button.Category.Regional" = "ภูมิภาค"; -"Scene.ServerPicker.Button.Category.Tech" = "tech"; +"Scene.ServerPicker.Button.Category.Tech" = "เทคโนโลยี"; "Scene.ServerPicker.Button.SeeLess" = "ดูน้อยลง"; "Scene.ServerPicker.Button.SeeMore" = "ดูเพิ่มเติม"; "Scene.ServerPicker.EmptyState.BadNetwork" = "มีบางอย่างผิดพลาดขณะโหลดข้อมูล ตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณ"; @@ -299,7 +302,7 @@ Your profile looks like this to them."; อันไหนก็ได้"; "Scene.ServerRules.Button.Confirm" = "ฉันเห็นด้วย"; "Scene.ServerRules.PrivacyPolicy" = "นโยบายความเป็นส่วนตัว"; -"Scene.ServerRules.Prompt" = "By continuing, you’re subject to the terms of service and privacy policy for %@."; +"Scene.ServerRules.Prompt" = "เมื่อคุณดำเนินการต่อ คุณอยู่ภายใต้เงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัวสำหรับ %@"; "Scene.ServerRules.Subtitle" = "กฎเหล่านี้ถูกตั้งโดยผู้ดูแลของ %@"; "Scene.ServerRules.TermsOfService" = "เงื่อนไขการให้บริการ"; "Scene.ServerRules.Title" = "กฎพื้นฐานบางประการ"; @@ -337,4 +340,7 @@ Your profile looks like this to them."; "Scene.Thread.BackTitle" = "โพสต์"; "Scene.Thread.Title" = "โพสต์จาก %@"; "Scene.Welcome.Slogan" = "ให้เครือข่ายสังคม -กลับมาอยู่ในมือของคุณ"; \ No newline at end of file +กลับมาอยู่ในมือของคุณ"; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/th.lproj/Localizable.stringsdict b/Mastodon/Resources/th.lproj/Localizable.stringsdict index dc114db41..1d6ff10bc 100644 --- a/Mastodon/Resources/th.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/th.lproj/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/Mastodon/Resources/zh-Hans.lproj/Localizable.strings b/Mastodon/Resources/zh-Hans.lproj/Localizable.strings index 946502c93..21c41a15d 100644 --- a/Mastodon/Resources/zh-Hans.lproj/Localizable.strings +++ b/Mastodon/Resources/zh-Hans.lproj/Localizable.strings @@ -133,6 +133,9 @@ "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "正在加载帖子..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "显示更多回复"; "Common.Controls.Timeline.Timestamp.Now" = "现在"; +"Scene.AccountList.AddAccount" = "添加账户"; +"Scene.AccountList.DismissAccountSwitcher" = "关闭账户切换页面"; +"Scene.AccountList.TabBarHint" = "当前账户:%@。 双击并按住来打开账户切换页面"; "Scene.Compose.Accessibility.AppendAttachment" = "添加附件"; "Scene.Compose.Accessibility.AppendPoll" = "添加投票"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "自定义表情选择器"; @@ -337,4 +340,7 @@ "Scene.Thread.BackTitle" = "帖子"; "Scene.Thread.Title" = "来自 %@ 的帖子"; "Scene.Welcome.Slogan" = "社交网络 -回到你的手中。"; \ No newline at end of file +回到你的手中。"; +"Scene.Wizard.AccessibilityHint" = "双击关闭此向导"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "按住个人资料标签按钮,即可在多个账户之间进行切换。"; +"Scene.Wizard.NewInMastodon" = "新功能"; \ No newline at end of file diff --git a/Mastodon/Resources/zh-Hans.lproj/Localizable.stringsdict b/Mastodon/Resources/zh-Hans.lproj/Localizable.stringsdict index c28637620..12b8b5f6e 100644 --- a/Mastodon/Resources/zh-Hans.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/zh-Hans.lproj/Localizable.stringsdict @@ -2,6 +2,20 @@ + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 条未读通知 + + a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey diff --git a/MastodonIntent/ar.lproj/Intents.strings b/MastodonIntent/ar.lproj/Intents.strings index 6877490ba..bf3e77ed2 100644 --- a/MastodonIntent/ar.lproj/Intents.strings +++ b/MastodonIntent/ar.lproj/Intents.strings @@ -1,14 +1,14 @@ "16wxgf" = "Post on Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "محتوى نصي"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "انشر على ماستدون"; "HZSGTr" = "What content to post?"; "HdGikU" = "Posting failed"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "سبب الإخفاق"; "RHxKOw" = "Send Post with text content"; @@ -20,9 +20,9 @@ "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "مدى الظهور"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "مدى ظهور المنشور"; "apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; @@ -32,11 +32,11 @@ "ayoYEb-ehFLjY" = "${content}, Followers Only"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "النشر على ماستدون"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "للعامة"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "لمتابعيك فقط"; "gfePDu" = "Posting failed. ${failureReason}"; @@ -46,6 +46,6 @@ "oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; -"rM6dvp" = "URL"; +"rM6dvp" = "عنوان URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "تم إرسال المنشور بنجاح. "; diff --git a/MastodonIntent/fr.lproj/Intents.strings b/MastodonIntent/fr.lproj/Intents.strings index 6877490ba..628f794c9 100644 --- a/MastodonIntent/fr.lproj/Intents.strings +++ b/MastodonIntent/fr.lproj/Intents.strings @@ -1,28 +1,28 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Publier sur Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Contenu textuel"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Publier sur Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Quel contenu à publier ?"; "HdGikU" = "Posting failed"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Raison de l’échec"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Envoyer une publication avec du contenu texte"; "RxSqsb" = "Post"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Publier du ${content} sur Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Publication"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Visibilité"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Visibilité de la publication"; "apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; @@ -30,15 +30,15 @@ "ayoYEb-dYQ5NN" = "${content}, Public"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, abonné·e·s seulement"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Publier sur Mastodon"; "dYQ5NN" = "Public"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Abonné·e·s seulement"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Échec lors de la publication. ${failureReason}"; "k7dbKQ" = "Post was sent successfully."; @@ -48,4 +48,4 @@ "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "La publication a été envoyée avec succès. "; diff --git a/MastodonIntent/gd-GB.lproj/Intents.strings b/MastodonIntent/gd-GB.lproj/Intents.strings index 0f8ef5edc..526defecd 100644 --- a/MastodonIntent/gd-GB.lproj/Intents.strings +++ b/MastodonIntent/gd-GB.lproj/Intents.strings @@ -24,9 +24,9 @@ "Zo4jgJ" = "Faicsinneachd a’ phuist"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Tha ${count} roghainn(ean) dha “Poblach” ann."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Tha ${count} roghainn(ean) dha “Luchd-leantainn a-mhàin” ann."; "ayoYEb-dYQ5NN" = "${content}, poblach"; From cf528983486d032c6ea2438cce99bd61888e4ff7 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 18:26:35 +0800 Subject: [PATCH 167/392] chore: use i18n resource in stead of raw string --- Mastodon/Scene/Account/AccountViewController.swift | 2 +- Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift | 2 +- Mastodon/Scene/Account/View/BadgeButton.swift | 2 +- Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift | 4 ++-- Mastodon/Scene/MainTab/MainTabBarController.swift | 2 +- Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index a7a0992e1..bb87e0a6c 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -110,7 +110,7 @@ extension AccountListViewController { dragIndicatorView.addGestureRecognizer(dragIndicatorTapGestureRecognizer) dragIndicatorTapGestureRecognizer.addTarget(self, action: #selector(AccountListViewController.dragIndicatorTapGestureRecognizerHandler(_:))) dragIndicatorView.isAccessibilityElement = true - dragIndicatorView.accessibilityLabel = "Dismiss Account Switcher" + dragIndicatorView.accessibilityLabel = L10n.Scene.AccountList.dismissAccountSwitcher } } diff --git a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift index 0ac022c5d..09d3fa554 100644 --- a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift @@ -20,7 +20,7 @@ final class AddAccountTableViewCell: UITableViewCell { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22) label.textColor = Asset.Colors.Label.primary.color - label.text = "Add Account" // TODO: i18n + label.text = L10n.Scene.AccountList.addAccount return label }() let usernameLabel = MetaLabel(style: .accountListUsername) diff --git a/Mastodon/Scene/Account/View/BadgeButton.swift b/Mastodon/Scene/Account/View/BadgeButton.swift index c55448ae4..6d92a8471 100644 --- a/Mastodon/Scene/Account/View/BadgeButton.swift +++ b/Mastodon/Scene/Account/View/BadgeButton.swift @@ -41,6 +41,6 @@ extension BadgeButton { let number = min(99, max(0, number)) setTitle("\(number)", for: .normal) self.isHidden = number == 0 - accessibilityLabel = "\(number) unread notification" + accessibilityLabel = L10n.A11y.Plural.Count.Unread.notification(number) } } diff --git a/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift b/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift index 0f143a98e..8f3f2eea4 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift @@ -47,13 +47,13 @@ extension MainTabBarController.Wizard { case multipleAccountSwitch var title: String { - return "New in Mastodon" + return L10n.Scene.Wizard.newInMastodon } var description: String { switch self { case .multipleAccountSwitch: - return "Switch between multiple accounts by holding the profile button." + return L10n.Scene.Wizard.multipleAccountSwitchIntroDescription } } diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index f07a1f905..1b261af32 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -242,7 +242,7 @@ extension MainTabBarController { guard let profileTabItem = _profileTabItem else { return } let currentUserDisplayName = activeMastodonAuthentication?.user.displayNameWithFallback ?? "no user" - profileTabItem.accessibilityHint = "Current selected profile: \(currentUserDisplayName). Double tap then hold to show account switcher" + profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName) } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift index defe6f4ee..024fb205d 100644 --- a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift +++ b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift @@ -127,7 +127,7 @@ extension WizardCardView { override var accessibilityHint: String? { get { - return "Wizard for account switcher on the Profile tab. Double tap to dismiss this wizard" + return L10n.Scene.Wizard.accessibilityHint } set { } } From 7bc3ba32feccca8b195fe60f8c473be2d3153bb3 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 16 Sep 2021 18:35:18 +0800 Subject: [PATCH 168/392] chore: update version to 1.1.0 (62) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 22 +++---- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 52 insertions(+), 52 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index f7c58d0a7..b1aab1762 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index f7c58d0a7..b1aab1762 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index f7c58d0a7..b1aab1762 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index c67b879ea..59adbd291 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4697,7 +4697,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4832,11 +4832,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4863,11 +4863,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4892,11 +4892,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4922,11 +4922,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4989,7 +4989,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5014,7 +5014,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5039,7 +5039,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5064,7 +5064,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5089,7 +5089,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5114,7 +5114,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5139,7 +5139,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5164,7 +5164,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5255,7 +5255,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5321,11 +5321,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5370,7 +5370,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5395,11 +5395,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5491,7 +5491,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5557,11 +5557,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5606,7 +5606,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5631,11 +5631,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 61; + DYLIB_CURRENT_VERSION = 62; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5661,7 +5661,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5685,7 +5685,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 61; + CURRENT_PROJECT_VERSION = 62; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 2fec1c757..f3f106ce5 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 38 + 35 CoreDataStack.xcscheme_^#shared#^_ orderHint - 35 + 36 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -22,7 +22,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 13 + 14 Mastodon - Release.xcscheme_^#shared#^_ @@ -32,17 +32,17 @@ Mastodon - ar.xcscheme_^#shared#^_ orderHint - 10 + 11 Mastodon - ca.xcscheme_^#shared#^_ orderHint - 16 + 18 Mastodon - de.xcscheme_^#shared#^_ orderHint - 11 + 12 Mastodon - en.xcscheme_^#shared#^_ @@ -67,12 +67,12 @@ Mastodon - jp.xcscheme_^#shared#^_ orderHint - 14 + 16 Mastodon - nl.xcscheme_^#shared#^_ orderHint - 12 + 13 Mastodon - ru.xcscheme_^#shared#^_ @@ -87,7 +87,7 @@ Mastodon - zh_Hans.xcscheme_^#shared#^_ orderHint - 15 + 17 Mastodon.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 36 + 37 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 38 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 59c8b7297..0f6669fb0 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -28,7 +28,7 @@ CFBundleVersion - 61 + 62 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 9d54c3878..981537320 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index f7c58d0a7..b1aab1762 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index f7c58d0a7..b1aab1762 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index c457414df..1157b08ed 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 190dddeb8..ef93f77e6 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 61 + 62 NSExtension NSExtensionAttributes From 1b024caf9b2b8a4413869e2212e4cef898d20832 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 15:20:41 +0200 Subject: [PATCH 169/392] New translations app.json (Swedish) --- Localization/StringsConvertor/input/sv_SE/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/sv_SE/app.json b/Localization/StringsConvertor/input/sv_SE/app.json index c5910c887..d0a9ad795 100644 --- a/Localization/StringsConvertor/input/sv_SE/app.json +++ b/Localization/StringsConvertor/input/sv_SE/app.json @@ -538,7 +538,7 @@ "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" + "add_account": "Lägg till konto" }, "wizard": { "new_in_mastodon": "New in Mastodon", From f6f5d378ac502ee1355058f8989303256b76c68b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 15:21:05 +0200 Subject: [PATCH 170/392] New translations app.json (Swedish, Finland) --- Localization/StringsConvertor/input/sv_FI/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/sv_FI/app.json b/Localization/StringsConvertor/input/sv_FI/app.json index c5910c887..d0a9ad795 100644 --- a/Localization/StringsConvertor/input/sv_FI/app.json +++ b/Localization/StringsConvertor/input/sv_FI/app.json @@ -538,7 +538,7 @@ "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" + "add_account": "Lägg till konto" }, "wizard": { "new_in_mastodon": "New in Mastodon", From e6cee447de4f0468072d563fbbe725e037553ccd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 17:12:35 +0200 Subject: [PATCH 171/392] New translations Localizable.stringsdict (Catalan) --- .../StringsConvertor/input/ca_ES/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict index 65a83d363..cc7312938 100644 --- a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notificació per llegir other - %ld unread notification + %ld notificacions per llegir a11y.plural.count.input_limit_exceeds From 3ad384e7aea31a9010a488f9a18a664271fcf120 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 17:12:36 +0200 Subject: [PATCH 172/392] New translations Localizable.stringsdict (Spanish, Argentina) --- .../StringsConvertor/input/es_AR/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict index dbbd363fa..f4f0097eb 100644 --- a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notificación sin leer other - %ld unread notification + %ld notificaciones sin leer a11y.plural.count.input_limit_exceeds From 685897d282d5be27f78b74d4ea97b3fc7f3f8185 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 17:12:37 +0200 Subject: [PATCH 173/392] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index 99d0e97b5..f98024602 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -536,14 +536,14 @@ } }, "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 actual seleccionat: %s. Toca dues vegades i manté el dit per a mostrar el commutador de comptes", + "dismiss_account_switcher": "Descartar el commutador de comptes", + "add_account": "Afegir compte" }, "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" + "multiple_account_switch_intro_description": "Commuta entre diversos comptes mantenint premut el botó del perfil.", + "accessibility_hint": "Toca dues vegades per descartar l'assistent" } } } \ No newline at end of file From 8e0776da1b2ea7129ba825d9a3dcb79db6d26306 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 17:12:38 +0200 Subject: [PATCH 174/392] New translations app.json (Spanish, Argentina) --- Localization/StringsConvertor/input/es_AR/app.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index 302aab22c..4ae708521 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -536,14 +536,14 @@ } }, "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 seleccionado actualmente: %s. Tocá dos veces y mantenelo presionado para cambiar de cuenta", + "dismiss_account_switcher": "Descartar cambio de cuenta", + "add_account": "Agregar cuenta" }, "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": "Novedad en Mastodon", + "multiple_account_switch_intro_description": "Cambiá entre varias cuentas manteniendo presionado el botón del perfil.", + "accessibility_hint": "Tocá dos veces para descartar este asistente" } } } \ No newline at end of file From ebf79ddfa05e15420e4e16194d927a7e5482579b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Sep 2021 18:19:04 +0200 Subject: [PATCH 175/392] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index f98024602..9ffdc5bee 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -541,7 +541,7 @@ "add_account": "Afegir compte" }, "wizard": { - "new_in_mastodon": "New in Mastodon", + "new_in_mastodon": "Nou a Mastodon", "multiple_account_switch_intro_description": "Commuta entre diversos comptes mantenint premut el botó del perfil.", "accessibility_hint": "Toca dues vegades per descartar l'assistent" } From 177ebe61549b5ec7d5a3f3e32c9bbb3130239e57 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 17 Sep 2021 03:46:50 +0200 Subject: [PATCH 176/392] New translations Localizable.stringsdict (Indonesian) --- .../StringsConvertor/input/id_ID/Localizable.stringsdict | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict index 5cd02115d..88c0fac97 100644 --- a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict @@ -83,7 +83,7 @@ NSStringFormatValueTypeKey ld other - %ld favorites + %ld favorit plural.count.reblog @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld votes + %ld suara plural.count.voter @@ -125,7 +125,7 @@ NSStringFormatValueTypeKey ld other - %ld voters + %ld pemilih plural.people_talking From 477d3709d0f432ced7de962326d5ca3bc6795ccb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 17 Sep 2021 03:46:51 +0200 Subject: [PATCH 177/392] New translations app.json (Indonesian) --- Localization/StringsConvertor/input/id_ID/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/id_ID/app.json b/Localization/StringsConvertor/input/id_ID/app.json index 180c1356c..3e9251b0b 100644 --- a/Localization/StringsConvertor/input/id_ID/app.json +++ b/Localization/StringsConvertor/input/id_ID/app.json @@ -267,7 +267,7 @@ "unreachable": "%s sepertinya tidak ada", "taken": "%s sudah digunakan", "reserved": "%s is a reserved keyword", - "accepted": "%s must be accepted", + "accepted": "%s harus diterima", "blank": "%s diperlukan", "invalid": "%s tidak valid", "too_long": "%s terlalu panjang", From 1f1b8caf4d38e7e91ee5ba886f46777655957100 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 17 Sep 2021 04:42:59 +0200 Subject: [PATCH 178/392] New translations app.json (Indonesian) --- Localization/StringsConvertor/input/id_ID/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/id_ID/app.json b/Localization/StringsConvertor/input/id_ID/app.json index 3e9251b0b..6ba29ad8f 100644 --- a/Localization/StringsConvertor/input/id_ID/app.json +++ b/Localization/StringsConvertor/input/id_ID/app.json @@ -355,7 +355,7 @@ "option_number": "Option %ld" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "Tulis peringatan yang akurat di sini..." }, "visibility": { "public": "Publik", From 4c456fe8a9a2c14750455b82b47ee35db409f732 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 17 Sep 2021 16:32:30 +0800 Subject: [PATCH 179/392] chore: update haptic feedback for reblog and favorite action --- .../StatusProvider/StatusProviderFacade.swift | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift index 4c34c6749..d11870ed2 100644 --- a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift +++ b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift @@ -259,8 +259,8 @@ extension StatusProviderFacade { guard let context = provider.context else { return } // haptic feedback generator - let generator = UIImpactFeedbackGenerator(style: .light) - let responseFeedbackGenerator = UINotificationFeedbackGenerator() + let generator = UISelectionFeedbackGenerator() + // let responseFeedbackGenerator = UINotificationFeedbackGenerator() status .compactMap { status -> (NSManagedObjectID, Mastodon.API.Favorites.FavoriteKind)? in @@ -287,10 +287,10 @@ extension StatusProviderFacade { .handleEvents(receiveSubscription: { _ in generator.prepare() }, receiveOutput: { _, favoriteKind in - generator.impactOccurred() + generator.selectionChanged() os_log("%{public}s[%{public}ld], %{public}s: [Like] update local status like status to: %s", ((#file as NSString).lastPathComponent), #line, #function, favoriteKind == .create ? "like" : "unlike") }, receiveCompletion: { completion in - responseFeedbackGenerator.prepare() + // responseFeedbackGenerator.prepare() switch completion { case .failure: // TODO: handle error @@ -312,10 +312,10 @@ extension StatusProviderFacade { guard let _ = provider else { return } switch completion { case .failure(let error): - responseFeedbackGenerator.notificationOccurred(.error) + // responseFeedbackGenerator.notificationOccurred(.error) os_log("%{public}s[%{public}ld], %{public}s: [Like] remote like request fail: %{public}s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription) case .finished: - responseFeedbackGenerator.notificationOccurred(.success) + // responseFeedbackGenerator.notificationOccurred(.success) os_log("%{public}s[%{public}ld], %{public}s: [Like] remote like request success", ((#file as NSString).lastPathComponent), #line, #function) } } receiveValue: { response in @@ -368,8 +368,8 @@ extension StatusProviderFacade { guard let context = provider.context else { return } // haptic feedback generator - let generator = UIImpactFeedbackGenerator(style: .light) - let responseFeedbackGenerator = UINotificationFeedbackGenerator() + let generator = UISelectionFeedbackGenerator() + // let responseFeedbackGenerator = UINotificationFeedbackGenerator() status .compactMap { status -> (NSManagedObjectID, Mastodon.API.Reblog.ReblogKind)? in @@ -396,7 +396,7 @@ extension StatusProviderFacade { .handleEvents(receiveSubscription: { _ in generator.prepare() }, receiveOutput: { _, reblogKind in - generator.impactOccurred() + generator.selectionChanged() switch reblogKind { case .reblog: os_log("%{public}s[%{public}ld], %{public}s: [Reblog] update local status reblog status to: %s", ((#file as NSString).lastPathComponent), #line, #function, "reblog") @@ -404,7 +404,7 @@ extension StatusProviderFacade { os_log("%{public}s[%{public}ld], %{public}s: [Reblog] update local status reblog status to: %s", ((#file as NSString).lastPathComponent), #line, #function, "unreblog") } }, receiveCompletion: { completion in - responseFeedbackGenerator.prepare() + // responseFeedbackGenerator.prepare() switch completion { case .failure: // TODO: handle error @@ -426,10 +426,10 @@ extension StatusProviderFacade { guard let _ = provider else { return } switch completion { case .failure(let error): - responseFeedbackGenerator.notificationOccurred(.error) + // responseFeedbackGenerator.notificationOccurred(.error) os_log("%{public}s[%{public}ld], %{public}s: [Reblog] remote reblog request fail: %{public}s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription) case .finished: - responseFeedbackGenerator.notificationOccurred(.success) + // responseFeedbackGenerator.notificationOccurred(.success) os_log("%{public}s[%{public}ld], %{public}s: [Reblog] remote reblog request success", ((#file as NSString).lastPathComponent), #line, #function) } } receiveValue: { response in @@ -469,8 +469,8 @@ extension StatusProviderFacade { guard let provider = provider else { return } guard let status = status?.reblog ?? status else { return } - let generator = UIImpactFeedbackGenerator(style: .light) - generator.impactOccurred() + let generator = UISelectionFeedbackGenerator() + generator.selectionChanged() let composeViewModel = ComposeViewModel(context: provider.context, composeKind: .reply(repliedToStatusObjectID: status.objectID)) provider.coordinator.present(scene: .compose(viewModel: composeViewModel), from: provider, transition: .modal(animated: true, completion: nil)) From 142bc91437ef304b76eee0ed43f8647fb729a084 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 17 Sep 2021 16:50:13 +0800 Subject: [PATCH 180/392] chore: update avatar button size in tab bar --- Mastodon/Scene/MainTab/MainTabBarController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index 1b261af32..d6d40a5d0 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -19,7 +19,7 @@ class MainTabBarController: UITabBarController { weak var context: AppContext! weak var coordinator: SceneCoordinator! - static let avatarButtonSize = CGSize(width: 28, height: 28) + static let avatarButtonSize = CGSize(width: 25, height: 25) let avatarButton = CircleAvatarButton() let wizard = Wizard() @@ -314,7 +314,7 @@ extension MainTabBarController { view.addSubview(self.avatarButton) NSLayoutConstraint.activate([ self.avatarButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor, constant: 1), // 1pt offset + self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor, constant: 1.5), // 1.5pt offset self.avatarButton.widthAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.width).priority(.required - 1), self.avatarButton.heightAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.height).priority(.required - 1), ]) From b65e591a96488410ca4db1c331e6ede23ecb4f69 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 17 Sep 2021 17:07:46 +0800 Subject: [PATCH 181/392] chore: update pan modal height dynamic --- .../Scene/Account/AccountViewController.swift | 18 ++++++++++++++++-- .../Account/Cell/AddAccountTableViewCell.swift | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index bb87e0a6c..2898b9b5f 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -33,6 +33,7 @@ final class AccountListViewController: UIViewController, NeedsDependency { let dragIndicatorView = DragIndicatorView() + var hasLoaded = false private(set) lazy var tableView: UITableView = { let tableView = UITableView() tableView.register(AccountListTableViewCell.self, forCellReuseIdentifier: String(describing: AccountListTableViewCell.self)) @@ -51,11 +52,22 @@ extension AccountListViewController: PanModalPresentable { var showDragIndicator: Bool { false } var shortFormHeight: PanModalHeight { - return .contentHeight(300) + func calculateHeight(of numberOfItems: Int) -> CGFloat { + return CGFloat(numberOfItems * 60 + 64) + } + + if hasLoaded { + let height = calculateHeight(of: viewModel.diffableDataSource.snapshot().numberOfItems) + return .contentHeight(CGFloat(height)) + } + + let count = viewModel.context.authenticationService.mastodonAuthentications.value.count + 1 + let height = calculateHeight(of: count) + return .contentHeight(height) } var longFormHeight: PanModalHeight { - return .maxHeightWithTopInset(40) + return .maxHeightWithTopInset(0) } } @@ -101,7 +113,9 @@ extension AccountListViewController { .receive(on: DispatchQueue.main) .sink { [weak self] in guard let self = self else { return } + self.hasLoaded = true self.panModalSetNeedsLayoutUpdate() + self.panModalTransition(to: .shortForm) } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift index 09d3fa554..743ad1dc2 100644 --- a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift @@ -55,9 +55,9 @@ extension AddAccountTableViewCell { titleLabel.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ - titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 19), + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 15), titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 10), - contentView.bottomAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 19), + contentView.bottomAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15), iconImageView.heightAnchor.constraint(equalTo: titleLabel.heightAnchor, multiplier: 1.0).priority(.required - 10), titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), ]) From 75f1a4852ad7aa8b89d8509da69572d78e165c96 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 17 Sep 2021 19:30:14 +0800 Subject: [PATCH 182/392] chore: update poll option reorder UX --- .../ComposeStatusPollTableViewCell.swift | 136 ++++++++++-------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift index f1a1693a2..0c2abb262 100644 --- a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift +++ b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift @@ -5,6 +5,7 @@ // Created by MainasuK Cirno on 2021-6-29. // +import os.log import UIKit protocol ComposeStatusPollTableViewCellDelegate: AnyObject { @@ -12,6 +13,8 @@ protocol ComposeStatusPollTableViewCellDelegate: AnyObject { } final class ComposeStatusPollTableViewCell: UITableViewCell { + + let logger = Logger(subsystem: "ComposeStatusPollTableViewCell", category: "UI") private(set) var dataSource: UICollectionViewDiffableDataSource! var observations = Set() @@ -43,6 +46,7 @@ final class ComposeStatusPollTableViewCell: UITableViewCell { collectionView.backgroundColor = .clear collectionView.alwaysBounceVertical = true collectionView.isScrollEnabled = false + collectionView.dragInteractionEnabled = true return collectionView }() @@ -75,12 +79,8 @@ extension ComposeStatusPollTableViewCell { collectionViewHeightLayoutConstraint, ]) - let longPressReorderGesture = UILongPressGestureRecognizer(target: self, action: #selector(ComposeStatusPollTableViewCell.longPressReorderGestureHandler(_:))) - collectionView.addGestureRecognizer(longPressReorderGesture) - collectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] collectionView, _ in guard let self = self else { return } - print(collectionView.contentSize) self.collectionViewHeightLayoutConstraint.constant = collectionView.contentSize.height } .store(in: &observations) @@ -122,66 +122,84 @@ extension ComposeStatusPollTableViewCell { return cell } } - - dataSource.reorderingHandlers.canReorderItem = { item in - switch item { - case .pollOption: return true - default: return false - } - } - - // update reordered data source - dataSource.reorderingHandlers.didReorder = { [weak self] transaction in - guard let self = self else { return } - - let items = transaction.finalSnapshot.itemIdentifiers - var pollOptionAttributes: [ComposeStatusPollItem.PollOptionAttribute] = [] - for item in items { - guard case let .pollOption(attribute) = item else { continue } - pollOptionAttributes.append(attribute) - } - self.delegate?.composeStatusPollTableViewCell(self, pollOptionAttributesDidReorder: pollOptionAttributes) - } + + collectionView.dragDelegate = self + collectionView.dropDelegate = self } } -extension ComposeStatusPollTableViewCell { - - @objc private func longPressReorderGestureHandler(_ sender: UILongPressGestureRecognizer) { - switch(sender.state) { - case .began: - guard let selectedIndexPath = collectionView.indexPathForItem(at: sender.location(in: collectionView)), - let cell = collectionView.cellForItem(at: selectedIndexPath) as? ComposeStatusPollOptionCollectionViewCell else { - break - } - // check if pressing reorder bar no not - let locationInCell = sender.location(in: cell) - guard cell.reorderBarImageView.frame.contains(locationInCell) else { - return - } - - collectionView.beginInteractiveMovementForItem(at: selectedIndexPath) - case .changed: - guard let selectedIndexPath = collectionView.indexPathForItem(at: sender.location(in: collectionView)), - let dataSource = self.dataSource else { - break - } - guard let item = dataSource.itemIdentifier(for: selectedIndexPath), - case .pollOption = item else { - collectionView.cancelInteractiveMovement() - return - } - - var position = sender.location(in: collectionView) - position.x = collectionView.frame.width * 0.5 - collectionView.updateInteractiveMovementTargetPosition(position) - case .ended: - collectionView.endInteractiveMovement() - collectionView.reloadData() +// MARK: - UICollectionViewDragDelegate +extension ComposeStatusPollTableViewCell: UICollectionViewDragDelegate { + + func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { + guard let item = dataSource.itemIdentifier(for: indexPath) else { return [] } + switch item { + case .pollOption: + let itemProvider = NSItemProvider(object: String(item.hashValue) as NSString) + let dragItem = UIDragItem(itemProvider: itemProvider) + dragItem.localObject = item + return [dragItem] default: - collectionView.cancelInteractiveMovement() + return [] } } - + + func collectionView(_ collectionView: UICollectionView, dragSessionIsRestrictedToDraggingApplication session: UIDragSession) -> Bool { + // drag to app should be the same app + return true + } +} + +// MARK: - UICollectionViewDropDelegate +extension ComposeStatusPollTableViewCell: UICollectionViewDropDelegate { + // didUpdate + func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal { + guard collectionView.hasActiveDrag, + let destinationIndexPath = destinationIndexPath, + let item = dataSource.itemIdentifier(for: destinationIndexPath) + else { + return UICollectionViewDropProposal(operation: .forbidden) + } + + switch item { + case .pollOption: + return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) + default: + return UICollectionViewDropProposal(operation: .cancel) + } + } + + // performDrop + func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) { + guard let dropItem = coordinator.items.first, + let item = dropItem.dragItem.localObject as? ComposeStatusPollItem, + case .pollOption = item + else { return } + + guard coordinator.proposal.operation == .move else { return } + guard let destinationIndexPath = coordinator.destinationIndexPath, + let _ = collectionView.cellForItem(at: destinationIndexPath) as? ComposeStatusPollOptionCollectionViewCell + else { return } + + var snapshot = dataSource.snapshot() + guard destinationIndexPath.row < snapshot.itemIdentifiers.count else { return } + let anchorItem = snapshot.itemIdentifiers[destinationIndexPath.row] + snapshot.moveItem(item, afterItem: anchorItem) + dataSource.apply(snapshot) + + coordinator.drop(dropItem.dragItem, toItemAt: destinationIndexPath) + } +} + +extension ComposeStatusPollTableViewCell: UICollectionViewDelegate { + func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(originalIndexPath.debugDescription) -> \(proposedIndexPath.debugDescription)") + + guard let _ = collectionView.cellForItem(at: proposedIndexPath) as? ComposeStatusPollOptionCollectionViewCell else { + return originalIndexPath + } + + return proposedIndexPath + } } From 9ca011b28c919fa12647993a74f3849b22ccaa02 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 17 Sep 2021 19:38:24 +0800 Subject: [PATCH 183/392] chore: update i18n resources --- Mastodon/Resources/ca.lproj/Localizable.strings | 12 ++++++------ Mastodon/Resources/ca.lproj/Localizable.stringsdict | 4 ++-- Mastodon/Resources/es-419.lproj/Localizable.strings | 12 ++++++------ .../Resources/es-419.lproj/Localizable.stringsdict | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Mastodon/Resources/ca.lproj/Localizable.strings b/Mastodon/Resources/ca.lproj/Localizable.strings index f7492aa86..71eb62b00 100644 --- a/Mastodon/Resources/ca.lproj/Localizable.strings +++ b/Mastodon/Resources/ca.lproj/Localizable.strings @@ -133,9 +133,9 @@ El teu perfil els sembla així."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions que falten..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostra més respostes"; "Common.Controls.Timeline.Timestamp.Now" = "Ara"; -"Scene.AccountList.AddAccount" = "Add Account"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.AddAccount" = "Afegir compte"; +"Scene.AccountList.DismissAccountSwitcher" = "Descartar el commutador de comptes"; +"Scene.AccountList.TabBarHint" = "Perfil actual seleccionat: %@. Toca dues vegades i manté el dit per a mostrar el commutador de comptes"; "Scene.Compose.Accessibility.AppendAttachment" = "Afegeix Adjunt"; "Scene.Compose.Accessibility.AppendPoll" = "Afegir enquesta"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector d'Emoji Personalitzat"; @@ -341,6 +341,6 @@ qualsevol servidor."; "Scene.Thread.Title" = "Publicació de %@"; "Scene.Welcome.Slogan" = "Xarxa social de nou a les teves mans."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.AccessibilityHint" = "Toca dues vegades per descartar l'assistent"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Commuta entre diversos comptes mantenint premut el botó del perfil."; +"Scene.Wizard.NewInMastodon" = "Nou a Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/ca.lproj/Localizable.stringsdict b/Mastodon/Resources/ca.lproj/Localizable.stringsdict index 65a83d363..cc7312938 100644 --- a/Mastodon/Resources/ca.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ca.lproj/Localizable.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notificació per llegir other - %ld unread notification + %ld notificacions per llegir a11y.plural.count.input_limit_exceeds diff --git a/Mastodon/Resources/es-419.lproj/Localizable.strings b/Mastodon/Resources/es-419.lproj/Localizable.strings index eda6b4efd..209502b26 100644 --- a/Mastodon/Resources/es-419.lproj/Localizable.strings +++ b/Mastodon/Resources/es-419.lproj/Localizable.strings @@ -133,9 +133,9 @@ Tu perfil le aparece así a este usuario."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Cargando mensajes faltantes…"; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostrar más respuestas"; "Common.Controls.Timeline.Timestamp.Now" = "Ahora"; -"Scene.AccountList.AddAccount" = "Add Account"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.AddAccount" = "Agregar cuenta"; +"Scene.AccountList.DismissAccountSwitcher" = "Descartar cambio de cuenta"; +"Scene.AccountList.TabBarHint" = "Perfil seleccionado actualmente: %@. Tocá dos veces y mantenelo presionado para cambiar de cuenta"; "Scene.Compose.Accessibility.AppendAttachment" = "Agregar archivo adjunto"; "Scene.Compose.Accessibility.AppendPoll" = "Agregar encuesta"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector de emoji personalizado"; @@ -341,6 +341,6 @@ el que quieras."; "Scene.Thread.Title" = "Mensaje de %@"; "Scene.Welcome.Slogan" = "La red social, nuevamente en tu poder."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.AccessibilityHint" = "Tocá dos veces para descartar este asistente"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Cambiá entre varias cuentas manteniendo presionado el botón del perfil."; +"Scene.Wizard.NewInMastodon" = "Novedad en Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/es-419.lproj/Localizable.stringsdict b/Mastodon/Resources/es-419.lproj/Localizable.stringsdict index dbbd363fa..f4f0097eb 100644 --- a/Mastodon/Resources/es-419.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/es-419.lproj/Localizable.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notificación sin leer other - %ld unread notification + %ld notificaciones sin leer a11y.plural.count.input_limit_exceeds From 45c50e266fe136abb06fa6e5a9667319d82e2112 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 17 Sep 2021 19:41:56 +0800 Subject: [PATCH 184/392] chore: update version to 1.1.0 (63) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index b1aab1762..2eec0c77f 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index b1aab1762..2eec0c77f 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index b1aab1762..2eec0c77f 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 59adbd291..45bd07248 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4697,7 +4697,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4832,11 +4832,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4863,11 +4863,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4892,11 +4892,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4922,11 +4922,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4989,7 +4989,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5014,7 +5014,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5039,7 +5039,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5064,7 +5064,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5089,7 +5089,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5114,7 +5114,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5139,7 +5139,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5164,7 +5164,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5255,7 +5255,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5321,11 +5321,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5370,7 +5370,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5395,11 +5395,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5491,7 +5491,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5557,11 +5557,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5606,7 +5606,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5631,11 +5631,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 62; + DYLIB_CURRENT_VERSION = 63; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5661,7 +5661,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5685,7 +5685,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 62; + CURRENT_PROJECT_VERSION = 63; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index f3f106ce5..ebb300d54 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 35 + 36 CoreDataStack.xcscheme_^#shared#^_ orderHint - 36 + 38 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 37 + 35 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 38 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 0f6669fb0..fb5eb4767 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -28,7 +28,7 @@ CFBundleVersion - 62 + 63 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 981537320..bdf101d2d 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index b1aab1762..2eec0c77f 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index b1aab1762..2eec0c77f 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 1157b08ed..d3ed42c72 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index ef93f77e6..40bcd85e1 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.1.0 CFBundleVersion - 62 + 63 NSExtension NSExtensionAttributes From 5c6b5b56a89a85338ceef5f2ad239f357eaa4fa7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 18 Sep 2021 08:51:45 +0200 Subject: [PATCH 185/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 707add6f7..49e4324cc 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -537,13 +537,13 @@ }, "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" + "dismiss_account_switcher": "ปิดตัวสลับบัญชี", + "add_account": "เพิ่มบัญชี" }, "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" + "accessibility_hint": "แตะสองครั้งเพื่อปิดตัวช่วยสร้างนี้" } } } \ No newline at end of file From 9bfa5bb79514a88389a4bda93877869f10a7175e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 18 Sep 2021 08:51:46 +0200 Subject: [PATCH 186/392] New translations Localizable.stringsdict (Thai) --- .../StringsConvertor/input/th_TH/Localizable.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict index 1d6ff10bc..8971821f6 100644 --- a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict @@ -13,7 +13,7 @@ NSStringFormatValueTypeKey ld other - %ld unread notification + %ld การแจ้งเตือนที่ยังไม่ได้อ่าน a11y.plural.count.input_limit_exceeds From 1dad97946e60cc0c5553cbe574815e6f59feec74 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 18 Sep 2021 10:01:15 +0200 Subject: [PATCH 187/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 49e4324cc..fb3024f2b 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -536,13 +536,13 @@ } }, "account_list": { - "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", + "tab_bar_hint": "โปรไฟล์ที่เลือกในปัจจุบัน: %s แตะสองครั้งแล้วกดค้างไว้เพื่อแสดงตัวสลับบัญชี", "dismiss_account_switcher": "ปิดตัวสลับบัญชี", "add_account": "เพิ่มบัญชี" }, "wizard": { - "new_in_mastodon": "New in Mastodon", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "new_in_mastodon": "มาใหม่ใน Mastodon", + "multiple_account_switch_intro_description": "สลับระหว่างหลายบัญชีโดยกดปุ่มโปรไฟล์ค้างไว้", "accessibility_hint": "แตะสองครั้งเพื่อปิดตัวช่วยสร้างนี้" } } From 5b3e85b68ce6f831b78047d222761ddff2c647a8 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 22 Sep 2021 19:08:09 +0800 Subject: [PATCH 188/392] feat: add Root scene for iPad --- Mastodon.xcodeproj/project.pbxproj | 60 +++++-- .../xcschemes/xcschememanagement.plist | 18 +-- .../xcshareddata/swiftpm/Package.resolved | 21 +-- Mastodon/Coordinator/SceneCoordinator.swift | 11 +- .../StatusProvider/StatusProviderFacade.swift | 4 +- .../HomeTimelineViewController.swift | 2 +- .../Scene/MainTab/MainTabBarController.swift | 24 ++- .../Scene/Root/RootSplitViewController.swift | 101 ++++++++++++ .../Scene/Sidebar/SidebarViewController.swift | 98 ++++++++++++ Mastodon/Scene/Sidebar/SidebarViewModel.swift | 150 ++++++++++++++++++ Podfile.lock | 6 +- 11 files changed, 445 insertions(+), 50 deletions(-) create mode 100644 Mastodon/Scene/Root/RootSplitViewController.swift create mode 100644 Mastodon/Scene/Sidebar/SidebarViewController.swift create mode 100644 Mastodon/Scene/Sidebar/SidebarViewModel.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 45bd07248..c32f52550 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -359,6 +359,9 @@ DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */; }; DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7F48442620241000796008 /* ProfileHeaderViewModel.swift */; }; DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */; }; + DB852D1926FAEB6B00FC9D81 /* SidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */; }; + DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */; }; + DB852D1F26FB037800FC9D81 /* SidebarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */; }; DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB87D4442609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift */; }; DB87D44B2609C11900D12C0D /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB87D44A2609C11900D12C0D /* PollOptionView.swift */; }; DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB87D4502609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift */; }; @@ -1138,6 +1141,9 @@ DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewModel.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 = ""; }; + DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarViewController.swift; sourceTree = ""; }; + DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootSplitViewController.swift; sourceTree = ""; }; + DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarViewModel.swift; sourceTree = ""; }; DB87D4442609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollOptionCollectionViewCell.swift; sourceTree = ""; }; DB87D44A2609C11900D12C0D /* PollOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionView.swift; sourceTree = ""; }; DB87D4502609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollOptionAppendEntryCollectionViewCell.swift; sourceTree = ""; }; @@ -2517,6 +2523,23 @@ path = CollectionViewCell; sourceTree = ""; }; + DB852D1A26FAED0100FC9D81 /* Sidebar */ = { + isa = PBXGroup; + children = ( + DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */, + DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */, + ); + path = Sidebar; + sourceTree = ""; + }; + DB852D1D26FB021900FC9D81 /* Root */ = { + isa = PBXGroup; + children = ( + DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */, + ); + path = Root; + sourceTree = ""; + }; DB87D45C2609DE6600D12C0D /* TextField */ = { isa = PBXGroup; children = ( @@ -2628,6 +2651,8 @@ children = ( 2D7631A425C1532200929FB9 /* Share */, DB6180E426391A500018D199 /* Transition */, + DB852D1D26FB021900FC9D81 /* Root */, + DB852D1A26FAED0100FC9D81 /* Sidebar */, DB8AF54E25C13703002E6C99 /* MainTab */, DB01409B25C40BB600F9F3CF /* Onboarding */, DB9F58ED26EF435800E7BBE9 /* Account */, @@ -3979,6 +4004,7 @@ DBAEDE5C267A058D00D25FF5 /* BlurhashImageCacheService.swift in Sources */, 2D38F1DF25CD46A400561493 /* HomeTimelineViewController+Provider.swift in Sources */, DB1D843026566512000346B3 /* KeyboardPreference.swift in Sources */, + DB852D1926FAEB6B00FC9D81 /* SidebarViewController.swift in Sources */, 2D206B9225F60EA700143C56 /* UIControl.swift in Sources */, 2D9DB96B263A91D1007C1D71 /* APIService+DomainBlock.swift in Sources */, DBBF1DC92652538500E5B703 /* AutoCompleteSection.swift in Sources */, @@ -4010,6 +4036,7 @@ DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */, DB3667A6268AE2620027D07F /* ComposeStatusPollSection.swift in Sources */, DB59F10E25EF724F001F1DAB /* APIService+Poll.swift in Sources */, + DB852D1F26FB037800FC9D81 /* SidebarViewModel.swift in Sources */, DB47229725F9EFAD00DA7F53 /* NSManagedObjectContext.swift in Sources */, 2D34D9D126148D9E0081BFC0 /* APIService+Recommend.swift in Sources */, DBB525562611EDCA002F1F29 /* UserTimelineViewModel.swift in Sources */, @@ -4047,6 +4074,7 @@ DBC7A67C260DFADE00E57475 /* StatusPublishService.swift in Sources */, DBCBCC092680B01B000F5B51 /* AsyncHomeTimelineViewModel+LoadMiddleState.swift in Sources */, 2DCB73FD2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift in Sources */, + DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */, DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */, DB1FD44425F26CCC004CFCFC /* PickServerSection.swift in Sources */, 0FB3D30F25E525CD00AAD544 /* PickServerCategoryView.swift in Sources */, @@ -4711,7 +4739,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -4738,7 +4766,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -5003,7 +5031,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -5028,7 +5056,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5053,7 +5081,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5078,7 +5106,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -5103,7 +5131,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -5128,7 +5156,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5153,7 +5181,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5178,7 +5206,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -5269,7 +5297,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5383,7 +5411,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5505,7 +5533,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5619,7 +5647,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5674,7 +5702,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -5698,7 +5726,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index ebb300d54..ee1add271 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 36 + 39 CoreDataStack.xcscheme_^#shared#^_ orderHint - 38 + 36 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -22,7 +22,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 14 + 13 Mastodon - Release.xcscheme_^#shared#^_ @@ -32,17 +32,17 @@ Mastodon - ar.xcscheme_^#shared#^_ orderHint - 11 + 10 Mastodon - ca.xcscheme_^#shared#^_ orderHint - 18 + 16 Mastodon - de.xcscheme_^#shared#^_ orderHint - 12 + 11 Mastodon - en.xcscheme_^#shared#^_ @@ -67,12 +67,12 @@ Mastodon - jp.xcscheme_^#shared#^_ orderHint - 16 + 14 Mastodon - nl.xcscheme_^#shared#^_ orderHint - 13 + 12 Mastodon - ru.xcscheme_^#shared#^_ @@ -87,7 +87,7 @@ Mastodon - zh_Hans.xcscheme_^#shared#^_ orderHint - 17 + 15 Mastodon.xcscheme_^#shared#^_ diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index c6a659bd5..e5bae6f1f 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/Alamofire/Alamofire.git", "state": { "branch": null, - "revision": "f96b619bcb2383b43d898402283924b80e2c4bae", - "version": "5.4.3" + "revision": "d120af1e8638c7da36c8481fd61a66c0c08dc4fc", + "version": "5.4.4" } }, { @@ -105,8 +105,8 @@ "repositoryURL": "https://github.com/kean/Nuke.git", "state": { "branch": null, - "revision": "3bd3a1765bdf62d561d4c2e10e1c4fc7a010f44e", - "version": "10.3.2" + "revision": "0db18dd34998cca18e9a28bcee136f84518007a0", + "version": "10.4.1" } }, { @@ -159,8 +159,8 @@ "repositoryURL": "https://github.com/apple/swift-nio.git", "state": { "branch": null, - "revision": "8da5c5a4e6c5084c296b9f39dc54f00be146e0fa", - "version": "1.14.2" + "revision": "546610d52b19be3e19935e0880bb06b9c03f5cef", + "version": "1.14.4" } }, { @@ -216,15 +216,6 @@ "revision": "dad97167bf1be16aeecd109130900995dd01c515", "version": "2.6.0" } - }, - { - "package": "UITextView+Placeholder", - "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder", - "state": { - "branch": null, - "revision": "20f513ded04a040cdf5467f0891849b1763ede3b", - "version": "1.4.1" - } } ] }, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index f604ef546..4445eac2b 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -111,10 +111,15 @@ extension SceneCoordinator { extension SceneCoordinator { +// func setup() { +// let viewController = MainTabBarController(context: appContext, coordinator: self) +// sceneDelegate.window?.rootViewController = viewController +// tabBarController = viewController +// } + func setup() { - let viewController = MainTabBarController(context: appContext, coordinator: self) - sceneDelegate.window?.rootViewController = viewController - tabBarController = viewController + let splitViewController = RootSplitViewController(context: appContext, coordinator: self) + sceneDelegate.window?.rootViewController = splitViewController } func setupOnboardingIfNeeds(animated: Bool) { diff --git a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift index d11870ed2..02a564d82 100644 --- a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift +++ b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift @@ -111,10 +111,10 @@ extension StatusProviderFacade { if provider.navigationController == nil { let from = provider.presentingViewController ?? provider provider.dismiss(animated: true) { - provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show) + provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .showDetail) } } else { - provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: provider, transition: .show) + provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: provider, transition: .showDetail) } } } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index a08f162a8..c47eb3633 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -95,7 +95,7 @@ extension HomeTimelineViewController { self.view.backgroundColor = theme.secondarySystemBackgroundColor } .store(in: &disposeBag) - navigationItem.leftBarButtonItem = settingBarButtonItem +// navigationItem.leftBarButtonItem = settingBarButtonItem navigationItem.titleView = titleView titleView.delegate = self diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index d6d40a5d0..b184ff25f 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -97,6 +97,8 @@ class MainTabBarController: UITabBarController { } } + var _viewControllers: [UIViewController] = [] + init(context: AppContext, coordinator: SceneCoordinator) { self.context = context self.coordinator = coordinator @@ -140,6 +142,7 @@ extension MainTabBarController { viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0) return viewController } + _viewControllers = viewControllers setViewControllers(viewControllers, animated: false) selectedIndex = 0 @@ -252,7 +255,9 @@ extension MainTabBarController { let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer() tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:))) tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer) - + + updateTabBarDisplay() + #if DEBUG // selectedIndex = 1 #endif @@ -263,9 +268,26 @@ extension MainTabBarController { wizard.consume() } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + updateTabBarDisplay() + } } +extension MainTabBarController { + private func updateTabBarDisplay() { + switch traitCollection.horizontalSizeClass { + case .compact: + tabBar.isHidden = false + default: + tabBar.isHidden = true + } + } +} + extension MainTabBarController { @objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) { guard sender.state == .began else { return } diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift new file mode 100644 index 000000000..640219152 --- /dev/null +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -0,0 +1,101 @@ +// +// RootSplitViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-22. +// + +import os.log +import UIKit + +final class RootSplitViewController: UISplitViewController, NeedsDependency { + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + private(set) lazy var sidebarViewController: SidebarViewController = { + let sidebarViewController = SidebarViewController() + sidebarViewController.context = context + sidebarViewController.coordinator = coordinator + sidebarViewController.viewModel = SidebarViewModel(context: context) + sidebarViewController.delegate = self + return sidebarViewController + }() + + private(set) lazy var mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) + + init(context: AppContext, coordinator: SceneCoordinator) { + self.context = context + self.coordinator = coordinator + super.init(style: .tripleColumn) + + primaryBackgroundStyle = .sidebar + preferredDisplayMode = .oneBesideSecondary + preferredSplitBehavior = .tile + + if #available(iOS 14.5, *) { + displayModeButtonVisibility = .always + } else { + // Fallback on earlier versions + } + + setViewController(sidebarViewController, for: .primary) + setViewController(mainTabBarController.viewControllers!.first, for: .supplementary) + setViewController(UIViewController(), for: .secondary) + setViewController(mainTabBarController, for: .compact) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension RootSplitViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + updateBehavior(size: view.frame.size) + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + updateBehavior(size: size) + } + + private func updateBehavior(size: CGSize) { + // fix secondary too small on iPad mini issue + if size.width > 960 { + preferredDisplayMode = .oneBesideSecondary + preferredSplitBehavior = .tile + } else { + preferredDisplayMode = .oneBesideSecondary + preferredSplitBehavior = .displace + } + } + +} + +// MARK: - SidebarViewControllerDelegate +extension RootSplitViewController: SidebarViewControllerDelegate { + func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) { + + // FIXME: remove hard code + switch tab { + case .home: + setViewController(mainTabBarController._viewControllers[0], for: .supplementary) + case .search: + setViewController(mainTabBarController._viewControllers[1], for: .supplementary) + case .notification: + setViewController(mainTabBarController._viewControllers[2], for: .supplementary) + case .me: + setViewController(mainTabBarController._viewControllers[3], for: .supplementary) + } + } +} diff --git a/Mastodon/Scene/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Sidebar/SidebarViewController.swift new file mode 100644 index 000000000..4fe34c89a --- /dev/null +++ b/Mastodon/Scene/Sidebar/SidebarViewController.swift @@ -0,0 +1,98 @@ +// +// SidebarViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-22. +// + +import UIKit +import Combine +import CoreDataStack + +protocol SidebarViewControllerDelegate: AnyObject { + func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) +} + +final class SidebarViewController: UIViewController, NeedsDependency { + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: SidebarViewModel! + + weak var delegate: SidebarViewControllerDelegate? + + static func createLayout() -> UICollectionViewLayout { + let layout = UICollectionViewCompositionalLayout() { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in + var configuration = UICollectionLayoutListConfiguration(appearance: .plain) + configuration.showsSeparators = false + let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment) + return section + } + return layout + } + + let collectionView: UICollectionView = { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: SidebarViewController.createLayout()) + collectionView.backgroundColor = .clear + return collectionView + }() + +} + +extension SidebarViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + navigationItem.title = "Title" + navigationController?.navigationBar.prefersLargeTitles = true + + let barAppearance = UINavigationBarAppearance() + barAppearance.configureWithTransparentBackground() + navigationItem.standardAppearance = barAppearance + navigationItem.compactAppearance = barAppearance + navigationItem.scrollEdgeAppearance = barAppearance + + 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.delegate = self + viewModel.setupDiffableDataSource(collectionView: collectionView) + } + +} + +// MARK: - UICollectionViewDelegate +extension SidebarViewController: UICollectionViewDelegate { + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } + switch item { + case .tab(let tab): + delegate?.sidebarViewController(self, didSelectTab: tab) + case .account(let viewModel): + assert(Thread.isMainThread) + let authentication = context.managedObjectContext.object(with: viewModel.authenticationObjectID) as! MastodonAuthentication + context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID) + .receive(on: DispatchQueue.main) + .sink { [weak self] result in + guard let self = self else { return } + self.coordinator.setup() + } + .store(in: &disposeBag) + case .addAccount: + coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil)) + default: + // TODO: + break + } + } +} diff --git a/Mastodon/Scene/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Sidebar/SidebarViewModel.swift new file mode 100644 index 000000000..f65bb1d6f --- /dev/null +++ b/Mastodon/Scene/Sidebar/SidebarViewModel.swift @@ -0,0 +1,150 @@ +// +// SidebarViewModel.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-22. +// + +import UIKit +import Combine +import CoreData +import CoreDataStack + +final class SidebarViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + + // output + var diffableDataSource: UICollectionViewDiffableDataSource! + + + init(context: AppContext) { + self.context = context + } + +} + +extension SidebarViewModel { + enum Section: Hashable, CaseIterable { + case tab + case account + } + + enum Item: Hashable { + case tab(MainTabBarController.Tab) + case header(HeaderViewModel) + case account(AccountViewModel) + case addAccount + } + + struct HeaderViewModel: Hashable { + let title: String + } + + struct AccountViewModel: Hashable { + let authenticationObjectID: NSManagedObjectID + } + + struct AddAccountViewModel: Hashable { + let id = UUID() + } +} + +extension SidebarViewModel { + func setupDiffableDataSource( + collectionView: UICollectionView + ) { + let cellRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + var content = cell.defaultContentConfiguration() + content.text = item.title + content.image = item.image + cell.contentConfiguration = content + cell.accessories = [] + } + + let headerRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + var content = cell.defaultContentConfiguration() + content.text = item.title + cell.contentConfiguration = content + cell.accessories = [.outlineDisclosure()] + } + + let accountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + var content = cell.defaultContentConfiguration() + let authentication = AppContext.shared.managedObjectContext.object(with: item.authenticationObjectID) as! MastodonAuthentication + content.text = authentication.user.acctWithDomain + content.image = nil + cell.contentConfiguration = content + cell.accessories = [] + } + + let addAccountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + var content = cell.defaultContentConfiguration() + content.text = L10n.Scene.AccountList.addAccount + content.image = nil + cell.contentConfiguration = content + cell.accessories = [] + } + + diffableDataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, item in + switch item { + case .tab(let tab): + return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: tab) + case .header(let viewModel): + return collectionView.dequeueConfiguredReusableCell(using: headerRegistration, for: indexPath, item: viewModel) + case .account(let viewModel): + return collectionView.dequeueConfiguredReusableCell(using: accountRegistration, for: indexPath, item: viewModel) + case .addAccount: + return collectionView.dequeueConfiguredReusableCell(using: addAccountRegistration, for: indexPath, item: AddAccountViewModel()) + } + } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections(Section.allCases) + diffableDataSource.apply(snapshot) + + for section in Section.allCases { + switch section { + case .tab: + var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() + let items: [Item] = [ + .tab(.home), + .tab(.search), + .tab(.notification), + .tab(.me), + ] + sectionSnapshot.append(items, to: nil) + diffableDataSource.apply(sectionSnapshot, to: section) + case .account: + var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() + let headerItem = Item.header(HeaderViewModel(title: "Accounts")) + sectionSnapshot.append([headerItem], to: nil) + sectionSnapshot.append([], to: headerItem) + sectionSnapshot.append([.addAccount], to: headerItem) + sectionSnapshot.expand([headerItem]) + diffableDataSource.apply(sectionSnapshot, to: section) + } + } + + context.authenticationService.mastodonAuthentications + .receive(on: DispatchQueue.main) + .sink { [weak self] authentications in + guard let self = self else { return } + var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() + let headerItem = Item.header(HeaderViewModel(title: "Accounts")) + sectionSnapshot.append([headerItem], to: nil) + let items = authentications.map { authentication in + Item.account(AccountViewModel(authenticationObjectID: authentication.objectID)) + } + sectionSnapshot.append(items, to: headerItem) + sectionSnapshot.append([.addAccount], to: headerItem) + sectionSnapshot.expand([headerItem]) + self.diffableDataSource.apply(sectionSnapshot, to: .account) + } + .store(in: &disposeBag) + } + +} diff --git a/Podfile.lock b/Podfile.lock index 7c64e59b9..3541289d0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,7 +1,7 @@ PODS: - DateToolsSwift (5.0.0) - FLEX (4.4.1) - - Kanna (5.2.4) + - Kanna (5.2.7) - Keys (1.0.1) - PINCache (3.0.3): - PINCache/Arc-exception-safe (= 3.0.3) @@ -69,7 +69,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: DateToolsSwift: 4207ada6ad615d8dc076323d27037c94916dbfa6 FLEX: 7ca2c8cd3a435ff501ff6d2f2141e9bdc934eaab - Kanna: b9d00d7c11428308c7f95e1f1f84b8205f567a8f + Kanna: 01cfbddc127f5ff0963692f285fcbc8a9d62d234 Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9 PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 @@ -80,4 +80,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4db0bdf969729c5758bd923e33d9e097cb892086 -COCOAPODS: 1.11.0 +COCOAPODS: 1.11.2 From c30da6533e698be7c4c6e69a79152fc5270ac037 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 22 Sep 2021 19:10:00 +0800 Subject: [PATCH 189/392] chore: update version to 1.2.0 (64) --- AppShared/Info.plist | 4 +- CoreDataStack/Info.plist | 4 +- CoreDataStackTests/Info.plist | 4 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 4 +- MastodonIntent/Info.plist | 4 +- MastodonTests/Info.plist | 4 +- MastodonUITests/Info.plist | 4 +- NotificationService/Info.plist | 4 +- ShareActionExtension/Info.plist | 4 +- 11 files changed, 54 insertions(+), 54 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 2eec0c77f..d1f2b9d2a 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 2eec0c77f..d1f2b9d2a 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 2eec0c77f..d1f2b9d2a 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index c32f52550..4572c6148 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4753,7 +4753,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4860,11 +4860,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4891,11 +4891,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4920,11 +4920,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4950,11 +4950,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5017,7 +5017,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5042,7 +5042,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5092,7 +5092,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5117,7 +5117,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5142,7 +5142,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5167,7 +5167,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5192,7 +5192,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5283,7 +5283,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5349,11 +5349,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5398,7 +5398,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5423,11 +5423,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5519,7 +5519,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5585,11 +5585,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5634,7 +5634,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5659,11 +5659,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 63; + DYLIB_CURRENT_VERSION = 64; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5689,7 +5689,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5713,7 +5713,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 63; + CURRENT_PROJECT_VERSION = 64; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index ee1add271..bbc3b7847 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 39 + 56 CoreDataStack.xcscheme_^#shared#^_ orderHint - 36 + 59 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 35 + 57 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 58 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index fb5eb4767..df7268b7f 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleURLTypes @@ -28,7 +28,7 @@ CFBundleVersion - 63 + 64 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index bdf101d2d..ec349a1c8 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 2eec0c77f..d1f2b9d2a 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 2eec0c77f..d1f2b9d2a 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index d3ed42c72..b7b6199df 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 40bcd85e1..3d48a4121 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + 1.2.0 CFBundleVersion - 63 + 64 NSExtension NSExtensionAttributes From 275cce88b21117f1118b46fe2e659d508f6e7ce9 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 23 Sep 2021 19:32:44 +0800 Subject: [PATCH 190/392] feat: update navigation stack when transition from .regular to .compact --- Mastodon.xcodeproj/project.pbxproj | 4 +- Mastodon/Coordinator/SceneCoordinator.swift | 13 ++- .../StatusProvider/StatusProviderFacade.swift | 4 +- .../MainTab/MainTabBarController+Wizard.swift | 0 .../MainTab/MainTabBarController.swift | 8 +- .../Scene/Root/RootSplitViewController.swift | 105 ++++++++++++++++-- .../Sidebar/SidebarViewController.swift | 0 .../{ => Root}/Sidebar/SidebarViewModel.swift | 0 8 files changed, 113 insertions(+), 21 deletions(-) rename Mastodon/Scene/{ => Root}/MainTab/MainTabBarController+Wizard.swift (100%) rename Mastodon/Scene/{ => Root}/MainTab/MainTabBarController.swift (99%) rename Mastodon/Scene/{ => Root}/Sidebar/SidebarViewController.swift (100%) rename Mastodon/Scene/{ => Root}/Sidebar/SidebarViewModel.swift (100%) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 4572c6148..df0cc7010 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -2536,6 +2536,8 @@ isa = PBXGroup; children = ( DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */, + DB852D1A26FAED0100FC9D81 /* Sidebar */, + DB8AF54E25C13703002E6C99 /* MainTab */, ); path = Root; sourceTree = ""; @@ -2652,8 +2654,6 @@ 2D7631A425C1532200929FB9 /* Share */, DB6180E426391A500018D199 /* Transition */, DB852D1D26FB021900FC9D81 /* Root */, - DB852D1A26FAED0100FC9D81 /* Sidebar */, - DB8AF54E25C13703002E6C99 /* MainTab */, DB01409B25C40BB600F9F3CF /* Onboarding */, DB9F58ED26EF435800E7BBE9 /* Account */, 2D38F1D325CD463600561493 /* HomeTimeline */, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 4445eac2b..f5e0928d7 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -18,6 +18,8 @@ final public class SceneCoordinator { let id = UUID().uuidString + weak var splitViewController: RootSplitViewController? + init(scene: UIScene, sceneDelegate: SceneDelegate, appContext: AppContext) { self.scene = scene self.sceneDelegate = sceneDelegate @@ -119,6 +121,7 @@ extension SceneCoordinator { func setup() { let splitViewController = RootSplitViewController(context: appContext, coordinator: self) + self.splitViewController = splitViewController sceneDelegate.window?.rootViewController = splitViewController } @@ -172,8 +175,14 @@ extension SceneCoordinator { switch transition { case .show: - presentingViewController.show(viewController, sender: sender) - + if let splitViewController = splitViewController, !splitViewController.isCollapsed, + let supplementaryViewController = splitViewController.viewController(for: .supplementary) as? UINavigationController, + (supplementaryViewController === presentingViewController || supplementaryViewController.viewControllers.contains(presentingViewController)) + { + fallthrough + } else { + presentingViewController.show(viewController, sender: sender) + } case .showDetail: let navigationController = AdaptiveStatusBarStyleNavigationController(rootViewController: viewController) presentingViewController.showDetailViewController(navigationController, sender: sender) diff --git a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift index 02a564d82..d11870ed2 100644 --- a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift +++ b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift @@ -111,10 +111,10 @@ extension StatusProviderFacade { if provider.navigationController == nil { let from = provider.presentingViewController ?? provider provider.dismiss(animated: true) { - provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .showDetail) + provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show) } } else { - provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: provider, transition: .showDetail) + provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: provider, transition: .show) } } } diff --git a/Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift similarity index 100% rename from Mastodon/Scene/MainTab/MainTabBarController+Wizard.swift rename to Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift similarity index 99% rename from Mastodon/Scene/MainTab/MainTabBarController.swift rename to Mastodon/Scene/Root/MainTab/MainTabBarController.swift index b184ff25f..546988be4 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -24,7 +24,7 @@ class MainTabBarController: UITabBarController { let wizard = Wizard() - var currentTab = Tab.home + var currentTab = CurrentValueSubject(.home) enum Tab: Int, CaseIterable { case home @@ -361,10 +361,10 @@ extension MainTabBarController: UITabBarControllerDelegate { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select %s", ((#file as NSString).lastPathComponent), #line, #function, viewController.debugDescription) defer { if let tab = Tab(rawValue: tabBarController.selectedIndex) { - currentTab = tab + currentTab.value = tab } } - guard currentTab.rawValue == tabBarController.selectedIndex, + guard currentTab.value.rawValue == tabBarController.selectedIndex, let navigationController = viewController as? UINavigationController, navigationController.viewControllers.count == 1, let scrollViewContainer = navigationController.topViewController as? ScrollViewContainer else { @@ -535,7 +535,7 @@ extension MainTabBarController { let previousTab = Tab(rawValue: selectedIndex) selectedIndex = index if let tab = Tab(rawValue: index) { - currentTab = tab + currentTab.value = tab } if let previousTab = previousTab { diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 640219152..7437b2597 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -7,9 +7,12 @@ import os.log import UIKit +import Combine final class RootSplitViewController: UISplitViewController, NeedsDependency { + var disposeBag = Set() + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -21,6 +24,13 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { sidebarViewController.delegate = self return sidebarViewController }() + + var currentSupplementaryTab: MainTabBarController.Tab = .home + private(set) lazy var supplementaryViewControllers: [UIViewController] = { + return MainTabBarController.Tab.allCases.map { tab in + tab.viewController(context: context, coordinator: coordinator) + } + }() private(set) lazy var mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) @@ -32,6 +42,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { primaryBackgroundStyle = .sidebar preferredDisplayMode = .oneBesideSecondary preferredSplitBehavior = .tile + delegate = self if #available(iOS 14.5, *) { displayModeButtonVisibility = .always @@ -40,7 +51,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { } setViewController(sidebarViewController, for: .primary) - setViewController(mainTabBarController.viewControllers!.first, for: .supplementary) + setViewController(supplementaryViewControllers[0], for: .supplementary) setViewController(UIViewController(), for: .secondary) setViewController(mainTabBarController, for: .compact) } @@ -61,6 +72,18 @@ extension RootSplitViewController { super.viewDidLoad() updateBehavior(size: view.frame.size) + + mainTabBarController.currentTab + .receive(on: DispatchQueue.main) + .sink { [weak self] tab in + guard let self = self else { return } + guard tab != self.currentSupplementaryTab else { return } + guard let index = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { return } + self.currentSupplementaryTab = tab + self.setViewController(self.supplementaryViewControllers[index], for: .supplementary) + + } + .store(in: &disposeBag) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { @@ -86,16 +109,76 @@ extension RootSplitViewController { extension RootSplitViewController: SidebarViewControllerDelegate { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) { - // FIXME: remove hard code - switch tab { - case .home: - setViewController(mainTabBarController._viewControllers[0], for: .supplementary) - case .search: - setViewController(mainTabBarController._viewControllers[1], for: .supplementary) - case .notification: - setViewController(mainTabBarController._viewControllers[2], for: .supplementary) - case .me: - setViewController(mainTabBarController._viewControllers[3], for: .supplementary) + guard let index = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { + assertionFailure() + return + } + currentSupplementaryTab = tab + setViewController(supplementaryViewControllers[index], for: .supplementary) + } +} + +// MARK: - UISplitViewControllerDelegate +extension RootSplitViewController: UISplitViewControllerDelegate { + + // .regular to .compact + // move navigation stack from .supplementary & .secondary to .compact + func splitViewController( + _ svc: UISplitViewController, + topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column + ) -> UISplitViewController.Column { + switch proposedTopColumn { + case .compact: + guard let index = MainTabBarController.Tab.allCases.firstIndex(of: currentSupplementaryTab) else { + assertionFailure() + break + } + mainTabBarController.selectedIndex = index + mainTabBarController.currentTab.value = currentSupplementaryTab + + guard let navigationController = mainTabBarController.selectedViewController as? UINavigationController else { break } + navigationController.popToRootViewController(animated: false) + var viewControllers = navigationController.viewControllers // init navigation stack with topMost + + if let supplementaryNavigationController = viewController(for: .supplementary) as? UINavigationController { + // append supplementary + viewControllers.append(contentsOf: supplementaryNavigationController.popToRootViewController(animated: true) ?? []) + } + if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { + // append secondary + viewControllers.append(contentsOf: secondaryNavigationController.popToRootViewController(animated: true) ?? []) + } + // set navigation stack + navigationController.setViewControllers(viewControllers, animated: false) + + default: + assertionFailure() + } + + return proposedTopColumn + } + + // .compact to .regular + // restore navigation stack to .supplementary & .secondary + func splitViewController( + _ svc: UISplitViewController, + displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode + ) -> UISplitViewController.DisplayMode { + + return proposedDisplayMode + } + + func splitViewController( + _ splitViewController: UISplitViewController, + show vc: UIViewController, + sender: Any? + ) -> Bool { + if !splitViewController.isCollapsed { + // display in .secondary when expand + splitViewController.showDetailViewController(vc, sender: sender) + return true + } else { + return false } } } diff --git a/Mastodon/Scene/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift similarity index 100% rename from Mastodon/Scene/Sidebar/SidebarViewController.swift rename to Mastodon/Scene/Root/Sidebar/SidebarViewController.swift diff --git a/Mastodon/Scene/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift similarity index 100% rename from Mastodon/Scene/Sidebar/SidebarViewModel.swift rename to Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift From 98bec294f64598547b4f75846ba717b46f669a9d Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 23 Sep 2021 19:33:38 +0800 Subject: [PATCH 191/392] chore: update version to 1.2.0 (65) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index d1f2b9d2a..0ec5a69ad 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index d1f2b9d2a..0ec5a69ad 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index d1f2b9d2a..0ec5a69ad 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index df0cc7010..4fc1963cb 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4753,7 +4753,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4860,11 +4860,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4891,11 +4891,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4920,11 +4920,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4950,11 +4950,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5017,7 +5017,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5042,7 +5042,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5092,7 +5092,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5117,7 +5117,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5142,7 +5142,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5167,7 +5167,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5192,7 +5192,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5283,7 +5283,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5349,11 +5349,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5398,7 +5398,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5423,11 +5423,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5519,7 +5519,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5585,11 +5585,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5634,7 +5634,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5659,11 +5659,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 64; + DYLIB_CURRENT_VERSION = 65; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5689,7 +5689,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5713,7 +5713,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 65; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index bbc3b7847..648f74156 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 56 + 59 CoreDataStack.xcscheme_^#shared#^_ orderHint - 59 + 62 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 57 + 60 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 58 + 61 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index df7268b7f..a04553608 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -28,7 +28,7 @@ CFBundleVersion - 64 + 65 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index ec349a1c8..be1a7fdcd 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index d1f2b9d2a..0ec5a69ad 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index d1f2b9d2a..0ec5a69ad 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index b7b6199df..dde206116 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 3d48a4121..4e38864ef 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 64 + 65 NSExtension NSExtensionAttributes From d8de3c4f651fbb399276fecf727f8f5349c09e89 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 24 Sep 2021 19:58:50 +0800 Subject: [PATCH 192/392] feat: update sidebar UI --- Mastodon.xcodeproj/project.pbxproj | 16 ++ .../xcschemes/xcschememanagement.plist | 8 +- .../xcshareddata/swiftpm/Package.resolved | 9 + Mastodon/Coordinator/SceneCoordinator.swift | 22 +- Mastodon/Extension/MetaLabel.swift | 30 ++- Mastodon/Generated/Assets.swift | 2 + Mastodon/Info.plist | 2 + .../sidebar.background.colorset/Contents.json | 38 ++++ .../sidebar.background.colorset/Contents.json | 38 ++++ .../Scene/Compose/ComposeViewController.swift | 8 +- .../HomeTimelineViewController.swift | 8 +- .../HomeTimeline/HomeTimelineViewModel.swift | 2 +- .../Root/MainTab/MainTabBarController.swift | 9 + .../Scene/Root/RootSplitViewController.swift | 12 +- .../Root/Sidebar/SidebarViewController.swift | 57 ++++- .../Scene/Root/Sidebar/SidebarViewModel.swift | 83 +++++-- .../View/SidebarListCollectionViewCell.swift | 48 ++++ .../Sidebar/View/SidebarListContentView.swift | 215 ++++++++++++++++++ .../Service/ThemeService/MastodonTheme.swift | 2 + .../Service/ThemeService/SystemTheme.swift | 2 + Mastodon/Service/ThemeService/Theme.swift | 2 + 21 files changed, 557 insertions(+), 56 deletions(-) create mode 100644 Mastodon/Resources/Assets.xcassets/Theme/Mastodon/Background/sidebar.background.colorset/Contents.json create mode 100644 Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json create mode 100644 Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift create mode 100644 Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 4fc1963cb..a63d76b89 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -199,6 +199,8 @@ DB0C947226A7D2D70088FB11 /* AvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947126A7D2D70088FB11 /* AvatarButton.swift */; }; DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */; }; DB0E91EA26A9675100BD2ACC /* MetaLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0E91E926A9675100BD2ACC /* MetaLabel.swift */; }; + DB0EF72B26FDB1D200347686 /* SidebarListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */; }; + DB0EF72E26FDB24F00347686 /* SidebarListContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */; }; DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift */; }; DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */; }; DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D186B25EF5BA7003F1F23 /* PollTableView.swift */; }; @@ -954,6 +956,8 @@ DB0C947126A7D2D70088FB11 /* AvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarButton.swift; sourceTree = ""; }; DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAvatarButton.swift; sourceTree = ""; }; DB0E91E926A9675100BD2ACC /* MetaLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaLabel.swift; sourceTree = ""; }; + DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListCollectionViewCell.swift; sourceTree = ""; }; + DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListContentView.swift; sourceTree = ""; }; DB0F814D264CFFD300F2A12B /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; DB0F814E264CFFD300F2A12B /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = ""; }; DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerLoaderTableViewCell.swift; sourceTree = ""; }; @@ -2082,6 +2086,15 @@ path = Button; sourceTree = ""; }; + DB0EF72C26FDB1D600347686 /* View */ = { + isa = PBXGroup; + children = ( + DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */, + DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */, + ); + path = View; + sourceTree = ""; + }; DB1D187125EF5BBD003F1F23 /* TableView */ = { isa = PBXGroup; children = ( @@ -2526,6 +2539,7 @@ DB852D1A26FAED0100FC9D81 /* Sidebar */ = { isa = PBXGroup; children = ( + DB0EF72C26FDB1D600347686 /* View */, DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */, DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */, ); @@ -4136,6 +4150,7 @@ DB9D6C0E25E4F9780051B173 /* MosaicImageViewContainer.swift in Sources */, DBCBCC0D2680B908000F5B51 /* HomeTimelinePreference.swift in Sources */, DB71FD3625F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift in Sources */, + DB0EF72E26FDB24F00347686 /* SidebarListContentView.swift in Sources */, DBBE1B4525F3474B0081417A /* MastodonPickServerAppearance.swift in Sources */, DB98338725C945ED00AD9700 /* Strings.swift in Sources */, 2D7867192625B77500211898 /* NotificationItem.swift in Sources */, @@ -4151,6 +4166,7 @@ 2D32EADA25CBCC3300C9ED86 /* PublicTimelineViewModel+LoadMiddleState.swift in Sources */, 5B90C48526259BF10002E742 /* APIService+Subscriptions.swift in Sources */, 0F20223926146553000C64BF /* Array.swift in Sources */, + DB0EF72B26FDB1D200347686 /* SidebarListCollectionViewCell.swift in Sources */, 5B90C460262599800002E742 /* SettingsAppearanceTableViewCell.swift in Sources */, DB0C946B26A700AB0088FB11 /* MastodonUser+Property.swift in Sources */, DB8AF54425C13647002E6C99 /* SceneCoordinator.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 648f74156..91145420e 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 59 + 36 CoreDataStack.xcscheme_^#shared#^_ orderHint - 62 + 35 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 60 + 37 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 61 + 38 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index e5bae6f1f..44043f885 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -216,6 +216,15 @@ "revision": "dad97167bf1be16aeecd109130900995dd01c515", "version": "2.6.0" } + }, + { + "package": "UITextView+Placeholder", + "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder", + "state": { + "branch": null, + "revision": "20f513ded04a040cdf5467f0891849b1763ede3b", + "version": "1.4.1" + } } ] }, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index f5e0928d7..4978c0a7e 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -113,16 +113,17 @@ extension SceneCoordinator { extension SceneCoordinator { -// func setup() { -// let viewController = MainTabBarController(context: appContext, coordinator: self) -// sceneDelegate.window?.rootViewController = viewController -// tabBarController = viewController -// } - func setup() { - let splitViewController = RootSplitViewController(context: appContext, coordinator: self) - self.splitViewController = splitViewController - sceneDelegate.window?.rootViewController = splitViewController + switch UIDevice.current.userInterfaceIdiom { + case .phone: + let viewController = MainTabBarController(context: appContext, coordinator: self) + sceneDelegate.window?.rootViewController = viewController + tabBarController = viewController + default: + let splitViewController = RootSplitViewController(context: appContext, coordinator: self) + self.splitViewController = splitViewController + sceneDelegate.window?.rootViewController = splitViewController + } } func setupOnboardingIfNeeds(animated: Bool) { @@ -177,7 +178,8 @@ extension SceneCoordinator { case .show: if let splitViewController = splitViewController, !splitViewController.isCollapsed, let supplementaryViewController = splitViewController.viewController(for: .supplementary) as? UINavigationController, - (supplementaryViewController === presentingViewController || supplementaryViewController.viewControllers.contains(presentingViewController)) + (supplementaryViewController === presentingViewController || supplementaryViewController.viewControllers.contains(presentingViewController)) || + (presentingViewController is UserTimelineViewController && presentingViewController.view.isDescendant(of: supplementaryViewController.view)) { fallthrough } else { diff --git a/Mastodon/Extension/MetaLabel.swift b/Mastodon/Extension/MetaLabel.swift index a9696892a..04b214d82 100644 --- a/Mastodon/Extension/MetaLabel.swift +++ b/Mastodon/Extension/MetaLabel.swift @@ -22,6 +22,8 @@ extension MetaLabel { case autoCompletion case accountListName case accountListUsername + case sidebarHeadline(isSelected: Bool) + case sidebarSubheadline(isSelected: Bool) } convenience init(style: Style) { @@ -32,41 +34,45 @@ extension MetaLabel { textContainer.lineBreakMode = .byTruncatingTail textContainer.lineFragmentPadding = 0 + setup(style: style) + } + + func setup(style: Style) { let font: UIFont let textColor: UIColor - + switch style { case .statusHeader: font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium), maximumPointSize: 17) textColor = Asset.Colors.Label.secondary.color - + case .statusName: font = .systemFont(ofSize: 17, weight: .semibold) textColor = Asset.Colors.Label.primary.color - + case .notificationTitle: font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20) textColor = Asset.Colors.Label.secondary.color - + case .profileFieldName: font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 20) textColor = Asset.Colors.Label.primary.color - + case .profileFieldValue: font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 20) textColor = Asset.Colors.Label.primary.color textAlignment = .right - + case .titleView: font = .systemFont(ofSize: 17, weight: .semibold) textColor = Asset.Colors.Label.primary.color textAlignment = .center paragraphStyle.alignment = .center - + case .recommendAccountName: font = .systemFont(ofSize: 18, weight: .semibold) textColor = .white - + case .settingTableFooter: font = .preferredFont(forTextStyle: .footnote) textColor = Asset.Colors.Label.secondary.color @@ -82,8 +88,14 @@ extension MetaLabel { case .accountListUsername: font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20) textColor = Asset.Colors.Label.secondary.color + case .sidebarHeadline(let isSelected): + font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 22, weight: .regular), maximumPointSize: 20) + textColor = isSelected ? .white : Asset.Colors.Label.primary.color + case .sidebarSubheadline(let isSelected): + font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular), maximumPointSize: 18) + textColor = isSelected ? .white : Asset.Colors.Label.secondary.color } - + self.font = font self.textColor = textColor diff --git a/Mastodon/Generated/Assets.swift b/Mastodon/Generated/Assets.swift index 36edb7bcd..96fe0fca8 100644 --- a/Mastodon/Generated/Assets.swift +++ b/Mastodon/Generated/Assets.swift @@ -126,6 +126,7 @@ internal enum Asset { internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/Mastodon/profile.field.collection.view.background") internal static let secondaryGroupedSystemBackground = ColorAsset(name: "Theme/Mastodon/secondary.grouped.system.background") internal static let secondarySystemBackground = ColorAsset(name: "Theme/Mastodon/secondary.system.background") + internal static let sidebarBackground = ColorAsset(name: "Theme/Mastodon/sidebar.background") internal static let systemBackground = ColorAsset(name: "Theme/Mastodon/system.background") internal static let systemElevatedBackground = ColorAsset(name: "Theme/Mastodon/system.elevated.background") internal static let systemGroupedBackground = ColorAsset(name: "Theme/Mastodon/system.grouped.background") @@ -145,6 +146,7 @@ internal enum Asset { internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/system/profile.field.collection.view.background") internal static let secondaryGroupedSystemBackground = ColorAsset(name: "Theme/system/secondary.grouped.system.background") internal static let secondarySystemBackground = ColorAsset(name: "Theme/system/secondary.system.background") + internal static let sidebarBackground = ColorAsset(name: "Theme/system/sidebar.background") internal static let systemBackground = ColorAsset(name: "Theme/system/system.background") internal static let systemElevatedBackground = ColorAsset(name: "Theme/system/system.elevated.background") internal static let systemGroupedBackground = ColorAsset(name: "Theme/system/system.grouped.background") diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index a04553608..73d3654f9 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDuration + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable diff --git a/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/Background/sidebar.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/Background/sidebar.background.colorset/Contents.json new file mode 100644 index 000000000..c24074078 --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/Background/sidebar.background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF1", + "green" : "0xF1", + "red" : "0xF1" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.263", + "green" : "0.208", + "red" : "0.192" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json new file mode 100644 index 000000000..e30d6cabe --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.945", + "green" : "0.945", + "red" : "0.945" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.263", + "green" : "0.208", + "red" : "0.192" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index 275c8e456..9be0e4f7d 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -924,8 +924,12 @@ extension ComposeViewController: UICollectionViewDelegate { extension ComposeViewController: UIAdaptivePresentationControllerDelegate { func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { - return .overFullScreen - //return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic + switch traitCollection.horizontalSizeClass { + case .compact: + return .overFullScreen + default: + return .pageSheet + } } func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index c47eb3633..154fad528 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -95,7 +95,13 @@ extension HomeTimelineViewController { self.view.backgroundColor = theme.secondarySystemBackgroundColor } .store(in: &disposeBag) -// navigationItem.leftBarButtonItem = settingBarButtonItem + viewModel.displaySettingBarButtonItem + .receive(on: DispatchQueue.main) + .sink { [weak self] displaySettingBarButtonItem in + guard let self = self else { return } + self.navigationItem.leftBarButtonItem = displaySettingBarButtonItem ? self.settingBarButtonItem : nil + } + .store(in: &disposeBag) navigationItem.titleView = titleView titleView.delegate = self diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index 0bf1e1041..cf0b69b9d 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -68,7 +68,7 @@ final class HomeTimelineViewModel: NSObject { let loadMiddleSateMachineList = CurrentValueSubject<[NSManagedObjectID: GKStateMachine], Never>([:]) // TimelineIndex.objectID : middle loading state machine var diffableDataSource: UITableViewDiffableDataSource? var cellFrameCache = NSCache() - + let displaySettingBarButtonItem = CurrentValueSubject(true) init(context: AppContext) { self.context = context diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 546988be4..1681b6171 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -63,6 +63,15 @@ class MainTabBarController: UITabBarController { } } + var sidebarImage: UIImage { + switch self { + case .home: return UIImage(systemName: "house")! + case .search: return UIImage(systemName: "magnifyingglass")! + case .notification: return UIImage(systemName: "bell")! + case .me: return UIImage(systemName: "person.fill")! + } + } + func viewController(context: AppContext, coordinator: SceneCoordinator) -> UIViewController { let viewController: UIViewController switch self { diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 7437b2597..441cc992e 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -27,9 +27,19 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { var currentSupplementaryTab: MainTabBarController.Tab = .home private(set) lazy var supplementaryViewControllers: [UIViewController] = { - return MainTabBarController.Tab.allCases.map { tab in + let viewControllers = MainTabBarController.Tab.allCases.map { tab in tab.viewController(context: context, coordinator: coordinator) } + for viewController in viewControllers { + guard let navigationController = viewController as? UINavigationController else { + assertionFailure() + continue + } + if let homeViewController = navigationController.topViewController as? HomeTimelineViewController { + homeViewController.viewModel.displaySettingBarButtonItem.value = false + } + } + return viewControllers }() private(set) lazy var mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 4fe34c89a..d93fcd807 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -5,6 +5,7 @@ // Created by Cirno MainasuK on 2021-9-22. // +import os.log import UIKit import Combine import CoreDataStack @@ -22,10 +23,17 @@ final class SidebarViewController: UIViewController, NeedsDependency { var viewModel: SidebarViewModel! weak var delegate: SidebarViewControllerDelegate? + + let settingBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.tintColor = Asset.Colors.brandBlue.color + barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate) + return barButtonItem + }() static func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout() { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in - var configuration = UICollectionLayoutListConfiguration(appearance: .plain) + var configuration = UICollectionLayoutListConfiguration(appearance: .sidebar) configuration.showsSeparators = false let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment) return section @@ -46,14 +54,27 @@ extension SidebarViewController { override func viewDidLoad() { super.viewDidLoad() - navigationItem.title = "Title" + viewModel.context.authenticationService.activeMastodonAuthenticationBox + .receive(on: DispatchQueue.main) + .sink { [weak self] activeMastodonAuthenticationBox in + guard let self = self else { return } + let domain = activeMastodonAuthenticationBox?.domain + self.navigationItem.title = domain + } + .store(in: &disposeBag) + navigationItem.rightBarButtonItem = settingBarButtonItem + settingBarButtonItem.target = self + settingBarButtonItem.action = #selector(SidebarViewController.settingBarButtonItemPressed(_:)) navigationController?.navigationBar.prefersLargeTitles = true - let barAppearance = UINavigationBarAppearance() - barAppearance.configureWithTransparentBackground() - navigationItem.standardAppearance = barAppearance - navigationItem.compactAppearance = barAppearance - navigationItem.scrollEdgeAppearance = barAppearance + setupBackground(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupBackground(theme: theme) + } + .store(in: &disposeBag) collectionView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(collectionView) @@ -68,6 +89,28 @@ extension SidebarViewController { viewModel.setupDiffableDataSource(collectionView: collectionView) } + private func setupBackground(theme: Theme) { + let barAppearance = UINavigationBarAppearance() + barAppearance.configureWithOpaqueBackground() + barAppearance.backgroundColor = theme.sidebarBackgroundColor + barAppearance.shadowColor = .clear + barAppearance.shadowImage = UIImage() // remove separator line + navigationItem.standardAppearance = barAppearance + navigationItem.compactAppearance = barAppearance + navigationItem.scrollEdgeAppearance = barAppearance + + view.backgroundColor = theme.sidebarBackgroundColor + } + +} + +extension SidebarViewController { + @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, setting: setting) + coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil)) + } } // MARK: - UICollectionViewDelegate diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index f65bb1d6f..9de5c1bb2 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -9,6 +9,8 @@ import UIKit import Combine import CoreData import CoreDataStack +import Meta +import MastodonMeta final class SidebarViewModel { @@ -57,28 +59,61 @@ extension SidebarViewModel { func setupDiffableDataSource( collectionView: UICollectionView ) { - let cellRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in - var content = cell.defaultContentConfiguration() - content.text = item.title - content.image = item.image - cell.contentConfiguration = content - cell.accessories = [] + let tabCellRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + let imageURL: URL? = { + switch item { + case .me: + let authentication = self.context.authenticationService.activeMastodonAuthentication.value + return authentication?.user.avatarImageURL() + default: + return nil + } + }() + let headline: MetaContent = { + switch item { + case .me: + return PlaintextMetaContent(string: item.title) + // TODO: + // return PlaintextMetaContent(string: "Myself") + default: + return PlaintextMetaContent(string: item.title) + } + }() + cell.item = SidebarListContentView.Item( + image: item.sidebarImage, + imageURL: imageURL, + headline: headline, + subheadline: nil + ) + cell.setNeedsUpdateConfiguration() } let headerRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in - var content = cell.defaultContentConfiguration() + var content = UIListContentConfiguration.sidebarHeader() content.text = item.title cell.contentConfiguration = content cell.accessories = [.outlineDisclosure()] } - let accountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in - var content = cell.defaultContentConfiguration() + let accountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in let authentication = AppContext.shared.managedObjectContext.object(with: item.authenticationObjectID) as! MastodonAuthentication - content.text = authentication.user.acctWithDomain - content.image = nil - cell.contentConfiguration = content - cell.accessories = [] + let user = authentication.user + let imageURL = user.avatarImageURL() + let headline: MetaContent = { + do { + let content = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojiMeta) + return try MastodonMetaContent.convert(document: content) + } catch { + return PlaintextMetaContent(string: user.displayNameWithFallback) + } + }() + cell.item = SidebarListContentView.Item( + image: .placeholder(color: .systemFill), + imageURL: imageURL, + headline: headline, + subheadline: PlaintextMetaContent(string: "@" + user.acctWithDomain) + ) + cell.setNeedsUpdateConfiguration() } let addAccountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in @@ -92,7 +127,7 @@ extension SidebarViewModel { diffableDataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, item in switch item { case .tab(let tab): - return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: tab) + return collectionView.dequeueConfiguredReusableCell(using: tabCellRegistration, for: indexPath, item: tab) case .header(let viewModel): return collectionView.dequeueConfiguredReusableCell(using: headerRegistration, for: indexPath, item: viewModel) case .account(let viewModel): @@ -133,16 +168,22 @@ extension SidebarViewModel { .receive(on: DispatchQueue.main) .sink { [weak self] authentications in guard let self = self else { return } - var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() + // tab + var snapshot = self.diffableDataSource.snapshot() + snapshot.reloadItems([.tab(.me)]) + self.diffableDataSource.apply(snapshot) + + // account + var accountSectionSnapshot = NSDiffableDataSourceSectionSnapshot() let headerItem = Item.header(HeaderViewModel(title: "Accounts")) - sectionSnapshot.append([headerItem], to: nil) - let items = authentications.map { authentication in + accountSectionSnapshot.append([headerItem], to: nil) + let accountItems = authentications.map { authentication in Item.account(AccountViewModel(authenticationObjectID: authentication.objectID)) } - sectionSnapshot.append(items, to: headerItem) - sectionSnapshot.append([.addAccount], to: headerItem) - sectionSnapshot.expand([headerItem]) - self.diffableDataSource.apply(sectionSnapshot, to: .account) + accountSectionSnapshot.append(accountItems, to: headerItem) + accountSectionSnapshot.append([.addAccount], to: headerItem) + accountSectionSnapshot.expand([headerItem]) + self.diffableDataSource.apply(accountSectionSnapshot, to: .account) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift new file mode 100644 index 000000000..0c9a95fef --- /dev/null +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift @@ -0,0 +1,48 @@ +// +// SidebarListTableViewCell.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-24. +// + +import UIKit + +final class SidebarListCollectionViewCell: UICollectionViewListCell { + + var item: SidebarListContentView.Item? + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension SidebarListCollectionViewCell { + private func _init() { + + } + + override func updateConfiguration(using state: UICellConfigurationState) { + var newConfiguration = SidebarListContentView.ContentConfiguration().updated(for: state) + newConfiguration.item = item + contentConfiguration = newConfiguration + + var newBackgroundConfiguration = UIBackgroundConfiguration.listSidebarCell().updated(for: state) + // Customize the background color to use the tint color when the cell is highlighted or selected. + if state.isSelected || state.isHighlighted { + newBackgroundConfiguration.backgroundColor = Asset.Colors.brandBlue.color + } + if state.isHighlighted { + newBackgroundConfiguration.backgroundColorTransformer = .init { $0.withAlphaComponent(0.8) } + } + + + backgroundConfiguration = newBackgroundConfiguration + } +} diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift new file mode 100644 index 000000000..6d665eb81 --- /dev/null +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -0,0 +1,215 @@ +// +// SidebarListContentView.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-24. +// + +import os.log +import UIKit +import MetaTextKit +import FLAnimatedImage + +final class SidebarListContentView: UIView, UIContentView { + + let logger = Logger(subsystem: "SidebarListContentView", category: "UI") + + let imageView = UIImageView() + let animationImageView = FLAnimatedImageView() // for animation image + let headlineLabel = MetaLabel(style: .sidebarHeadline(isSelected: false)) + let subheadlineLabel = MetaLabel(style: .sidebarSubheadline(isSelected: false)) + + private var currentConfiguration: ContentConfiguration! + var configuration: UIContentConfiguration { + get { + currentConfiguration + } + set { + guard let newConfiguration = newValue as? ContentConfiguration else { return } + apply(configuration: newConfiguration) + } + } + + init(configuration: ContentConfiguration) { + super.init(frame: .zero) + + _init() + apply(configuration: configuration) + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension SidebarListContentView { + private func _init() { + let imageViewContainer = UIView() + imageViewContainer.translatesAutoresizingMaskIntoConstraints = false + addSubview(imageViewContainer) + NSLayoutConstraint.activate([ + imageViewContainer.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor), + imageViewContainer.centerYAnchor.constraint(equalTo: centerYAnchor), + ]) + imageViewContainer.setContentHuggingPriority(.defaultLow, for: .horizontal) + imageViewContainer.setContentHuggingPriority(.defaultLow, for: .vertical) + + animationImageView.translatesAutoresizingMaskIntoConstraints = false + imageViewContainer.addSubview(animationImageView) + NSLayoutConstraint.activate([ + animationImageView.centerXAnchor.constraint(equalTo: imageViewContainer.centerXAnchor), + animationImageView.centerYAnchor.constraint(equalTo: imageViewContainer.centerYAnchor), + animationImageView.widthAnchor.constraint(equalTo: imageViewContainer.widthAnchor, multiplier: 1.0).priority(.required - 1), + animationImageView.heightAnchor.constraint(equalTo: imageViewContainer.heightAnchor, multiplier: 1.0).priority(.required - 1), + ]) + animationImageView.setContentHuggingPriority(.defaultLow - 10, for: .vertical) + animationImageView.setContentHuggingPriority(.defaultLow - 10, for: .horizontal) + + imageView.translatesAutoresizingMaskIntoConstraints = false + imageViewContainer.addSubview(imageView) + NSLayoutConstraint.activate([ + imageView.centerXAnchor.constraint(equalTo: imageViewContainer.centerXAnchor), + imageView.centerYAnchor.constraint(equalTo: imageViewContainer.centerYAnchor), + imageView.widthAnchor.constraint(equalTo: imageViewContainer.widthAnchor, multiplier: 1.0).priority(.required - 1), + imageView.heightAnchor.constraint(equalTo: imageViewContainer.heightAnchor, multiplier: 1.0).priority(.required - 1), + ]) + imageView.setContentHuggingPriority(.defaultLow - 10, for: .vertical) + imageView.setContentHuggingPriority(.defaultLow - 10, for: .horizontal) + + let textContainer = UIStackView() + textContainer.axis = .vertical + textContainer.translatesAutoresizingMaskIntoConstraints = false + addSubview(textContainer) + NSLayoutConstraint.activate([ + textContainer.topAnchor.constraint(equalTo: topAnchor, constant: 10), + textContainer.leadingAnchor.constraint(equalTo: imageViewContainer.trailingAnchor, constant: 10), + textContainer.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), + bottomAnchor.constraint(equalTo: textContainer.bottomAnchor, constant: 12), + ]) + + textContainer.addArrangedSubview(headlineLabel) + textContainer.addArrangedSubview(subheadlineLabel) + headlineLabel.setContentHuggingPriority(.required - 9, for: .vertical) + headlineLabel.setContentCompressionResistancePriority(.required - 9, for: .vertical) + subheadlineLabel.setContentHuggingPriority(.required - 10, for: .vertical) + subheadlineLabel.setContentCompressionResistancePriority(.required - 10, for: .vertical) + + NSLayoutConstraint.activate([ + imageViewContainer.heightAnchor.constraint(equalTo: headlineLabel.heightAnchor, multiplier: 1.0).priority(.required - 1), + imageViewContainer.widthAnchor.constraint(equalTo: imageViewContainer.heightAnchor, multiplier: 1.0).priority(.required - 1), + ]) + + animationImageView.isUserInteractionEnabled = false + headlineLabel.isUserInteractionEnabled = false + subheadlineLabel.isUserInteractionEnabled = false + + imageView.contentMode = .scaleAspectFit + animationImageView.contentMode = .scaleAspectFit + imageView.tintColor = Asset.Colors.brandBlue.color + animationImageView.tintColor = Asset.Colors.brandBlue.color + } + + private func apply(configuration: ContentConfiguration) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + guard currentConfiguration != configuration else { return } + currentConfiguration = configuration + + guard let item = configuration.item else { return } + + // configure state + imageView.tintColor = item.isSelected ? .white : Asset.Colors.brandBlue.color + animationImageView.tintColor = item.isSelected ? .white : Asset.Colors.brandBlue.color + headlineLabel.setup(style: .sidebarHeadline(isSelected: item.isSelected)) + subheadlineLabel.setup(style: .sidebarSubheadline(isSelected: item.isSelected)) + + // configure model + imageView.isHidden = item.imageURL != nil + animationImageView.isHidden = item.imageURL == nil + imageView.image = item.image.withRenderingMode(.alwaysTemplate) + animationImageView.setImage( + url: item.imageURL, + placeholder: animationImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink + scaleToSize: nil + ) + animationImageView.layer.masksToBounds = true + animationImageView.layer.cornerCurve = .continuous + animationImageView.layer.cornerRadius = 4 + + headlineLabel.configure(content: item.headline) + + if let subheadline = item.subheadline { + subheadlineLabel.configure(content: subheadline) + subheadlineLabel.isHidden = false + } else { + subheadlineLabel.isHidden = true + } + } +} + +extension SidebarListContentView { + struct Item: Hashable { + // state + var isSelected: Bool = false + + // model + let image: UIImage + let imageURL: URL? + let headline: MetaContent + let subheadline: MetaContent? + + static func == (lhs: SidebarListContentView.Item, rhs: SidebarListContentView.Item) -> Bool { + return lhs.isSelected == rhs.isSelected + && lhs.image == rhs.image + && lhs.imageURL == rhs.imageURL + && lhs.headline.string == rhs.headline.string + && lhs.subheadline?.string == rhs.subheadline?.string + } + + func hash(into hasher: inout Hasher) { + hasher.combine(isSelected) + hasher.combine(image) + imageURL.flatMap { hasher.combine($0) } + hasher.combine(headline.string) + subheadline.flatMap { hasher.combine($0.string) } + } + } + + struct ContentConfiguration: UIContentConfiguration, Hashable { + let logger = Logger(subsystem: "SidebarListContentView.ContentConfiguration", category: "ContentConfiguration") + + var item: Item? + + func makeContentView() -> UIView & UIContentView { + SidebarListContentView(configuration: self) + } + + func updated(for state: UIConfigurationState) -> ContentConfiguration { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + var updatedConfiguration = self + + if let state = state as? UICellConfigurationState { + updatedConfiguration.item?.isSelected = state.isHighlighted || state.isSelected + } else { + assertionFailure() + updatedConfiguration.item?.isSelected = false + } + + return updatedConfiguration + } + + static func == ( + lhs: ContentConfiguration, + rhs: ContentConfiguration + ) -> Bool { + return lhs.item == rhs.item + } + + func hash(into hasher: inout Hasher) { + hasher.combine(item) + } + } +} diff --git a/Mastodon/Service/ThemeService/MastodonTheme.swift b/Mastodon/Service/ThemeService/MastodonTheme.swift index dbf2324cd..85b0d42db 100644 --- a/Mastodon/Service/ThemeService/MastodonTheme.swift +++ b/Mastodon/Service/ThemeService/MastodonTheme.swift @@ -22,6 +22,8 @@ struct MastodonTheme: Theme { let tertiarySystemGroupedBackgroundColor = Asset.Theme.Mastodon.tertiarySystemGroupedBackground.color let navigationBarBackgroundColor = Asset.Theme.Mastodon.navigationBarBackground.color + + let sidebarBackgroundColor = Asset.Theme.Mastodon.sidebarBackground.color let tabBarBackgroundColor = Asset.Theme.Mastodon.tabBarBackground.color let tabBarItemSelectedIconColor = Asset.Colors.brandBlue.color diff --git a/Mastodon/Service/ThemeService/SystemTheme.swift b/Mastodon/Service/ThemeService/SystemTheme.swift index 3a8ddd2d8..2e3b290db 100644 --- a/Mastodon/Service/ThemeService/SystemTheme.swift +++ b/Mastodon/Service/ThemeService/SystemTheme.swift @@ -23,6 +23,8 @@ struct SystemTheme: Theme { let navigationBarBackgroundColor = Asset.Theme.System.navigationBarBackground.color + let sidebarBackgroundColor = Asset.Theme.Mastodon.sidebarBackground.color + let tabBarBackgroundColor = Asset.Theme.System.tabBarBackground.color let tabBarItemSelectedIconColor = Asset.Colors.brandBlue.color let tabBarItemFocusedIconColor = Asset.Theme.System.tabBarItemInactiveIconColor.color diff --git a/Mastodon/Service/ThemeService/Theme.swift b/Mastodon/Service/ThemeService/Theme.swift index 4074e0904..1a3b3c5d1 100644 --- a/Mastodon/Service/ThemeService/Theme.swift +++ b/Mastodon/Service/ThemeService/Theme.swift @@ -22,6 +22,8 @@ public protocol Theme { var tertiarySystemGroupedBackgroundColor: UIColor { get } var navigationBarBackgroundColor: UIColor { get } + + var sidebarBackgroundColor: UIColor { get } var tabBarBackgroundColor: UIColor { get } var tabBarItemSelectedIconColor: UIColor { get } From d35f163623056f2280f7a407c67c7a5dc504348f Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 24 Sep 2021 19:59:39 +0800 Subject: [PATCH 193/392] chore: update version to 1.2.0 (66) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 0ec5a69ad..6329631ff 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 0ec5a69ad..6329631ff 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 0ec5a69ad..6329631ff 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a63d76b89..218f25fd4 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4741,7 +4741,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4769,7 +4769,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4876,11 +4876,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4907,11 +4907,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4936,11 +4936,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4966,11 +4966,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5033,7 +5033,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5058,7 +5058,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5083,7 +5083,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5108,7 +5108,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5133,7 +5133,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5158,7 +5158,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5183,7 +5183,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5208,7 +5208,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5299,7 +5299,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5365,11 +5365,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5414,7 +5414,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5439,11 +5439,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5535,7 +5535,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5601,11 +5601,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5650,7 +5650,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5675,11 +5675,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 65; + DYLIB_CURRENT_VERSION = 66; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5705,7 +5705,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5729,7 +5729,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 91145420e..cb88c3960 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 36 + 42 CoreDataStack.xcscheme_^#shared#^_ orderHint - 35 + 43 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 37 + 44 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 38 + 41 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 73d3654f9..b89a15f37 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 65 + 66 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index be1a7fdcd..62580d104 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 0ec5a69ad..6329631ff 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 0ec5a69ad..6329631ff 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index dde206116..846239c27 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 4e38864ef..beffb8405 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 65 + 66 NSExtension NSExtensionAttributes From 4bb9f66e41ec50b77579a1776f40549541839cd5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 27 Sep 2021 03:34:41 +0200 Subject: [PATCH 194/392] New translations Localizable.stringsdict (German) --- .../StringsConvertor/input/de_DE/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict index c868bdc0f..66b7f2a2d 100644 --- a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 ungelesene Benachrichtigung other - %ld unread notification + %ld ungelesene Benachrichtigungen a11y.plural.count.input_limit_exceeds From 2619dacc6d4674ccaa85f8c0c221d26beb8ff428 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 27 Sep 2021 03:34:42 +0200 Subject: [PATCH 195/392] New translations app.json (German) --- Localization/StringsConvertor/input/de_DE/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/de_DE/app.json b/Localization/StringsConvertor/input/de_DE/app.json index 47e57498c..ff29e8d64 100644 --- a/Localization/StringsConvertor/input/de_DE/app.json +++ b/Localization/StringsConvertor/input/de_DE/app.json @@ -538,12 +538,12 @@ "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" + "add_account": "Konto hinzufügen" }, "wizard": { - "new_in_mastodon": "New in Mastodon", + "new_in_mastodon": "Neu in Mastodon", "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", - "accessibility_hint": "Double tap to dismiss this wizard" + "accessibility_hint": "Doppeltippen, um diesen Assistenten zu schließen" } } } \ No newline at end of file From 1da803fb97312c413b874fdb6d908f0dcadfc49f Mon Sep 17 00:00:00 2001 From: CMK Date: Sun, 26 Sep 2021 18:29:08 +0800 Subject: [PATCH 196/392] feat: add recent search history in sidebar --- .../CoreData.xcdatamodeld/.xccurrentversion | 8 + .../CoreData 2.xcdatamodel/contents | 298 ++++++++++++++++++ CoreDataStack/Entity/MastodonUser.swift | 11 +- CoreDataStack/Entity/SearchHistory.swift | 10 +- CoreDataStack/Entity/Status.swift | 8 +- CoreDataStack/Entity/Tag.swift | 12 +- Mastodon.xcodeproj/project.pbxproj | 4 +- .../xcschemes/xcschememanagement.plist | 8 +- Mastodon/Info.plist | 4 +- .../Cell/AccountListTableViewCell.swift | 3 + .../HashtagTimelineViewModel.swift | 22 +- .../HomeTimelineViewController.swift | 10 + .../Scene/Root/RootSplitViewController.swift | 26 ++ .../Root/Sidebar/SidebarViewController.swift | 20 +- .../Scene/Root/Sidebar/SidebarViewModel.swift | 160 +++++++++- .../View/SidebarListCollectionViewCell.swift | 32 ++ .../Sidebar/View/SidebarListContentView.swift | 35 +- .../SearchHistoryViewModel.swift | 20 +- .../SearchResult/SearchResultViewModel.swift | 31 +- .../SearchResultTableViewCell.swift | 4 + .../Settings/SettingsViewController.swift | 2 +- .../CoreData/APIService+CoreData+Status.swift | 11 +- .../CoreData/APIService+CoreData+Tag.swift | 2 +- 23 files changed, 674 insertions(+), 67 deletions(-) create mode 100644 CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion create mode 100644 CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents diff --git a/CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion b/CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion new file mode 100644 index 000000000..3d5e5761c --- /dev/null +++ b/CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion @@ -0,0 +1,8 @@ + + + + + _XCCurrentVersionName + CoreData 2.xcdatamodel + + diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents new file mode 100644 index 000000000..670241f35 --- /dev/null +++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CoreDataStack/Entity/MastodonUser.swift b/CoreDataStack/Entity/MastodonUser.swift index b7a101152..913aa1f16 100644 --- a/CoreDataStack/Entity/MastodonUser.swift +++ b/CoreDataStack/Entity/MastodonUser.swift @@ -43,11 +43,11 @@ final public class MastodonUser: NSManagedObject { // one-to-one relationship @NSManaged public private(set) var pinnedStatus: Status? @NSManaged public private(set) var mastodonAuthentication: MastodonAuthentication? - @NSManaged public private(set) var searchHistory: SearchHistory? // one-to-many relationship @NSManaged public private(set) var statuses: Set? @NSManaged public private(set) var notifications: Set? + @NSManaged public private(set) var searchHistories: Set // many-to-many relationship @NSManaged public private(set) var favourite: Set? @@ -274,6 +274,15 @@ extension MastodonUser { } +extension MastodonUser { + public func findSearchHistory(domain: String, userID: MastodonUser.ID) -> SearchHistory? { + return searchHistories.first { searchHistory in + return searchHistory.domain == domain + && searchHistory.userID == userID + } + } +} + extension MastodonUser { public struct Property { public let identifier: String diff --git a/CoreDataStack/Entity/SearchHistory.swift b/CoreDataStack/Entity/SearchHistory.swift index 3894d1c1b..05e441906 100644 --- a/CoreDataStack/Entity/SearchHistory.swift +++ b/CoreDataStack/Entity/SearchHistory.swift @@ -16,7 +16,7 @@ public final class SearchHistory: NSManagedObject { @NSManaged public private(set) var createAt: Date @NSManaged public private(set) var updatedAt: Date - // one-to-one relationship + // many-to-one relationship @NSManaged public private(set) var account: MastodonUser? @NSManaged public private(set) var hashtag: Tag? @NSManaged public private(set) var status: Status? @@ -31,10 +31,10 @@ extension SearchHistory { setPrimitiveValue(Date(), forKey: #keyPath(SearchHistory.updatedAt)) } - public override func willSave() { - super.willSave() - setPrimitiveValue(Date(), forKey: #keyPath(SearchHistory.updatedAt)) - } +// public override func willSave() { +// super.willSave() +// setPrimitiveValue(Date(), forKey: #keyPath(SearchHistory.updatedAt)) +// } @discardableResult public static func insert( diff --git a/CoreDataStack/Entity/Status.swift b/CoreDataStack/Entity/Status.swift index 717e54ab7..ee168e418 100644 --- a/CoreDataStack/Entity/Status.swift +++ b/CoreDataStack/Entity/Status.swift @@ -52,18 +52,18 @@ public final class Status: NSManagedObject { // one-to-one relationship @NSManaged public private(set) var pinnedBy: MastodonUser? @NSManaged public private(set) var poll: Poll? - @NSManaged public private(set) var searchHistory: SearchHistory? // one-to-many relationship @NSManaged public private(set) var reblogFrom: Set? @NSManaged public private(set) var mentions: Set? - @NSManaged public private(set) var tags: Set? @NSManaged public private(set) var homeTimelineIndexes: Set? @NSManaged public private(set) var mediaAttachments: Set? @NSManaged public private(set) var replyFrom: Set? @NSManaged public private(set) var inNotifications: Set? + @NSManaged public private(set) var searchHistories: Set + @NSManaged public private(set) var updatedAt: Date @NSManaged public private(set) var deletedAt: Date? @NSManaged public private(set) var revealedAt: Date? @@ -81,7 +81,6 @@ extension Status { replyTo: Status?, poll: Poll?, mentions: [Mention]?, - tags: [Tag]?, mediaAttachments: [Attachment]?, favouritedBy: MastodonUser?, rebloggedBy: MastodonUser?, @@ -126,9 +125,6 @@ extension Status { if let mentions = mentions { status.mutableSetValue(forKey: #keyPath(Status.mentions)).addObjects(from: mentions) } - if let tags = tags { - status.mutableSetValue(forKey: #keyPath(Status.tags)).addObjects(from: tags) - } if let mediaAttachments = mediaAttachments { status.mutableSetValue(forKey: #keyPath(Status.mediaAttachments)).addObjects(from: mediaAttachments) } diff --git a/CoreDataStack/Entity/Tag.swift b/CoreDataStack/Entity/Tag.swift index 6aeee520e..fa9e098de 100644 --- a/CoreDataStack/Entity/Tag.swift +++ b/CoreDataStack/Entity/Tag.swift @@ -18,13 +18,12 @@ public final class Tag: NSManagedObject { @NSManaged public private(set) var url: String // one-to-one relationship - @NSManaged public private(set) var searchHistory: SearchHistory? // many-to-many relationship - @NSManaged public private(set) var statuses: Set? // one-to-many relationship @NSManaged public private(set) var histories: Set? + @NSManaged public private(set) var searchHistories: Set } public extension Tag { @@ -55,6 +54,15 @@ public extension Tag { } } +extension Tag { + public func findSearchHistory(domain: String, userID: MastodonUser.ID) -> SearchHistory? { + return searchHistories.first { searchHistory in + return searchHistory.domain == domain + && searchHistory.userID == userID + } + } +} + public extension Tag { struct Property { public let name: String diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 218f25fd4..8de9739e0 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -1352,6 +1352,7 @@ DBE3CE0C261D767100430CC6 /* FavoriteViewController+Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FavoriteViewController+Provider.swift"; sourceTree = ""; }; DBE3CE12261D7D4200430CC6 /* StatusTableViewControllerAspect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewControllerAspect.swift; sourceTree = ""; }; DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPreference.swift; sourceTree = ""; }; + DBF156DD27006F5D00EC00B7 /* CoreData 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreData 2.xcdatamodel"; sourceTree = ""; }; DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewController.swift; sourceTree = ""; }; DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryViewController.swift; sourceTree = ""; }; DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewModel.swift; sourceTree = ""; }; @@ -6129,9 +6130,10 @@ DB89BA3525C1145C008580ED /* CoreData.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DBF156DD27006F5D00EC00B7 /* CoreData 2.xcdatamodel */, DB89BA3625C1145C008580ED /* CoreData.xcdatamodel */, ); - currentVersion = DB89BA3625C1145C008580ED /* CoreData.xcdatamodel */; + currentVersion = DBF156DD27006F5D00EC00B7 /* CoreData 2.xcdatamodel */; path = CoreData.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index cb88c3960..07d0f6d73 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 42 + 38 CoreDataStack.xcscheme_^#shared#^_ orderHint - 43 + 35 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 44 + 37 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 41 + 36 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index b89a15f37..0da19b3ba 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -2,8 +2,8 @@ - CADisableMinimumFrameDuration - + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable diff --git a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift index 4c9977f37..b8f7d5381 100644 --- a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift @@ -109,6 +109,9 @@ extension AccountListTableViewCell { separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), ]) + + badgeButton.setBadge(number: 0) + checkmarkImageView.isHidden = true } } diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift index c1698f5dc..1bb76493a 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift @@ -85,16 +85,20 @@ final class HashtagTimelineViewModel: NSObject { return } let query = Mastodon.API.V2.Search.Query(q: hashtag, type: .hashtags) - context.apiService.search(domain: activeMastodonAuthenticationBox.domain, query: query, mastodonAuthenticationBox: activeMastodonAuthenticationBox) - .sink { _ in - - } receiveValue: { [weak self] response in - let matchedTag = response.value.hashtags.first { tag -> Bool in - return tag.name == self?.hashtag - } - self?.hashtagEntity.send(matchedTag) + context.apiService.search( + domain: activeMastodonAuthenticationBox.domain, + query: query, + mastodonAuthenticationBox: activeMastodonAuthenticationBox + ) + .sink { _ in + + } receiveValue: { [weak self] response in + let matchedTag = response.value.hashtags.first { tag -> Bool in + return tag.name == self?.hashtag } - .store(in: &disposeBag) + self?.hashtagEntity.send(matchedTag) + } + .store(in: &disposeBag) } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 154fad528..e815ba8c4 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -99,7 +99,17 @@ extension HomeTimelineViewController { .receive(on: DispatchQueue.main) .sink { [weak self] displaySettingBarButtonItem in guard let self = self else { return } + #if DEBUG + // display debug menu + self.navigationItem.leftBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.image = UIImage(systemName: "ellipsis.circle") + barButtonItem.menu = self.debugMenu + return barButtonItem + }() + #else self.navigationItem.leftBarButtonItem = displaySettingBarButtonItem ? self.settingBarButtonItem : nil + #endif } .store(in: &disposeBag) navigationItem.titleView = titleView diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 441cc992e..bba68defb 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -8,6 +8,7 @@ import os.log import UIKit import Combine +import CoreDataStack final class RootSplitViewController: UISplitViewController, NeedsDependency { @@ -117,6 +118,7 @@ extension RootSplitViewController { // MARK: - SidebarViewControllerDelegate extension RootSplitViewController: SidebarViewControllerDelegate { + func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) { guard let index = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { @@ -126,6 +128,30 @@ extension RootSplitViewController: SidebarViewControllerDelegate { currentSupplementaryTab = tab setViewController(supplementaryViewControllers[index], for: .supplementary) } + + func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectSearchHistory searchHistoryViewModel: SidebarViewModel.SearchHistoryViewModel) { + // self.sidebarViewController(sidebarViewController, didSelectTab: .search) + + let supplementaryViewController = viewController(for: .supplementary) + let managedObjectContext = context.managedObjectContext + managedObjectContext.perform { + let searchHistory = managedObjectContext.object(with: searchHistoryViewModel.searchHistoryObjectID) as! SearchHistory + if let account = searchHistory.account { + DispatchQueue.main.async { + let profileViewModel = CachedProfileViewModel(context: self.context, mastodonUser: account) + self.coordinator.present(scene: .profile(viewModel: profileViewModel), from: supplementaryViewController, transition: .show) + } + } else if let hashtag = searchHistory.hashtag { + DispatchQueue.main.async { + let hashtagTimelineViewModel = HashtagTimelineViewModel(context: self.context, hashtag: hashtag.name) + self.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: supplementaryViewController, transition: .show) + } + } else { + assertionFailure() + } + } + } + } // MARK: - UISplitViewControllerDelegate diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index d93fcd807..e1ae87646 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -12,6 +12,7 @@ import CoreDataStack protocol SidebarViewControllerDelegate: AnyObject { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) + func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectSearchHistory searchHistoryViewModel: SidebarViewModel.SearchHistoryViewModel) } final class SidebarViewController: UIViewController, NeedsDependency { @@ -34,6 +35,13 @@ final class SidebarViewController: UIViewController, NeedsDependency { static func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout() { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in var configuration = UICollectionLayoutListConfiguration(appearance: .sidebar) + if sectionIndex == SidebarViewModel.Section.tab.rawValue { + // with indentation + configuration.headerMode = .none + } else { + // remove indentation + configuration.headerMode = .firstItemInSection + } configuration.showsSeparators = false let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment) return section @@ -59,6 +67,11 @@ extension SidebarViewController { .sink { [weak self] activeMastodonAuthenticationBox in guard let self = self else { return } let domain = activeMastodonAuthenticationBox?.domain + self.navigationItem.backBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.image = UIImage(systemName: "sidebar.leading") + return barButtonItem + }() self.navigationItem.title = domain } .store(in: &disposeBag) @@ -121,6 +134,10 @@ extension SidebarViewController: UICollectionViewDelegate { switch item { case .tab(let tab): delegate?.sidebarViewController(self, didSelectTab: tab) + case .searchHistory(let viewModel): + delegate?.sidebarViewController(self, didSelectSearchHistory: viewModel) + case .header: + break case .account(let viewModel): assert(Thread.isMainThread) let authentication = context.managedObjectContext.object(with: viewModel.authenticationObjectID) as! MastodonAuthentication @@ -133,9 +150,6 @@ extension SidebarViewController: UICollectionViewDelegate { .store(in: &disposeBag) case .addAccount: coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil)) - default: - // TODO: - break } } } diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 9de5c1bb2..a6dd82cc8 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -18,30 +18,51 @@ final class SidebarViewModel { // input let context: AppContext - + let searchHistoryFetchedResultController: SearchHistoryFetchedResultController + // output var diffableDataSource: UICollectionViewDiffableDataSource! + let activeMastodonAuthenticationObjectID = CurrentValueSubject(nil) - init(context: AppContext) { self.context = context + self.searchHistoryFetchedResultController = SearchHistoryFetchedResultController(managedObjectContext: context.managedObjectContext) + + context.authenticationService.activeMastodonAuthentication + .sink { [weak self] authentication in + guard let self = self else { return } + // bind search history + self.searchHistoryFetchedResultController.domain.value = authentication?.domain + self.searchHistoryFetchedResultController.userID.value = authentication?.userID + + // bind objectID + self.activeMastodonAuthenticationObjectID.value = authentication?.objectID + } + .store(in: &disposeBag) + + try? searchHistoryFetchedResultController.fetchedResultsController.performFetch() } } extension SidebarViewModel { - enum Section: Hashable, CaseIterable { + enum Section: Int, Hashable, CaseIterable { case tab case account } enum Item: Hashable { case tab(MainTabBarController.Tab) + case searchHistory(SearchHistoryViewModel) case header(HeaderViewModel) case account(AccountViewModel) case addAccount } + struct SearchHistoryViewModel: Hashable { + let searchHistoryObjectID: NSManagedObjectID + } + struct HeaderViewModel: Hashable { let title: String } @@ -59,7 +80,9 @@ extension SidebarViewModel { func setupDiffableDataSource( collectionView: UICollectionView ) { - let tabCellRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + let tabCellRegistration = UICollectionView.CellRegistration { [weak self] cell, indexPath, item in + guard let self = self else { return } + let imageURL: URL? = { switch item { case .me: @@ -79,13 +102,76 @@ extension SidebarViewModel { return PlaintextMetaContent(string: item.title) } }() + let needsOutlineDisclosure = item == .search cell.item = SidebarListContentView.Item( image: item.sidebarImage, imageURL: imageURL, headline: headline, - subheadline: nil + subheadline: nil, + needsOutlineDisclosure: needsOutlineDisclosure ) cell.setNeedsUpdateConfiguration() + + switch item { + case .notification: + Publishers.CombineLatest( + self.context.authenticationService.activeMastodonAuthentication, + self.context.notificationService.unreadNotificationCountDidUpdate + ) + .receive(on: DispatchQueue.main) + .sink { [weak cell] authentication, _ in + guard let cell = cell else { return } + let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in + let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken) + return count > 0 + } ?? false + + let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge")! : UIImage(systemName: "bell")! + cell._contentView?.imageView.image = image + } + .store(in: &cell.disposeBag) + default: + break + } + } + + let searchHistoryCellRegistration = UICollectionView.CellRegistration { [weak self] cell, indexPath, item in + guard let self = self else { return } + let managedObjectContext = self.searchHistoryFetchedResultController.fetchedResultsController.managedObjectContext + + guard let searchHistory = try? managedObjectContext.existingObject(with: item.searchHistoryObjectID) as? SearchHistory else { return } + + if let account = searchHistory.account { + let headline: MetaContent = { + do { + let content = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojiMeta) + return try MastodonMetaContent.convert(document: content) + } catch { + return PlaintextMetaContent(string: account.displayNameWithFallback) + } + }() + cell.item = SidebarListContentView.Item( + image: .placeholder(color: .systemFill), + imageURL: account.avatarImageURL(), + headline: headline, + subheadline: PlaintextMetaContent(string: "@" + account.acctWithDomain), + needsOutlineDisclosure: false + ) + } else if let hashtag = searchHistory.hashtag { + let image = UIImage(systemName: "number.square.fill")!.withRenderingMode(.alwaysTemplate) + let headline = PlaintextMetaContent(string: "#" + hashtag.name) + cell.item = SidebarListContentView.Item( + image: image, + imageURL: nil, + headline: headline, + subheadline: nil, + needsOutlineDisclosure: false + ) + } else { + assertionFailure() + } + + cell.setNeedsUpdateConfiguration() } let headerRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in @@ -95,7 +181,9 @@ extension SidebarViewModel { cell.accessories = [.outlineDisclosure()] } - let accountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + let accountRegistration = UICollectionView.CellRegistration { [weak self] (cell, indexPath, item) in + guard let self = self else { return } + let authentication = AppContext.shared.managedObjectContext.object(with: item.authenticationObjectID) as! MastodonAuthentication let user = authentication.user let imageURL = user.avatarImageURL() @@ -111,15 +199,37 @@ extension SidebarViewModel { image: .placeholder(color: .systemFill), imageURL: imageURL, headline: headline, - subheadline: PlaintextMetaContent(string: "@" + user.acctWithDomain) + subheadline: PlaintextMetaContent(string: "@" + user.acctWithDomain), + needsOutlineDisclosure: false ) cell.setNeedsUpdateConfiguration() + + // FIXME: use notification, not timer + let accessToken = authentication.userAccessToken + AppContext.shared.timestampUpdatePublisher + .map { _ in UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken) } + .removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak cell] count in + guard let cell = cell else { return } + cell._contentView?.badgeButton.setBadge(number: count) + } + .store(in: &cell.disposeBag) + + let authenticationObjectID = item.authenticationObjectID + self.activeMastodonAuthenticationObjectID + .receive(on: DispatchQueue.main) + .sink { [weak cell] objectID in + guard let cell = cell else { return } + cell._contentView?.checkmarkImageView.isHidden = authenticationObjectID != objectID + } + .store(in: &cell.disposeBag) } let addAccountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in var content = cell.defaultContentConfiguration() content.text = L10n.Scene.AccountList.addAccount - content.image = nil + content.image = UIImage(systemName: "plus.square.fill")! cell.contentConfiguration = content cell.accessories = [] } @@ -128,6 +238,8 @@ extension SidebarViewModel { switch item { case .tab(let tab): return collectionView.dequeueConfiguredReusableCell(using: tabCellRegistration, for: indexPath, item: tab) + case .searchHistory(let viewModel): + return collectionView.dequeueConfiguredReusableCell(using: searchHistoryCellRegistration, for: indexPath, item: viewModel) case .header(let viewModel): return collectionView.dequeueConfiguredReusableCell(using: headerRegistration, for: indexPath, item: viewModel) case .account(let viewModel): @@ -164,6 +276,38 @@ extension SidebarViewModel { } } + // update .search tab + searchHistoryFetchedResultController.objectIDs + .removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak self] objectIDs in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + // update .search tab + var sectionSnapshot = diffableDataSource.snapshot(for: .tab) + + // remove children + let searchHistorySnapshot = sectionSnapshot.snapshot(of: .tab(.search)) + sectionSnapshot.delete(searchHistorySnapshot.items) + + // append children + let managedObjectContext = self.searchHistoryFetchedResultController.fetchedResultsController.managedObjectContext + let items: [Item] = objectIDs.compactMap { objectID -> Item? in + guard let searchHistory = try? managedObjectContext.existingObject(with: objectID) as? SearchHistory else { return nil } + guard searchHistory.account != nil || searchHistory.hashtag != nil else { return nil } + let viewModel = SearchHistoryViewModel(searchHistoryObjectID: objectID) + return Item.searchHistory(viewModel) + } + sectionSnapshot.append(Array(items.prefix(5)), to: .tab(.search)) + sectionSnapshot.expand([.tab(.search)]) + + // apply snapshot + diffableDataSource.apply(sectionSnapshot, to: .tab, animatingDifferences: false) + } + .store(in: &disposeBag) + + // update .me tab and .account section context.authenticationService.mastodonAuthentications .receive(on: DispatchQueue.main) .sink { [weak self] authentications in diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift index 0c9a95fef..1bb76f59e 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift @@ -6,11 +6,29 @@ // import UIKit +import Combine final class SidebarListCollectionViewCell: UICollectionViewListCell { + + var disposeBag = Set() var item: SidebarListContentView.Item? + var _contentView: SidebarListContentView? { + guard let view = contentView as? SidebarListContentView else { + assertionFailure() + return nil + } + + return view + } + + override func prepareForReuse() { + super.prepareForReuse() + + disposeBag.removeAll() + } + override init(frame: CGRect) { super.init(frame: frame) _init() @@ -44,5 +62,19 @@ extension SidebarListCollectionViewCell { backgroundConfiguration = newBackgroundConfiguration + + let needsOutlineDisclosure = item?.needsOutlineDisclosure ?? false + if !needsOutlineDisclosure { + accessories = [] + } else { + let tintColor: UIColor = state.isHighlighted || state.isSelected ? .white : Asset.Colors.brandBlue.color + accessories = [ + UICellAccessory.outlineDisclosure( + displayed: .always, + options: UICellAccessory.OutlineDisclosureOptions(tintColor: tintColor), + actionHandler: nil + ) + ] + } } } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift index 6d665eb81..62b188325 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -18,6 +18,13 @@ final class SidebarListContentView: UIView, UIContentView { let animationImageView = FLAnimatedImageView() // for animation image let headlineLabel = MetaLabel(style: .sidebarHeadline(isSelected: false)) let subheadlineLabel = MetaLabel(style: .sidebarSubheadline(isSelected: false)) + let badgeButton = BadgeButton() + let checkmarkImageView: UIImageView = { + let image = UIImage(systemName: "checkmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .semibold)) + let imageView = UIImageView(image: image) + imageView.tintColor = .label + return imageView + }() private var currentConfiguration: ContentConfiguration! var configuration: UIContentConfiguration { @@ -85,7 +92,7 @@ extension SidebarListContentView { NSLayoutConstraint.activate([ textContainer.topAnchor.constraint(equalTo: topAnchor, constant: 10), textContainer.leadingAnchor.constraint(equalTo: imageViewContainer.trailingAnchor, constant: 10), - textContainer.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), + // textContainer.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), bottomAnchor.constraint(equalTo: textContainer.bottomAnchor, constant: 12), ]) @@ -96,11 +103,32 @@ extension SidebarListContentView { subheadlineLabel.setContentHuggingPriority(.required - 10, for: .vertical) subheadlineLabel.setContentCompressionResistancePriority(.required - 10, for: .vertical) + badgeButton.translatesAutoresizingMaskIntoConstraints = false + addSubview(badgeButton) + NSLayoutConstraint.activate([ + badgeButton.leadingAnchor.constraint(equalTo: textContainer.trailingAnchor, constant: 4), + badgeButton.centerYAnchor.constraint(equalTo: centerYAnchor), + badgeButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 16).priority(.required - 1), + badgeButton.widthAnchor.constraint(equalTo: badgeButton.heightAnchor, multiplier: 1.0).priority(.required - 1), + ]) + badgeButton.setContentHuggingPriority(.required - 10, for: .horizontal) + badgeButton.setContentCompressionResistancePriority(.required - 10, for: .horizontal) + NSLayoutConstraint.activate([ imageViewContainer.heightAnchor.constraint(equalTo: headlineLabel.heightAnchor, multiplier: 1.0).priority(.required - 1), imageViewContainer.widthAnchor.constraint(equalTo: imageViewContainer.heightAnchor, multiplier: 1.0).priority(.required - 1), ]) + checkmarkImageView.translatesAutoresizingMaskIntoConstraints = false + addSubview(checkmarkImageView) + NSLayoutConstraint.activate([ + checkmarkImageView.centerYAnchor.constraint(equalTo: centerYAnchor), + checkmarkImageView.leadingAnchor.constraint(equalTo: badgeButton.trailingAnchor, constant: 16), + checkmarkImageView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), + ]) + checkmarkImageView.setContentHuggingPriority(.required - 9, for: .horizontal) + checkmarkImageView.setContentCompressionResistancePriority(.required - 9, for: .horizontal) + animationImageView.isUserInteractionEnabled = false headlineLabel.isUserInteractionEnabled = false subheadlineLabel.isUserInteractionEnabled = false @@ -109,6 +137,9 @@ extension SidebarListContentView { animationImageView.contentMode = .scaleAspectFit imageView.tintColor = Asset.Colors.brandBlue.color animationImageView.tintColor = Asset.Colors.brandBlue.color + + badgeButton.setBadge(number: 0) + checkmarkImageView.isHidden = true } private func apply(configuration: ContentConfiguration) { @@ -160,6 +191,8 @@ extension SidebarListContentView { let headline: MetaContent let subheadline: MetaContent? + let needsOutlineDisclosure: Bool + static func == (lhs: SidebarListContentView.Item, rhs: SidebarListContentView.Item) -> Bool { return lhs.isSelected == rhs.isSelected && lhs.image == rhs.image diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift index 934c55b1b..0ed58b07e 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift @@ -98,14 +98,19 @@ extension SearchHistoryViewModel { let managedObjectContext = context.backgroundManagedObjectContext managedObjectContext.performChanges { guard let user = try? managedObjectContext.existingObject(with: objectID) as? MastodonUser else { return } - if let searchHistory = user.searchHistory { + if let searchHistory = user.findSearchHistory(domain: box.domain, userID: box.userID) { searchHistory.update(updatedAt: Date()) } else { SearchHistory.insert(into: managedObjectContext, property: property, account: user) } } .sink { result in - // do nothing + switch result { + case .failure(let error): + assertionFailure(error.localizedDescription) + case .success: + break + } } .store(in: &context.disposeBag) @@ -113,14 +118,19 @@ extension SearchHistoryViewModel { let managedObjectContext = context.backgroundManagedObjectContext managedObjectContext.performChanges { guard let hashtag = try? managedObjectContext.existingObject(with: objectID) as? Tag else { return } - if let searchHistory = hashtag.searchHistory { + if let searchHistory = hashtag.findSearchHistory(domain: box.domain, userID: box.userID) { searchHistory.update(updatedAt: Date()) } else { - SearchHistory.insert(into: managedObjectContext, property: property, hashtag: hashtag) + _ = SearchHistory.insert(into: managedObjectContext, property: property, hashtag: hashtag) } } .sink { result in - // do nothing + switch result { + case .failure(let error): + assertionFailure(error.localizedDescription) + case .success: + break + } } .store(in: &context.disposeBag) diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift index 181302a24..b22e91c8d 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift @@ -146,44 +146,57 @@ extension SearchResultViewModel { let domain = box.domain switch item { - case .account(let account): + case .account(let entity): let managedObjectContext = context.backgroundManagedObjectContext managedObjectContext.performChanges { let (user, _) = APIService.CoreData.createOrMergeMastodonUser( into: managedObjectContext, for: nil, in: domain, - entity: account, + entity: entity, userCache: nil, networkDate: Date(), log: OSLog.api ) - if let searchHistory = user.searchHistory { + if let searchHistory = user.findSearchHistory(domain: box.domain, userID: box.userID) { searchHistory.update(updatedAt: Date()) } else { SearchHistory.insert(into: managedObjectContext, property: property, account: user) } } .sink { result in - // do nothing + switch result { + case .failure(let error): + assertionFailure(error.localizedDescription) + case .success: + break + } } .store(in: &context.disposeBag) - case .hashtag(let hashtag): + case .hashtag(let entity): let managedObjectContext = context.backgroundManagedObjectContext + var tag: Tag? managedObjectContext.performChanges { let (hashtag, _) = APIService.CoreData.createOrMergeTag( into: managedObjectContext, - entity: hashtag + entity: entity ) - if let searchHistory = hashtag.searchHistory { + tag = hashtag + if let searchHistory = hashtag.findSearchHistory(domain: box.domain, userID: box.userID) { searchHistory.update(updatedAt: Date()) } else { - SearchHistory.insert(into: managedObjectContext, property: property, hashtag: hashtag) + _ = SearchHistory.insert(into: managedObjectContext, property: property, hashtag: hashtag) } } .sink { result in - // do nothing + switch result { + case .failure(let error): + assertionFailure(error.localizedDescription) + case .success: + print(tag?.searchHistories) + break + } } .store(in: &context.disposeBag) diff --git a/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift b/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift index d0106a334..a872fca43 100644 --- a/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift +++ b/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift @@ -104,6 +104,10 @@ extension SearchResultTableViewCell { separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), ]) resetSeparatorLineLayout() + + _titleLabel.isUserInteractionEnabled = false + _subTitleLabel.isUserInteractionEnabled = false + _imageView.isUserInteractionEnabled = false } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index 7804a70de..667752a83 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -545,7 +545,7 @@ extension SettingsViewController: ASWebAuthenticationPresentationContextProvidin // MARK: - UIAdaptivePresentationControllerDelegate extension SettingsViewController: UIAdaptivePresentationControllerDelegate { func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { - return .formSheet + return .pageSheet } } diff --git a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Status.swift b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Status.swift index 201e400d1..673cb4de3 100644 --- a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Status.swift +++ b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Status.swift @@ -86,15 +86,9 @@ extension APIService.CoreData { let object = Poll.insert(into: managedObjectContext, property: Poll.Property(id: poll.id, expiresAt: poll.expiresAt, expired: poll.expired, multiple: poll.multiple, votesCount: poll.votesCount, votersCount: poll.votersCount, networkDate: networkDate), votedBy: votedBy, options: options) return object } - let metions = entity.mentions?.enumerated().compactMap { index, mention -> Mention in + let mentions = entity.mentions?.enumerated().compactMap { index, mention -> Mention in Mention.insert(into: managedObjectContext, property: Mention.Property(id: mention.id, username: mention.username, acct: mention.acct, url: mention.url), index: index) } - let tags = entity.tags?.compactMap { tag -> Tag in - let histories = tag.history?.compactMap { history -> History in - History.insert(into: managedObjectContext, property: History.Property(day: history.day, uses: history.uses, accounts: history.accounts)) - } - return Tag.insert(into: managedObjectContext, property: Tag.Property(name: tag.name, url: tag.url, histories: histories)) - } let mediaAttachments: [Attachment]? = { let encoder = JSONEncoder() var attachments: [Attachment] = [] @@ -117,8 +111,7 @@ extension APIService.CoreData { application: application, replyTo: replyTo, poll: poll, - mentions: metions, - tags: tags, + mentions: mentions, mediaAttachments: mediaAttachments, favouritedBy: (entity.favourited ?? false) ? requestMastodonUser : nil, rebloggedBy: (entity.reblogged ?? false) ? requestMastodonUser : nil, diff --git a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Tag.swift b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Tag.swift index 9b4319572..bc5718bc0 100644 --- a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Tag.swift +++ b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Tag.swift @@ -15,7 +15,7 @@ extension APIService.CoreData { into managedObjectContext: NSManagedObjectContext, entity: Mastodon.Entity.Tag ) -> (Tag: Tag, isCreated: Bool) { - // fetch old mastodon user + // fetch old hashtag  let oldTag: Tag? = { let request = Tag.sortedFetchRequest request.predicate = Tag.predicate(name: entity.name) From 9d66119f9edbe6fc724f721c5b1a0250a37b26ba Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 27 Sep 2021 15:28:26 +0800 Subject: [PATCH 197/392] feat: make search bar works on iPad --- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../Search/Search/SearchViewController.swift | 26 +++- .../SearchDetailViewController.swift | 147 ++++++++++++------ 3 files changed, 124 insertions(+), 53 deletions(-) diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 44043f885..1fe981b44 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -69,8 +69,8 @@ "repositoryURL": "https://github.com/MainasuK/FPSIndicator.git", "state": { "branch": null, - "revision": "b2a002d689c400485f2ba41f9e71e15f7b99764a", - "version": "1.0.1" + "revision": "e4a5067ccd5293b024c767f09e51056afd4a4796", + "version": "1.1.0" } }, { diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index a3d84cd6a..1c073b4b9 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -11,6 +11,12 @@ import GameplayKit import MastodonSDK import UIKit +final class HeightFixedSearchBar: UISearchBar { + override var intrinsicContentSize: CGSize { + return CGSize(width: CGFloat.greatestFiniteMagnitude, height: 44) + } +} + final class SearchViewController: UIViewController, NeedsDependency { let logger = Logger(subsystem: "Search", category: "UI") @@ -41,6 +47,11 @@ final class SearchViewController: UIViewController, NeedsDependency { var disposeBag = Set() private(set) lazy var viewModel = SearchViewModel(context: context) + + // use AutoLayout could set search bar margin automatically to + // layout alongside with split mode button (on iPad) + let titleViewContainer = UIView() + let searchBar = HeightFixedSearchBar() // recommend let scrollView: UIScrollView = { @@ -112,6 +123,10 @@ extension SearchViewController { super.viewDidAppear(animated) viewModel.viewDidAppeared.send() + + // note: + // need set alpha because (maybe) SDK forget set alpha back + titleViewContainer.alpha = 1 } } @@ -121,10 +136,17 @@ extension SearchViewController { } private func setupSearchBar() { - let searchBar = UISearchBar() searchBar.placeholder = L10n.Scene.Search.SearchBar.placeholder searchBar.delegate = self - navigationItem.titleView = searchBar + 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), + ]) + navigationItem.titleView = titleViewContainer searchBarTapPublisher .throttle(for: 0.5, scheduler: DispatchQueue.main, latest: false) diff --git a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift index 1debc188c..b401e7955 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift @@ -10,6 +10,8 @@ import UIKit import Combine import Pageboy +// Fake search bar not works on iPad with UISplitViewController +// check device and fallback to standard UISearchController final class SearchDetailViewController: PageboyViewController, NeedsDependency { let logger = Logger(subsystem: "SearchDetail", category: "UI") @@ -19,6 +21,10 @@ final class SearchDetailViewController: PageboyViewController, NeedsDependency { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + let isPhoneDevice: Bool = { + return UIDevice.current.userInterfaceIdiom == .phone + }() var viewModel: SearchDetailViewModel! var viewControllers: [SearchResultViewController]! @@ -39,8 +45,22 @@ final class SearchDetailViewController: PageboyViewController, NeedsDependency { navigationBar.setItems([navigationItem], animated: false) return navigationBar }() - let searchBar: UISearchBar = { - let searchBar = UISearchBar() + + let searchController: UISearchController = { + let searchController = UISearchController() + searchController.automaticallyShowsScopeBar = false + searchController.dimsBackgroundDuringPresentation = false + return searchController + }() + private(set) lazy var searchBar: UISearchBar = { + let searchBar: UISearchBar + if isPhoneDevice { + searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 320, height: 44)) + } else { + searchBar = searchController.searchBar + searchController.automaticallyShowsScopeBar = false + searchController.searchBar.setShowsScope(true, animated: false) + } searchBar.placeholder = L10n.Scene.Search.SearchBar.placeholder searchBar.scopeButtonTitles = SearchDetailViewModel.SearchScope.allCases.map { $0.segmentedControlTitle } searchBar.sizeToFit() @@ -71,48 +91,27 @@ extension SearchDetailViewController { } .store(in: &disposeBag) - navigationBar.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(navigationBar) - NSLayoutConstraint.activate([ - navigationBar.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor), - navigationBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), - navigationBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), - ]) setupSearchBar() - navigationBar.layer.observe(\.bounds, options: [.new]) { [weak self] navigationBar, _ in - guard let self = self else { return } - self.viewModel.navigationBarFrame.value = navigationBar.frame - } - .store(in: &observations) - - navigationBarBackgroundView.translatesAutoresizingMaskIntoConstraints = false - view.insertSubview(navigationBarBackgroundView, belowSubview: navigationBar) - NSLayoutConstraint.activate([ - navigationBarBackgroundView.topAnchor.constraint(equalTo: view.topAnchor), - navigationBarBackgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - navigationBarBackgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - navigationBarBackgroundView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor), - ]) - - 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), - ]) - + addChild(searchHistoryViewController) searchHistoryViewController.view.translatesAutoresizingMaskIntoConstraints = false view.addSubview(searchHistoryViewController.view) searchHistoryViewController.didMove(toParent: self) - NSLayoutConstraint.activate([ - searchHistoryViewController.view.topAnchor.constraint(equalTo: navigationBarBackgroundView.bottomAnchor), - searchHistoryViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), - searchHistoryViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), - searchHistoryViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) + if isPhoneDevice { + NSLayoutConstraint.activate([ + searchHistoryViewController.view.topAnchor.constraint(equalTo: navigationBarBackgroundView.bottomAnchor), + searchHistoryViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + searchHistoryViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + 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), + ]) + } transition = Transition(style: .fade, duration: 0.1) isScrollEnabled = false @@ -215,33 +214,83 @@ extension SearchDetailViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - navigationController?.setNavigationBarHidden(true, animated: animated) - searchBar.setShowsScope(true, animated: false) - searchBar.setNeedsLayout() - searchBar.layoutIfNeeded() + if isPhoneDevice { + navigationController?.setNavigationBarHidden(true, animated: animated) + searchBar.setShowsScope(true, animated: false) + searchBar.setNeedsLayout() + searchBar.layoutIfNeeded() + } else { + // do nothing + } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - if !isModal { - // prevent bar restore conflict with modal style issue - navigationController?.setNavigationBarHidden(false, animated: animated) + if isPhoneDevice { + if !isModal { + // prevent bar restore conflict with modal style issue + navigationController?.setNavigationBarHidden(false, animated: animated) + } + } else { + // do nothing } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - searchBar.setShowsCancelButton(true, animated: animated) - searchBar.becomeFirstResponder() + if isPhoneDevice { + searchBar.setShowsCancelButton(true, animated: animated) + searchBar.becomeFirstResponder() + } else { + searchController.isActive = true + searchController.searchBar.becomeFirstResponder() + } } } extension SearchDetailViewController { private func setupSearchBar() { - navigationBar.topItem?.titleView = searchBar + if isPhoneDevice { + navigationBar.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(navigationBar) + NSLayoutConstraint.activate([ + navigationBar.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor), + navigationBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]) + navigationBar.topItem?.titleView = searchBar + navigationBar.layer.observe(\.bounds, options: [.new]) { [weak self] navigationBar, _ in + guard let self = self else { return } + self.viewModel.navigationBarFrame.value = navigationBar.frame + } + .store(in: &observations) + + navigationBarBackgroundView.translatesAutoresizingMaskIntoConstraints = false + view.insertSubview(navigationBarBackgroundView, belowSubview: navigationBar) + NSLayoutConstraint.activate([ + navigationBarBackgroundView.topAnchor.constraint(equalTo: view.topAnchor), + navigationBarBackgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationBarBackgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + navigationBarBackgroundView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor), + ]) + + 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), + ]) + } else { + navigationItem.setHidesBackButton(true, animated: false) + navigationItem.titleView = nil + navigationItem.searchController = searchController + searchController.searchBar.sizeToFit() + } searchBar.delegate = self } From eaa915f96c59983760e52d7e4430801aad1259a6 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 27 Sep 2021 16:30:36 +0800 Subject: [PATCH 198/392] feat: update scene modal style and update Settings scene tableView style --- Mastodon.xcodeproj/project.pbxproj | 4 ++ Mastodon/Coordinator/SceneCoordinator.swift | 2 +- .../MastodonServerRulesViewController.swift | 6 +++ .../Welcome/WelcomeViewController.swift | 13 +++++- .../Scene/Root/Sidebar/SidebarViewModel.swift | 30 +++++++++----- .../SidebarAddAccountCollectionViewCell.swift | 41 +++++++++++++++++++ .../Settings/SettingsViewController.swift | 10 ++++- 7 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 8de9739e0..1dbb546e0 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -572,6 +572,7 @@ DBE3CE13261D7D4200430CC6 /* StatusTableViewControllerAspect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE3CE12261D7D4200430CC6 /* StatusTableViewControllerAspect.swift */; }; DBE54AC62636C89F004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; }; DBE54ACC2636C8FD004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; }; + DBF156DF2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */; }; DBF1D24E269DAF5D00C1C08A /* SearchDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */; }; DBF1D251269DB01200C1C08A /* SearchHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */; }; DBF1D257269DBAC600C1C08A /* SearchDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */; }; @@ -1353,6 +1354,7 @@ DBE3CE12261D7D4200430CC6 /* StatusTableViewControllerAspect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewControllerAspect.swift; sourceTree = ""; }; DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPreference.swift; sourceTree = ""; }; DBF156DD27006F5D00EC00B7 /* CoreData 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreData 2.xcdatamodel"; sourceTree = ""; }; + DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarAddAccountCollectionViewCell.swift; sourceTree = ""; }; DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewController.swift; sourceTree = ""; }; DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryViewController.swift; sourceTree = ""; }; DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewModel.swift; sourceTree = ""; }; @@ -2090,6 +2092,7 @@ DB0EF72C26FDB1D600347686 /* View */ = { isa = PBXGroup; children = ( + DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */, DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */, DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */, ); @@ -3906,6 +3909,7 @@ DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */, DBB5250E2611EBAF002F1F29 /* ProfileSegmentedViewController.swift in Sources */, 2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */, + DBF156DF2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift in Sources */, DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */, DB938F0926240F3C00E5B6C1 /* RemoteThreadViewModel.swift in Sources */, DBBC24AE26A53DC100398BB9 /* ReplicaStatusView.swift in Sources */, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 4978c0a7e..216394c50 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -213,7 +213,7 @@ extension SceneCoordinator { case .custom(let transitioningDelegate): viewController.modalPresentationStyle = .custom viewController.transitioningDelegate = transitioningDelegate - sender?.present(viewController, animated: true, completion: nil) + (splitViewController ?? presentingViewController)?.present(viewController, animated: true, completion: nil) case .customPush: // set delegate in view controller diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift index c31e91304..b9a332d05 100644 --- a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift +++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift @@ -162,6 +162,12 @@ extension MastodonServerRulesViewController { confirmButton.addTarget(self, action: #selector(MastodonServerRulesViewController.confirmButtonPressed(_:)), for: .touchUpInside) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + scrollView.flashScrollIndicators() + } + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() updateScrollViewContentInset() diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index e424d350a..705ae6132 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -240,7 +240,16 @@ extension WelcomeViewController: OnboardingViewControllerAppearance { } // MARK: - UIAdaptivePresentationControllerDelegate extension WelcomeViewController: UIAdaptivePresentationControllerDelegate { func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { - // make underneath view controller alive to fix layout issue due to view life cycle - return .fullScreen + switch traitCollection.userInterfaceIdiom { + case .phone: + // make underneath view controller alive to fix layout issue due to view life cycle + return .fullScreen + default: + return .pageSheet + } + } + + func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { + return false } } diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index a6dd82cc8..d7ec5b717 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -21,7 +21,7 @@ final class SidebarViewModel { let searchHistoryFetchedResultController: SearchHistoryFetchedResultController // output - var diffableDataSource: UICollectionViewDiffableDataSource! + var diffableDataSource: UICollectionViewDiffableDataSource? let activeMastodonAuthenticationObjectID = CurrentValueSubject(nil) init(context: AppContext) { @@ -184,7 +184,12 @@ extension SidebarViewModel { let accountRegistration = UICollectionView.CellRegistration { [weak self] (cell, indexPath, item) in guard let self = self else { return } - let authentication = AppContext.shared.managedObjectContext.object(with: item.authenticationObjectID) as! MastodonAuthentication + // accounts maybe already sign-out + // check isDeleted before using + guard let authentication = try? AppContext.shared.managedObjectContext.existingObject(with: item.authenticationObjectID) as? MastodonAuthentication, + !authentication.isDeleted else { + return + } let user = authentication.user let imageURL = user.avatarImageURL() let headline: MetaContent = { @@ -226,15 +231,16 @@ extension SidebarViewModel { .store(in: &cell.disposeBag) } - let addAccountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in - var content = cell.defaultContentConfiguration() + let addAccountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in + var content = UIListContentConfiguration.sidebarCell() content.text = L10n.Scene.AccountList.addAccount content.image = UIImage(systemName: "plus.square.fill")! + cell.contentConfiguration = content cell.accessories = [] } - diffableDataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, item in + let _diffableDataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, item in switch item { case .tab(let tab): return collectionView.dequeueConfiguredReusableCell(using: tabCellRegistration, for: indexPath, item: tab) @@ -248,10 +254,11 @@ extension SidebarViewModel { return collectionView.dequeueConfiguredReusableCell(using: addAccountRegistration, for: indexPath, item: AddAccountViewModel()) } } + diffableDataSource = _diffableDataSource var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections(Section.allCases) - diffableDataSource.apply(snapshot) + _diffableDataSource.apply(snapshot) for section in Section.allCases { switch section { @@ -264,7 +271,7 @@ extension SidebarViewModel { .tab(.me), ] sectionSnapshot.append(items, to: nil) - diffableDataSource.apply(sectionSnapshot, to: section) + _diffableDataSource.apply(sectionSnapshot, to: section) case .account: var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() let headerItem = Item.header(HeaderViewModel(title: "Accounts")) @@ -272,7 +279,7 @@ extension SidebarViewModel { sectionSnapshot.append([], to: headerItem) sectionSnapshot.append([.addAccount], to: headerItem) sectionSnapshot.expand([headerItem]) - diffableDataSource.apply(sectionSnapshot, to: section) + _diffableDataSource.apply(sectionSnapshot, to: section) } } @@ -312,10 +319,11 @@ extension SidebarViewModel { .receive(on: DispatchQueue.main) .sink { [weak self] authentications in guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } // tab - var snapshot = self.diffableDataSource.snapshot() + var snapshot = diffableDataSource.snapshot() snapshot.reloadItems([.tab(.me)]) - self.diffableDataSource.apply(snapshot) + diffableDataSource.apply(snapshot) // account var accountSectionSnapshot = NSDiffableDataSourceSectionSnapshot() @@ -327,7 +335,7 @@ extension SidebarViewModel { accountSectionSnapshot.append(accountItems, to: headerItem) accountSectionSnapshot.append([.addAccount], to: headerItem) accountSectionSnapshot.expand([headerItem]) - self.diffableDataSource.apply(accountSectionSnapshot, to: .account) + diffableDataSource.apply(accountSectionSnapshot, to: .account) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift new file mode 100644 index 000000000..a4bd5833e --- /dev/null +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift @@ -0,0 +1,41 @@ +// +// SidebarAddAccountCollectionViewCell.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-27. +// + +import UIKit + +final class SidebarAddAccountCollectionViewCell: UICollectionViewListCell { + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension SidebarAddAccountCollectionViewCell { + + private func _init() { } + + override func updateConfiguration(using state: UICellConfigurationState) { + var newBackgroundConfiguration = UIBackgroundConfiguration.listSidebarCell().updated(for: state) + + // Customize the background color to use the tint color when the cell is highlighted or selected. + if state.isSelected || state.isHighlighted { + newBackgroundConfiguration.backgroundColor = Asset.Colors.brandBlue.color + } + if state.isHighlighted { + newBackgroundConfiguration.backgroundColorTransformer = .init { $0.withAlphaComponent(0.8) } + } + + backgroundConfiguration = newBackgroundConfiguration + } +} diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index 667752a83..c4658d7da 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -98,7 +98,15 @@ class SettingsViewController: UIViewController, NeedsDependency { private(set) lazy var tableView: UITableView = { // init with a frame to fix a conflict ('UIView-Encapsulated-Layout-Width' UIStackView:0x7f8c2b6c0590.width == 0) - let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 320, height: 320), style: .grouped) + let style: UITableView.Style = { + switch UIDevice.current.userInterfaceIdiom { + case .phone: + return .grouped + default: + return .insetGrouped + } + }() + let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 320, height: 320), style: style) tableView.translatesAutoresizingMaskIntoConstraints = false tableView.delegate = self tableView.rowHeight = UITableView.automaticDimension From cc36d473c51be9bd67187562e8066e9991a07bd0 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 27 Sep 2021 16:31:36 +0800 Subject: [PATCH 199/392] chore: update build version to 1.2.0 (67) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- .../xcshareddata/swiftpm/Package.resolved | 9 --- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 12 files changed, 45 insertions(+), 54 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 6329631ff..14b9687af 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 6329631ff..14b9687af 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 6329631ff..14b9687af 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 1dbb546e0..a70076a37 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4746,7 +4746,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4774,7 +4774,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4881,11 +4881,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4912,11 +4912,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4941,11 +4941,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4971,11 +4971,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5038,7 +5038,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5063,7 +5063,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5088,7 +5088,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5113,7 +5113,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5138,7 +5138,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5163,7 +5163,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5188,7 +5188,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5213,7 +5213,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5304,7 +5304,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5370,11 +5370,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5419,7 +5419,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5444,11 +5444,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5540,7 +5540,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5606,11 +5606,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5655,7 +5655,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5680,11 +5680,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 66; + DYLIB_CURRENT_VERSION = 67; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5710,7 +5710,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5734,7 +5734,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 07d0f6d73..b0f597fa2 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 38 + 44 CoreDataStack.xcscheme_^#shared#^_ orderHint - 35 + 42 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 37 + 41 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 36 + 43 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1fe981b44..2c878ce14 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -216,15 +216,6 @@ "revision": "dad97167bf1be16aeecd109130900995dd01c515", "version": "2.6.0" } - }, - { - "package": "UITextView+Placeholder", - "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder", - "state": { - "branch": null, - "revision": "20f513ded04a040cdf5467f0891849b1763ede3b", - "version": "1.4.1" - } } ] }, diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 0da19b3ba..277d8f778 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 66 + 67 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 62580d104..f98786dcb 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 6329631ff..14b9687af 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 6329631ff..14b9687af 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 846239c27..13a855a93 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index beffb8405..967d3602f 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 66 + 67 NSExtension NSExtensionAttributes From 5272f3de678c67d00e5d2210527726b6a808cfea Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 27 Sep 2021 17:58:52 +0800 Subject: [PATCH 200/392] fix: iOS 15 new section padding issue --- .../MastodonPickServerViewController.swift | 21 +++++++++++++++++-- .../SidebarAddAccountCollectionViewCell.swift | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index 604e23825..3da704f0b 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -44,6 +44,11 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency tableView.backgroundColor = .clear tableView.keyboardDismissMode = .onDrag tableView.translatesAutoresizingMaskIntoConstraints = false + if #available(iOS 15.0, *) { + tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude + } else { + // Fallback on earlier versions + } return tableView }() @@ -428,7 +433,9 @@ extension MastodonPickServerViewController: UITableViewDelegate { } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - guard let diffableDataSource = viewModel.diffableDataSource else { return 0 } + guard let diffableDataSource = viewModel.diffableDataSource else { + return .leastNonzeroMagnitude + } let sections = diffableDataSource.snapshot().sectionIdentifiers let section = sections[section] switch section { @@ -442,10 +449,20 @@ extension MastodonPickServerViewController: UITableViewDelegate { // Same reason as above return 10 case .servers: - return 0 + return .leastNonzeroMagnitude } } + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + let footerView = UIView() + footerView.backgroundColor = .yellow + return footerView + } + + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + return .leastNonzeroMagnitude + } + func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { guard let diffableDataSource = viewModel.diffableDataSource else { return nil } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift index a4bd5833e..72b2577f1 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarAddAccountCollectionViewCell.swift @@ -26,6 +26,8 @@ extension SidebarAddAccountCollectionViewCell { private func _init() { } override func updateConfiguration(using state: UICellConfigurationState) { + super.updateConfiguration(using: state) + var newBackgroundConfiguration = UIBackgroundConfiguration.listSidebarCell().updated(for: state) // Customize the background color to use the tint color when the cell is highlighted or selected. From 25d6515c98f1b134186ee263cec361c1a674e20d Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 27 Sep 2021 18:00:53 +0800 Subject: [PATCH 201/392] chore: update version to 1.2.0 (68) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 14b9687af..2c4e9e7a7 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 14b9687af..2c4e9e7a7 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 14b9687af..2c4e9e7a7 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a70076a37..ab4afaa66 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4746,7 +4746,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4774,7 +4774,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4881,11 +4881,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4912,11 +4912,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4941,11 +4941,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4971,11 +4971,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5038,7 +5038,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5063,7 +5063,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5088,7 +5088,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5113,7 +5113,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5138,7 +5138,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5163,7 +5163,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5188,7 +5188,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5213,7 +5213,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5304,7 +5304,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5370,11 +5370,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5419,7 +5419,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5444,11 +5444,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5540,7 +5540,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5606,11 +5606,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5655,7 +5655,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5680,11 +5680,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 67; + DYLIB_CURRENT_VERSION = 68; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5710,7 +5710,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5734,7 +5734,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 67; + CURRENT_PROJECT_VERSION = 68; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b0f597fa2..91eb04e32 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 44 + 47 CoreDataStack.xcscheme_^#shared#^_ orderHint - 42 + 44 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 41 + 46 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 43 + 45 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 277d8f778..ed361f36e 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 67 + 68 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index f98786dcb..fc0b410bb 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 14b9687af..2c4e9e7a7 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 14b9687af..2c4e9e7a7 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 13a855a93..47b86c665 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 967d3602f..0e16ba8ce 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 67 + 68 NSExtension NSExtensionAttributes From 3bc1a3de39fc521bf87458c6434bd460121092f5 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 28 Sep 2021 19:58:14 +0800 Subject: [PATCH 202/392] feat: add scroll position record and shortcut bar --- Mastodon.xcodeproj/project.pbxproj | 16 ++- .../Scene/Compose/ComposeViewController.swift | 32 +++++- .../Compose/View/ComposeToolbarView.swift | 35 ++++++ .../HomeTimelineViewController.swift | 105 +++++++++++++++++- .../HomeTimeline/HomeTimelineViewModel.swift | 11 ++ Mastodon/Supporting Files/SceneDelegate.swift | 16 --- Mastodon/Vender/HandleTapAction.swift | 16 +++ Mastodon/Vender/Mastodon-Bridging-Header.h | 4 + .../UIStatusBarManager+HandleTapAction.m | 38 +++++++ 9 files changed, 245 insertions(+), 28 deletions(-) create mode 100644 Mastodon/Vender/HandleTapAction.swift create mode 100644 Mastodon/Vender/Mastodon-Bridging-Header.h create mode 100644 Mastodon/Vender/UIStatusBarManager+HandleTapAction.m diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index ab4afaa66..50d73c112 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -573,6 +573,8 @@ DBE54AC62636C89F004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; }; DBE54ACC2636C8FD004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; }; DBF156DF2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */; }; + DBF156E22702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m in Sources */ = {isa = PBXBuildFile; fileRef = DBF156E12702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m */; }; + DBF156E42702DB3F00EC00B7 /* HandleTapAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF156E32702DB3F00EC00B7 /* HandleTapAction.swift */; }; DBF1D24E269DAF5D00C1C08A /* SearchDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */; }; DBF1D251269DB01200C1C08A /* SearchHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */; }; DBF1D257269DBAC600C1C08A /* SearchDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */; }; @@ -1355,6 +1357,9 @@ DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPreference.swift; sourceTree = ""; }; DBF156DD27006F5D00EC00B7 /* CoreData 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreData 2.xcdatamodel"; sourceTree = ""; }; DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarAddAccountCollectionViewCell.swift; sourceTree = ""; }; + DBF156E02702DA6800EC00B7 /* Mastodon-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Mastodon-Bridging-Header.h"; sourceTree = ""; }; + DBF156E12702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIStatusBarManager+HandleTapAction.m"; sourceTree = ""; }; + DBF156E32702DB3F00EC00B7 /* HandleTapAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleTapAction.swift; sourceTree = ""; }; DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewController.swift; sourceTree = ""; }; DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryViewController.swift; sourceTree = ""; }; DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewModel.swift; sourceTree = ""; }; @@ -1737,6 +1742,9 @@ DB6180EC26391C6C0018D199 /* TransitioningMath.swift */, DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */, DBAC649A267DF8C8007FE9FD /* ActivityIndicatorNode.swift */, + DBF156E32702DB3F00EC00B7 /* HandleTapAction.swift */, + DBF156E12702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m */, + DBF156E02702DA6800EC00B7 /* Mastodon-Bridging-Header.h */, ); path = Vender; sourceTree = ""; @@ -3437,7 +3445,7 @@ TargetAttributes = { DB427DD125BAA00100D1B89D = { CreatedOnToolsVersion = 12.4; - LastSwiftMigration = 1220; + LastSwiftMigration = 1300; }; DB427DE725BAA00100D1B89D = { CreatedOnToolsVersion = 12.4; @@ -4067,6 +4075,7 @@ DB3667A1268ABB2E0027D07F /* ComposeStatusAttachmentItem.swift in Sources */, DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */, DBA94434265CBB5300C537E1 /* ProfileFieldSection.swift in Sources */, + DBF156E42702DB3F00EC00B7 /* HandleTapAction.swift in Sources */, DB023295267F0AB800031745 /* ASMetaEditableTextNode.swift in Sources */, 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, DB4F096C269EFA2000D62E92 /* SearchResultViewController+StatusProvider.swift in Sources */, @@ -4114,6 +4123,7 @@ 2DAC9E46262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift in Sources */, DB4FFC2C269EC39600D62E92 /* SearchTransitionController.swift in Sources */, DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */, + DBF156E22702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m in Sources */, DB45FADD25CA6F6B005A8AC7 /* APIService+CoreData+MastodonUser.swift in Sources */, 2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */, 2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */, @@ -4758,6 +4768,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -4786,6 +4797,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -5316,6 +5328,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -5552,6 +5565,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index 9be0e4f7d..460d12cac 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -18,7 +18,7 @@ import MastodonUI final class ComposeViewController: UIViewController, NeedsDependency { static let minAutoCompleteVisibleHeight: CGFloat = 100 - + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -137,6 +137,16 @@ extension ComposeViewController { override func viewDidLoad() { super.viewDidLoad() + let groups = [UIBarButtonItemGroup(barButtonItems: [ + composeToolbarView.mediaBarButtonItem, + composeToolbarView.pollBarButtonItem, + composeToolbarView.contentWarningBarButtonItem, + composeToolbarView.visibilityBarButtonItem, + ], representativeItem: nil)] + + tableView.inputAssistantItem.trailingBarButtonGroups = groups + textEditorView()?.textView.inputAssistantItem.trailingBarButtonGroups = groups + viewModel.title .receive(on: DispatchQueue.main) .sink { [weak self] title in @@ -330,13 +340,21 @@ extension ComposeViewController { // bind media button toolbar state viewModel.isMediaToolbarButtonEnabled .receive(on: DispatchQueue.main) - .assign(to: \.isEnabled, on: composeToolbarView.mediaButton) + .sink { [weak self] isMediaToolbarButtonEnabled in + guard let self = self else { return } +// self.composeToolbarView.mediaBarButtonItem.isEnabled = isMediaToolbarButtonEnabled + self.composeToolbarView.mediaButton.isEnabled = isMediaToolbarButtonEnabled + } .store(in: &disposeBag) // bind poll button toolbar state viewModel.isPollToolbarButtonEnabled .receive(on: DispatchQueue.main) - .assign(to: \.isEnabled, on: composeToolbarView.pollButton) + .sink { [weak self] isPollToolbarButtonEnabled in + guard let self = self else { return } +// self.composeToolbarView.pollBarButtonItem.isEnabled = isPollToolbarButtonEnabled + self.composeToolbarView.pollButton.isEnabled = isPollToolbarButtonEnabled + } .store(in: &disposeBag) Publishers.CombineLatest( @@ -347,10 +365,14 @@ extension ComposeViewController { .sink { [weak self] isPollComposing, isPollToolbarButtonEnabled in guard let self = self else { return } guard isPollToolbarButtonEnabled else { - self.composeToolbarView.pollButton.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendPoll + let accessibilityLabel = L10n.Scene.Compose.Accessibility.appendPoll +// self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.pollButton.accessibilityLabel = accessibilityLabel return } - self.composeToolbarView.pollButton.accessibilityLabel = isPollComposing ? L10n.Scene.Compose.Accessibility.removePoll : L10n.Scene.Compose.Accessibility.appendPoll + let accessibilityLabel = isPollComposing ? L10n.Scene.Compose.Accessibility.removePoll : L10n.Scene.Compose.Accessibility.appendPoll +// self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.pollButton.accessibilityLabel = accessibilityLabel } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift index 99fe88ce7..a8ceeee3a 100644 --- a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift +++ b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift @@ -27,6 +27,41 @@ final class ComposeToolbarView: UIView { weak var delegate: ComposeToolbarViewDelegate? + // barButtonItem + let mediaBarButton: UIButton = { + let button = UIButton() + button.setImage(UIImage(systemName: "photo"), for: .normal) + return button + }() + private(set) lazy var mediaBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem(customView: mediaBarButton) + barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendAttachment + return barButtonItem + }() + + let pollBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.image = UIImage(systemName: "list.bullet") + barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendPoll + return barButtonItem + }() + + let contentWarningBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.image = UIImage(systemName: "exclamationmark.shield") + barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.enableContentWarning + return barButtonItem + }() + + let visibilityBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.image = UIImage(systemName: "person.3") + barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.postVisibilityMenu + return barButtonItem + }() + + // button + let mediaButton: UIButton = { let button = HighlightDimmableButton() ComposeToolbarView.configureToolbarButtonAppearance(button: button) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index e815ba8c4..b496c76b1 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -17,6 +17,8 @@ import AlamofireImage final class HomeTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + let logger = Logger(subsystem: "HomeTimelineViewController", category: "UI") + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -218,6 +220,31 @@ extension HomeTimelineViewController { } } .store(in: &disposeBag) + + NotificationCenter.default + .publisher(for: .statusBarTapped, object: nil) + .throttle(for: 0.5, scheduler: DispatchQueue.main, latest: false) + .sink { [weak self] notification in + guard let self = self else { return } + guard let _ = self.view.window else { return } // displaying + + // https://developer.limneos.net/index.php?ios=13.1.3&framework=UIKitCore.framework&header=UIStatusBarTapAction.h + guard let action = notification.object as AnyObject?, + let xPosition = action.value(forKey: "xPosition") as? Double + else { return } + + let viewFrameInWindow = self.view.convert(self.view.frame, to: nil) + guard xPosition >= viewFrameInWindow.minX && xPosition <= viewFrameInWindow.maxX else { return } + + // works on iOS 14 + self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): receive notification \(xPosition)") + + // check if scroll to top + guard self.shouldRestoreScrollPosition() else { return } + self.restorePositionWhenScrollToTop() + } + .store(in: &disposeBag) + } override func viewWillAppear(_ animated: Bool) { @@ -234,9 +261,15 @@ extension HomeTimelineViewController { viewModel.viewDidAppear.send() - DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in - guard let self = self else { return } - // always try to refresh timeline after appear + if let timestamp = viewModel.lastAutomaticFetchTimestamp.value { + let now = Date() + if now.timeIntervalSince(timestamp) > 60 { + self.viewModel.lastAutomaticFetchTimestamp.value = now + self.viewModel.homeTimelineNeedRefresh.send() + } else { + // do nothing + } + } else { self.viewModel.homeTimelineNeedRefresh.send() } } @@ -394,9 +427,62 @@ extension HomeTimelineViewController: TableViewCellHeightCacheableContainer { // MARK: - UIScrollViewDelegate extension HomeTimelineViewController { func scrollViewDidScroll(_ scrollView: UIScrollView) { + switch scrollView { + case tableView: + aspectScrollViewDidScroll(scrollView) + viewModel.homeTimelineNavigationBarTitleViewModel.handleScrollViewDidScroll(scrollView) + default: + break + } + } + + func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { + switch scrollView { + case tableView: + // handle scrollToTop + savePositionBeforeScrollToTop() + return true + default: + assertionFailure() + return true + } + } + + private func savePositionBeforeScrollToTop() { + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard let anchorIndexPaths = tableView.indexPathsForVisibleRows?.sorted() else { return } + guard !anchorIndexPaths.isEmpty else { return } + let anchorIndexPath = anchorIndexPaths[anchorIndexPaths.count / 2] + guard let anchorItem = diffableDataSource.itemIdentifier(for: anchorIndexPath) else { return } - aspectScrollViewDidScroll(scrollView) - viewModel.homeTimelineNavigationBarTitleViewModel.handleScrollViewDidScroll(scrollView) + let offset: CGFloat = { + guard let anchorCell = tableView.cellForRow(at: anchorIndexPath) else { return 0 } + let cellFrameInView = tableView.convert(anchorCell.frame, to: view) + return cellFrameInView.origin.y + }() + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): save position record for \(anchorIndexPath) with offset: \(offset)") + viewModel.scrollPositionRecord.value = HomeTimelineViewModel.ScrollPositionRecord( + item: anchorItem, + offset: offset, + timestamp: Date() + ) + } + + private func shouldRestoreScrollPosition() -> Bool { + // check if scroll to top + guard self.tableView.safeAreaInsets.top > 0 else { return false } + let zeroOffset = -self.tableView.safeAreaInsets.top + return abs(self.tableView.contentOffset.y - zeroOffset) < 2.0 + } + + private func restorePositionWhenScrollToTop() { + guard let diffableDataSource = self.viewModel.diffableDataSource else { return } + guard let record = self.viewModel.scrollPositionRecord.value, + let indexPath = diffableDataSource.indexPath(for: record.item) + else { return } + + self.tableView.scrollToRow(at: indexPath, at: .middle, animated: true) + self.viewModel.scrollPositionRecord.value = nil } } @@ -544,6 +630,8 @@ extension HomeTimelineViewController: ScrollViewContainer { } else { let indexPath = IndexPath(row: 0, section: 0) guard viewModel.diffableDataSource?.itemIdentifier(for: indexPath) != nil else { return } + // save position + savePositionBeforeScrollToTop() tableView.scrollToRow(at: indexPath, at: .top, animated: true) } } @@ -572,7 +660,12 @@ extension HomeTimelineViewController: StatusTableViewCellDelegate { // MARK: - HomeTimelineNavigationBarTitleViewDelegate extension HomeTimelineViewController: HomeTimelineNavigationBarTitleViewDelegate { func homeTimelineNavigationBarTitleView(_ titleView: HomeTimelineNavigationBarTitleView, logoButtonDidPressed sender: UIButton) { - scrollToTop(animated: true) + if shouldRestoreScrollPosition() { + restorePositionWhenScrollToTop() + } else { + savePositionBeforeScrollToTop() + scrollToTop(animated: true) + } } func homeTimelineNavigationBarTitleView(_ titleView: HomeTimelineNavigationBarTitleView, buttonDidPressed sender: UIButton) { diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index cf0b69b9d..a3fbcbd74 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -28,6 +28,8 @@ final class HomeTimelineViewModel: NSObject { let isFetchingLatestTimeline = CurrentValueSubject(false) let viewDidAppear = PassthroughSubject() let homeTimelineNavigationBarTitleViewModel: HomeTimelineNavigationBarTitleViewModel + let lastAutomaticFetchTimestamp = CurrentValueSubject(nil) + let scrollPositionRecord = CurrentValueSubject(nil) weak var contentOffsetAdjustableTimelineViewControllerDelegate: ContentOffsetAdjustableTimelineViewControllerDelegate? weak var tableView: UITableView? @@ -153,3 +155,12 @@ final class HomeTimelineViewModel: NSObject { } extension HomeTimelineViewModel: SuggestionAccountViewModelDelegate { } + + +extension HomeTimelineViewModel { + struct ScrollPositionRecord { + let item: Item + let offset: CGFloat + let timestamp: Date + } +} diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift index f5cc269b0..6c5752c4c 100644 --- a/Mastodon/Supporting Files/SceneDelegate.swift +++ b/Mastodon/Supporting Files/SceneDelegate.swift @@ -155,19 +155,3 @@ extension SceneDelegate { return true } } - -#if DEBUG -class TestWindow: UIWindow { - - override func sendEvent(_ event: UIEvent) { - event.allTouches?.forEach({ (touch) in - let location = touch.location(in: self) - let view = hitTest(location, with: event) - print(view.debugDescription) - }) - - super.sendEvent(event) - } -} -#endif - diff --git a/Mastodon/Vender/HandleTapAction.swift b/Mastodon/Vender/HandleTapAction.swift new file mode 100644 index 000000000..2ebdd9201 --- /dev/null +++ b/Mastodon/Vender/HandleTapAction.swift @@ -0,0 +1,16 @@ +// +// HandleTapAction.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-28. +// + +import Foundation + +@objc class HandleTapAction: NSObject { + @objc static let statusBarTappedNotification = Notification(name: .statusBarTapped) +} + +extension Notification.Name { + static let statusBarTapped = Notification.Name(rawValue: "org.joinmastodon.app.statusBarTapped") +} diff --git a/Mastodon/Vender/Mastodon-Bridging-Header.h b/Mastodon/Vender/Mastodon-Bridging-Header.h new file mode 100644 index 000000000..1b2cb5d6d --- /dev/null +++ b/Mastodon/Vender/Mastodon-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/Mastodon/Vender/UIStatusBarManager+HandleTapAction.m b/Mastodon/Vender/UIStatusBarManager+HandleTapAction.m new file mode 100644 index 000000000..3fbb76227 --- /dev/null +++ b/Mastodon/Vender/UIStatusBarManager+HandleTapAction.m @@ -0,0 +1,38 @@ +#import +#import +#import +#import + +@implementation UIStatusBarManager (CAPHandleTapAction) + ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class class = [self class]; + SEL originalSelector = NSSelectorFromString(@"handleTapAction:"); + SEL swizzledSelector = @selector(custom_handleTapAction:); + + Method originalMethod = class_getInstanceMethod(self, originalSelector); + Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector); + + BOOL didAddMethod = class_addMethod(class, + originalSelector, + method_getImplementation(swizzledMethod), + method_getTypeEncoding(swizzledMethod)); + if (didAddMethod) { + class_replaceMethod(class, + swizzledSelector, + method_getImplementation(originalMethod), + method_getTypeEncoding(originalMethod)); + } else { + method_exchangeImplementations(originalMethod, swizzledMethod); + } + }); +} + +-(void)custom_handleTapAction:(id)sender { + [[NSNotificationCenter defaultCenter] postNotificationName:@"org.joinmastodon.app.statusBarTapped" object:sender]; + [self custom_handleTapAction:sender]; +} + +@end From 4af5023c4cfa1fb390d5a02872eb043a81af7ab2 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 28 Sep 2021 19:58:53 +0800 Subject: [PATCH 203/392] chore: update version to 1.2.0 (69) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 2c4e9e7a7..f4fc24abb 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 2c4e9e7a7..f4fc24abb 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 2c4e9e7a7..f4fc24abb 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 50d73c112..13755e8b8 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4756,7 +4756,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4785,7 +4785,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4893,11 +4893,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4924,11 +4924,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4953,11 +4953,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4983,11 +4983,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5050,7 +5050,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5075,7 +5075,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5100,7 +5100,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5125,7 +5125,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5150,7 +5150,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5175,7 +5175,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5200,7 +5200,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5225,7 +5225,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5316,7 +5316,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5383,11 +5383,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5432,7 +5432,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5457,11 +5457,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5553,7 +5553,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5620,11 +5620,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5669,7 +5669,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5694,11 +5694,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 68; + DYLIB_CURRENT_VERSION = 69; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5724,7 +5724,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5748,7 +5748,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 68; + CURRENT_PROJECT_VERSION = 69; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 91eb04e32..62ed7d88b 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 47 + 44 CoreDataStack.xcscheme_^#shared#^_ orderHint - 44 + 50 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 46 + 48 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 45 + 49 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index ed361f36e..b61ed27b0 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 68 + 69 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index fc0b410bb..077c5a1f3 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 2c4e9e7a7..f4fc24abb 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 2c4e9e7a7..f4fc24abb 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 47b86c665..e82983eb4 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 0e16ba8ce..d8bdbae5a 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 68 + 69 NSExtension NSExtensionAttributes From 14cefe2d0d6fb742215a4a50831b5917eaea1587 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 29 Sep 2021 16:27:35 +0800 Subject: [PATCH 204/392] feat: update iPad UI for compose scene --- .../ComposeStatusContentTableViewCell.swift | 11 +- .../Scene/Compose/ComposeViewController.swift | 187 ++++++++++++++---- .../Compose/ComposeViewModel+DataSource.swift | 34 +++- ...ComposeStatusAttachmentTableViewCell.swift | 2 + .../ComposeStatusPollTableViewCell.swift | 3 + .../Compose/View/ComposeToolbarView.swift | 36 ++-- 6 files changed, 214 insertions(+), 59 deletions(-) diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift index 885840110..f44d29a68 100644 --- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift +++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift @@ -11,12 +11,17 @@ import Combine import MetaTextKit import UITextView_Placeholder +protocol ComposeStatusContentTableViewCellDelegate: AnyObject { + func composeStatusContentTableViewCell(_ cell: ComposeStatusContentTableViewCell, textViewShouldBeginEditing textView: UITextView) -> Bool +} + final class ComposeStatusContentTableViewCell: UITableViewCell { let logger = Logger(subsystem: "ComposeStatusContentTableViewCell", category: "UI") var disposeBag = Set() - + weak var delegate: ComposeStatusContentTableViewCellDelegate? + let statusView = ReplicaStatusView() let statusContentWarningEditorView = StatusContentWarningEditorView() @@ -136,6 +141,10 @@ extension ComposeStatusContentTableViewCell { // MARK: - UITextViewDelegate extension ComposeStatusContentTableViewCell: UITextViewDelegate { + + func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { + return delegate?.composeStatusContentTableViewCell(self, textViewShouldBeginEditing: textView) ?? true + } func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { switch textView { diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index 460d12cac..3f8327909 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -26,9 +26,20 @@ final class ComposeViewController: UIViewController, NeedsDependency { var viewModel: ComposeViewModel! let logger = Logger(subsystem: "ComposeViewController", category: "logic") - - private var suffixedAttachmentViews: [UIView] = [] + private(set) lazy var cancelBarButtonItem = UIBarButtonItem(title: L10n.Common.Controls.Actions.cancel, style: .plain, target: self, action: #selector(ComposeViewController.cancelBarButtonItemPressed(_:))) + let characterCountLabel: UILabel = { + let label = UILabel() + label.font = .systemFont(ofSize: 15, weight: .regular) + label.text = "500" + label.textColor = Asset.Colors.Label.secondary.color + label.accessibilityLabel = L10n.A11y.Plural.Count.inputLimitRemains(500) + return label + }() + private(set) lazy var characterCountBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem(customView: characterCountLabel) + return barButtonItem + }() let publishButton: UIButton = { let button = RoundedEdgesButton(type: .custom) button.setTitle(L10n.Scene.Compose.composeAction, for: .normal) @@ -41,8 +52,6 @@ final class ComposeViewController: UIViewController, NeedsDependency { button.adjustsImageWhenHighlighted = false return button }() - - private(set) lazy var cancelBarButtonItem = UIBarButtonItem(title: L10n.Common.Controls.Actions.cancel, style: .plain, target: self, action: #selector(ComposeViewController.cancelBarButtonItemPressed(_:))) private(set) lazy var publishBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem(customView: publishButton) return barButtonItem @@ -136,17 +145,16 @@ extension ComposeViewController { override func viewDidLoad() { super.viewDidLoad() - - let groups = [UIBarButtonItemGroup(barButtonItems: [ - composeToolbarView.mediaBarButtonItem, - composeToolbarView.pollBarButtonItem, - composeToolbarView.contentWarningBarButtonItem, - composeToolbarView.visibilityBarButtonItem, - ], representativeItem: nil)] - - tableView.inputAssistantItem.trailingBarButtonGroups = groups - textEditorView()?.textView.inputAssistantItem.trailingBarButtonGroups = groups + configureNavigationBarTitleStyle() + viewModel.traitCollectionDidChangePublisher + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.configureNavigationBarTitleStyle() + } + .store(in: &disposeBag) + viewModel.title .receive(on: DispatchQueue.main) .sink { [weak self] title in @@ -164,6 +172,18 @@ extension ComposeViewController { .store(in: &disposeBag) navigationItem.leftBarButtonItem = cancelBarButtonItem navigationItem.rightBarButtonItem = publishBarButtonItem + viewModel.traitCollectionDidChangePublisher + .receive(on: DispatchQueue.main) + .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) + } + self.navigationItem.rightBarButtonItems = items + } + .store(in: &disposeBag) publishButton.addTarget(self, action: #selector(ComposeViewController.publishBarButtonItemPressed(_:)), for: .touchUpInside) @@ -229,8 +249,12 @@ extension ComposeViewController { dependency: self ) + viewModel.composeStatusContentTableViewCell.delegate = self + // update layout when keyboard show/dismiss view.layoutIfNeeded() + + let keyboardHasShortcutBar = CurrentValueSubject(traitCollection.userInterfaceIdiom == .pad) // update default value later let keyboardEventPublishers = Publishers.CombineLatest3( KeyboardResponderService.shared.isShow, KeyboardResponderService.shared.state, @@ -243,8 +267,16 @@ extension ComposeViewController { ) .sink(receiveValue: { [weak self] keyboardEvents, isCustomEmojiComposing, autoCompleteInfo in guard let self = self else { return } - + let (isShow, state, endFrame) = keyboardEvents + + switch self.traitCollection.userInterfaceIdiom { + case .pad: + keyboardHasShortcutBar.value = state != .floating + default: + keyboardHasShortcutBar.value = false + } + let extraMargin: CGFloat = { var margin = self.composeToolbarView.frame.height if autoCompleteInfo != nil { @@ -342,7 +374,7 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isMediaToolbarButtonEnabled in guard let self = self else { return } -// self.composeToolbarView.mediaBarButtonItem.isEnabled = isMediaToolbarButtonEnabled + self.composeToolbarView.mediaBarButtonItem.isEnabled = isMediaToolbarButtonEnabled self.composeToolbarView.mediaButton.isEnabled = isMediaToolbarButtonEnabled } .store(in: &disposeBag) @@ -352,7 +384,7 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isPollToolbarButtonEnabled in guard let self = self else { return } -// self.composeToolbarView.pollBarButtonItem.isEnabled = isPollToolbarButtonEnabled + self.composeToolbarView.pollBarButtonItem.isEnabled = isPollToolbarButtonEnabled self.composeToolbarView.pollButton.isEnabled = isPollToolbarButtonEnabled } .store(in: &disposeBag) @@ -366,12 +398,12 @@ extension ComposeViewController { guard let self = self else { return } guard isPollToolbarButtonEnabled else { let accessibilityLabel = L10n.Scene.Compose.Accessibility.appendPoll -// self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel self.composeToolbarView.pollButton.accessibilityLabel = accessibilityLabel return } let accessibilityLabel = isPollComposing ? L10n.Scene.Compose.Accessibility.removePoll : L10n.Scene.Compose.Accessibility.appendPoll -// self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel self.composeToolbarView.pollButton.accessibilityLabel = accessibilityLabel } .store(in: &disposeBag) @@ -381,7 +413,9 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] attachmentServices in guard let self = self else { return } - self.composeToolbarView.mediaButton.isEnabled = attachmentServices.count < 4 + let isEnabled = attachmentServices.count < 4 + self.composeToolbarView.mediaBarButtonItem.isEnabled = isEnabled + self.composeToolbarView.mediaButton.isEnabled = isEnabled self.resetImagePicker() } .store(in: &disposeBag) @@ -391,7 +425,9 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isContentWarningComposing in guard let self = self else { return } - self.composeToolbarView.contentWarningButton.accessibilityLabel = isContentWarningComposing ? L10n.Scene.Compose.Accessibility.disableContentWarning : L10n.Scene.Compose.Accessibility.enableContentWarning + let accessibilityLabel = isContentWarningComposing ? L10n.Scene.Compose.Accessibility.disableContentWarning : L10n.Scene.Compose.Accessibility.enableContentWarning + self.composeToolbarView.contentWarningBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.contentWarningButton.accessibilityLabel = accessibilityLabel } .store(in: &disposeBag) @@ -404,6 +440,7 @@ extension ComposeViewController { .sink { [weak self] type, _ in guard let self = self else { return } let image = type.image(interfaceStyle: self.traitCollection.userInterfaceStyle) + self.composeToolbarView.visibilityBarButtonItem.image = image self.composeToolbarView.visibilityButton.setImage(image, for: .normal) self.composeToolbarView.activeVisibilityType.value = type } @@ -415,16 +452,27 @@ extension ComposeViewController { guard let self = self else { return } let count = ComposeViewModel.composeContentLimit - characterCount self.composeToolbarView.characterCountLabel.text = "\(count)" + self.characterCountLabel.text = "\(count)" + let font: UIFont + let textColor: UIColor + let accessibilityLabel: String switch count { case _ where count < 0: - self.composeToolbarView.characterCountLabel.font = .monospacedDigitSystemFont(ofSize: 24, weight: .bold) - self.composeToolbarView.characterCountLabel.textColor = Asset.Colors.danger.color - self.composeToolbarView.characterCountLabel.accessibilityLabel = L10n.A11y.Plural.Count.inputLimitExceeds(abs(count)) + font = .monospacedDigitSystemFont(ofSize: 24, weight: .bold) + textColor = Asset.Colors.danger.color + accessibilityLabel = L10n.A11y.Plural.Count.inputLimitExceeds(abs(count)) default: - self.composeToolbarView.characterCountLabel.font = .monospacedDigitSystemFont(ofSize: 15, weight: .regular) - self.composeToolbarView.characterCountLabel.textColor = Asset.Colors.Label.secondary.color - self.composeToolbarView.characterCountLabel.accessibilityLabel = L10n.A11y.Plural.Count.inputLimitRemains(count) + font = .monospacedDigitSystemFont(ofSize: 15, weight: .regular) + textColor = Asset.Colors.Label.secondary.color + accessibilityLabel = L10n.A11y.Plural.Count.inputLimitRemains(count) } + self.composeToolbarView.characterCountLabel.font = font + self.composeToolbarView.characterCountLabel.textColor = textColor + self.composeToolbarView.characterCountLabel.accessibilityLabel = accessibilityLabel + self.characterCountLabel.font = font + self.characterCountLabel.textColor = textColor + self.characterCountLabel.accessibilityLabel = accessibilityLabel + self.characterCountLabel.sizeToFit() } .store(in: &disposeBag) @@ -467,6 +515,18 @@ extension ComposeViewController { } } .store(in: &disposeBag) + + configureToolbarDisplay(keyboardHasShortcutBar: keyboardHasShortcutBar.value) + Publishers.CombineLatest( + keyboardHasShortcutBar, + viewModel.traitCollectionDidChangePublisher + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] keyboardHasShortcutBar, _ in + guard let self = self else { return } + self.configureToolbarDisplay(keyboardHasShortcutBar: keyboardHasShortcutBar) + } + .store(in: &disposeBag) } override func viewWillAppear(_ animated: Bool) { @@ -578,11 +638,7 @@ extension ComposeViewController { } private func showDismissConfirmAlertController() { - let alertController = UIAlertController( - title: L10n.Common.Alerts.DiscardPostContent.title, - message: L10n.Common.Alerts.DiscardPostContent.message, - preferredStyle: .alert - ) + let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let discardAction = UIAlertAction(title: L10n.Common.Controls.Actions.discard, style: .destructive) { [weak self] _ in guard let self = self else { return } self.dismiss(animated: true, completion: nil) @@ -590,6 +646,7 @@ extension ComposeViewController { alertController.addAction(discardAction) let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel) alertController.addAction(cancelAction) + alertController.popoverPresentationController?.barButtonItem = cancelBarButtonItem present(alertController, animated: true, completion: nil) } @@ -610,6 +667,37 @@ extension ComposeViewController { tableView.backgroundColor = theme.systemElevatedBackgroundColor composeToolbarBackgroundView.backgroundColor = theme.composeToolbarBackgroundColor } + + private func setupInputAssistantItem(item: UITextInputAssistantItem) { + let groups = [UIBarButtonItemGroup(barButtonItems: [ + composeToolbarView.mediaBarButtonItem, + composeToolbarView.pollBarButtonItem, + composeToolbarView.contentWarningBarButtonItem, + composeToolbarView.visibilityBarButtonItem, + ], representativeItem: nil)] + + item.trailingBarButtonGroups = groups + } + + private func configureToolbarDisplay(keyboardHasShortcutBar: Bool) { + switch self.traitCollection.userInterfaceIdiom { + case .pad: + let shouldHideToolbar = keyboardHasShortcutBar && self.traitCollection.horizontalSizeClass == .regular + self.composeToolbarView.alpha = shouldHideToolbar ? 0 : 1 + self.composeToolbarBackgroundView.alpha = shouldHideToolbar ? 0 : 1 + default: + break + } + } + + private func configureNavigationBarTitleStyle() { + switch traitCollection.userInterfaceIdiom { + case .pad: + navigationController?.navigationBar.prefersLargeTitles = traitCollection.horizontalSizeClass == .regular + default: + break + } + } } @@ -661,6 +749,20 @@ extension ComposeViewController: MetaTextDelegate { // MARK: - UITextViewDelegate extension ComposeViewController: UITextViewDelegate { + + func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { + setupInputAssistantItem(item: textView.inputAssistantItem) + return true + } +// func textViewDidBeginEditing(_ textView: UITextView) { +// switch textView { +// case textEditorView()?.textView: +// setupInputAssistantItem(item: textView.inputAssistantItem) +// default: +// assertionFailure() +// break +// } +// } func textViewDidChange(_ textView: UITextView) { if textEditorView()?.textView === textView { @@ -801,7 +903,7 @@ extension ComposeViewController: UITextViewDelegate { // MARK: - ComposeToolbarViewDelegate extension ComposeViewController: ComposeToolbarViewDelegate { - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: UIButton, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) { switch type { case .photoLibrary: present(photoLibraryPicker, animated: true, completion: nil) @@ -812,7 +914,7 @@ extension ComposeViewController: ComposeToolbarViewDelegate { } } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: UIButton) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: Any) { // toggle poll composing state viewModel.isPollComposing.value.toggle() @@ -834,11 +936,11 @@ extension ComposeViewController: ComposeToolbarViewDelegate { } } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: UIButton) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: Any) { viewModel.isCustomEmojiComposing.value.toggle() } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: Any) { // cancel custom picker input viewModel.isCustomEmojiComposing.value = false @@ -858,7 +960,7 @@ extension ComposeViewController: ComposeToolbarViewDelegate { } } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: UIButton, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: Any, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) { viewModel.selectedStatusVisibility.value = type } @@ -1048,6 +1150,9 @@ extension ComposeViewController: ComposeStatusAttachmentCollectionViewCellDelega extension ComposeViewController: ComposeStatusPollOptionCollectionViewCellDelegate { func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textFieldDidBeginEditing textField: UITextField) { + + setupInputAssistantItem(item: textField.inputAssistantItem) + // FIXME: make poll section visible // DispatchQueue.main.async { // self.collectionView.scroll(to: .bottom, animated: true) @@ -1144,6 +1249,14 @@ extension ComposeViewController: ComposeStatusPollExpiresOptionCollectionViewCel } } +// MARK: - ComposeStatusContentTableViewCellDelegate +extension ComposeViewController: ComposeStatusContentTableViewCellDelegate { + func composeStatusContentTableViewCell(_ cell: ComposeStatusContentTableViewCell, textViewShouldBeginEditing textView: UITextView) -> Bool { + setupInputAssistantItem(item: textView.inputAssistantItem) + return true + } +} + // MARK: - AutoCompleteViewControllerDelegate extension ComposeViewController: AutoCompleteViewControllerDelegate { func autoCompleteViewController(_ viewController: AutoCompleteViewController, didSelectItem item: AutoCompleteItem) { diff --git a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift index f6e700fbb..03ee911e4 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift @@ -39,6 +39,24 @@ extension ComposeViewModel { // setup data source tableView.dataSource = self + + composeStatusAttachmentTableViewCell.collectionViewHeightDidUpdate + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let _ = self else { return } + tableView.beginUpdates() + tableView.endUpdates() + } + .store(in: &disposeBag) + +// composeStatusPollTableViewCell.collectionViewHeightDidUpdate +// .receive(on: DispatchQueue.main) +// .sink { [weak self] _ in +// guard let _ = self else { return } +// tableView.beginUpdates() +// tableView.endUpdates() +// } +// .store(in: &disposeBag) attachmentServices .removeDuplicates() @@ -55,10 +73,10 @@ extension ComposeViewModel { let items = attachmentServices.map { ComposeStatusAttachmentItem.attachment(attachmentService: $0) } snapshot.appendItems(items, toSection: .main) - tableView.performBatchUpdates { - dataSource.apply(snapshot, animatingDifferences: true) - } completion: { _ in - // do nothing + if #available(iOS 15.0, *) { + dataSource.applySnapshotUsingReloadData(snapshot) + } else { + dataSource.apply(snapshot, animatingDifferences: false) } } .store(in: &disposeBag) @@ -90,9 +108,11 @@ extension ComposeViewModel { snapshot.appendItems(items, toSection: .main) tableView.performBatchUpdates { - dataSource.apply(snapshot, animatingDifferences: true) - } completion: { _ in - // do nothing + if #available(iOS 15.0, *) { + dataSource.apply(snapshot, animatingDifferences: false) + } else { + dataSource.apply(snapshot, animatingDifferences: true) + } } } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift index 561c6c3ba..6d2bbe93a 100644 --- a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift +++ b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift @@ -35,6 +35,7 @@ final class ComposeStatusAttachmentTableViewCell: UITableViewCell { collectionView.isScrollEnabled = false return collectionView }() + let collectionViewHeightDidUpdate = PassthroughSubject() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -68,6 +69,7 @@ extension ComposeStatusAttachmentTableViewCell { collectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] collectionView, _ in guard let self = self else { return } self.collectionViewHeightLayoutConstraint.constant = collectionView.contentSize.height + self.collectionViewHeightDidUpdate.send() } .store(in: &observations) diff --git a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift index 0c2abb262..ac8d5094f 100644 --- a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift +++ b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift @@ -7,6 +7,7 @@ import os.log import UIKit +import Combine protocol ComposeStatusPollTableViewCellDelegate: AnyObject { func composeStatusPollTableViewCell(_ cell: ComposeStatusPollTableViewCell, pollOptionAttributesDidReorder options: [ComposeStatusPollItem.PollOptionAttribute]) @@ -49,6 +50,7 @@ final class ComposeStatusPollTableViewCell: UITableViewCell { collectionView.dragInteractionEnabled = true return collectionView }() + let collectionViewHeightDidUpdate = PassthroughSubject() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -82,6 +84,7 @@ extension ComposeStatusPollTableViewCell { collectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] collectionView, _ in guard let self = self else { return } self.collectionViewHeightLayoutConstraint.constant = collectionView.contentSize.height + self.collectionViewHeightDidUpdate.send() } .store(in: &observations) diff --git a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift index a8ceeee3a..373ce1a15 100644 --- a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift +++ b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift @@ -11,11 +11,11 @@ import Combine import MastodonSDK protocol ComposeToolbarViewDelegate: AnyObject { - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: UIButton, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: UIButton) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: UIButton) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: UIButton, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: Any) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: Any) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: Any) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: Any, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) } final class ComposeToolbarView: UIView { @@ -28,13 +28,9 @@ final class ComposeToolbarView: UIView { weak var delegate: ComposeToolbarViewDelegate? // barButtonItem - let mediaBarButton: UIButton = { - let button = UIButton() - button.setImage(UIImage(systemName: "photo"), for: .normal) - return button - }() private(set) lazy var mediaBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(customView: mediaBarButton) + let barButtonItem = UIBarButtonItem() + barButtonItem.image = UIImage(systemName: "photo") barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendAttachment return barButtonItem }() @@ -177,11 +173,17 @@ extension ComposeToolbarView { ]) characterCountLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) + mediaBarButtonItem.menu = createMediaContextMenu() mediaButton.menu = createMediaContextMenu() mediaButton.showsMenuAsPrimaryAction = true + pollBarButtonItem.target = self + pollBarButtonItem.action = #selector(ComposeToolbarView.pollButtonDidPressed(_:)) pollButton.addTarget(self, action: #selector(ComposeToolbarView.pollButtonDidPressed(_:)), for: .touchUpInside) emojiButton.addTarget(self, action: #selector(ComposeToolbarView.emojiButtonDidPressed(_:)), for: .touchUpInside) + contentWarningBarButtonItem.target = self + contentWarningBarButtonItem.action = #selector(ComposeToolbarView.contentWarningButtonDidPressed(_:)) contentWarningButton.addTarget(self, action: #selector(ComposeToolbarView.contentWarningButtonDidPressed(_:)), for: .touchUpInside) + visibilityBarButtonItem.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) visibilityButton.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) visibilityButton.showsMenuAsPrimaryAction = true @@ -192,6 +194,7 @@ extension ComposeToolbarView { .receive(on: RunLoop.main) .sink { [weak self] type in guard let self = self else { return } + self.visibilityBarButtonItem.menu = self.createVisibilityContextMenu(interfaceStyle: self.traitCollection.userInterfaceStyle) self.visibilityButton.menu = self.createVisibilityContextMenu(interfaceStyle: self.traitCollection.userInterfaceStyle) } .store(in: &disposeBag) @@ -275,17 +278,22 @@ extension ComposeToolbarView { switch traitCollection.userInterfaceStyle { case .light: + mediaBarButtonItem.image = UIImage(systemName: "photo") mediaButton.setImage(UIImage(systemName: "photo", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) + contentWarningBarButtonItem.image = UIImage(systemName: "exclamationmark.shield") contentWarningButton.setImage(UIImage(systemName: "exclamationmark.shield", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) case .dark: + mediaBarButtonItem.image = UIImage(systemName: "photo.fill") mediaButton.setImage(UIImage(systemName: "photo.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) + contentWarningBarButtonItem.image = UIImage(systemName: "exclamationmark.shield.fill") contentWarningButton.setImage(UIImage(systemName: "exclamationmark.shield.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) default: assertionFailure() } + visibilityBarButtonItem.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) visibilityButton.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) } @@ -331,17 +339,17 @@ extension ComposeToolbarView { extension ComposeToolbarView { - @objc private func pollButtonDidPressed(_ sender: UIButton) { + @objc private func pollButtonDidPressed(_ sender: Any) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) delegate?.composeToolbarView(self, pollButtonDidPressed: sender) } - @objc private func emojiButtonDidPressed(_ sender: UIButton) { + @objc private func emojiButtonDidPressed(_ sender: Any) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) delegate?.composeToolbarView(self, emojiButtonDidPressed: sender) } - @objc private func contentWarningButtonDidPressed(_ sender: UIButton) { + @objc private func contentWarningButtonDidPressed(_ sender: Any) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) delegate?.composeToolbarView(self, contentWarningButtonDidPressed: sender) } From 051f436abea04409f62b0809ef81f258125f8f9f Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 29 Sep 2021 17:05:40 +0800 Subject: [PATCH 205/392] feat: add missing scroll restore action for "See More Posts" title view --- .../HomeTimelineViewController.swift | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index b496c76b1..38d6e90ac 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -439,9 +439,16 @@ extension HomeTimelineViewController { func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { switch scrollView { case tableView: - // handle scrollToTop + + let indexPath = IndexPath(row: 0, section: 0) + guard viewModel.diffableDataSource?.itemIdentifier(for: indexPath) != nil else { + return true + } + // save position savePositionBeforeScrollToTop() - return true + // override by custom scrollToRow + tableView.scrollToRow(at: indexPath, at: .top, animated: true) + return false default: assertionFailure() return true @@ -449,6 +456,16 @@ extension HomeTimelineViewController { } private func savePositionBeforeScrollToTop() { + // check save action interval + // should not fast than 0.5s to prevent save when scrollToTop on-flying + if let record = viewModel.scrollPositionRecord.value { + let now = Date() + guard now.timeIntervalSince(record.timestamp) > 0.5 else { + // skip this save action + return + } + } + guard let diffableDataSource = viewModel.diffableDataSource else { return } guard let anchorIndexPaths = tableView.indexPathsForVisibleRows?.sorted() else { return } guard !anchorIndexPaths.isEmpty else { return } @@ -674,6 +691,8 @@ extension HomeTimelineViewController: HomeTimelineNavigationBarTitleViewDelegate guard let diffableDataSource = viewModel.diffableDataSource else { return } let indexPath = IndexPath(row: 0, section: 0) guard diffableDataSource.itemIdentifier(for: indexPath) != nil else { return } + + savePositionBeforeScrollToTop() tableView.scrollToRow(at: indexPath, at: .top, animated: true) case .offlineButton: // TODO: retry From ad0df8542e5e85870fb7abadc3cd63c02c8bdcb5 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 29 Sep 2021 17:37:32 +0800 Subject: [PATCH 206/392] feat: add compact to regular split view controller expand restore logic --- Mastodon/Coordinator/SceneCoordinator.swift | 6 ++++ .../Scene/Root/RootSplitViewController.swift | 35 +++++++++++-------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 216394c50..83ae61a84 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -20,6 +20,8 @@ final public class SceneCoordinator { weak var splitViewController: RootSplitViewController? + private(set) var secondaryStackHashValues = Set() + init(scene: UIScene, sceneDelegate: SceneDelegate, appContext: AppContext) { self.scene = scene self.sceneDelegate = sceneDelegate @@ -183,9 +185,13 @@ extension SceneCoordinator { { fallthrough } else { + if secondaryStackHashValues.contains(presentingViewController.hashValue) { + secondaryStackHashValues.insert(viewController.hashValue) + } presentingViewController.show(viewController, sender: sender) } case .showDetail: + secondaryStackHashValues.insert(viewController.hashValue) let navigationController = AdaptiveStatusBarStyleNavigationController(rootViewController: viewController) presentingViewController.showDetailViewController(navigationController, sender: sender) diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index bba68defb..e7a632cb8 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -132,7 +132,7 @@ extension RootSplitViewController: SidebarViewControllerDelegate { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectSearchHistory searchHistoryViewModel: SidebarViewModel.SearchHistoryViewModel) { // self.sidebarViewController(sidebarViewController, didSelectTab: .search) - let supplementaryViewController = viewController(for: .supplementary) + let supplementaryViewController = viewController(for: .supplementary) let managedObjectContext = context.managedObjectContext managedObjectContext.perform { let searchHistory = managedObjectContext.object(with: searchHistoryViewModel.searchHistoryObjectID) as! SearchHistory @@ -200,21 +200,26 @@ extension RootSplitViewController: UISplitViewControllerDelegate { _ svc: UISplitViewController, displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode ) -> UISplitViewController.DisplayMode { + let compactNavigationController = mainTabBarController.selectedViewController as? UINavigationController + let viewControllers = compactNavigationController?.popToRootViewController(animated: true) ?? [] + var supplementaryViewControllers: [UIViewController] = [] + var secondaryViewControllers: [UIViewController] = [] + for viewController in viewControllers { + if coordinator.secondaryStackHashValues.contains(viewController.hashValue) { + secondaryViewControllers.append(viewController) + } else { + supplementaryViewControllers.append(viewController) + } + + } + if let supplementary = viewController(for: .supplementary) as? UINavigationController { + supplementary.setViewControllers(supplementary.viewControllers + supplementaryViewControllers, animated: false) + } + if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { + secondaryNavigationController.setViewControllers(secondaryNavigationController.viewControllers + secondaryViewControllers, animated: false) + } return proposedDisplayMode } - - func splitViewController( - _ splitViewController: UISplitViewController, - show vc: UIViewController, - sender: Any? - ) -> Bool { - if !splitViewController.isCollapsed { - // display in .secondary when expand - splitViewController.showDetailViewController(vc, sender: sender) - return true - } else { - return false - } - } + } From 9104602893d48e9767c0bd515cf3d260b3374f9a Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 29 Sep 2021 18:42:28 +0800 Subject: [PATCH 207/392] chore: update sidebar color and Detail placeholder background color --- Mastodon.xcodeproj/project.pbxproj | 4 +++ .../Scene/Root/RootSplitViewController.swift | 2 +- .../SecondaryPlaceholderViewController.swift | 36 +++++++++++++++++++ .../Root/Sidebar/SidebarViewController.swift | 12 +++++-- .../ThemeService+Appearance.swift | 3 ++ 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 Mastodon/Scene/Root/Sidebar/SecondaryPlaceholderViewController.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 13755e8b8..cbb28acec 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -575,6 +575,7 @@ DBF156DF2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */; }; DBF156E22702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m in Sources */ = {isa = PBXBuildFile; fileRef = DBF156E12702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m */; }; DBF156E42702DB3F00EC00B7 /* HandleTapAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF156E32702DB3F00EC00B7 /* HandleTapAction.swift */; }; + DBF1572F27046F1A00EC00B7 /* SecondaryPlaceholderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1572E27046F1A00EC00B7 /* SecondaryPlaceholderViewController.swift */; }; DBF1D24E269DAF5D00C1C08A /* SearchDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */; }; DBF1D251269DB01200C1C08A /* SearchHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */; }; DBF1D257269DBAC600C1C08A /* SearchDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */; }; @@ -1360,6 +1361,7 @@ DBF156E02702DA6800EC00B7 /* Mastodon-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Mastodon-Bridging-Header.h"; sourceTree = ""; }; DBF156E12702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIStatusBarManager+HandleTapAction.m"; sourceTree = ""; }; DBF156E32702DB3F00EC00B7 /* HandleTapAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleTapAction.swift; sourceTree = ""; }; + DBF1572E27046F1A00EC00B7 /* SecondaryPlaceholderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryPlaceholderViewController.swift; sourceTree = ""; }; DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewController.swift; sourceTree = ""; }; DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryViewController.swift; sourceTree = ""; }; DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewModel.swift; sourceTree = ""; }; @@ -2554,6 +2556,7 @@ DB0EF72C26FDB1D600347686 /* View */, DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */, DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */, + DBF1572E27046F1A00EC00B7 /* SecondaryPlaceholderViewController.swift */, ); path = Sidebar; sourceTree = ""; @@ -3972,6 +3975,7 @@ DB36679F268ABAF20027D07F /* ComposeStatusAttachmentSection.swift in Sources */, 2DA7D04425CA52B200804E11 /* TimelineLoaderTableViewCell.swift in Sources */, DB87D44B2609C11900D12C0D /* PollOptionView.swift in Sources */, + DBF1572F27046F1A00EC00B7 /* SecondaryPlaceholderViewController.swift in Sources */, DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */, 2D4AD8A826316D3500613EFC /* SelectedAccountItem.swift in Sources */, DBE3CDFB261C6CA500430CC6 /* FavoriteViewModel.swift in Sources */, diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index e7a632cb8..2e8beef9e 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -63,7 +63,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { setViewController(sidebarViewController, for: .primary) setViewController(supplementaryViewControllers[0], for: .supplementary) - setViewController(UIViewController(), for: .secondary) + setViewController(SecondaryPlaceholderViewController(), for: .secondary) setViewController(mainTabBarController, for: .compact) } diff --git a/Mastodon/Scene/Root/Sidebar/SecondaryPlaceholderViewController.swift b/Mastodon/Scene/Root/Sidebar/SecondaryPlaceholderViewController.swift new file mode 100644 index 000000000..a381844df --- /dev/null +++ b/Mastodon/Scene/Root/Sidebar/SecondaryPlaceholderViewController.swift @@ -0,0 +1,36 @@ +// +// SecondaryPlaceholderViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-9-29. +// + +import UIKit +import Combine + +final class SecondaryPlaceholderViewController: UIViewController { + var disposeBag = Set() +} + +extension SecondaryPlaceholderViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + setupBackground(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupBackground(theme: theme) + } + .store(in: &disposeBag) + } + +} + +extension SecondaryPlaceholderViewController { + private func setupBackground(theme: Theme) { + view.backgroundColor = theme.secondarySystemBackgroundColor + } +} diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index e1ae87646..69d9f55c8 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -35,6 +35,7 @@ final class SidebarViewController: UIViewController, NeedsDependency { static func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout() { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in var configuration = UICollectionLayoutListConfiguration(appearance: .sidebar) + configuration.backgroundColor = .clear if sectionIndex == SidebarViewModel.Section.tab.rawValue { // with indentation configuration.headerMode = .none @@ -103,16 +104,23 @@ extension SidebarViewController { } private func setupBackground(theme: Theme) { + let color: UIColor = theme.sidebarBackgroundColor let barAppearance = UINavigationBarAppearance() barAppearance.configureWithOpaqueBackground() - barAppearance.backgroundColor = theme.sidebarBackgroundColor + barAppearance.backgroundColor = color barAppearance.shadowColor = .clear barAppearance.shadowImage = UIImage() // remove separator line navigationItem.standardAppearance = barAppearance navigationItem.compactAppearance = barAppearance navigationItem.scrollEdgeAppearance = barAppearance + if #available(iOS 15.0, *) { + navigationItem.compactScrollEdgeAppearance = barAppearance + } else { + // Fallback on earlier versions + } - view.backgroundColor = theme.sidebarBackgroundColor + view.backgroundColor = color + collectionView.backgroundColor = color } } diff --git a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift b/Mastodon/Service/ThemeService/ThemeService+Appearance.swift index 182fe870a..8130942aa 100644 --- a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift +++ b/Mastodon/Service/ThemeService/ThemeService+Appearance.swift @@ -24,6 +24,9 @@ extension ThemeService { UINavigationBar.appearance().standardAppearance = appearance UINavigationBar.appearance().compactAppearance = appearance UINavigationBar.appearance().scrollEdgeAppearance = appearance + if #available(iOS 15.0, *) { + UINavigationBar.appearance().compactScrollEdgeAppearance = appearance + } // set tab bar appearance let tabBarAppearance = UITabBarAppearance() From 0d7d659e012234efdb2e9c967f3a98f850eba614 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 29 Sep 2021 18:42:52 +0800 Subject: [PATCH 208/392] fix: notification settings persist logic issue --- .../Settings/SettingsViewController.swift | 3 +++ .../APIService+CoreData+Subscriptions.swift | 10 +++----- Mastodon/Service/NotificationService.swift | 2 +- Mastodon/Service/SettingService.swift | 24 ++++++++++--------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index c4658d7da..3b4e522e6 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -289,6 +289,9 @@ class SettingsViewController: UIViewController, NeedsDependency { return } + // clear badge before sign-out + context.notificationService.clearNotificationCountForActiveUser() + context.authenticationService.signOutMastodonUser( domain: activeMastodonAuthenticationBox.domain, userID: activeMastodonAuthenticationBox.userID diff --git a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Subscriptions.swift b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Subscriptions.swift index 6eebc9e56..d5958cf8f 100644 --- a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Subscriptions.swift +++ b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Subscriptions.swift @@ -18,13 +18,9 @@ extension APIService.CoreData { setting: Setting, policy: Mastodon.API.Subscriptions.Policy ) -> (subscription: Subscription, isCreated: Bool) { - let oldSubscription: Subscription? = { - let request = Subscription.sortedFetchRequest - request.predicate = Subscription.predicate(policyRaw: policy.rawValue) - request.fetchLimit = 1 - request.returnsObjectsAsFaults = false - return managedObjectContext.safeFetch(request).first - }() + let oldSubscription = setting.subscriptions?.first(where: { subscription in + subscription.policyRaw == policy.rawValue + }) if let oldSubscription = oldSubscription { oldSubscription.setting = setting diff --git a/Mastodon/Service/NotificationService.swift b/Mastodon/Service/NotificationService.swift index 6437e1b66..463a2def8 100644 --- a/Mastodon/Service/NotificationService.swift +++ b/Mastodon/Service/NotificationService.swift @@ -27,7 +27,7 @@ final class NotificationService { let applicationIconBadgeNeedsUpdate = CurrentValueSubject(Void()) // output - /// [Token: UserID] + /// [Token: NotificationViewModel] let notificationSubscriptionDict: [String: NotificationViewModel] = [:] let unreadNotificationCountDidUpdate = CurrentValueSubject(Void()) let requestRevealNotificationPublisher = PassthroughSubject() diff --git a/Mastodon/Service/SettingService.swift b/Mastodon/Service/SettingService.swift index 5985f6fce..1c030c519 100644 --- a/Mastodon/Service/SettingService.swift +++ b/Mastodon/Service/SettingService.swift @@ -44,19 +44,21 @@ final class SettingService { .compactMap { [weak self] mastodonAuthenticationBoxes -> AnyPublisher<[MastodonAuthenticationBox], Never>? in guard let self = self else { return nil } guard let authenticationService = self.authenticationService else { return nil } - guard let activeMastodonAuthenticationBox = mastodonAuthenticationBoxes.first else { return nil } - let domain = activeMastodonAuthenticationBox.domain - let userID = activeMastodonAuthenticationBox.userID - return authenticationService.backgroundManagedObjectContext.performChanges { - _ = APIService.CoreData.createOrMergeSetting( - into: authenticationService.backgroundManagedObjectContext, - property: Setting.Property( - domain: domain, - userID: userID, - appearanceRaw: SettingsItem.AppearanceMode.automatic.rawValue + let managedObjectContext = authenticationService.backgroundManagedObjectContext + return managedObjectContext.performChanges { + for authenticationBox in mastodonAuthenticationBoxes { + let domain = authenticationBox.domain + let userID = authenticationBox.userID + _ = APIService.CoreData.createOrMergeSetting( + into: managedObjectContext, + property: Setting.Property( + domain: domain, + userID: userID, + appearanceRaw: SettingsItem.AppearanceMode.automatic.rawValue + ) ) - ) + } // end for } .map { _ in mastodonAuthenticationBoxes } .eraseToAnyPublisher() From 95020e6446a443d880015b2fe458ce5306292c68 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 29 Sep 2021 19:34:54 +0800 Subject: [PATCH 209/392] fix: rotate media preview raise layout issue --- Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift index 29ddc206a..88beda0f5 100644 --- a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift +++ b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift @@ -55,6 +55,7 @@ extension MediaPreviewViewController { overrideUserInterfaceStyle = .dark visualEffectView.frame = view.bounds + visualEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(visualEffectView) pagingViewController.view.translatesAutoresizingMaskIntoConstraints = false From bd60804e2fdcd1443f0c49d77569718e2770943d Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 29 Sep 2021 19:59:56 +0800 Subject: [PATCH 210/392] chore: update version to 1.2.0 (70). Add database size log in DEBUG mode --- AppShared/Info.plist | 2 +- CoreDataStack/CoreDataStack.swift | 18 +++++- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 12 files changed, 62 insertions(+), 46 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index f4fc24abb..99255fa90 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 diff --git a/CoreDataStack/CoreDataStack.swift b/CoreDataStack/CoreDataStack.swift index 2d6224e72..2dfa0c38c 100644 --- a/CoreDataStack/CoreDataStack.swift +++ b/CoreDataStack/CoreDataStack.swift @@ -13,6 +13,8 @@ import AppShared public final class CoreDataStack { + static let logger = Logger(subsystem: "CoreDataStack", category: "DB") + private(set) var storeDescriptions: [NSPersistentStoreDescription] public let didFinishLoad = CurrentValueSubject(false) @@ -90,8 +92,22 @@ public final class CoreDataStack { container.viewContext.automaticallyMergesChangesFromParent = true os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, storeDescription.debugDescription) - + callback() + + #if DEBUG + do { + let storeURL = URL.storeURL(for: AppName.groupID, databaseName: "shared") + let data = try Data(contentsOf: storeURL) + let formatter = ByteCountFormatter() + formatter.allowedUnits = [.useMB] + formatter.countStyle = .file + let size = formatter.string(fromByteCount: Int64(data.count)) + CoreDataStack.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): Database size: \(size)") + } catch { + CoreDataStack.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): Cannot get database size") + } + #endif }) } diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index f4fc24abb..99255fa90 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index f4fc24abb..99255fa90 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index cbb28acec..b41484465 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4760,7 +4760,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4789,7 +4789,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4897,11 +4897,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4928,11 +4928,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4957,11 +4957,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4987,11 +4987,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5054,7 +5054,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5079,7 +5079,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5104,7 +5104,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5129,7 +5129,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5154,7 +5154,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5179,7 +5179,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5204,7 +5204,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5229,7 +5229,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5320,7 +5320,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5387,11 +5387,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5436,7 +5436,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5461,11 +5461,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5557,7 +5557,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5624,11 +5624,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5673,7 +5673,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5698,11 +5698,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 69; + DYLIB_CURRENT_VERSION = 70; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5728,7 +5728,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5752,7 +5752,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 69; + CURRENT_PROJECT_VERSION = 70; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 62ed7d88b..be8c2df95 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 44 + 51 CoreDataStack.xcscheme_^#shared#^_ orderHint - 50 + 53 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 48 + 47 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 49 + 52 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index b61ed27b0..cd377a41e 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 69 + 70 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 077c5a1f3..9540c525e 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index f4fc24abb..99255fa90 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index f4fc24abb..99255fa90 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index e82983eb4..e80488b0b 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index d8bdbae5a..25ff496f4 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 69 + 70 NSExtension NSExtensionAttributes From c88daf56be2fc2f315a6eb29392161505e58df04 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 30 Sep 2021 14:14:30 +0800 Subject: [PATCH 211/392] fix: use PDF asset avoid wrong svg render issue --- .../Asset/email.imageset/Contents.json | 2 +- .../Asset/email.imageset/c1 1.svg | 73 ------------------ .../Asset/email.imageset/c1 1~universal.pdf | Bin 0 -> 49638 bytes 3 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 Mastodon/Resources/Assets.xcassets/Asset/email.imageset/c1 1.svg create mode 100644 Mastodon/Resources/Assets.xcassets/Asset/email.imageset/c1 1~universal.pdf diff --git a/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/Contents.json index ba3df05b6..bcc8dce80 100644 --- a/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "c1 1.svg", + "filename" : "c1 1~universal.pdf", "idiom" : "universal" } ], diff --git a/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/c1 1.svg b/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/c1 1.svg deleted file mode 100644 index d3869cda5..000000000 --- a/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/c1 1.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/c1 1~universal.pdf b/Mastodon/Resources/Assets.xcassets/Asset/email.imageset/c1 1~universal.pdf new file mode 100644 index 0000000000000000000000000000000000000000..93c448982f618e4e52b1f5f7e5d1c13bdfda0b5f GIT binary patch literal 49638 zcmV(#K;*wAP((&8F)lL-CB)_ObY*fNFGg%( zbY(Vma%Ev{3U~pH-OI8iJCfe_`F@Ig0UqYQ zXpQQEHiWQ6gJ`~Lam`_~^|{>y*-^1prgPhbB1|N0;Q%U}NE|MUO;fB*YGfB7%}mp0w6-M_2R z*ERjiU%&kO|K+c*U;d~6`^$fLiO%QSmv3)hK0m*H`TX|nze}n6qg11H`SImQz5Pi_ zgFilh{`~p<^P8bR{`fHBcYmMk{lmY!e)-G4e0kk}|MHhFAK%{p_-^R8KYo7s>z9wu zZ>xR$@&5Ah`T7T@zM=Q!FtjnNRlfb9>(7_Jkm5(QUHB2P z&-YJ^e0zKS)=Z}wSpI`O(BoXCzb9RNU#`yO! z__O=wS$u`1wYMFCX8I z^1Jb$+WUNO%ruGC$2U}dx2eB;`KK@c$J1H8GZlc zLRtJj{?qH1fB7d=A5Qph(tTLGsl5ICczxxBf4sfDf2t_G{`jH%{)H#JzrT|-ZJNzr zSNpcw`^)?L$4Z~BrlZM0*IjldSo^5~P*`zU>nqfhhusRfz&`x9-rx0&+-_t>&)^S^f%uMJFd<$E@6 zq#xf&?7b^wVs76*qk6IePn#D+?9Mp%7gbkq{yqPD|8dy%4kc((&nNYFejW!K&-GaV z+%?Z@1rN;X#`>1cMeAD869U67KvkDX!SI~kXZ!gupW$`SjK8;gtHosbB+Wl2-%y0(< zmUw+!%R*7x2yiQI9y1GR)#f?Mdhi1Ce?|2(q>R!>SElQ`uKuF5)^S*y&$uU>_3iKZ znUPT}oW#p|FB)7V{65Kl z=nH8Vf8?X)2Wy-Cy!r>*fefSc3lSGFU?u62g|goLz`LM2Nx|T* z$Bj9`{;S~{YWw>mexArYZ-%Rl5w`cYF<3E7p8OYMQTj2&eZ+xbD0*frjV4DRIw2n$MYEv6t$E7ZaBYUg?FSluqy^>4;B|O28{zBW7oKEu?@EjHB519j z7?(3uwKaz?oMt@xr{nuxW&?%?o-5iFLd|$^0wFwVzifHy?nsGr*{9& zBBn0iH;=cMn@6=4lHK{Cyx@7QJ_4FY56<6Q)7|R_Lw}S4y1$I6PuG)eciz4*E91N^ zp?aNNL@5}1B?{&)097vRB|#$#7p36U>^`6(IiNYM7T(^3T;&DcWSj2Pl(LRje;K{M z_@jkyQJNzs+_iE&H%do8m77Uz3Nx<)z0s6OcrK$NH35z9UlcJq%v2neEof9I zY7W%G;pJ`KfZ(Xiz!{FN>~v$|`poT8@;8a@XN+N1EKnRENs&KZOkq@pduEA80WOJW z-)~GYsXZ)Pa7srsyrs+Q(wnzJEGzh$>=||zkxfArOl-P zN9Fs=D?~UdG_|dt2X#E<<<;={o%AM(SId+*PF=6tX3^$*<-+#c7GRYLVT+r}o4TF2 zS69&4;_X>3P*)C}-i+T^dc3^hvL3Tk36r@m@M~phK|ZLYi;}ZfVLO$EPOs!zn)k+E z^oh#Ln;`I^OcpGoHYLZ}kgPFCNpGoVa-3(q&3{PpjIbreYpS+|!1(GTR24$rhD;&X z_p7;+q`UJA3;w2Nr0%@b?onQ!Lh3)cmz5vAA;`+Zk3UPzK<`O4JU}b2ISl>1WQMLD zw}m*|>X|og9?B))Z%ZYCGX1G7>?eoKk5rm_3u)3ya%9-z;PsK-3U+a9`!I=TbHlO% zHrvWd(pWl9)A>mH8Y0l@L)*1koXQf|y?$vpZ++A6^`-Kx`e8eBGPV)jE7z}ba(tV& zM~jQHRD3I=^&?7!d2RS|y_ZZV*JiQ#M?5`kzfGy9SBzV;!(V`7c3E?jN?u;gCLg)- zQ0U5LTzb--G_hrwvib4fM=*MMmAniw&&#FfaX!S{!XPQ=4Ob_H$@Nu&Xhd9m{~|Y` z7%KVk^79eaSoM!Dc1}#2G8OZ&H(CZv1qLk5h$n})MJa=8z2tyLi#)Vw3wr{Vbtz6e zpmW7d3#6)K18;y9x^5V5w&FaoMcvC(^7i)i3p@$U!!FtV8bJAP0Vf);-)zQ*@C5tQ z3|2)OF(DH#ki5P~YRv{>vQ8Mf=_~@hTB@T@Qmj(sAtBf4bXTG@T=ADz_4lQS_8_ZO zbZgbLs?};XD?rhfGP=uoj;m_*hV?JS)qFMi6mh3fGty>@*|#kiU*ErKGer9>cC&|H zQJrl)qJ0^_t0lluDm|7TG;=t?Vjp?Kl@AZr=8HfldAp-mTxu? z3a(Eb0zly}9Tp9@ayU^?T=8@YBD+N#668VTJgH8lNly|!yB6EfnSS;V1fj|8@HKok zf9S(97O>$AdRi^^73;o*StLZpT9~Q7q{M@0i*f3Y;`%I&&ko3M7-p?jhumI(el4<+ zF8?TV$R*ygN_5U^f)h;y0*T1*mJTWBRBWF>7pw+`5%k1Uk=Ws9qA zd(_H2TNStiRosDr%FD9u`Ue`LwKV2Kj#dA7`Jm4~%khQQ?!4Q)b%!Q?(Iw-`4_b?q zTax2(cgQgA|D5AfEFV9=zWx+x_|doi*Sg{3)74*6u{v2^LMp?%HdU$Yu~E#r=*@Zt zE)6{h_O^`QXege_w<^0XUs#k^vod<1_%>I-=DX!x3Vf&OA@4)h%dA_1l4pzBJU%&O z<@Zpa^;k>XAgk4pHPo=<7Pea5<`ECZ0}Iu5o^4yJ9_)LI+GQvYsj}bJZY{0f_t>Xa z8B;5@)@x-PyYFwZ?XTGyBg4%ma17pmt=I5n3l`sTzwtKDwru0N;L#Rua@qQBR)f+a zcbg?B@kqUceVaC0snX22nq*r)MrETuY-|q*WWnP~E1Yu0ZC70%IP$Z{HEP?+c-*T^ zn;hn}IQ+3~*~)E&T%@ShCP`atQQ+b)AL0P{Do3r{<2bFnl`Ov7d`VjM$r3(jt3KIC zWs+6)V3r3=QnrCSbX`=iCG_P3s%1?@b`QE{Ep2SxB=v8^67VtTX(2 z;KQQdSzVs}qB;RDc2MFX|o`ljK7*^BU1KCQo34bb2&otuhdh{T%5vFr_4V0OT zQQ9h@vD3KTI5H+wJINkWje1+Wu&e9CBX-oB%e2sO9)qnlvrtU=qTJbIV;U7|cjMB!27quCt zD3koq`d6%nj-f)uXo%&1{%3)GEs?TkbKkdXz1rv&!hlk`*oA(#x@ivTKWIx$;_pIP{J4b1HNEMPVVe#@T5FhMtwAd*tS@zju@b1j7p;T>?7rta%q)_VTk=8v9pLg;*dVaQg zME&{DAwG0O{WN9t(Yg!*M`#_+;1P8a&8`luLkd!vjg}8~XY0|QmEu|ADmyYd+xsp* z+NkWRJZLkRHfyyR-j0e^dOX(1f8uSeip4`{84^#tWH%gBPEwcP{`i&2{djEmveY)i z9U)0hNvUY%$cLRv4{KKQn0D9wwQj1-Bfi~EIPEP?@9N{x(s{alh429C{TVT2G_K)~ zS4g!F8|&58hi^{~&pT!eF|}k-S(=vfqC?q5k!1+woO#r;E=Pv4$LM9bIF~&|V^LIY z)k7dHXthT_iwcjdZPEIdBu;Yw#?hKzhspjtvh(7snHbRN|n+usd-BpP*%2MP4KVBBQvf%ul$>ais zId(2iFJEQ;)^unU*natfh1_-~1SU8pj`NjPKp-jFIrl$*nbovw+R?VI8@cmz4YQFu za@IhGa~3T0Z~xcvEk)a&rJbEP>pFXKE^e(6=p0@Id2nnA5V!7hec1vZa6)eL2NxOb zaS4ZhHczd$&BPb*B0}eqVhOn09L}4<-rox#*TXZO<59 zY^Q8)(UAt+kmPXHZcZ|WwsLzs(+L#8e|k>7A!}{7_Xc0fl-gq~cBC^KkCWC#?)Lh- zlhdCq9wKL>$?Mk0WMFMv7IOPPmGjAsCV;g+3)w1xmEz9sv!2nI%tAVME_$1j7({Q7 z%^qOmEMvyG+2FGXwM>pSiyg~xZVyK;gHD;W_)^|lhFz@LSeJ*-uSrPET1=Xky$}72 zrDo3CEsp_3aS zR9)m=wypNu5ip9{_8a_*7ZOdbc|`|qD~Adn@OrtSnw9ZZFx{!uGSVwQtyB%qw@!SN zmk%k+jI9C5QTgNLgFo!Zftpo;8lIKy4=A&8Wuwz#9)3Gl4iPj)Lp_T%cM!W%;dt$wyRV4a&9Z zukju=vq6i_lCz#^@9uAPc$naNTA8ojSoAopLg?<~SNUV>M;3OaSs}R$#k19EPmQ%e zf?5^vI_gcXH@0Im@irODkY$-NYO{gB+VfDep^Z_JRqMSKMyEO4fkY^YWtAVRm_5z- zAZs`%&f*q6kQq!f*Lk)Pm#=+@I^EgK=|ECJvt*{6^h?OD_SV|N^3AQidD+{d z<43EeM=bfEedV*kp|w`9qCPbC($ilvG>^9NXQ}>fy!G_rgzNDdcV#Wjp~zB9ym^lg z@qqNN6&XbTcKLcX!G1q3nlx7U)6<*dp%`}0rjlT}LGj3rqw&p8u8}m$9FDuRCg!uZ zXcc*1x1*et#qL>K@>m{Ie({o|mJdS)oIw5M29iy*-^F-%)Ah?p@`Mkzl<(|0x>{Z< zvnU>;79#chH61igPeAEh`TC3+%gN(=mQHJX8rjoMb0#VAm)-q%`PhD$ahB$O$lS_f zLiL^)6xHY99{FiQhwXo)DRf(ds+H4K#uqu4>*TSO#|us4vb;;gL3R0C8O80SOp;K< zjGrqA8f-Uo*}^o~zDzmJBF6~rk z7h8kV!L7unS(NT@;53CpH8Y%ks%1lm7^|(!(!IP;ju+iOSB|ZBZ@qB$T1gIZP}y2y zR@Od1{hD1nDpA|)@jOl3&Vb$FJ1ukBRHvcfAk>>ZXNAs!IvMWJa{e-``weWNj~O!Nci-&(A?NObe`+E z%boYgqtA=coEGwQxJ3(Ltn)N@EB7;Vc?Pc}Z#@>TLX@q7*lL(m{6P6~ERva5bfe)$hyJAjKfT-q}H`Rdko(=rPZ^*n8)X zDx=FV{ToAEgO0_JMYhwOwu^mb-na?{i>bxD+TN*{ zi?2q!cw$_fh|b9&EG=$Fx4fk2KEBj=#rB4iFiZ9vq?naN^4p{f3AcVuwv}6-Hu7>J z9v@ZMC@)zaiSzQ3n`<_L($;yN^zP1bk?nPq)#xprEYqDWl?Ro7EfOz=l?R#YkQJ?8 zwR<^3e@}tSw5DZQSb5!6HRZY}h2>?_m&0vD5qPc2@qU%Ysr6eg?LoBbCpuKl=F4d( z7qw-zuE%AWXqj8lxeWE@l9YN)vODSWlax^+<#&1S`9nL&^}jns#d^qa$@4PbZ0MOq zhvMbhq~ETF@^SUZah=5~!==wh4!^NO5!WBNvKo8vB(H3KxFEBwoTSQfE5~i?2b|Lk zdmtlvhY_wTZ+>M8ql+hY8PzP_x@4st5|?Gro9o)Zj_Vx?&vuQFRXSfi3 z9BtLL)>AXaR!)_(hv$mw%Cl;B>R%>dCQc@PY^U%_v;^trU2JLAaJAppeAa^IjSgup zPB->)a@V@k3S=*DqScH)T*-&;xkf9_BG9tJt=w9vvC;3#;(x7QXR&IyO-jGk#ajco z4x_fFL-$eJ`sh(k=Ih(~uCdif0djbjpiEM1BR($6ZBDf+vW5WlKlG+Cc3?)(ezx{& z58(Dl%F~i&y9PA7=SwJ|fkSo=G1xs{TDE&W^ZU*O9?GJ6=D*m`se$W*rWooz{CDNK zBEMW~7Sbr$;O(V^Nj?ABldqwC_OIvG54TH{r$jwli_7iH*qxCB@f&`%NPFwmy>yUe zp<)fe{*px;-TAynE7F{Vht%yCu~KwltMlBq=d<0VC>=5z-K=m0nJ<^YtvE8ItW`0x zozB~pX=lsKZfzy2-OdJCiRfgCbJ!`X;}iHZ7g>X6*XW2>#oGM4*DT7>lT^FqMR&5n zQ){wLxQZ)m9UU{Yeqjm9la@BTyxMwaL(5T$L~&M@oCmgZh;FM!zIBJI%4>?`t-#8s zcNVp*SUKG#899Wq`O5+DqMQa>X{l*zGzd|SwY-VuZ_KTf_(pw_pV=veG_6t^4L>N| z?Ao1d^yX9sl$Ta33YHHoqhecT0P7l!9EWt}dCDPO)I=9Oc!v?D$+96F$xU%eZsSXI zbIopyR`hDbMXK8of0gBYMr-?&Wixu-d|4UlH0SU3f@xj&4LzUrc66%iy!d2Vb<2eje{%&{E}iyHj>iN>*w~QEwJI zKkb>p>D7r_uOi)Z1H$OUxLvk8EBDVGEX^buQUz*zc2I;K z@b)yr+0!hfVo1%*rC%9OMMM=n*qMkZIRJh>6M;1Y$I`8gQ>B??IUK~O99JP4%|*xY z!g+m_API!NlwL7t)*x%>*q{b8Yal5+$7IiJnj8>C&|Tp?{Ot*k4+UH?1~gG|jy`MA z8cW}`ZFcY`E;bjg-D&nkElirTFn6=dm+@;tOGSzK^#wI-PU2({jNOz@Trh*U>VJ=Q z3EgOmv?Q9i-4M=%31X&%;d zg0i7}rgAw6)1=DKS4=x()mx9faE7{nyPruuuI+Btuzh}4i?X$$dD&ojSLOP`;Ny#+ zmJP6$=wt;&mCK6a{#kyuvc_A6ROXdg{JulmJQLY7S3`@5)h0z0!;SIGqrSEO+|@;S zhF~;ioP6Q}-)bj0iqW?$?@rUK8DYkR`q z15cc-)~WU6mA-O^ioPYM6hKp3HI@Pco1Dw9VIn_SKB_NTERLW z+ryPo7wnfpJYF+v8cRn9g0Bl-rFxuikNK}m7q|U*cc!1FgV8L(2IyKxJAg zWt;s{>ew<+c6!=2}n*Zw;ghi4+Ul7h} z2ti&^AjzE7wiGPMS7ywgFD($1mmy*6w^|1V++pAZ!JL&PvkN3FQEkj$>UM__9t#&V z){1ZlQ!1_hupuf$0s*>S`7e9X`M-KYSZMt1Ge`ewA_i~$Hc!0rp#RZ|DK2#~IZ2c0 z_BPLan}viCIgV#E>43pizBOHLkQnOK)yzwq?O9YaVMa(`kMi7f)U*PMcv91QIpEfa zzln1?Czv>xr78bJD>r0!cOGTlach@*SMi>6b%G@rZReF^Qe^Wlh_rs>c%_TI{iIFn z8+QRZ5wqcxHg|I(KJ}F{-mdHI!M_cEZVx{7v@+X@6qwYbv0BgI8%-8_m^<`B=~g!k zp*zRj@_B9Z2;7xXEFcCzd|g}cV-Ac0JT;%&`Rk>hYRfiuq9-#7P05rtx8g%(YV3Qjx4t~m<;qI z^-;>h)iyiMQn_%qSF4qq4_b%wjJ~*oo~J;hL0h?kEH3Oa5+2}7wl*|z$IO;)hA z(iroH9}v>D{w{_%|Jj>>$J6c_JI-^o-r7T(J{vU@ZGIcW4*s7rPlu1F#lu?B-sFw7C0n~84J%#R6KB;Fl3nrtreTau{%Kr12Mh{cd;AEwiKDR8Q!Sp|g zi?VrnC%xm!7@Z@!c*}0$d@waGYjgIseEBr1EqSv?vv9Z7KPf0L9L`e;r%A05@9AW1 zy5GJ=K^7P69@qQ@Z)@2X2a4;jq|IaYT%+>or0b7llWpXm2Z}=;ev^I%!^Td3fwu9? zhOf;2@|bLKh~*T2ZCXg?8Tf%F$)+^ybt}t|`$}_kQmK@r08!IsetRavIcXyJMZ;OP`w!M3#(P^kmn=ShXzv z<`!r309TuRyhf?=G#*D=V-E2JumarwX!^*ZQbx--F_CDIU2Pj>17xf|fcoNCHEL$G z+XPd~pbP(i8>=T?RJRmNBuyqoUO8b6vhNN9P6Z1$rbyIIlQzLXBS3oGBl_qphF8uk zwjxO>-5JeOkX4I$C{LVQv{pL~XY6y?_*J9IL>BK<#Uv8#fYqTKqiiXj;4`f8dASx7 zP4pKS+b;96`rTprcwc7!com+smih0oXX@std!(1!RX&Hxjks5?<8|(>9Bh@D-E0rG7tgFD{EEDp5fn}4hTIxy*^fyExU*?v0S#_+b{WN{?Pka;doK8-S^P- z;%8?gc&5(5niM#hx9~@54&PdLIlpVQT5tl< z1`!5L>ep&=A)n3uy2HAnwWZ4JzqRP5KKpN#M~t-Jif=HtgL6b^g_q4dcw$|xV<+@K zIXCfbh5XXyFGg-r9|Ap>i;>!Hpn?C~fhf~5y;$&XIQkqmc_yafL9DfonCu_r6W_B{ z==o@6#aM|&%(>e@xTW~E0r0?V6QO5Qf38}t+;pD8jLVkdC*~Qx>BsGa*@v5`WpNHJ z_5rXHPNOe(`X#34JW|B&JjDI4%Vyi1Q8L?yx{8l&Hb(amR|gq!oV0S|Z58|t=TnUI z`@0Z!uU6YndVHMeS;`6t>M7nPdlSq#-nNRn2c0Y11bU>M?hu2(%~329D+m1TJ5a2k zJSlU4N<|{B7$2g_+v` zM`%#HHeS^3^XLuUo#=l-=`qwX|zhp&vJa@K& z@sr6xZye<)0rYm#@Uzi@^5GvNR>leY@KQrytvtt4W?g4Ppt{|zQIamR3rXM{o3!;H z$AG&wv$+y$I>=aXxJNwMrZyh&Xn#qwG_ZZM{%Y0naZ%kt3bvPiAh#Uj3Wu5 zHj>%eu>2CMwLYL}{5!sy=R|X9CMl2-`b&K0%yE(D3N@`}hjg!JFd9WEgC=aE#y;9AH+h=-~ zqm=dIY0JPUX#@468gkr1za4pP&R=k^jfFJnlX1|L^Vay|Bhe}~iw9;Of(+rXpzP9jwNDd0rD%~`GDdcK4iknYmG0B5# zx_EN1g?5y2Fq8-*Z@$evxh9p%tYDgLLGvY(Fd^$rRwvz!r>6Iz#iKm0R-WZ-fxJF; z`-eyF7(0EA?pelB-lioBXq3wXhn;wzh0#Vwacosi7aipxYb~>%@jWYgB-wgp=jn?z z&rYBAZ)6^SUeZhT!(Gzq`kxkmwezyd^Q8X0nN6a3Rhwg3yp;aoZ|OHbJfG6HZHnYN z9p<~^DgL%_&bw>%@DsJt@Vq5NSbDCs$9fQC)+Xz4sAx#jaTSmC`T(DUt9=;aT4Z^v z$##pWwKnc>vGQdy;dwQ^$tpUt&dIIvw793jVU$M)53D2?vI?ypF^^orQ*%}_f0Bu2 zf0OWy*24RV%q`f{;Ze$VGU#>up@~N zL$;anuoUqys~P$)9%=;*@O2TfGt`OIBh}+jK(778{Qmy0O$=za=SNB(;38F8Gr_Nwfe+#aIsG!zkKRR@shgE13gam@!Q$)pAN{_DouD48RkA;*@{k|t$yZsv!?DU~ zcfH{T{SH9zm7 zCL+;)ltRE>SL#=2T1EfGG5@GeF>v`pFtsYE%44eZ_BHLY2w#qIbXHlGooWMxT9N=hV8xghfsq zi2!k3j)3lM6P7Q$^lLIAz;cIAbIQw}wWL$o*x}Mqf>-fd>R! z%RS)5#?{BVshATbqudL1jc8mEYZ}BQUfEt8qd}%|n>@UxfU{os%))ZGf8KF=8fJ$b zkIRkFVu>_-GngeNLt`(>qhK#33SH~>ip=Ew4M3bbA2xoXkxeJr0wj+0<(Gy*1D0^2w|lPvVarZ^uy@O#UdzW4lgk z@u_q^_Bjak%R*g~BN~Ag&U^7UNKZ=BWLWg_$@1J^?vw}Xw})z4?cYxlBqtg(r&+1r zVM5{jr{8D7NAZjgZbr-Xv!xIuUq^|R#m~uQV12TL6MoAV$GBtyfz5om zK-?v38o*ltFb&}4RqN#wT6pCw`Qz40ep!>cz^A@-vKHrC%NoK#*gSvu^Z>kiS@`F2 zl#r3`wjTE@T2VqTZ7vX!u^#7-P&&=h5~~P})Bd$8L;ZxGal5~*!j;QV3aa64^D}R? z<~{GlGYu^BN!PWhMF_(O$u+H~lS7TX>C^fqX{6iQhZos-@;jN$b{BQ>jM=lARt`o# zqA&D{W*B)0n0ER5vZ&-u>)&uT8_#FwU$eKoIZe!7PNu9spMRhe>E-AByj`61YBNg9 z!+IfWT=VrXHd*IgA#CNi4Uab3RzJP|b$E0!x>!asG{>@rnf)eO_*n$`G?o!}lz?n# zw%XF0!%SuJ?PV$-g8hr%N@J_EW^A~N4?RhnH1$LAd?gKB)=*@M!=d~oL_5Bg+1Vrtp&YLRRg}Gwe;{AJ95ohT__s1lbar zmspC++Ttqd^?D4hvoeq2(o9E_{pC?<{XDq5qBz>Ini5l^sOiTy>oG0C3gfYpeFpC` z9C9d%XO#{UFSe5&G)Q8X4TJ%bTInk34sUJ`u-D3ZW_BNdy{LGfT?@&|ELs~E74y+* zX(T+my^GNL$}C!zayH{o_pY8H#CE9~3cre4XQLU_a8AR#5lY{eDzEFN# z)X45DHyc!C7G=ekKP3M$=W_DVS}yU)GPB=BQrMT3J|oq0+4AGp zr+$BI;nzohpI=38*~e%S?bntq1j0b52J65%5T3J@-ak|K8E?RJDKG_t5$%bQ(fK>$ z;)*7Q60^A^UU=8)Km*Wjs)Fpj$tv&|alzDjG@b_M`greC>XoUD)&)af=gGB~2mpdc zN^ybv@#C)r1&1<=l(=L>dO030HM>OXIeTsXt;KP{?m}8AfZ+N+uxi{AdeRII3uFCK z=6`DmojHpeYBjLQncYLI6`*00i{f z&~#}%+nR-F!9D9SmVk%*Lax6p1!-W(1*f*m1Ndy`U~g&Gy)~Q#3=9U`CB*D%8>P~T z*^F_QN)RZE{sC?RP++j_Pr_cv304*qI9)0z!0TbRA$MG$1dzF7yk_C=6nGZd!l8vX z1qzx$LRMa=tvotQzpCl`SeRETMVuJ~sf;2J+A@Jrkiua7z8(-r4x9iZ#SR97$tadM zp%w&AYCMQsU0=GFAypns(vY$cfJ2_ZYrJi)g}()s_@1WFG8?lbd1f;Jy2TCvZ~mjR zha;8oN_z{>3^v2dVDYywA6|HekzYTP5ELd^sV`|)Ci4aJWWJPHxEW+`xmLPNuh0Q) zK}iy^L_>L63Uo`Zjrf~;RNEW}$7)OG3e%_mEsFwu-wT>mDzh1gLq^JTu%V!u>s#zy z@Ys&ku&?oL`nA}AN;%pV9wf;r<2HS2Q(~%&4z2P4<^B%EmWc3%$?2%(>}++s=3)87 zBjxpuVDiA@7Oc1A4k(g)yrU#!vjtE7G<*>Jy~ocEk=6~*O>F)rR>K+p3v98N=Yhbn-3i2 zKiOId#(C4t{CsheCWrI1`CMh*Si+NM=B2YbWgPS6ILP90$%zDvCnLekx$HvF9E`FWtM|x*7QtC7z{n-|8etNOAf74#lYhi6h*LL~BA=5LrGdr&% zyi0%`jHuH4l~>vhK8GSA4!3=t9M5j&)k`(p^VgfT`!{!cWMJu1t%L2>=A7R?N7wO`{s`aO90jnC)Qo(Jy;*s~ofH_1oo<{$n1`LC0#eMFChwm0H6WMtH~&*7!q?ST|vfB{O)<&qZne(QH{Jm1;Weto_` zwGXb$kP8HNl7Vqm7KZGFGP<1f_g+V*^s60#5*`aCz@o<8mO_|BwLlJ}*`Mwl!Qxo*cwhs2N(H(7#u#%g7V+b@$F|vGUslt`LP*){ zIzF_6>3`1D_SxSYAii_xd+8w|fIa8xEj8}EI+LR}6XCtRoRA(2sn)rE$?QvI%$b(I z%K9xhUaM?8= zgMX*um2pn20r~IqeA>=i})E>ZP4|!?305X8`?`0aT+Oc&t;JJ-SE0P%9d zA;}|(P4B<)j#e7~&+wyn!T()BQBdeZi4@+Dv~7Y*ebXO=BDeH;8&L7VqZw0e<1`Kg zrP!2FD#xTdO5wDs(qZ4WTqiWxXsuVn3FCT?lA@ssKnf3r#`WWT@W1`CX37Rudo4w7 zum_Jkp=j*kCxT7K<{`-wsiM@GW)(nN$)fWC+0fR={YdcA@7{A?9^++pH!XLZnJ|cK z+d)KY_TDh<(j4Mfxi^_zMftw(=*Yr^RNH9x=1l|YU+Hnkwco7$dtmkZG?yawIjGXl z-j%V}X-ZyYTvB$(UD*!oKG}R9#O%yt34d?Qbf>iOUKZ=)g7?bN{mj5$P)Z|Dti8`{ zcdAkkpcD$v)`w=OF!{Hp_#*?J6l|oWqN-~A< z$1zG6XJCSH6CmTckRqyOfX%V-`)M^DCmi`}t>qUNK2Q*$9Svh;?J2BUX!@fEhj8H$UcmqWg!oj}goMZQ~ z(Ace%QBEke*)ph_J9OV@%*2~n8O4pP6>EvBl-CQwX3%Dv@`R8FM{5a5=O^7^iD;2} zuPKk$*?+B;bS!+Fcit;2B@@}nZG!|d%xX)Kd*QLqDvH`mKl&+*?6KE^Ws&|3)8AQX z)wb0EHz*{V{ZbO`;QyR3Wv@NHk8~BrG@54>zNw#Hux;T8gL~9lz9A!Z* z>;mm8Z?tW^q;E36xW|~$dRRq>VKf-^z&MHCKv_;cpZy3fk8jio>Lc@hqH&QdNuDDFDHF~a#$c$0q&u_~4+og;57aclwC ztoJLCjpxD(X=;tjg}Mdv1(#06ue&{=l#w@H+b!$2mh3R?Yjk;4*%$ayp@`))dS{LE z|J3LEc4)BY>?GfK6jOk<;1UETITg!3hv zdLTW%JKtIp*DlMtt85B5=1?6^ooHGCmf9I6_b*V$7TW9(OZs_PG#GCVix2$qyEb!= zL*^dTm;_!d&&7hdlORrCdC{HXC&rE&=dwH*Z5Y5L0;&RW)PWuv!&l&MRDCY{(46cC zQADXnsOkF~b2WBTGBp=O?^?}0)w+{Pdc2y+hSm3YHp9*ss`ZOM_FET8C!hH@i! z8!oo1(uN^zI@CiDH+Tz#% z;RoE{WunQb>ni9<${1%(EA&r= z;T>cW+q3#=+f@z}Lr(3pWSUpI?iSU+1kEm0{KBCjyTOUU77GLMW%6tlp-K)Im$@nj z=M|c0R!z5adzfmr+A_3+2Rje)NDJ{9uzu`5wm6)>MEs<~mHu)eoUunhRJSFr;Ok}T*vU<709I{s|Ag59Vc%!}&lzNT`gKA8@ zY)I_{h6Aise6KB;>MDezyveWP++#0$Kj2wmt=$xs_0@tovdZs6tXnQQr&#cDssKs< zzO(&NG+mYa7_$uh(UkMDS+C%VyPp$FI;_Px5ntp?jGCpH!Ha{--A^~yhY3RXZCBVZ zsuAF{KBb6UH7+z6sS_u>%Jws!yJip;ugfIC2jmP&rgiwej9wP6`XNfH&0G`^oeYk+ zth7I`jv61%EGQ_!SFX~SI8+}3AW8>)ZCU42Ia;knqfXOFdbVG?NIcINk@11M=&<~m~TA53VY;TPS0tYL_ zgo(t>H!i+QsNn`<1XJErdSzA`P`SO*h@6I~+KkgD>tLFR^`*7dfw_6_jz6<3>*{nR z=2rc=_TB7Z+{Xi!EN^2~_^t}wepPqYSHlnX^wtco|D@Z<^0IjOJp7V zE8F`FfpdmX-VaXwRHlNN`XiRpgbN4Na$BmedS0F1UZrv_6xWr(88;k$QsT>nCO~wF zp8cwxbntoLkkd%AGrhNLeZ4Of+e+n`rH3ml{>3?OcX~(OfKlb zzAdxiWNOBNx`p1M>LS!a(Ht>0=TQMM*!H++pXHcgT%L>EfE~?{<3_9JkDs$wm5)sE z;k5xZ;hR+*3IonBq6lpcUXCc0av9@p&VgtZ7X4y<&Tf__2!$9@8^T!Q9WrL(XME|ETEkgX(;q0Rbu_*TSrN$zQ(}g!GT+3%EFI0_YF0mbRC1BQ@H98>6H{GVP zE_Qnp60kk-!(}sih60+m!3xhR!846S4V~Bl)-sAMp-4b{&qTdGRUX=)Qb)0OGVjFp zxPjfJa&O;7KWda!Etxd86s>YMMGe}nOE59J@)$6gR1p_hHcisheu}nms3%!#Nq{=& zI-ACHxEH`VB<2&!w97nuYrNY>d%DWK-DlUA=N|sm*Sq-oD`RfEF=?%E^M&QCXlZG2 zvc0rx&#gVXMZCM?2zs!(YKT_@2z26$1qn&@jfF>spp~W( zJgN2%Y2BDr29F`RQKOF!#)7Ou_9=>7wZba5wJH%DpZa4fVh@xWqpj|<#<9cqu_Li}G&Zy{YSB*if&KZKRZ^iu~LJS%|2iYfkZ(i>zV7 z=aErYl&np{W$sla(TKFMahjhza`y@MsUvprBsl&2xqKVbW_!J*&wmhhT3D)Z9*FRw z_fBrR2xkwoH+|6Cs^N$DZn?uKPDp0|mGs_|yx*>7FJa?uAHG0}#LbM|Y8>0BU&zKf zWN9QDbLk|~HhDUVb)TZUj@ zssAgR66oC{2@~V*$e0wItwHQdGCD>-f7=>Z+7mN@s^y63tFs~|B4c85YzKpnOoV)TkGf<5I?d-@!K&Hv;MpwsAGCTCwpOe zdk}Bb&pKgH9pmH0L8B42VZ>*zlVrlfVk-RY@G21VVn5^@??6Pg_W(o z9ca4DKmZ+x)QXsyg_(|l5lGC;%1Xz=3Ls_%FwikGvLb+HEMR4!V`2$v%RtQdC;`wU zK@tT0Z*S{h@XIeysgQ%Ep1p~cB{AbKH|XC3dmQUO9~dJ$kPZN3A_f51=okR3!~h@* zXn@3w>;O7OCbs|0xPH-#e~;@?=D&^W7d`v!uF%Un=-U6(yq|hNO#jYAAH@Fks6+H3 z1|~+v_K&&*(h88q*;-pY5{3Pg1H$jM<2S)e>e!hPGybZid?xmGG6uH%Rug88%F(4C2?0?5T_NcP|;v3r^@&W_B+CE>&6Rr8l=rn%-hlF{C%b@-A=1B-on(%~z zCloxP;0Xm!D0o7_6AGSC@PvXV6g;8e2?b9mctXJw3Z78#gn}m&JfYwT1y3mWhbZt` z^a5W_0|Wo7x$euGHRWLC=I+6a(QNsC^6?J@a+I{j|esbS_LctRXo>1_A69rxm&0yjzf4k24$1yK| zG1mMq);WyKY>fYGor8q(w9a`lQT{^{<u|J(g_O01)T{4{pJ zU;}Hz5c(@((ldM)c;XQb5iBU#K+z8}5dOYo?**WRFwrQL^c9-Hg#%vc31TApc2hWWRJwXR>5@^V8>~Ttf@mVx`US=4=w-457z1X4R^KLBx_KazAST{H z;0Xj6Ty#78H(TW3D|X{lFsCm@Ye7(fqPkzuCgV-kx4I3lkIUt+bQ!6m+a#AiI!O$k zRXqE|fb*f)DpnAjRK+5}IAXu>`ToAj#D?)z)AZsC5BWQ;ZkHRyW3s)$)VCq2DvRcO z1@sNrVCN*NNrdH%F^XUn7BIZ)%LUSh#9$}TU=<6=r!V}?H6zAInf<_zZ`3Gie$OU3B-wz_Fkg2GERZN z_c65w8}o7*f|BwETEnPAy=z9YMtt@`m>0pnMVtYA!OH~B`v?^)<859zb{0wk-vlaw zDx5R_TNyS?$PWI%aMVcNt0A%+Tq>WubbcAGv)A_cb#NL!*PmgBhygHn;O@R?@erdr zNK;@{AErwZeqR!B!b*n4X`WpctHI_*u5QIyCO874@zZLJg5&LmgB%u8h9fu@ z;0sqK0Y`gj7V#*F{J6`%lnY@7KJv-y*#ttI?%%dACbONV8w! z^NnUZkJMC1R=k-pm|-9kX3e@8joR)wBid>>gEt^GPy=OwdA^RnUfwGQ)5@TI$t;JL z9TF8%9};#7*r**`9h?Ogn`l0Kql~$tvZQj0c@<+A10EBWC!uIHjyax^XOSm8#$ZZj zs$)8BdNWR!A3FGT&@pu|MGNq-b{nu$QWxk_b8Y&gZHH?o3O^CQ5g!j<5kC&l$%2l(osj&qG?YhB=!DnV0#$}{OgZkf(WSJa4H!OFoY*z?$0H2XC2w7WD!DwHbF$`%znCD&~; z?TKa@dhT8RrmK4810XiN%EDaQ#rIA7?i`64CG*(zQuTx9$mg$a$Zi;6xdNO58jvrh z?B7$=`?`;#?QSjC3>=57!jij^myU{lT})9Kpd3IN$V7aGbA&TSi)%YEzMo_2i8-6dP0l{1!qMln|5> zEH@$(JUX-kR9g#pOT9M{{fHKc`WQ9@-!1=pKTdd-XBt@7cDQsjfC92T=Nd&P4<|<` zT3tZ_{`Pv2uR`*sARuAZy)nm)|W^60hbH5K3g=@8_*igM7AR=5ueF(&8&0Uu$I@79k zT!)&Bst>q{-0Y;@3_aGkG`Nj`it{b=9Ttdd*9g=TEfU2NU4@W-Te;*=rgh@AmKz-& zok_`@JDl5Z;#+Z9G0I1(6I4R2!OTV8K;H()WZlaH!LqSosD~?Is8NS`%2J?H0fOA?xKqOyQ}%WbKm`j?DOm!$EEjhj&t+d zb*IV+x+`)dLdLA{two2<+;TzN;BLlFU6YZgmZ!kJ z$Z^D=u%B>tS8JHVILFu|YYuBPur)NYvvk#_%j$0F2fr&u{u+e`N2m99&o z!_;S-)6PNedE4Z7Y3Ef#szIvh6LS-RRarn2R|(g}?GK|Vgad@MJV_63XCdbaiRHaU z;)4+bSjkE3X^tKze4T#B!GSmdZ{FE+*Hx^Iq!g7DEqwQiE7m-&wauMvxVcq~%Qq@w z*WhqZac|i7zYCpsQJ)&CwdY~7U3qBHux(v_7rR>csS((gEjIPH)?7C5<8l{7A0x`o&!=N&pilgBu_{Nb@f+RD&js{v zYvR8%`q2L;5)vURTMN)S7WDgP3(#50zsPS87=NW1;rq#S!wh0bVPXf7r7$oPGqW>* zXjz19tsJa>VUQuFSFqKww6oR$(dg)bmhSxW#7w_1($I_kN?#&QY^Y;yXYiAv=GR3u zEBha;QPc`>3KR+qKn4YdGQc|q0E1i!K#4+35$;{L{1A!=t(X)o1*K%4EJZIA6{IKu zSUQ~yl1OlAwilmmk$0m}QK`2$_q)%0#9+wi7|MSYOGKg=M}v$7GhFaZ9)6F-X_0|2PR0A!M90J19l zC-L_@ieCgxCM?%0@K^B%{!9F&7+QZL{@-);{BOk%AZGfFYUg+2|9MM(yR-jE)BixX z!^i;Iz5PnJ!w%Z({g-SzziIL>TUMt30o~63h-~LqFY)_atAF4ne#F2K#Jr30SMmOo z%RiC04pLcd~%mao|S;Aj+SlXxeA?&xn zQc9GeW;Vm}@3vS*E7NPxe3uK#c~%CI8&E?0Oe^HYNB{)C1XVCgDI5(&xr|t~!`J!j z@oBDygsXd_&aX3Z33r1R?oDy~Z4jSO{{u+7mUZeA#YieI|6BrD{vRQjRC6IN!fZ zI(k>dXZP{lF<{Xue1^M|BJY~>9o3?d>QX}MkhE(R%~u$~OZ&p_*=)c-wmz8Yr zQeHranFpm8of{RrJzg1c1o81C@3g_r`{x;wI&#}}p~rb&z@7>nW%?zRYfF(Oif&yi zWya_G640@u=)`|4wkDzch7zjEy={Q$x&b+Fq6;-LLa*{AK3=OLMxKzCp>1!aecMEX zlq_D@MM`O2!}McdT%txhc1>_7gF(jIq7&CBaF|BSq_TjxE!~YNfc66L+h|JWMLaO# zWljDhp6dXEr+C$9{1#(VbL>7CSGE_ct2IVm_rRS0UA#3#VzV!juAzEm(r5kE_cGH$ zG6O!E>Kn;qx|&Px6>5b(lQ0~#$o2xg$}lRK>;)mRy_SWt382O3O%1l>d?*8-F;h7p zgh8muQu9w@%wc86f~p;%#0Wsuz0kdm{sb{a2w(d6Q=ZL>2r!U_fof@6P}hk;)#nJ& zE}-fl@%Q~XSd;9&MHGZJ1d2+*(UkEWv4PQH#)vwEjM}|mdqRF)?L`!8y>$2@+v;OX z7tCTN*<|;mT<-M-q!A~UFJUA~*S+NUcX8;nHBFO|P`dCxQVq~GHl_@j(j1};e1?&b zkroy9w+B47Ye1g6`pW)r){k5j$q+CmCo6**Gjx;UkJXM zeJV1G_5jODRRi>R)%Q4n(|0X_@4_MVG2UQn-Czu)qSh(JcOY~{;ZIQ`;rO9`E~#+H zh#C5%M}{gU0<@#c(i=G>cujpgx&$^XQ4u`_$Bn|xi(#SxW1q4+l0dpGk%3>f+OS=` z7$<_8kew6sQf~lOpLY5=zU#~uz&b0QTs!Czf1a8@sV|tC%T$8Y`EY|9r)V=gUl^MU z%_D76X|Y{SQpKrC3lWs~s+uM`O67aO?#Vo5jqC2d3zl>>F_pW;gs$n^u-J#|}FdiZmlWttq^x>V0ihJr%xYx{uqc(LdU?U48c zy8ygZ&WSf>`{k3@`;{K9gFJTUR)s%Y-6pNlx-{wAtRK`N=)mJXh&Piipx6ncRcH(CmfV1vji4hH3I?rV4}MZd_jztJF52Y->)?otv8VJ4wNH z*TQzt54(C3OIc-+Rx|shN+9-)ddmjdJP%Tszn{_~N^T)>;E_fi;}I+(pw&wC#M0$b zihAN?W%;HJR;SXygDi+BkVW`KnOLjp&1x|~fu>NR9)siTGYiZs)imegY?Cf5Q`F%L zBQ#8?t;@CdVSMTmwULc)d2cfm%o}E-5AzhH5~&eB5OWb&%0nYn6GhNktP|h~A zfVF&x$(fSNPMZEotu&tn^@5H(qbvFNSiLarbjQw5+cSG3X&hqnQ1V!W@Wqu=+5M5D zT5Z1f!MPEBn~#flbSC!R&`Ca??3DW4d##c|1TiV2e9pO;+=DJLUM-Kwxed3>#4uO- zX2lqK=`bZ`!rcPd1l1BNf+X3~mPT)(Ssy}0HCvY~+bH+M+dLpsh9fmyDgCZUY?Pui zoKTh^)JeC)USwfwD(t>}RTtCUBd|=zQrv%~WlZfQp*O z5MODr(k1eV!1wGq-c1?JU>i_CudXn$GhS45-~g&^@A zg_rXFx$j2!)Ik$Wc!-KQE1>vTIMOYo4Pey1e6MhYnYL!le@gXrN3@Gg*-n7-AS_l2 zZF~(KVPsLyKyOd5G(>Dp7$|67F8;CMq0&64Fwn3RzBneN^d(Tc-AP}1E|65UgKUo8 zb>`eXN_fCx1nd>CeMF-0c-+@E7Wcd2`lc5~O z&4Syr*LrNizRlUjQhUL4{J4L{+i+GiBiQhXqp$D3EnR?yiG39f#&?FND zl^Uj=b&NH1XW(Fe3M{;)A9sLt(kaOaD%zClytK*{d#=^Ya~8Sjq+}0v=WJ&KrxBnQ z*)LiOy@T|uV57yJJBV?%0H1IE{xx^dV1~aodkuXp1(2r79InzkMIF;9(@>kMMvoIS zY0IPLql45lBu=BT#-5>NY^@fl&Y6Si=Sr#8&v)0tRm5rJ(tBsi>}1Q!+4%*j^F!RX z>@A+d&UZsNNm&sY(k)Pqb0e=ONCY7#Tp8qYOrM%KuyxF%Lx6{pGuREgqqcPRy%2Zs zb0OQ^kktroayX09)H+kPA}1vVv4MP3ra z*4QcCr~YmJvBX19PJ*pxV&x1!ARaRmPs*tMQ<~n=I$0I=*GaaH0YS)lyr@==h7g~X zaUmizx>r0mk_)D_3fG)BmXdi+}9VR`8HJ*bI%3a zJ|5mwmIp>;uu7JCyUeIxkf-yAr!Ee+Y^!>%*m$xaH&MY0wUg#@jo>A%A7yu;(HUlm z9jhGRkDrEIM1a}!uE0FlYKFEwsLfu`84eXAZ@$Chb|qo4*X=a8-LO5gL_iA61bAHP zblKeo`C#OWt(;0dESypzqP=r&P!HIvmag5EIDqCiNaXz9gF?lfWy`2G&P*AgCBM>9`%)3lil04KpOCibQQ`CrHnjoPD>RpakvVJ3#=ypto0YU2ecsoeWSrWLfhpmFy zajZxLY51|_y>a!tpXmyuq%CLH1mKonE-Qb-d?yAjq%Z?b-$B{_AsY_kh+EIsIYWM$ z+6f19o`iJ2TkNZLL-zM&?hK?=j{;1@Zk5-J4i6OSw z&xYfX`Nbkut)=lJ8P-IIMD~y%{rt#|+2Zo(Dn5`Te_?BK3`2nR^8*%Vy6JrzhlsFF zJZ}>zmDrhKf!Nr z_D#&)Fgj63wSW=6nifr?7QHs)HMf0rhIr>S_wd_>Km(Gl~;i|gOC()g!i8?TG2_gpG#yD?0T%F5EzKl4}p97CgkISJzr zYd?>K)$#R14s@dETftIUZ71GI*{^6ixA<_XB?&~RvVCyKC?ej*dgArm>C`SeX->8_ z&@wA%ePEVt?5N?QUC z1o@6%u<1jI$1SlFQ23U=&; zq%Vn31&io|e&0(N7%GX;)D@2{mF}$j=^~EKE>YRH--V2&Y}7CTjFAo0fV2;Bk_ZTz z=Zy22>d`P z$nS50(%bvt7-DC+k?o-U7a5@6FOCZB9Kw~^P^~NZU}!nYc!sR+FFVQ7RI(NDbnf%Q zy33)aVpR)-hrZ@(hgGoO*W52Z7C=YMM>R~`n|QH$^Rm^4s!rnJM_yG}tHRlMhq(P< zXCaylB~Gixy-a+cj+m;BSdi88a*I2JDig zajTjnRI;|~S9NEHuh@qil475KUmkQjZo_s$W0CpZrYH>EsdM2F`W1OQE({vMy-~qI zyH%c7-g#i}p3~|&>v)w+BH_p4VIiUYMCZZU>!~op8hKl8Y`1tjtDwca;E(=}pEU4* zy`sJpdpLsjYGk`+PTSX_7eizN9S%K6huoJc4Qh2|81m#|xaA9}uCRLf`5!-(w_Po` zG~6W!9}`~}LBDdm;XZlW1cNDlzam~97Vp6?s|^_9fm_Uf6GnptQRdb*W#3f&R_k?3 zF@{}`q^&w(fdHjwO2DRSGFZvxe$yl~ft=6P21D!=PxBxGBa{1FqV+-n74P%z?=}9} zsp<=(a~BhUGVG45V?w*wq~PyrY-YUjh_WPw%u%0IuxY?qEynC_TQv;!mU5!k1P4uz5F+-?PduU_|4lY~K43amhq|W^436X73g-cY~Vl3TUcIn6+o(nb^%3IYy z;YnrOOYnR~^k!{1wYpLit#Oisr&BjEsc7!#TbsvCPM+*!haf3xc`Qz5U6W=`OAD5I z4@Z9)L9#TyYF!dD-uM)@v`TYwldiee=ogx1yHBJkYrUQ3m6;{;^*A*Yc~_q&-aCyW zkFgK<9QW^BA0WO0F9Ibj{3xlR!{UXRIvgC9mtRlc4dqm2qAX^)BbE=ZZ~KjL#z|GX zGR?FpXV6BxSdIe<>)R?Dy-7BLN8Wy${yA-f#6FzDQ4wrX#tmNoUe2|75Oadq9Kv22 zeUyfX1jJq#jsdnggI;NIE9V9+S7EIC!nSUL-nh{)vndU{0`9hmA)S(f@*r!H*fIlY zJ@8{dhNE`)@gI&`bqHMBH828=OXz2h>9PH|seA1i5oTo6P( zFg9JqvJBD#grc@u+&j#Q70w3mwpqPS;J^y&JT`Ms?eD6kY}^6>$W}C(#cjgo$+zO+ z5b8{!+#L*-3*@ZW`oU@Suwu2+=-> z7g}pK{0sfLYzuRtTh2Y5-Al?~T-S7CETWL|Ho75>hhD-x=Fmo^p~&95gM#Oyn4t@s z@+CW-&W@*V=CFmD^;Bo2#l|bdQ_rS@zFf*m`jjm03ytQd?nQrFA22B!B4lJeCp_P4 z{O7fqKK?qjfAf%g1Lv+Qt2j$l5P*BjYjrJc?~`Z2k; zxgDzN%I;}NA6jSc7Y=Vcvz<0p%e$R7H7P=LJyYCHjp@2;D zAU|AE2x^-zeGJyCEGDG2iBp7Z5<19&xTt8>pCVSq*zzBf(+88mS|N!=2FiYGiXMD6vZ5 zm$s5`DQpX|mLz(Ta@OUM!enf4-gyZJ}_aXGH zt_e>9gis>}p^LIliOx}AK}Ws!rpt2y(la5K5NdPiShD5foTm$kBd&IHrAyOBu62gj zd4r|lU{l=safixMhy{Vwax7)>si4Ukx?eko26zCq;#!C+9=nn1#xT`Q@50OmBEr%LiZp*Gtk!|rrF4BZZfNa(juH+drypO9sQ^Vx5ga1f zEYvHtb#iQxYt9$G~=OJtJ zvzNF<@uFqnkP$tKAscT2-4gIv&IkbxoFA>g1*DO`y|&wjc!rx2T>9*#BLSBb6JIVD z;<@5EH)CpXc=)rIKcdX9T;1;J$@Rysx}yu2BE*cwzjwrodQ~|u1 z(4+pybQ2`sTVYtoxGf?41vaX!JwEoRhS>*9g}E?(Sb`rnRC|V*KYo?FQ;$TimiQ%} z0Mj7`PK*ORQo(Z_{OvTjGJ1Ih_JxwBhway9A#wW9m|@&T@i58y*<=Ptc*E@I?*#q3 z6o&MNNQ6$Ck@4DN3XsurxC$8Ux@RPnXtgY;ZR-~<3`0;GjZw@Ds*=H!TAn@z4ARGGg~vZ zYC$(J?=ig^O#Q^|XFW-QiQVQ7oxbE|5-5>ON~LeJWJscKL+bXKb754{YEOAySEIKWp2mvFS% zo>8w4qP!!S!Lg43v6-*bm!GX^*)8U(Ls&^Sw6GRJAhVd;Izj8XX7P z^U6f$u;;Pf@?(@Pn9Muck7Rxl#&RRB>-Y69rR*3$rF&09J2(m`EJMGEqc(`H*GI2(zx0AMRw#m0A zx46zGpRxEux22$UiWrIDu7}`vYIeeRvUKWoh6lw46$TZH6$J5S3m9bg(#0sne5c}~ z;?JAOJI}k%6V02>6IWo(1Lmd5HxystvofIH?CnoL-@|m-`_t)C|sycD7_OQ6eg4zAB9De*&(4wf=<3!y}iHy$XLvn zW|C(-V`>X9GKn>vFn%%dtzf!1JHy~BRzb(8YK~(5c!qZ^Ggw$Wx6ikR&-Q-QxJ z4yR?MWoQ*><$J0(eFtMLVP3*t!!H1^>06I36{aV=?2<9A=_?sNN?fMSv=MqM#Ft5x z2`Q8!WEHB?ncm6XnI9U4&%^Li;<@CCh??=bAaYIcMEcuHa9(5jBFr5KBAW1V>>@D__$fQ^!?C zIK;AOo0#J1P*%_BIQQ6g_byOP=gsYW7>6`dG_%^3*man&n1BRg1LZAx&CjRjDiuqA zRAEh9mRMA~8yH!|nO2V-w+mrfj)VRZD2itbg6Z|5@9wV>^xRbfsbb|E~G%aGBb#$mZO zLN@j7&h1hqb)+LC*_qZAORSE(m*ihMi8zTUc4y0^46P0Ir=zqLw3fA=`yu(d`VOM- zV7(3f7^F;S6KvMGZbwi98KD`0_-arnSC~}D;?p(z45KRc{F@ji7TcYf+zUN(JrYJ? zJy{yo_ZE9TY&SKvHj7=OE2}GJtDch9;uPY>(qodzDK)Ie1|!i~F`^fdgpun#7L{*?X$D!v+J{#?ex(}>BEF&#!TDJ{)BVpU?a_V z114(6iR0e4fkr%c~L( zeJlwLD)%a8<<|mU8ThhIY|7tMZaFz#xw@X`Cr>5MvlH3M+o7y6o-m!LlDvt0-ZSlX zdb@I)FGp^YU13&qIQPR2R$sR48lphk@U30?i(C1bmyY3{bcb{Z6nV5RT=WJD%ewoz zqBg>TdOc;4UD-O>T7%>pr<>I=DzUVbyPC}^C3-KbtOr`F1Sf*2uz%1XYke~c+=)yk z<%uc(J{kRRrLtpGh-HWsO#Q4ak8 zjosbe4;)jnar4E`b#EKf&GgPXHza{cN)|5FDiyWm@5T1LXuqh%S~yoKmi(Bh`fL$8 z+h6t0%JU}XGJlq%)e$g0JwCpdwNEp1wObUev9IOoIWJ=+r={^QY1wm7#0Bp<0CZvj z?6J((+Y%Y1xoIulwS86k=cdB7-hu3!pda+%mVY@_H&U`-vIs#G1#ifx` zBU5*HQXH;jXZNaHjlQJR+5qqOvh8Fy2Odz*+Y;VO-SnK^Z-!|cH4L3(UW5tLyJ(v4 z9Br|kM0H6E(>ZIJ*6lgeUIh)tOyoxur`BLQ?VtS!-{qNGTBw=A8+HC+c+x*xZ8*16 zM_V)RN`5hLS}*7ra6s!H>^=@z2+M*ZNi=b1cH4w(@BE(d5PAFHlKptoHS97h^pK#zva(2Jz=>Rc-#lzvxX&+6miW6#RQFc;4U z{)GUP2N-yiOWnWOp8b}`@efY1zeJJ!%PIEJPxFrsagVtk?f#Oz5fsS9%FYCGsN}bD z0Ae&#Ry#ewxP{OoZAk6khS=8XI34El@X5x?&oe$cFa9d9YHA3ml({51ulw5`5@?c*o}4D_t@|E9sO9!c^# z7S`ql2q2c1za&w#{PzbzIT#=FD*l#1@#mO96uI&yE{{DkG6Pv2tAFvwMPLOv1par9 z1naFWXx?C8kSz;Q2fV15f}f*rlwrbVRs5|d8FRS3cQ6$;wQru~iOXpC>`>=42Jb5= z@Cg1;Q@GH*q0SSQuvp+-tkF1|4BSdzxOf*dC=-R=z%na!a_$+ zTAuhfjbmh_0}`uK@Hv>6Kl+IaGXh!EDT!qrbZqTih(Y;Bf2J~ZvZn;8yRCuFV^&Q8 zP>3S}g}@so1`ufwJ2L|VGstz5L6w1l9P|TfCuybs*o62$H~BX}oNNsY5g0&z;s^}? zdJzLzSeRLe4T*m#V`O7v0V(_Ai`eqlG5{L`BgmcR4`rZ#9{qa%P{zo{&hqDWpsbxh z5G?=Dj){ex86>PflraO@LFCYXEMsJ61f>D}a~bnr#sbP%3Isv-kNp7{|I#0T4FCYS zIsc&@fbFl>U}j)q{_|LvnOGhZy8hv_pfR(7o@#$AV`T#Q&HuTKne{K9Wd;6aZp;8C z=0D2{z{(DCDgSeStSo<-FX$fqwTu<`=X=S_&d&Jf{s17c{J9 Date: Thu, 30 Sep 2021 14:19:15 +0800 Subject: [PATCH 212/392] fix: status menu cause memory leaking issue --- .../Section/Status/StatusSection.swift | 9 +- .../UserProvider/UserProviderFacade.swift | 91 +++++++++++++++---- .../HashtagTimelineViewModel+Diffable.swift | 6 -- .../HomeTimelineViewModel+Diffable.swift | 6 -- .../NotificationViewController.swift | 4 + .../Favorite/FavoriteViewModel+Diffable.swift | 8 +- .../Scene/Profile/ProfileViewController.swift | 2 +- .../UserTimelineViewModel+Diffable.swift | 6 -- .../PublicTimelineViewModel+Diffable.swift | 6 -- .../Search/Search/SearchViewController.swift | 4 + .../TableviewCell/StatusTableViewCell.swift | 4 + .../Thread/ThreadViewModel+Diffable.swift | 6 -- 12 files changed, 89 insertions(+), 63 deletions(-) diff --git a/Mastodon/Diffiable/Section/Status/StatusSection.swift b/Mastodon/Diffiable/Section/Status/StatusSection.swift index f16311b6a..fe95c4c75 100644 --- a/Mastodon/Diffiable/Section/Status/StatusSection.swift +++ b/Mastodon/Diffiable/Section/Status/StatusSection.swift @@ -67,7 +67,6 @@ extension StatusSection { timelineContext: TimelineContext, dependency: NeedsDependency, managedObjectContext: NSManagedObjectContext, - timestampUpdatePublisher: AnyPublisher, statusTableViewCellDelegate: StatusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate?, threadReplyLoaderTableViewCellDelegate: ThreadReplyLoaderTableViewCellDelegate? @@ -363,7 +362,6 @@ extension StatusSection { } }() - if status.author.id == requestUserID || status.reblog?.author.id == requestUserID { // do not filter myself } else { @@ -473,9 +471,10 @@ extension StatusSection { .receive(on: RunLoop.main) .sink { _ in // do nothing - } receiveValue: { [weak cell, weak tableView] change in + } receiveValue: { [weak cell, weak tableView, weak dependency] change in guard let cell = cell else { return } guard let tableView = tableView else { return } + guard let dependency = dependency else { return } guard case .update(let object) = change.changeType, let status = object as? Status, !status.isDeleted else { return @@ -1072,7 +1071,7 @@ extension StatusSection { cell.statusView.actionToolbarContainer.reblogButton.isEnabled = false } } - + // set like let isLike = status.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false let favoriteCountTitle: String = { @@ -1107,7 +1106,7 @@ extension StatusSection { StatusSection.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status) }) .store(in: &cell.disposeBag) - self.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status) + setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status) } static func configureStatusAccessibilityLabel(cell: StatusTableViewCell) { diff --git a/Mastodon/Protocol/UserProvider/UserProviderFacade.swift b/Mastodon/Protocol/UserProvider/UserProviderFacade.swift index bf634b07b..47490c2d8 100644 --- a/Mastodon/Protocol/UserProvider/UserProviderFacade.swift +++ b/Mastodon/Protocol/UserProvider/UserProviderFacade.swift @@ -212,8 +212,17 @@ extension UserProviderFacade { let name = mastodonUser.displayNameWithFallback if let shareUser = shareUser { - let shareAction = UIAction(title: L10n.Common.Controls.Actions.shareUser(name), image: UIImage(systemName: "square.and.arrow.up"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in + let shareAction = UIAction( + title: L10n.Common.Controls.Actions.shareUser(name), + image: UIImage(systemName: "square.and.arrow.up"), + identifier: nil, + discoverabilityTitle: nil, + attributes: [], + state: .off + ) { [weak provider, weak sourceView, weak barButtonItem] _ in guard let provider = provider else { return } + guard let sourceView = sourceView else { return } + guard let barButtonItem = barButtonItem else { return } let activityViewController = createActivityViewControllerForMastodonUser(mastodonUser: shareUser, dependency: provider) provider.coordinator.present( scene: .activityViewController( @@ -229,8 +238,17 @@ extension UserProviderFacade { } if let shareStatus = shareStatus { - let shareAction = UIAction(title: L10n.Common.Controls.Actions.sharePost, image: UIImage(systemName: "square.and.arrow.up"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in + let shareAction = UIAction( + title: L10n.Common.Controls.Actions.sharePost, + image: UIImage(systemName: "square.and.arrow.up"), + identifier: nil, + discoverabilityTitle: nil, + attributes: [], + state: .off + ) { [weak provider, weak sourceView, weak barButtonItem] _ in guard let provider = provider else { return } + guard let sourceView = sourceView else { return } + guard let barButtonItem = barButtonItem else { return } let activityViewController = createActivityViewControllerForMastodonUser(status: shareStatus, dependency: provider) provider.coordinator.present( scene: .activityViewController( @@ -253,8 +271,9 @@ extension UserProviderFacade { discoverabilityTitle: isMuting ? nil : L10n.Common.Controls.Friendship.muteUser(name), attributes: isMuting ? [] : .destructive, state: .off - ) { [weak provider] _ in + ) { [weak provider, weak cell] _ in guard let provider = provider else { return } + guard let cell = cell else { return } UserProviderFacade.toggleUserMuteRelationship( provider: provider, @@ -283,8 +302,9 @@ extension UserProviderFacade { discoverabilityTitle: isBlocking ? nil : L10n.Common.Controls.Friendship.blockUser(name), attributes: isBlocking ? [] : .destructive, state: .off - ) { [weak provider] _ in + ) { [weak provider, weak cell] _ in guard let provider = provider else { return } + guard let cell = cell else { return } UserProviderFacade.toggleUserBlockRelationship( provider: provider, @@ -306,7 +326,14 @@ extension UserProviderFacade { } if !isMyself { - let reportAction = UIAction(title: L10n.Common.Controls.Actions.reportUser(name), image: UIImage(systemName: "flag"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in + let reportAction = UIAction( + title: L10n.Common.Controls.Actions.reportUser(name), + image: UIImage(systemName: "flag"), + identifier: nil, + discoverabilityTitle: nil, + attributes: [], + state: .off + ) { [weak provider] _ in guard let provider = provider else { return } guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return @@ -328,19 +355,37 @@ extension UserProviderFacade { if !isInSameDomain { if isDomainBlocking { - let unblockDomainAction = UIAction(title: L10n.Common.Controls.Actions.unblockDomain(mastodonUser.domainFromAcct), image: UIImage(systemName: "nosign"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in + let unblockDomainAction = UIAction( + title: L10n.Common.Controls.Actions.unblockDomain(mastodonUser.domainFromAcct), + image: UIImage(systemName: "nosign"), + identifier: nil, + discoverabilityTitle: nil, + attributes: [], + state: .off + ) { [weak provider, weak cell] _ in guard let provider = provider else { return } + guard let cell = cell else { return } provider.context.blockDomainService.unblockDomain(userProvider: provider, cell: cell) } children.append(unblockDomainAction) } else { - let blockDomainAction = UIAction(title: L10n.Common.Controls.Actions.blockDomain(mastodonUser.domainFromAcct), image: UIImage(systemName: "nosign"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak provider] _ in + let blockDomainAction = UIAction( + title: L10n.Common.Controls.Actions.blockDomain(mastodonUser.domainFromAcct), + image: UIImage(systemName: "nosign"), + identifier: nil, + discoverabilityTitle: nil, + attributes: [], + state: .off + ) { [weak provider, weak cell] _ in guard let provider = provider else { return } + guard let cell = cell else { return } + let alertController = UIAlertController(title: L10n.Common.Alerts.BlockDomain.title(mastodonUser.domainFromAcct), message: nil, preferredStyle: .alert) - let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in - } + let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in } alertController.addAction(cancelAction) - let blockDomainAction = UIAlertAction(title: L10n.Common.Alerts.BlockDomain.blockEntireDomain, style: .destructive) { _ in + let blockDomainAction = UIAlertAction(title: L10n.Common.Alerts.BlockDomain.blockEntireDomain, style: .destructive) { [weak provider, weak cell] _ in + guard let provider = provider else { return } + guard let cell = cell else { return } provider.context.blockDomainService.blockDomain(userProvider: provider, cell: cell) } alertController.addAction(blockDomainAction) @@ -351,19 +396,26 @@ extension UserProviderFacade { } if let status = shareStatus, isMyself { - let deleteAction = UIAction(title: L10n.Common.Controls.Actions.delete, image: UIImage(systemName: "delete.left"), identifier: nil, discoverabilityTitle: nil, attributes: [.destructive], state: .off) { - [weak provider] _ in + let deleteAction = UIAction( + title: L10n.Common.Controls.Actions.delete, + image: UIImage(systemName: "delete.left"), + identifier: nil, + discoverabilityTitle: nil, + attributes: [.destructive], + state: .off + ) { [weak provider] _ in guard let provider = provider else { return } - + let alertController = UIAlertController(title: L10n.Common.Alerts.DeletePost.title, message: nil, preferredStyle: .alert) - let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in - } + let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in } alertController.addAction(cancelAction) - let deleteAction = UIAlertAction(title: L10n.Common.Alerts.DeletePost.delete, style: .destructive) { _ in + let deleteAction = UIAlertAction(title: L10n.Common.Alerts.DeletePost.delete, style: .destructive) { [weak provider] _ in + guard let provider = provider else { return } guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return } - provider.context.apiService.deleteStatus(domain: activeMastodonAuthenticationBox.domain, - statusID: status.id, - authorizationBox: activeMastodonAuthenticationBox + provider.context.apiService.deleteStatus( + domain: activeMastodonAuthenticationBox.domain, + statusID: status.id, + authorizationBox: activeMastodonAuthenticationBox ) .sink { _ in // do nothing @@ -374,7 +426,6 @@ extension UserProviderFacade { } alertController.addAction(deleteAction) provider.present(alertController, animated: true, completion: nil) - } children.append(deleteAction) } diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift index 093258733..23ed744fc 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift @@ -17,17 +17,11 @@ extension HashtagTimelineViewModel { statusTableViewCellDelegate: StatusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate ) { - let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) - .autoconnect() - .share() - .eraseToAnyPublisher() - diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, timelineContext: .hashtag, dependency: dependency, managedObjectContext: context.managedObjectContext, - timestampUpdatePublisher: timestampUpdatePublisher, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate, threadReplyLoaderTableViewCellDelegate: nil diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift index d25f30aee..73d2c1739 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift @@ -18,17 +18,11 @@ extension HomeTimelineViewModel { statusTableViewCellDelegate: StatusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate ) { - let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) - .autoconnect() - .share() - .eraseToAnyPublisher() - diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, timelineContext: .home, dependency: dependency, managedObjectContext: fetchedResultsController.managedObjectContext, - timestampUpdatePublisher: timestampUpdatePublisher, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate, threadReplyLoaderTableViewCellDelegate: nil diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift index e00749657..55b4504dc 100644 --- a/Mastodon/Scene/Notification/NotificationViewController.swift +++ b/Mastodon/Scene/Notification/NotificationViewController.swift @@ -42,6 +42,10 @@ final class NotificationViewController: UIViewController, NeedsDependency { }() let refreshControl = UIRefreshControl() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } } extension NotificationViewController { diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift index f21498aaf..314721413 100644 --- a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift @@ -13,18 +13,12 @@ extension FavoriteViewModel { for tableView: UITableView, dependency: NeedsDependency, statusTableViewCellDelegate: StatusTableViewCellDelegate - ) { - let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) - .autoconnect() - .share() - .eraseToAnyPublisher() - + ) { diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, timelineContext: .favorite, dependency: dependency, managedObjectContext: statusFetchedResultsController.fetchedResultsController.managedObjectContext, - timestampUpdatePublisher: timestampUpdatePublisher, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, threadReplyLoaderTableViewCellDelegate: nil diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index f78079d2e..434836ab4 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -97,7 +97,7 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi } deinit { - os_log("%{public}s[%{public}ld], %{public}s: deinit", ((#file as NSString).lastPathComponent), #line, #function) + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } } diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift index 5ccc1441f..0d6d47823 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift @@ -14,17 +14,11 @@ extension UserTimelineViewModel { dependency: NeedsDependency, statusTableViewCellDelegate: StatusTableViewCellDelegate ) { - let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) - .autoconnect() - .share() - .eraseToAnyPublisher() - diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, timelineContext: .account, dependency: dependency, managedObjectContext: statusFetchedResultsController.fetchedResultsController.managedObjectContext, - timestampUpdatePublisher: timestampUpdatePublisher, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, threadReplyLoaderTableViewCellDelegate: nil diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift index 7e6eb30f0..e9d5c518b 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift @@ -17,17 +17,11 @@ extension PublicTimelineViewModel { statusTableViewCellDelegate: StatusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate ) { - let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) - .autoconnect() - .share() - .eraseToAnyPublisher() - diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, timelineContext: .public, dependency: dependency, managedObjectContext: fetchedResultsController.managedObjectContext, - timestampUpdatePublisher: timestampUpdatePublisher, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate, threadReplyLoaderTableViewCellDelegate: nil diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index 1c073b4b9..8dcf9cd3b 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -94,6 +94,10 @@ final class SearchViewController: UIViewController, NeedsDependency { }() let searchBarTapPublisher = PassthroughSubject() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } } diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift index 8e9f4a641..38c86c112 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift @@ -111,6 +111,10 @@ final class StatusTableViewCell: UITableViewCell, StatusCell { _init() } + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + } extension StatusTableViewCell { diff --git a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift index e09d6acc1..5bbc383e4 100644 --- a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift +++ b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift @@ -19,17 +19,11 @@ extension ThreadViewModel { statusTableViewCellDelegate: StatusTableViewCellDelegate, threadReplyLoaderTableViewCellDelegate: ThreadReplyLoaderTableViewCellDelegate ) { - let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) - .autoconnect() - .share() - .eraseToAnyPublisher() - diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, timelineContext: .thread, dependency: dependency, managedObjectContext: context.managedObjectContext, - timestampUpdatePublisher: timestampUpdatePublisher, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, threadReplyLoaderTableViewCellDelegate: threadReplyLoaderTableViewCellDelegate From f335bd7112b54ee20da4f72da8e9b7a103fe7b4b Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 30 Sep 2021 14:19:58 +0800 Subject: [PATCH 213/392] chore: set home timeline friend placeholder asset display on iPad --- Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 38d6e90ac..dbd552d97 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -336,8 +336,6 @@ extension HomeTimelineViewController { emptyView.addArrangedSubview(friendsAssetImageView) emptyView.addArrangedSubview(bottomPaddingView) - friendsAssetImageView.isHidden = traitCollection.userInterfaceIdiom != .phone - topPaddingView.translatesAutoresizingMaskIntoConstraints = false bottomPaddingView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ From b18250c92879cd2da205f9f2387a04027f8673a6 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 30 Sep 2021 14:28:07 +0800 Subject: [PATCH 214/392] chore: update version to 1.2.0 (71) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 99255fa90..4c76ebcf8 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 99255fa90..4c76ebcf8 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 99255fa90..4c76ebcf8 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index b41484465..07a833da7 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4760,7 +4760,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4789,7 +4789,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4897,11 +4897,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4928,11 +4928,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4957,11 +4957,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4987,11 +4987,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5054,7 +5054,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5079,7 +5079,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5104,7 +5104,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5129,7 +5129,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5154,7 +5154,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5179,7 +5179,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5204,7 +5204,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5229,7 +5229,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5320,7 +5320,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5387,11 +5387,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5436,7 +5436,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5461,11 +5461,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5557,7 +5557,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5624,11 +5624,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5673,7 +5673,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5698,11 +5698,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 70; + DYLIB_CURRENT_VERSION = 71; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5728,7 +5728,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5752,7 +5752,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 71; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index be8c2df95..068a73491 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 51 + 56 CoreDataStack.xcscheme_^#shared#^_ orderHint - 53 + 54 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 47 + 51 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 52 + 55 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index cd377a41e..129f6bf10 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 70 + 71 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 9540c525e..e4bdca72f 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 99255fa90..4c76ebcf8 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 99255fa90..4c76ebcf8 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index e80488b0b..ddb99a597 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 25ff496f4..08ddef3f3 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 70 + 71 NSExtension NSExtensionAttributes From 5eefb620fa34c3d7be5c82dea4879ff86d58da43 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 30 Sep 2021 14:59:07 +0800 Subject: [PATCH 215/392] chore: fix CI build issue --- .gitignore | 1 + .../xcshareddata/swiftpm/Package.resolved | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/.gitignore b/.gitignore index 24e748a9e..2c475f675 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ Packages/ .swiftpm .build/ +!**/swiftpm/Package.resolved # CocoaPods # We recommend against adding the Pods directory to your .gitignore. However diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2c878ce14..1fe981b44 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -216,6 +216,15 @@ "revision": "dad97167bf1be16aeecd109130900995dd01c515", "version": "2.6.0" } + }, + { + "package": "UITextView+Placeholder", + "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder", + "state": { + "branch": null, + "revision": "20f513ded04a040cdf5467f0891849b1763ede3b", + "version": "1.4.1" + } } ] }, From bcf0262608ea19750b49c1c9d9c0813276e6eb84 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 30 Sep 2021 15:04:46 +0800 Subject: [PATCH 216/392] chore: update CI build with Xcode 13 for iOS 15 SDK --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea588983c..ea365bca9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,8 +19,8 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 - - name: force Xcode 12.5.1 - run: sudo xcode-select -switch /Applications/Xcode_12.5.1.app + - name: force Xcode 13.0 + run: sudo xcode-select -switch /Applications/Xcode_13.0.app - name: setup run: exec ./.github/scripts/setup.sh - name: build From 1245f99d67d2b9d440ea07aa388b1ce9f2276360 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Oct 2021 18:46:13 +0200 Subject: [PATCH 217/392] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index db8de394d..1dec5b408 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -308,7 +308,7 @@ "title": "Check your inbox.", "description": "We just sent you an email. Check your junk folder if you haven’t.", "mail": "البريد", - "open_email_client": "Open Email Client" + "open_email_client": "فتح عميل البريد الإلكتروني" } }, "home_timeline": { From b24c699cd0e10ea181693f782c302ca27bfde88a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Oct 2021 20:12:50 +0200 Subject: [PATCH 218/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 1dec5b408..ef009776c 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -2,8 +2,8 @@ "common": { "alerts": { "common": { - "please_try_again": "الرجاء المحاولة مرة أخرى.", - "please_try_again_later": "الرجاء المحاولة مرة أخرى لاحقاً." + "please_try_again": "يُرجى المحاولة مرة أُخرى.", + "please_try_again_later": "يُرجى المحاولة مرة أُخرى لاحقاً." }, "sign_up_failure": { "title": "فشل التسجيل" @@ -29,7 +29,7 @@ }, "edit_profile_failure": { "title": "Edit Profile Error", - "message": "لا يمكن تعديل الملف الشخصي. الرجاء المحاولة مرة أخرى." + "message": "لا يمكن تعديل الملف الشخصي. يُرجى المحاولة مرة أُخرى." }, "sign_out": { "title": "تسجيل الخروج", @@ -49,8 +49,8 @@ "delete": "احذف" }, "clean_cache": { - "title": "تنظيف ذاكرة التخزين المؤقت", - "message": "تم تنظيف ذاكرة التخزين المؤقت %s بنجاح." + "title": "مَحو ذاكرة التخزين المؤقت", + "message": "تمَّ مَحو ذاكرة التخزين المؤقت %s بنجاح." } }, "controls": { @@ -64,17 +64,17 @@ "edit": "تعديل", "save": "حفظ", "ok": "حسنًا", - "done": "تم", + "done": "تمّ", "confirm": "تأكيد", "continue": "واصل", "cancel": "إلغاء", "discard": "تجاهل", - "try_again": "حاول مرة أخرى", + "try_again": "المُحاولة مرة أُخرى", "take_photo": "التقط صورة", "save_photo": "حفظ الصورة", "copy_photo": "نسخ الصورة", - "sign_in": "لِج", - "sign_up": "انشئ حسابًا", + "sign_in": "تسجيل الدخول", + "sign_up": "إنشاء حِساب", "see_more": "عرض المزيد", "preview": "معاينة", "share": "شارك", @@ -122,7 +122,7 @@ } }, "status": { - "user_reblogged": "%s reblogged", + "user_reblogged": "أعادَ %s تدوينها", "user_replied_to": "رد على %s", "show_post": "اظهر المنشور", "show_user_profile": "اظهر الملف التعريفي للمستخدم", @@ -152,8 +152,8 @@ "friendship": { "follow": "اتبع", "following": "مُتابَع", - "request": "Request", - "pending": "Pending", + "request": "إرسال طَلَب", + "pending": "قيد المُراجعة", "block": "حظر", "block_user": "حظر %s", "block_domain": "حظر %s", @@ -168,12 +168,12 @@ "edit_info": "تعديل المعلومات" }, "timeline": { - "filtered": "Filtered", + "filtered": "مُصفَّى", "timestamp": { "now": "الأن" }, "loader": { - "load_missing_posts": "Load missing posts", + "load_missing_posts": "تحميل المنشورات المَفقودة", "loading_missing_posts": "تحميل المزيد من المنشورات...", "show_more_replies": "إظهار المزيد من الردود" }, @@ -206,7 +206,7 @@ "games": "ألعاب", "general": "عام", "journalism": "صحافة", - "lgbt": "lgbt", + "lgbt": "مجتمع الشواذ", "regional": "اقليمي", "art": "فن", "music": "موسيقى", @@ -302,10 +302,10 @@ "dont_receive_email": { "title": "تحقق من بريدك الإلكتروني", "description": "Check if your email address is correct as well as your junk folder if you haven’t.", - "resend_email": "Resend Email" + "resend_email": "إعادة إرسال البريد الإلكتروني" }, "open_email_app": { - "title": "Check your inbox.", + "title": "تحقَّق من بريدك الوارِد.", "description": "We just sent you an email. Check your junk folder if you haven’t.", "mail": "البريد", "open_email_client": "فتح عميل البريد الإلكتروني" @@ -315,7 +315,7 @@ "title": "الخيط الرئيسي", "navigation_bar_state": { "offline": "غير متصل", - "new_posts": "See new posts", + "new_posts": "إظهار منشورات جديدة", "published": "تم نشره!", "Publishing": "جارٍ نشر المشاركة…" } @@ -334,7 +334,7 @@ "photo_library": "مكتبة الصور", "browse": "تصفح" }, - "content_input_placeholder": "ما الذي يجول ببالك", + "content_input_placeholder": "أخبِرنا بِما يَجُولُ فِي ذِهنَك", "compose_action": "انشر", "replying_to_user": "رد على %s", "attachment": { @@ -367,7 +367,7 @@ "space_to_add": "Space to add" }, "accessibility": { - "append_attachment": "Add Attachment", + "append_attachment": "إضافة مُرفَق", "append_poll": "اضافة استطلاع رأي", "remove_poll": "إزالة الاستطلاع", "custom_emoji_picker": "منتقي مخصص للإيموجي", @@ -376,11 +376,11 @@ "post_visibility_menu": "Post Visibility Menu" }, "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", + "discard_post": "تجاهُل المنشور", + "publish_post": "نَشر المَنشُور", + "toggle_poll": "تبديل الاستطلاع", + "toggle_content_warning": "تبديل تحذير المُحتوى", + "append_attachment_entry": "إضافة مُرفَق - %s", "select_visibility_entry": "اختر مدى الظهور - %s" } }, @@ -393,7 +393,7 @@ "fields": { "add_row": "إضافة صف", "placeholder": { - "label": "Label", + "label": "التسمية", "content": "المحتوى" } }, @@ -424,7 +424,7 @@ "hash_tag": { "title": "ذات شعبية على ماستدون", "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "people_talking": "%s أشخاص يتحدَّثوا" }, "accounts": { "title": "حسابات قد تعجبك", @@ -459,15 +459,15 @@ "user_reblogged_your_post": "أعاد %s تدوين مشاركتك", "user_mentioned_you": "أشار إليك %s", "user_requested_to_follow_you": "طلب %s متابعتك", - "user_your_poll_has_ended": "%s Your poll has ended", + "user_your_poll_has_ended": "%s اِنتهى استطلاعُكَ للرأي", "keyobard": { "show_everything": "إظهار كل شيء", - "show_mentions": "Show Mentions" + "show_mentions": "إظهار الإشارات" } }, "thread": { - "back_title": "Post", - "title": "Post from %s" + "back_title": "منشور", + "title": "مَنشور مِن %s" }, "settings": { "title": "الإعدادات", @@ -475,29 +475,29 @@ "appearance": { "title": "المظهر", "automatic": "تلقائي", - "light": "Always Light", - "dark": "Always Dark" + "light": "مضيءٌ دائمًا", + "dark": "مظلمٌ دائِمًا" }, "notifications": { "title": "الإشعارات", - "favorites": "Favorites my post", + "favorites": "الإعجاب بِمنشوراتي", "follows": "يتابعني", - "boosts": "Reblogs my post", - "mentions": "Mentions me", + "boosts": "إعادة تدوين منشوراتي", + "mentions": "الإشارة لي", "trigger": { - "anyone": "anyone", + "anyone": "أي شخص", "follower": "مشترِك", - "follow": "anyone I follow", - "noone": "no one", - "title": "Notify me when" + "follow": "أي شخص أُتابِعُه", + "noone": "لا أحد", + "title": "إشعاري عِندَ" } }, "preference": { "title": "التفضيلات", - "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" + "true_black_dark_mode": "النمط الأسود الداكِن الحقيقي", + "disable_avatar_animation": "تعطيل الصور الرمزية المتحرِّكة", + "disable_emoji_animation": "تعطيل الرموز التعبيرية المتحرِّكَة", + "using_default_browser": "اِستخدام المتصفح الافتراضي لفتح الروابط" }, "boring_zone": { "title": "المنطقة المملة", @@ -537,13 +537,13 @@ }, "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" + "dismiss_account_switcher": "تجاهُل مبدِّل الحساب", + "add_account": "إضافة حساب" }, "wizard": { - "new_in_mastodon": "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" + "accessibility_hint": "انقر نقرًا مزدوجًا لتجاهل النافذة المنبثقة" } } } \ No newline at end of file From 956c0cf0e1a9cd0779b1b939d6f0423ecbd674e7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Oct 2021 20:12:51 +0200 Subject: [PATCH 219/392] New translations ios-infoPlist.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json b/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json index 54fb1aacc..22fb2868e 100644 --- a/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json @@ -1,6 +1,6 @@ { - "NSCameraUsageDescription": "Used to take photo for post status", - "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", + "NSCameraUsageDescription": "يُستخدم لالتقاط الصورة عِندَ نشر الحالات", + "NSPhotoLibraryAddUsageDescription": "يُستخدم لحِفظ الصورة في مكتبة الصور", "NewPostShortcutItemTitle": "منشور جديد", "SearchShortcutItemTitle": "البحث" } From 45d212e2f0ce7363cf267a31ae8cc0047ecb9500 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Oct 2021 20:12:52 +0200 Subject: [PATCH 220/392] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index e6b0d5f95..be6601b3a 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -15,21 +15,21 @@ zero %ld unread notification one - 1 unread notification + إشعار واحِد غير مقروء two - %ld unread notification + إشعاران غير مقروءان few %ld unread notification many - %ld unread notification + %ld إشعارًا غيرَ مقروء other - %ld unread notification + %ld إشعار غير مقروء a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + تمَّ تجاوز حدّ الإدخال %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -37,23 +37,23 @@ NSStringFormatValueTypeKey ld zero - %ld characters + لا حرف one - 1 character + حرفٌ واحِد two - %ld characters + حرفان اثنان few - %ld characters + %ld حُرُوف many - %ld characters + %ld حرفًا other - %ld characters + %ld حَرف a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + يتبقَّى على حدّ الإدخال %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -61,17 +61,17 @@ NSStringFormatValueTypeKey ld zero - %ld characters + لا حرف one - 1 character + حرفٌ واحِد two - %ld characters + حرفان اثنان few - %ld characters + %ld حُرُوف many - %ld characters + %ld حرفًا other - %ld characters + %ld حَرف plural.count.metric_formatted.post @@ -85,17 +85,17 @@ NSStringFormatValueTypeKey ld zero - posts + لا منشور one - post + منشور two - posts + منشوران few - posts + منشورات many - posts + منشورًا other - posts + منشور plural.count.post @@ -109,17 +109,17 @@ NSStringFormatValueTypeKey ld zero - %ld posts + لا منشور one - 1 post + منشورٌ واحِد two - %ld posts + منشورانِ اثنان few - %ld posts + %ld منشورات many - %ld posts + %ld منشورًا other - %ld posts + %ld منشور plural.count.favorite @@ -133,17 +133,17 @@ NSStringFormatValueTypeKey ld zero - %ld favorites + لا إعجاب one - 1 favorite + إعجابٌ واحِد two - %ld favorites + إعجابانِ اثنان few - %ld favorites + %ld إعجابات many - %ld favorites + %ld إعجابًا other - %ld favorites + %ld إعجاب plural.count.reblog @@ -157,17 +157,17 @@ NSStringFormatValueTypeKey ld zero - %ld reblogs + لا إعاد تدوين one - 1 reblog + إعادةُ تدوينٍ واحِدة two - %ld reblogs + إعادتا تدوين few - %ld reblogs + %ld إعاداتِ تدوين many - %ld reblogs + %ld إعادةٍ للتدوين other - %ld reblogs + %ld إعادة تدوين plural.count.vote @@ -181,17 +181,17 @@ NSStringFormatValueTypeKey ld zero - %ld votes + لا صوت one - 1 vote + صوتٌ واحِد two - %ld votes + صوتانِ اثنان few - %ld votes + %ld أصوات many - %ld votes + %ld صوتًا other - %ld votes + %ld صوت plural.count.voter @@ -205,17 +205,17 @@ NSStringFormatValueTypeKey ld zero - %ld voters + لا مُصوِّتون one - 1 voter + مُصوِّتٌ واحِد two - %ld voters + مُصوِّتانِ اثنان few - %ld voters + %ld مُصوِّتين many - %ld voters + %ld مُصوِّتًا other - %ld voters + %ld مُصوِّت plural.people_talking From 69aa36876c13ce0e51fb8a1e3dcbf840e6e8e8de Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 4 Oct 2021 16:41:42 +0100 Subject: [PATCH 221/392] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index be6601b3a..e85dc907e 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -469,17 +469,17 @@ NSStringFormatValueTypeKey ld zero - %ldM ago + مُنذُ لَحظة one - 1M ago + مُنذُ شهر two - %ldM ago + مُنذُ شهرين few - %ldM ago + مُنذُ %ld أشهُر many - %ldM ago + مُنذُ %ld شهرًا other - %ldM ago + مُنذُ %ld شهر date.day.ago.abbr @@ -493,17 +493,17 @@ NSStringFormatValueTypeKey ld zero - %ldd ago + مُنذُ لَحظة one - 1d ago + مُنذُ يوم two - %ldd ago + مُنذُ يومين few - %ldd ago + مُنذُ %ld أيام many - %ldd ago + مُنذُ %ld يومًا other - %ldd ago + مُنذُ %ld يوم date.hour.ago.abbr @@ -517,17 +517,17 @@ NSStringFormatValueTypeKey ld zero - %ldh ago + مُنذُ لَحظة one - 1h ago + مُنذُ ساعة two - %ldh ago + مُنذُ ساعتين few - %ldh ago + مُنذُ %ld ساعات many - %ldh ago + مُنذُ %ld ساعتًا other - %ldh ago + مُنذُ %ld ساعة date.minute.ago.abbr @@ -541,17 +541,17 @@ NSStringFormatValueTypeKey ld zero - %ldm ago + مُنذُ لَحظة one - 1m ago + مُنذُ دقيقة two - %ldm ago + مُنذُ دقيقتان few - %ldm ago + مُنذُ %ld دقائق many - %ldm ago + مُنذُ %ld دقيقتًا other - %ldm ago + مُنذُ %ld دقيقة date.second.ago.abbr @@ -565,17 +565,17 @@ NSStringFormatValueTypeKey ld zero - %lds ago + مُنذُ لَحظة one - 1s ago + مُنذُ ثانية two - %lds ago + مُنذُ ثانيتين few - %lds ago + مُنذُ %ld ثوان many - %lds ago + مُنذُ %ld ثانيتًا other - %lds ago + مُنذُ %ld ثانية From 5318e63ced9db5a2be851e7974f8c19feb2a6d76 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 4 Oct 2021 17:41:52 +0100 Subject: [PATCH 222/392] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 124 +++++++++--------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index e85dc907e..e3dee0d80 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -229,17 +229,17 @@ NSStringFormatValueTypeKey ld zero - %ld people talking + لا أحَدَ يتحدَّث one - 1 people talking + شخصٌ واحدٌ يتحدَّث two - %ld people talking + شخصانِ اثنان يتحدَّثا few - %ld people talking + %ld أشخاصٍ يتحدَّثون many - %ld people talking + %ld شخصًا يتحدَّثون other - %ld people talking + %ld شخصٍ يتحدَّثون plural.count.following @@ -253,17 +253,17 @@ NSStringFormatValueTypeKey ld zero - %ld following + لا مُتابَع one - 1 following + مُتابَعٌ واحد two - %ld following + مُتابَعانِ few - %ld following + %ld مُتابَعين many - %ld following + %ld مُتابَعًا other - %ld following + %ld مُتابَع plural.count.follower @@ -279,15 +279,15 @@ zero %ld followers one - 1 follower + مُتابِعٌ واحد two - %ld followers + مُتابِعانِ اثنان few - %ld followers + %ld مُتابِعين many - %ld followers + %ld مُتابِعًا other - %ld followers + %ld مُتابِع date.year.left @@ -301,17 +301,17 @@ NSStringFormatValueTypeKey ld zero - %ld years left + تتبقى لَحظة one - 1 year left + تتبقى سنة two - %ld years left + تتبقى سنتين few - %ld years left + تتبقى %ld سنوات many - %ld years left + تتبقى %ld سنةً other - %ld years left + تتبقى %ld سنة date.month.left @@ -325,17 +325,17 @@ NSStringFormatValueTypeKey ld zero - %ld months left + تتبقى لَحظة one - 1 months left + يتبقى شهر two - %ld months left + يتبقى شهرين few - %ld months left + يتبقى %ld أشهر many - %ld months left + يتبقى %ld شهرًا other - %ld months left + يتبقى %ld شهر date.day.left @@ -349,17 +349,17 @@ NSStringFormatValueTypeKey ld zero - %ld days left + تتبقى لحظة one - 1 day left + يتبقى يوم two - %ld days left + يتبقى يومين few - %ld days left + يتبقى %ld أيام many - %ld days left + يتبقى %ld يومًا other - %ld days left + يتبقى %ld يوم date.hour.left @@ -373,17 +373,17 @@ NSStringFormatValueTypeKey ld zero - %ld hours left + تتبقى لَحظة one - 1 hour left + تتبقى ساعة two - %ld hours left + تتبقى ساعتين few - %ld hours left + تتبقى %ld ساعات many - %ld hours left + تتبقى %ld ساعةً other - %ld hours left + تتبقى %ld ساعة date.minute.left @@ -397,17 +397,17 @@ NSStringFormatValueTypeKey ld zero - %ld minutes left + تتبقى لَحظة one - 1 minute left + تتبقى دقيقة two - %ld minutes left + تتبقى دقيقتين few - %ld minutes left + تتبقى %ld دقائق many - %ld minutes left + تتبقى %ld دقيقةً other - %ld minutes left + تتبقى %ld دقيقة date.second.left @@ -421,17 +421,17 @@ NSStringFormatValueTypeKey ld zero - %ld seconds left + تتبقى لَحظة one - 1 second left + تتبقى ثانية two - %ld seconds left + تتبقى ثانيتين few - %ld seconds left + تتبقى %ld ثوان many - %ld seconds left + تتبقى %ld ثانيةً other - %ld seconds left + تتبقى %ld ثانية date.year.ago.abbr @@ -445,17 +445,17 @@ NSStringFormatValueTypeKey ld zero - %ldy ago + مُنذُ لَحظة one - 1y ago + مُنذُ سنة two - %ldy ago + مُنذُ سنتين few - %ldy ago + مُنذُ %ld سنين many - %ldy ago + مُنذُ %ld سنةً other - %ldy ago + مُنذُ %ld سنة date.month.ago.abbr @@ -525,7 +525,7 @@ few مُنذُ %ld ساعات many - مُنذُ %ld ساعتًا + مُنذُ %ld ساعةًَ other مُنذُ %ld ساعة @@ -549,7 +549,7 @@ few مُنذُ %ld دقائق many - مُنذُ %ld دقيقتًا + مُنذُ %ld دقيقةً other مُنذُ %ld دقيقة @@ -573,7 +573,7 @@ few مُنذُ %ld ثوان many - مُنذُ %ld ثانيتًا + مُنذُ %ld ثانية other مُنذُ %ld ثانية From 6b1d3f8738d0789bbe63cb35cf7dc9b581026803 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 8 Oct 2021 18:10:06 +0800 Subject: [PATCH 223/392] chore: update onboarding layout for iPad --- .../xcschemes/xcschememanagement.plist | 8 +- Mastodon/Coordinator/SceneCoordinator.swift | 8 +- .../MastodonConfirmEmailViewController.swift | 41 +++++- .../MastodonPickServerViewController.swift | 127 +++++++++++------- .../PickServerCategoriesCell.swift | 27 +++- .../TableViewCell/PickServerCell.swift | 23 +++- .../PickServerLoaderTableViewCell.swift | 24 +++- .../TableViewCell/PickServerSearchCell.swift | 23 +++- .../TableViewCell/PickServerTitleCell.swift | 46 ++++++- .../MastodonRegisterViewController.swift | 106 +++++++++++---- .../MastodonServerRulesViewController.swift | 54 +++++++- .../OnboardingViewControllerAppearance.swift | 42 +++++- .../Welcome/WelcomeViewController.swift | 25 +++- .../Root/MainTab/MainTabBarController.swift | 3 +- .../Scene/Root/RootSplitViewController.swift | 7 + 15 files changed, 448 insertions(+), 116 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 068a73491..e6093a218 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 56 + 35 CoreDataStack.xcscheme_^#shared#^_ orderHint - 54 + 38 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 51 + 36 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 55 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 83ae61a84..3178a2cb7 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -214,7 +214,13 @@ extension SceneCoordinator { assertionFailure() return nil } - presentingViewController.presentPanModal(panModalPresentable) + + // https://github.com/slackhq/PanModal/issues/74#issuecomment-572426441 + panModalPresentable.modalPresentationStyle = .custom + panModalPresentable.modalPresentationCapturesStatusBarAppearance = true + panModalPresentable.transitioningDelegate = PanModalPresentationDelegate.default + presentingViewController.present(panModalPresentable, animated: true, completion: nil) + //presentingViewController.presentPanModal(panModalPresentable) case .custom(let transitioningDelegate): viewController.modalPresentationStyle = .custom diff --git a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift index 1abb35617..0718938f6 100644 --- a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift +++ b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift @@ -20,6 +20,8 @@ final class MastodonConfirmEmailViewController: UIViewController, NeedsDependenc var viewModel: MastodonConfirmEmailViewModel! + let stackView = UIStackView() + let largeTitleLabel: UILabel = { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.systemFont(ofSize: 34, weight: .bold)) @@ -72,9 +74,10 @@ extension MastodonConfirmEmailViewController { override func viewDidLoad() { setupOnboardingAppearance() + configureTitleLabel() + configureMargin() // stackView - let stackView = UIStackView() stackView.axis = .vertical stackView.distribution = .fill stackView.spacing = 10 @@ -92,8 +95,8 @@ extension MastodonConfirmEmailViewController { stackView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ stackView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor), - stackView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor), - stackView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor), + stackView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), + stackView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor), stackView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor), ]) NSLayoutConstraint.activate([ @@ -139,6 +142,38 @@ extension MastodonConfirmEmailViewController { .store(in: &self.disposeBag) } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + configureTitleLabel() + configureMargin() + } + +} + +extension MastodonConfirmEmailViewController { + private func configureTitleLabel() { + switch traitCollection.horizontalSizeClass { + case .regular: + navigationItem.largeTitleDisplayMode = .always + navigationItem.title = L10n.Scene.ConfirmEmail.title.replacingOccurrences(of: "\n", with: " ") + largeTitleLabel.isHidden = true + default: + navigationItem.largeTitleDisplayMode = .never + navigationItem.title = nil + largeTitleLabel.isHidden = false + } + } + + private func configureMargin() { + switch traitCollection.horizontalSizeClass { + case .regular: + let margin = MastodonConfirmEmailViewController.viewEdgeMargin + stackView.layoutMargins = UIEdgeInsets(top: 18, left: margin, bottom: 23, right: margin) + default: + stackView.layoutMargins = UIEdgeInsets(top: 10, left: 0, bottom: 23, right: 0) + } + } } extension MastodonConfirmEmailViewController { diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index 3da704f0b..f3570c6c5 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -29,6 +29,8 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency private var expandServerDomainSet = Set() private let emptyStateView = PickServerEmptyStateView() + private var emptyStateViewLeadingLayoutConstraint: NSLayoutConstraint! + private var emptyStateViewTrailingLayoutConstraint: NSLayoutConstraint! let tableViewTopPaddingView = UIView() // fix empty state view background display when tableView bounce scrolling var tableViewTopPaddingViewHeightLayoutConstraint: NSLayoutConstraint! @@ -52,13 +54,14 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency return tableView }() + let buttonContainer = UIView() let nextStepButton: PrimaryActionButton = { let button = PrimaryActionButton() button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal) button.translatesAutoresizingMaskIntoConstraints = false return button }() - var nextStepButtonBottomLayoutConstraint: NSLayoutConstraint! + var buttonContainerBottomLayoutConstraint: NSLayoutConstraint! var mastodonAuthenticationController: MastodonAuthenticationController? @@ -77,6 +80,8 @@ extension MastodonPickServerViewController { setupOnboardingAppearance() defer { setupNavigationBarBackgroundView() } + configureTitleLabel() + configureMargin() #if DEBUG navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), style: .plain, target: nil, action: nil) @@ -89,14 +94,24 @@ extension MastodonPickServerViewController { navigationItem.rightBarButtonItem?.menu = UIMenu(title: "Debug Tool", image: nil, identifier: nil, options: [], children: children) #endif - view.addSubview(nextStepButton) - nextStepButtonBottomLayoutConstraint = view.bottomAnchor.constraint(equalTo: nextStepButton.bottomAnchor, constant: 0).priority(.defaultHigh) + buttonContainer.translatesAutoresizingMaskIntoConstraints = false + buttonContainer.preservesSuperviewLayoutMargins = true + view.addSubview(buttonContainer) + buttonContainerBottomLayoutConstraint = view.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor, constant: 0).priority(.defaultHigh) NSLayoutConstraint.activate([ - nextStepButton.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: MastodonPickServerViewController.actionButtonMargin), - view.readableContentGuide.trailingAnchor.constraint(equalTo: nextStepButton.trailingAnchor, constant: MastodonPickServerViewController.actionButtonMargin), + buttonContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor), + buttonContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor), + view.safeAreaLayoutGuide.bottomAnchor.constraint(greaterThanOrEqualTo: buttonContainer.bottomAnchor, constant: WelcomeViewController.viewBottomPaddingHeight), + buttonContainerBottomLayoutConstraint, + ]) + + view.addSubview(nextStepButton) + NSLayoutConstraint.activate([ + nextStepButton.topAnchor.constraint(equalTo: buttonContainer.topAnchor), + nextStepButton.leadingAnchor.constraint(equalTo: buttonContainer.layoutMarginsGuide.leadingAnchor), + buttonContainer.layoutMarginsGuide.trailingAnchor.constraint(equalTo: nextStepButton.trailingAnchor), + nextStepButton.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor), nextStepButton.heightAnchor.constraint(equalToConstant: MastodonPickServerViewController.actionButtonHeight).priority(.defaultHigh), - view.safeAreaLayoutGuide.bottomAnchor.constraint(greaterThanOrEqualTo: nextStepButton.bottomAnchor, constant: WelcomeViewController.viewBottomPaddingHeight), - nextStepButtonBottomLayoutConstraint, ]) // fix AutoLayout warning when observe before view appear @@ -127,16 +142,18 @@ extension MastodonPickServerViewController { tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - nextStepButton.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 7), + buttonContainer.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 7), ]) emptyStateView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(emptyStateView) + emptyStateViewLeadingLayoutConstraint = emptyStateView.leadingAnchor.constraint(equalTo: tableView.leadingAnchor) + emptyStateViewTrailingLayoutConstraint = tableView.trailingAnchor.constraint(equalTo: emptyStateView.trailingAnchor) NSLayoutConstraint.activate([ emptyStateView.topAnchor.constraint(equalTo: view.topAnchor), - emptyStateView.leadingAnchor.constraint(equalTo: tableView.readableContentGuide.leadingAnchor), - emptyStateView.trailingAnchor.constraint(equalTo: tableView.readableContentGuide.trailingAnchor), - nextStepButton.topAnchor.constraint(equalTo: emptyStateView.bottomAnchor, constant: 21), + emptyStateViewLeadingLayoutConstraint, + emptyStateViewTrailingLayoutConstraint, + buttonContainer.topAnchor.constraint(equalTo: emptyStateView.bottomAnchor, constant: 21), ]) view.sendSubviewToBack(emptyStateView) @@ -154,18 +171,18 @@ extension MastodonPickServerViewController { // guard external keyboard connected guard isShow, state == .dock, GCKeyboard.coalesced != nil else { - self.nextStepButtonBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight + self.buttonContainerBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight return } let externalKeyboardToolbarHeight = self.view.frame.maxY - endFrame.minY guard externalKeyboardToolbarHeight > 0 else { - self.nextStepButtonBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight + self.buttonContainerBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight return } UIView.animate(withDuration: 0.3) { - self.nextStepButtonBottomLayoutConstraint.constant = externalKeyboardToolbarHeight + 16 + self.buttonContainerBottomLayoutConstraint.constant = externalKeyboardToolbarHeight + 16 self.view.layoutIfNeeded() } } @@ -274,9 +291,34 @@ extension MastodonPickServerViewController { viewModel.viewWillAppear.send() } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + setupNavigationBarAppearance() + updateEmptyStateViewLayout() + configureTitleLabel() + configureMargin() + } } +extension MastodonPickServerViewController { + private func configureTitleLabel() { + guard UIDevice.current.userInterfaceIdiom == .pad else { + return + } + + switch traitCollection.horizontalSizeClass { + case .regular: + navigationItem.largeTitleDisplayMode = .always + navigationItem.title = L10n.Scene.ServerPicker.title.replacingOccurrences(of: "\n", with: " ") + default: + navigationItem.largeTitleDisplayMode = .never + navigationItem.title = nil + } + } +} + extension MastodonPickServerViewController { @objc @@ -426,43 +468,6 @@ extension MastodonPickServerViewController: UITableViewDelegate { } } - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let headerView = UIView() - headerView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color - return headerView - } - - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - guard let diffableDataSource = viewModel.diffableDataSource else { - return .leastNonzeroMagnitude - } - let sections = diffableDataSource.snapshot().sectionIdentifiers - let section = sections[section] - switch section { - case .header: - return 20 - case .category: - // Since category view has a blur shadow effect, its height need to be large than the actual height, - // Thus we reduce the section header's height by 10, and make the category cell height 60+20(10 inset for top and bottom) - return 10 - case .search: - // Same reason as above - return 10 - case .servers: - return .leastNonzeroMagnitude - } - } - - func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { - let footerView = UIView() - footerView.backgroundColor = .yellow - return footerView - } - - func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { - return .leastNonzeroMagnitude - } - func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { guard let diffableDataSource = viewModel.diffableDataSource else { return nil } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil } @@ -521,6 +526,26 @@ extension MastodonPickServerViewController { let rectInTableView = tableView.rectForRow(at: indexPath) emptyStateView.topPaddingViewTopLayoutConstraint.constant = rectInTableView.maxY + + switch traitCollection.horizontalSizeClass { + case .regular: + emptyStateViewLeadingLayoutConstraint.constant = MastodonPickServerViewController.viewEdgeMargin + emptyStateViewTrailingLayoutConstraint.constant = MastodonPickServerViewController.viewEdgeMargin + default: + let margin = tableView.layoutMarginsGuide.layoutFrame.origin.x + emptyStateViewLeadingLayoutConstraint.constant = margin + emptyStateViewTrailingLayoutConstraint.constant = margin + } + } + + private func configureMargin() { + switch traitCollection.horizontalSizeClass { + case .regular: + let margin = MastodonPickServerViewController.viewEdgeMargin + buttonContainer.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin) + default: + buttonContainer.layoutMargins = .zero + } } } diff --git a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCategoriesCell.swift b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCategoriesCell.swift index 8207ccdb9..659317752 100644 --- a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCategoriesCell.swift +++ b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCategoriesCell.swift @@ -56,12 +56,13 @@ extension PickServerCategoriesCell { private func _init() { selectionStyle = .none backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color + configureMargin() metricView.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(metricView) NSLayoutConstraint.activate([ - metricView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), - metricView.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), + metricView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + metricView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), metricView.topAnchor.constraint(equalTo: contentView.topAnchor), metricView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), metricView.heightAnchor.constraint(equalToConstant: 80).priority(.defaultHigh), @@ -71,14 +72,20 @@ extension PickServerCategoriesCell { NSLayoutConstraint.activate([ collectionView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), - collectionView.topAnchor.constraint(equalTo: contentView.topAnchor), - collectionView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + collectionView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), + contentView.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 20), collectionView.heightAnchor.constraint(equalToConstant: 80).priority(.defaultHigh), ]) collectionView.delegate = self } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + configureMargin() + } + override func layoutSubviews() { super.layoutSubviews() @@ -87,6 +94,18 @@ extension PickServerCategoriesCell { } +extension PickServerCategoriesCell { + private func configureMargin() { + switch traitCollection.horizontalSizeClass { + case .regular: + let margin = MastodonPickServerViewController.viewEdgeMargin + contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin) + default: + contentView.layoutMargins = .zero + } + } +} + // MARK: - UICollectionViewDelegateFlowLayout extension PickServerCategoriesCell: UICollectionViewDelegateFlowLayout { diff --git a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift index ee2471878..2f60a5206 100644 --- a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift +++ b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerCell.swift @@ -198,6 +198,7 @@ extension PickServerCell { private func _init() { selectionStyle = .none backgroundColor = .clear + configureMargin() contentView.addSubview(containerView) containerView.addSubview(domainLabel) @@ -229,8 +230,8 @@ extension PickServerCell { NSLayoutConstraint.activate([ // Set background view containerView.topAnchor.constraint(equalTo: contentView.topAnchor), - containerView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), - contentView.readableContentGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + containerView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + contentView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), // Set bottom separator @@ -291,6 +292,12 @@ extension PickServerCell { expandButton.addTarget(self, action: #selector(expandButtonDidPressed(_:)), for: .touchUpInside) } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + configureMargin() + } + private func makeVerticalInfoStackView(arrangedView: UIView...) -> UIStackView { let stackView = UIStackView() stackView.translatesAutoresizingMaskIntoConstraints = false @@ -318,6 +325,18 @@ extension PickServerCell { } } +extension PickServerCell { + private func configureMargin() { + switch traitCollection.horizontalSizeClass { + case .regular: + let margin = MastodonPickServerViewController.viewEdgeMargin + contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin) + default: + contentView.layoutMargins = .zero + } + } +} + extension PickServerCell { enum ExpandMode { diff --git a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerLoaderTableViewCell.swift b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerLoaderTableViewCell.swift index 1b8264ec3..945ecac6a 100644 --- a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerLoaderTableViewCell.swift +++ b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerLoaderTableViewCell.swift @@ -37,14 +37,16 @@ final class PickServerLoaderTableViewCell: TimelineLoaderTableViewCell { override func _init() { super._init() + configureMargin() + contentView.addSubview(containerView) contentView.addSubview(seperator) NSLayoutConstraint.activate([ // Set background view containerView.topAnchor.constraint(equalTo: contentView.topAnchor), - containerView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), - contentView.readableContentGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + containerView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + contentView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 1), // Set bottom separator @@ -67,6 +69,24 @@ final class PickServerLoaderTableViewCell: TimelineLoaderTableViewCell { activityIndicatorView.isHidden = false startAnimating() } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + configureMargin() + } +} + +extension PickServerLoaderTableViewCell { + private func configureMargin() { + switch traitCollection.horizontalSizeClass { + case .regular: + let margin = MastodonPickServerViewController.viewEdgeMargin + contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin) + default: + contentView.layoutMargins = .zero + } + } } #if canImport(SwiftUI) && DEBUG diff --git a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift index fa3e3ae27..0a64103d2 100644 --- a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift +++ b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift @@ -109,6 +109,7 @@ extension PickServerSearchCell { private func _init() { selectionStyle = .none backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color + configureMargin() searchTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged) searchTextField.delegate = self @@ -118,9 +119,9 @@ extension PickServerSearchCell { contentView.addSubview(searchTextField) NSLayoutConstraint.activate([ - bgView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + bgView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), bgView.topAnchor.constraint(equalTo: contentView.topAnchor), - bgView.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), + bgView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), bgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), textFieldBgView.leadingAnchor.constraint(equalTo: bgView.leadingAnchor, constant: 14), @@ -134,6 +135,24 @@ extension PickServerSearchCell { textFieldBgView.bottomAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 4), ]) } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + configureMargin() + } +} + +extension PickServerSearchCell { + private func configureMargin() { + switch traitCollection.horizontalSizeClass { + case .regular: + let margin = MastodonPickServerViewController.viewEdgeMargin + contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin) + default: + contentView.layoutMargins = .zero + } + } } extension PickServerSearchCell { diff --git a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerTitleCell.swift b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerTitleCell.swift index 682ebbf30..f0d78eb41 100644 --- a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerTitleCell.swift +++ b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerTitleCell.swift @@ -20,6 +20,8 @@ final class PickServerTitleCell: UITableViewCell { return label }() + var containerHeightLayoutConstraint: NSLayoutConstraint! + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) _init() @@ -36,13 +38,45 @@ extension PickServerTitleCell { private func _init() { selectionStyle = .none backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color - - contentView.addSubview(titleLabel) + + let container = UIStackView() + container.axis = .vertical + container.translatesAutoresizingMaskIntoConstraints = false + containerHeightLayoutConstraint = container.heightAnchor.constraint(equalToConstant: .leastNonzeroMagnitude) + contentView.addSubview(container) NSLayoutConstraint.activate([ - titleLabel.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), - contentView.readableContentGuide.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor), - titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor), - titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + container.topAnchor.constraint(equalTo: contentView.topAnchor), + container.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + container.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), + container.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) + + container.addArrangedSubview(titleLabel) + + configureTitleLabelDisplay() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + configureTitleLabelDisplay() + } +} + +extension PickServerTitleCell { + private func configureTitleLabelDisplay() { + guard traitCollection.userInterfaceIdiom == .pad else { + titleLabel.isHidden = false + return + } + + switch traitCollection.horizontalSizeClass { + case .regular: + titleLabel.isHidden = true + containerHeightLayoutConstraint.isActive = true + default: + titleLabel.isHidden = false + containerHeightLayoutConstraint.isActive = false + } } } diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift index ffef3d872..b86c46745 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift @@ -61,6 +61,8 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O return scrollview }() + let stackView = UIStackView() + let largeTitleLabel: UILabel = { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold)) @@ -287,7 +289,11 @@ extension MastodonRegisterViewController { super.viewDidLoad() setupOnboardingAppearance() - defer { setupNavigationBarBackgroundView() } + configureTitleLabel() + defer { + setupNavigationBarBackgroundView() + configureFormLayout() + } avatarButton.menu = createMediaContextMenu() avatarButton.showsMenuAsPrimaryAction = true @@ -307,7 +313,6 @@ extension MastodonRegisterViewController { tapGestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerHandler)) // stackview - let stackView = UIStackView() stackView.axis = .vertical stackView.distribution = .fill stackView.spacing = 40 @@ -315,17 +320,24 @@ extension MastodonRegisterViewController { stackView.isLayoutMarginsRelativeArrangement = true stackView.addArrangedSubview(largeTitleLabel) stackView.addArrangedSubview(avatarView) - stackView.addArrangedSubview(usernameTextField) - stackView.addArrangedSubview(displayNameTextField) - stackView.addArrangedSubview(emailTextField) - stackView.addArrangedSubview(passwordTextField) - stackView.addArrangedSubview(passwordCheckLabel) + + let formTableStackView = UIStackView() + stackView.addArrangedSubview(formTableStackView) + formTableStackView.axis = .vertical + formTableStackView.distribution = .fill + formTableStackView.spacing = 40 + + formTableStackView.addArrangedSubview(usernameTextField) + formTableStackView.addArrangedSubview(displayNameTextField) + formTableStackView.addArrangedSubview(emailTextField) + formTableStackView.addArrangedSubview(passwordTextField) + formTableStackView.addArrangedSubview(passwordCheckLabel) if viewModel.approvalRequired { - stackView.addArrangedSubview(reasonTextField) + formTableStackView.addArrangedSubview(reasonTextField) } usernameErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false - stackView.addSubview(usernameErrorPromptLabel) + formTableStackView.addSubview(usernameErrorPromptLabel) NSLayoutConstraint.activate([ usernameErrorPromptLabel.topAnchor.constraint(equalTo: usernameTextField.bottomAnchor, constant: 6), usernameErrorPromptLabel.leadingAnchor.constraint(equalTo: usernameTextField.leadingAnchor), @@ -333,7 +345,7 @@ extension MastodonRegisterViewController { ]) emailErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false - stackView.addSubview(emailErrorPromptLabel) + formTableStackView.addSubview(emailErrorPromptLabel) NSLayoutConstraint.activate([ emailErrorPromptLabel.topAnchor.constraint(equalTo: emailTextField.bottomAnchor, constant: 6), emailErrorPromptLabel.leadingAnchor.constraint(equalTo: emailTextField.leadingAnchor), @@ -341,7 +353,7 @@ extension MastodonRegisterViewController { ]) passwordErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false - stackView.addSubview(passwordErrorPromptLabel) + formTableStackView.addSubview(passwordErrorPromptLabel) NSLayoutConstraint.activate([ passwordErrorPromptLabel.topAnchor.constraint(equalTo: passwordCheckLabel.bottomAnchor, constant: 2), passwordErrorPromptLabel.leadingAnchor.constraint(equalTo: passwordTextField.leadingAnchor), @@ -373,12 +385,14 @@ extension MastodonRegisterViewController { avatarView.translatesAutoresizingMaskIntoConstraints = false avatarView.addSubview(avatarButton) NSLayoutConstraint.activate([ - avatarView.heightAnchor.constraint(equalToConstant: 90).priority(.defaultHigh), + avatarView.heightAnchor.constraint(equalToConstant: 92).priority(.required - 1), ]) avatarButton.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ - avatarButton.heightAnchor.constraint(equalToConstant: 92).priority(.defaultHigh), - avatarButton.widthAnchor.constraint(equalToConstant: 92).priority(.defaultHigh), + avatarButton.heightAnchor.constraint(equalToConstant: 92).priority(.required - 1), + avatarButton.widthAnchor.constraint(equalToConstant: 92).priority(.required - 1), + avatarButton.leadingAnchor.constraint(greaterThanOrEqualTo: avatarView.leadingAnchor).priority(.required - 1), + avatarView.trailingAnchor.constraint(greaterThanOrEqualTo: avatarButton.trailingAnchor).priority(.required - 1), avatarButton.centerXAnchor.constraint(equalTo: avatarView.centerXAnchor), avatarButton.centerYAnchor.constraint(equalTo: avatarView.centerYAnchor), ]) @@ -392,15 +406,15 @@ extension MastodonRegisterViewController { // textfield NSLayoutConstraint.activate([ - usernameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), - displayNameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), - emailTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), - passwordTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), + usernameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1), + displayNameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1), + emailTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1), + passwordTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1), ]) // password - stackView.setCustomSpacing(6, after: passwordTextField) - stackView.setCustomSpacing(32, after: passwordCheckLabel) + formTableStackView.setCustomSpacing(6, after: passwordTextField) + formTableStackView.setCustomSpacing(32, after: passwordCheckLabel) // return if viewModel.approvalRequired { @@ -410,16 +424,22 @@ extension MastodonRegisterViewController { } // button - stackView.addArrangedSubview(buttonContainer) + formTableStackView.addArrangedSubview(buttonContainer) signUpButton.translatesAutoresizingMaskIntoConstraints = false buttonContainer.addSubview(signUpButton) NSLayoutConstraint.activate([ signUpButton.topAnchor.constraint(equalTo: buttonContainer.topAnchor), - signUpButton.leadingAnchor.constraint(equalTo: buttonContainer.leadingAnchor, constant: MastodonRegisterViewController.actionButtonMargin), - buttonContainer.trailingAnchor.constraint(equalTo: signUpButton.trailingAnchor, constant: MastodonRegisterViewController.actionButtonMargin), + signUpButton.leadingAnchor.constraint(equalTo: buttonContainer.leadingAnchor), + buttonContainer.trailingAnchor.constraint(equalTo: signUpButton.trailingAnchor), buttonContainer.bottomAnchor.constraint(equalTo: signUpButton.bottomAnchor), - signUpButton.heightAnchor.constraint(equalToConstant: MastodonRegisterViewController.actionButtonHeight).priority(.defaultHigh), + signUpButton.heightAnchor.constraint(equalToConstant: MastodonRegisterViewController.actionButtonHeight).priority(.required - 1), + buttonContainer.heightAnchor.constraint(equalToConstant: MastodonRegisterViewController.actionButtonHeight).priority(.required - 1), ]) + signUpButton.setContentHuggingPriority(.defaultLow, for: .horizontal) + signUpButton.setContentHuggingPriority(.defaultLow, for: .vertical) + signUpButton.setContentCompressionResistancePriority(.required - 1, for: .vertical) + signUpButton.setContentCompressionResistancePriority(.required - 1, for: .horizontal) + buttonContainer.setContentCompressionResistancePriority(.required - 1, for: .vertical) Publishers.CombineLatest( KeyboardResponderService.shared.state.eraseToAnyPublisher(), @@ -645,6 +665,12 @@ extension MastodonRegisterViewController { plusIconImageView.layer.masksToBounds = true } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + configureTitleLabel() + configureFormLayout() + } } extension MastodonRegisterViewController: UITextFieldDelegate { @@ -714,7 +740,7 @@ extension MastodonRegisterViewController: UITextFieldDelegate { textField.layer.shadowRadius = 2.0 textField.layer.shadowOffset = CGSize.zero textField.layer.shadowColor = color.cgColor - textField.layer.shadowPath = UIBezierPath(roundedRect: textField.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 2.0, height: 2.0)).cgPath + // textField.layer.shadowPath = UIBezierPath(roundedRect: textField.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 2.0, height: 2.0)).cgPath } private func setTextFieldValidAppearance(_ textField: UITextField, validateState: MastodonRegisterViewModel.ValidateState) { @@ -729,6 +755,36 @@ extension MastodonRegisterViewController: UITextFieldDelegate { } } +extension MastodonRegisterViewController { + private func configureTitleLabel() { + switch traitCollection.horizontalSizeClass { + case .regular: + navigationItem.largeTitleDisplayMode = .always + navigationItem.title = L10n.Scene.ServerPicker.title.replacingOccurrences(of: "\n", with: " ") + largeTitleLabel.isHidden = true + default: + navigationItem.largeTitleDisplayMode = .never + navigationItem.title = nil + largeTitleLabel.isHidden = false + } + } + + private func configureFormLayout() { + switch traitCollection.horizontalSizeClass { + case .regular: + stackView.axis = .horizontal + stackView.distribution = .fillProportionally + default: + stackView.axis = .vertical + stackView.distribution = .fill + } + } + + private func configureMargin() { + + } +} + extension MastodonRegisterViewController { @objc private func tapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { view.endEditing(true) diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift index b9a332d05..e93d06e19 100644 --- a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift +++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift @@ -21,6 +21,8 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency var viewModel: MastodonServerRulesViewModel! + let stackView = UIStackView() + let largeTitleLabel: UILabel = { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold)) @@ -96,6 +98,8 @@ extension MastodonServerRulesViewController { super.viewDidLoad() setupOnboardingAppearance() + configureTitleLabel() + configureMargin() configTextView() defer { setupNavigationBarBackgroundView() } @@ -116,8 +120,8 @@ extension MastodonServerRulesViewController { bottomContainerView.addSubview(confirmButton) NSLayoutConstraint.activate([ bottomContainerView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: confirmButton.bottomAnchor, constant: MastodonServerRulesViewController.viewBottomPaddingHeight), - confirmButton.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin), - bottomContainerView.readableContentGuide.trailingAnchor.constraint(equalTo: confirmButton.trailingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin), + confirmButton.leadingAnchor.constraint(equalTo: bottomContainerView.layoutMarginsGuide.leadingAnchor), + bottomContainerView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: confirmButton.trailingAnchor), confirmButton.heightAnchor.constraint(equalToConstant: MastodonServerRulesViewController.actionButtonHeight).priority(.defaultHigh), ]) @@ -125,8 +129,8 @@ extension MastodonServerRulesViewController { bottomContainerView.addSubview(bottomPromptMetaText.textView) NSLayoutConstraint.activate([ bottomPromptMetaText.textView.frameLayoutGuide.topAnchor.constraint(equalTo: bottomContainerView.topAnchor, constant: 20), - bottomPromptMetaText.textView.frameLayoutGuide.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor), - bottomPromptMetaText.textView.frameLayoutGuide.trailingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.trailingAnchor), + bottomPromptMetaText.textView.frameLayoutGuide.leadingAnchor.constraint(equalTo: bottomContainerView.layoutMarginsGuide.leadingAnchor), + bottomPromptMetaText.textView.frameLayoutGuide.trailingAnchor.constraint(equalTo: bottomContainerView.layoutMarginsGuide.trailingAnchor), confirmButton.topAnchor.constraint(equalTo: bottomPromptMetaText.textView.frameLayoutGuide.bottomAnchor, constant: 20), ]) @@ -140,10 +144,10 @@ extension MastodonServerRulesViewController { scrollView.frameLayoutGuide.widthAnchor.constraint(equalTo: scrollView.contentLayoutGuide.widthAnchor), ]) - let stackView = UIStackView() stackView.axis = .vertical stackView.distribution = .fill stackView.spacing = 10 + stackView.isLayoutMarginsRelativeArrangement = true stackView.layoutMargins = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0) stackView.addArrangedSubview(largeTitleLabel) stackView.addArrangedSubview(subtitleLabel) @@ -178,6 +182,46 @@ extension MastodonServerRulesViewController { updateScrollViewContentInset() } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + setupNavigationBarAppearance() + configureTitleLabel() + configureMargin() + } + +} + +extension MastodonServerRulesViewController { + private func configureTitleLabel() { + guard UIDevice.current.userInterfaceIdiom == .pad else { + return + } + + switch traitCollection.horizontalSizeClass { + case .regular: + navigationItem.largeTitleDisplayMode = .always + navigationItem.title = L10n.Scene.ServerRules.title.replacingOccurrences(of: "\n", with: " ") + largeTitleLabel.isHidden = true + default: + navigationItem.leftBarButtonItem = nil + navigationItem.largeTitleDisplayMode = .never + navigationItem.title = nil + largeTitleLabel.isHidden = false + } + } + + private func configureMargin() { + switch traitCollection.horizontalSizeClass { + case .regular: + let margin = MastodonPickServerViewController.viewEdgeMargin + stackView.layoutMargins = UIEdgeInsets(top: 32, left: margin, bottom: 20, right: margin) + bottomContainerView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin) + default: + stackView.layoutMargins = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0) + bottomContainerView.layoutMargins = .zero + } + } } extension MastodonServerRulesViewController { diff --git a/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift b/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift index d93c677f8..4a4d04bf6 100644 --- a/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift +++ b/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift @@ -24,19 +24,38 @@ extension OnboardingViewControllerAppearance { setupNavigationBarAppearance() - let backItem = UIBarButtonItem() - backItem.title = L10n.Common.Controls.Actions.back + let backItem = UIBarButtonItem( + title: L10n.Common.Controls.Actions.back, + style: .plain, + target: nil, + action: nil + ) navigationItem.backBarButtonItem = backItem } func setupNavigationBarAppearance() { // use TransparentBackground so view push / dismiss will be more visual nature // please add opaque background for status bar manually if needs - let barAppearance = UINavigationBarAppearance() - barAppearance.configureWithTransparentBackground() - navigationController?.navigationBar.standardAppearance = barAppearance - navigationController?.navigationBar.compactAppearance = barAppearance - navigationController?.navigationBar.scrollEdgeAppearance = barAppearance + + switch traitCollection.userInterfaceIdiom { + case .pad: + if traitCollection.horizontalSizeClass == .regular { + // do nothing + } else { + fallthrough + } + default: + let barAppearance = UINavigationBarAppearance() + barAppearance.configureWithTransparentBackground() + navigationItem.standardAppearance = barAppearance + navigationItem.compactAppearance = barAppearance + navigationItem.scrollEdgeAppearance = barAppearance + if #available(iOS 15.0, *) { + navigationItem.compactScrollEdgeAppearance = barAppearance + } else { + // Fallback on earlier versions + } + } } func setupNavigationBarBackgroundView() { @@ -57,3 +76,12 @@ extension OnboardingViewControllerAppearance { } } + +extension OnboardingViewControllerAppearance { + static var viewEdgeMargin: CGFloat { + guard UIDevice.current.userInterfaceIdiom == .pad else { return .zero } + + let shortEdgeWidth = min(UIScreen.main.bounds.height, UIScreen.main.bounds.width) + return shortEdgeWidth * 0.17 // magic + } +} diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index 705ae6132..a2a266f9d 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -75,6 +75,8 @@ extension WelcomeViewController { override func viewDidLoad() { super.viewDidLoad() + navigationController?.navigationBar.prefersLargeTitles = true + navigationItem.largeTitleDisplayMode = .never view.overrideUserInterfaceStyle = .light setupOnboardingAppearance() @@ -235,7 +237,21 @@ extension WelcomeViewController { } // MARK: - OnboardingViewControllerAppearance -extension WelcomeViewController: OnboardingViewControllerAppearance { } +extension WelcomeViewController: OnboardingViewControllerAppearance { + func setupNavigationBarAppearance() { + // always transparent + let barAppearance = UINavigationBarAppearance() + barAppearance.configureWithTransparentBackground() + navigationItem.standardAppearance = barAppearance + navigationItem.compactAppearance = barAppearance + navigationItem.scrollEdgeAppearance = barAppearance + if #available(iOS 15.0, *) { + navigationItem.compactScrollEdgeAppearance = barAppearance + } else { + // Fallback on earlier versions + } + } +} // MARK: - UIAdaptivePresentationControllerDelegate extension WelcomeViewController: UIAdaptivePresentationControllerDelegate { @@ -245,7 +261,12 @@ extension WelcomeViewController: UIAdaptivePresentationControllerDelegate { // make underneath view controller alive to fix layout issue due to view life cycle return .fullScreen default: - return .pageSheet + switch traitCollection.horizontalSizeClass { + case .regular: + return .pageSheet + default: + return .fullScreen + } } } diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 1681b6171..d24a67c4a 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -317,7 +317,7 @@ extension MainTabBarController { switch tab { case .me: - coordinator.present(scene: .accountList, from: nil, transition: .panModal) + coordinator.present(scene: .accountList, from: self, transition: .panModal) default: break } @@ -353,7 +353,6 @@ extension MainTabBarController { self.avatarButton.setContentHuggingPriority(.required - 1, for: .vertical) self.avatarButton.isUserInteractionEnabled = false } - } extension MainTabBarController { diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 2e8beef9e..15464c9db 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -201,6 +201,12 @@ extension RootSplitViewController: UISplitViewControllerDelegate { displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode ) -> UISplitViewController.DisplayMode { let compactNavigationController = mainTabBarController.selectedViewController as? UINavigationController + + if let topMost = compactNavigationController?.topMost, + topMost is AccountListViewController { + topMost.dismiss(animated: false, completion: nil) + } + let viewControllers = compactNavigationController?.popToRootViewController(animated: true) ?? [] var supplementaryViewControllers: [UIViewController] = [] @@ -219,6 +225,7 @@ extension RootSplitViewController: UISplitViewControllerDelegate { if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { secondaryNavigationController.setViewControllers(secondaryNavigationController.viewControllers + secondaryViewControllers, animated: false) } + return proposedDisplayMode } From b5052cca5ec6183bd04bad7a5b963b489bff3216 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 8 Oct 2021 18:47:46 +0800 Subject: [PATCH 224/392] fix: make interface style preference as global setting --- .../CoreData 2.xcdatamodel/contents | 3 +-- CoreDataStack/Entity/Setting.swift | 24 +++++++++++-------- .../Diffiable/Section/SettingsSection.swift | 24 ++++++++----------- .../Extension/CoreDataStack/Setting.swift | 6 ++--- Mastodon/Info.plist | 2 ++ .../Settings/SettingsViewController.swift | 21 +++++++++------- .../SettingsAppearanceTableViewCell.swift | 2 ++ Mastodon/Service/SettingService.swift | 23 +++++++++--------- 8 files changed, 55 insertions(+), 50 deletions(-) diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents index 670241f35..c26a0bdbb 100644 --- a/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents +++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents @@ -191,7 +191,6 @@ - @@ -289,7 +288,7 @@ - + diff --git a/CoreDataStack/Entity/Setting.swift b/CoreDataStack/Entity/Setting.swift index 27971157f..94ee50959 100644 --- a/CoreDataStack/Entity/Setting.swift +++ b/CoreDataStack/Entity/Setting.swift @@ -13,7 +13,7 @@ public final class Setting: NSManagedObject { @NSManaged public var domain: String @NSManaged public var userID: String - @NSManaged public var appearanceRaw: String +// @NSManaged public var appearanceRaw: String @NSManaged public var preferredTrueBlackDarkMode: Bool @NSManaged public var preferredStaticAvatar: Bool @NSManaged public var preferredStaticEmoji: Bool @@ -41,17 +41,17 @@ extension Setting { property: Property ) -> Setting { let setting: Setting = context.insertObject() - setting.appearanceRaw = property.appearanceRaw +// setting.appearanceRaw = property.appearanceRaw setting.domain = property.domain setting.userID = property.userID return setting } - public func update(appearanceRaw: String) { - guard appearanceRaw != self.appearanceRaw else { return } - self.appearanceRaw = appearanceRaw - didUpdate(at: Date()) - } +// public func update(appearanceRaw: String) { +// guard appearanceRaw != self.appearanceRaw else { return } +// self.appearanceRaw = appearanceRaw +// didUpdate(at: Date()) +// } public func update(preferredTrueBlackDarkMode: Bool) { guard preferredTrueBlackDarkMode != self.preferredTrueBlackDarkMode else { return } @@ -87,12 +87,16 @@ extension Setting { public struct Property { public let domain: String public let userID: String - public let appearanceRaw: String +// public let appearanceRaw: String - public init(domain: String, userID: String, appearanceRaw: String) { + public init( + domain: String, + userID: String +// appearanceRaw: String + ) { self.domain = domain self.userID = userID - self.appearanceRaw = appearanceRaw +// self.appearanceRaw = appearanceRaw } } } diff --git a/Mastodon/Diffiable/Section/SettingsSection.swift b/Mastodon/Diffiable/Section/SettingsSection.swift index 939fd4315..f59c13587 100644 --- a/Mastodon/Diffiable/Section/SettingsSection.swift +++ b/Mastodon/Diffiable/Section/SettingsSection.swift @@ -41,21 +41,17 @@ extension SettingsSection { switch item { case .appearance(let objectID): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsAppearanceTableViewCell.self), for: indexPath) as! SettingsAppearanceTableViewCell - managedObjectContext.performAndWait { - let setting = managedObjectContext.object(with: objectID) as! Setting - cell.update(with: setting.appearance) - ManagedObjectObserver.observe(object: setting) - .receive(on: DispatchQueue.main) - .sink(receiveCompletion: { _ in - // do nothing - }, receiveValue: { [weak cell] change in - guard let cell = cell else { return } - guard case .update(let object) = change.changeType, - let setting = object as? Setting else { return } - cell.update(with: setting.appearance) - }) - .store(in: &cell.disposeBag) + UserDefaults.shared.observe(\.customUserInterfaceStyle, options: [.initial, .new]) { [weak cell] defaults, _ in + guard let cell = cell else { return } + switch defaults.customUserInterfaceStyle { + case .unspecified: cell.update(with: .automatic) + case .dark: cell.update(with: .dark) + case .light: cell.update(with: .light) + @unknown default: + assertionFailure() + } } + .store(in: &cell.observations) cell.delegate = settingsAppearanceTableViewCellDelegate return cell case .notification(let objectID, let switchMode): diff --git a/Mastodon/Extension/CoreDataStack/Setting.swift b/Mastodon/Extension/CoreDataStack/Setting.swift index b995b80e3..4d1fc0ca5 100644 --- a/Mastodon/Extension/CoreDataStack/Setting.swift +++ b/Mastodon/Extension/CoreDataStack/Setting.swift @@ -11,9 +11,9 @@ import MastodonSDK extension Setting { - var appearance: SettingsItem.AppearanceMode { - return SettingsItem.AppearanceMode(rawValue: appearanceRaw) ?? .automatic - } +// var appearance: SettingsItem.AppearanceMode { +// return SettingsItem.AppearanceMode(rawValue: appearanceRaw) ?? .automatic +// } var activeSubscription: Subscription? { return (subscriptions ?? Set()) diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 129f6bf10..c144fc6e7 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -2,6 +2,8 @@ + UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index 3b4e522e6..04c343647 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -439,7 +439,7 @@ extension SettingsViewController { .sink { _ in // do nothing } receiveValue: { _ in - // do nohting + // do nothing } .store(in: &disposeBag) } @@ -451,16 +451,19 @@ extension SettingsViewController: SettingsAppearanceTableViewCellDelegate { guard let dataSource = viewModel.dataSource else { return } guard let indexPath = tableView.indexPath(for: cell) else { return } let item = dataSource.itemIdentifier(for: indexPath) - guard case let .appearance(settingObjectID) = item else { return } + guard case .appearance = item else { return } - context.managedObjectContext.performChanges { - let setting = self.context.managedObjectContext.object(with: settingObjectID) as! Setting - setting.update(appearanceRaw: appearanceMode.rawValue) + switch appearanceMode { + case .automatic: + UserDefaults.shared.customUserInterfaceStyle = .unspecified + case .light: + UserDefaults.shared.customUserInterfaceStyle = .light + case .dark: + UserDefaults.shared.customUserInterfaceStyle = .dark } - .sink { _ in - let feedbackGenerator = UIImpactFeedbackGenerator(style: .light) - feedbackGenerator.impactOccurred() - }.store(in: &disposeBag) + + let feedbackGenerator = UIImpactFeedbackGenerator(style: .light) + feedbackGenerator.impactOccurred() } } diff --git a/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift b/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift index c4eb998e4..a4904136b 100644 --- a/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift +++ b/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift @@ -15,6 +15,7 @@ protocol SettingsAppearanceTableViewCellDelegate: AnyObject { class SettingsAppearanceTableViewCell: UITableViewCell { var disposeBag = Set() + var observations = Set() static let spacing: CGFloat = 18 @@ -59,6 +60,7 @@ class SettingsAppearanceTableViewCell: UITableViewCell { super.prepareForReuse() disposeBag.removeAll() + observations.removeAll() } // MARK: - Methods diff --git a/Mastodon/Service/SettingService.swift b/Mastodon/Service/SettingService.swift index 1c030c519..79ed47abf 100644 --- a/Mastodon/Service/SettingService.swift +++ b/Mastodon/Service/SettingService.swift @@ -54,8 +54,7 @@ final class SettingService { into: managedObjectContext, property: Setting.Property( domain: domain, - userID: userID, - appearanceRaw: SettingsItem.AppearanceMode.automatic.rawValue + userID: userID ) ) } // end for @@ -190,16 +189,16 @@ extension SettingService { static func updatePreference(setting: Setting) { // set appearance - let userInterfaceStyle: UIUserInterfaceStyle = { - switch setting.appearance { - case .automatic: return .unspecified - case .light: return .light - case .dark: return .dark - } - }() - if UserDefaults.shared.customUserInterfaceStyle != userInterfaceStyle { - UserDefaults.shared.customUserInterfaceStyle = userInterfaceStyle - } +// let userInterfaceStyle: UIUserInterfaceStyle = { +// switch setting.appearance { +// case .automatic: return .unspecified +// case .light: return .light +// case .dark: return .dark +// } +// }() +// if UserDefaults.shared.customUserInterfaceStyle != userInterfaceStyle { +// UserDefaults.shared.customUserInterfaceStyle = userInterfaceStyle +// } // set theme let themeName: ThemeName = setting.preferredTrueBlackDarkMode ? .system : .mastodon From 58daa930cb8f364ebedffef93b07cd0496c7d2ce Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 8 Oct 2021 19:05:28 +0800 Subject: [PATCH 225/392] feat: set status content direction if possible. resolve #295 --- Mastodon/Diffiable/Section/Status/StatusSection.swift | 9 +++++++++ Mastodon/Scene/Share/View/Content/StatusView.swift | 1 + 2 files changed, 10 insertions(+) diff --git a/Mastodon/Diffiable/Section/Status/StatusSection.swift b/Mastodon/Diffiable/Section/Status/StatusSection.swift index fe95c4c75..682422927 100644 --- a/Mastodon/Diffiable/Section/Status/StatusSection.swift +++ b/Mastodon/Diffiable/Section/Status/StatusSection.swift @@ -720,6 +720,15 @@ extension StatusSection { statusItemAttribute: Item.StatusAttribute ) { // set content + let paragraphStyle = cell.statusView.contentMetaText.paragraphStyle + if let language = (status.reblog ?? status).language { + let direction = Locale.characterDirection(forLanguage: language) + paragraphStyle.alignment = direction == .rightToLeft ? .right : .left + } else { + paragraphStyle.alignment = .natural + } + cell.statusView.contentMetaText.paragraphStyle = paragraphStyle + if let content = content { cell.statusView.contentMetaText.configure(content: content) cell.statusView.contentMetaText.textView.accessibilityLabel = content.trimmed diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift index 7afabd3a9..9a6907d1c 100644 --- a/Mastodon/Scene/Share/View/Content/StatusView.swift +++ b/Mastodon/Scene/Share/View/Content/StatusView.swift @@ -217,6 +217,7 @@ final class StatusView: UIView { let style = NSMutableParagraphStyle() style.lineSpacing = 5 style.paragraphSpacing = 8 + style.alignment = .natural return style }() metaText.textAttributes = [ From 2ef55bc5ca8db715bd7119d4cc1e5552974ef7d7 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 8 Oct 2021 19:09:34 +0800 Subject: [PATCH 226/392] chore: update version to 1.2.0 (72) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- .../xcshareddata/swiftpm/Package.resolved | 4 +- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 12 files changed, 47 insertions(+), 47 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 4c76ebcf8..d332d8527 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 4c76ebcf8..d332d8527 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 4c76ebcf8..d332d8527 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 07a833da7..674821cdb 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4760,7 +4760,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4789,7 +4789,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4897,11 +4897,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4928,11 +4928,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4957,11 +4957,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4987,11 +4987,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5054,7 +5054,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5079,7 +5079,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5104,7 +5104,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5129,7 +5129,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5154,7 +5154,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5179,7 +5179,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5204,7 +5204,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5229,7 +5229,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5320,7 +5320,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5387,11 +5387,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5436,7 +5436,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5461,11 +5461,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5557,7 +5557,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5624,11 +5624,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5673,7 +5673,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5698,11 +5698,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 71; + DYLIB_CURRENT_VERSION = 72; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5728,7 +5728,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5752,7 +5752,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 71; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index e6093a218..b0f597fa2 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 35 + 44 CoreDataStack.xcscheme_^#shared#^_ orderHint - 38 + 42 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 36 + 41 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 43 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1fe981b44..e118002a8 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -141,8 +141,8 @@ "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", "state": { "branch": null, - "revision": "76dd4b49110b8624317fc128e7fa0d8a252018bc", - "version": "5.11.1" + "revision": "d6367439527663d2038ca445a3c3c4e4bac40d60", + "version": "5.12.0" } }, { diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index c144fc6e7..601a346dd 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 71 + 72 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index e4bdca72f..cfbcd88df 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 4c76ebcf8..d332d8527 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 4c76ebcf8..d332d8527 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index ddb99a597..f5175f013 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 08ddef3f3..03a3f83e5 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 71 + 72 NSExtension NSExtensionAttributes From 714efa852c5d46e8c4f8cade1cff69641e499a86 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 8 Oct 2021 17:46:55 +0100 Subject: [PATCH 227/392] New translations Intents.stringsdict (Arabic) --- .../Intents/input/ar_SA/Intents.stringsdict | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.stringsdict index f273a551d..e44e666ae 100644 --- a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + هُناك %#@count_option@ تتطابق مَعَ '${content}'. count_option NSStringFormatSpecTypeKey @@ -13,23 +13,23 @@ NSStringFormatValueTypeKey %ld zero - %ld options + لا خيار one - 1 option + خيار واحد two - %ld options + خياران few - %ld options + %ld خيارات many - %ld options + %ld خيارًا other - %ld options + %ld خيار There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + هُناك %#@count_option@ تتطابق مَعَ '${visibility}'. count_option NSStringFormatSpecTypeKey @@ -37,17 +37,17 @@ NSStringFormatValueTypeKey %ld zero - %ld options + لا خيار one - 1 option + خيار واحد two - %ld options + خياران few - %ld options + %ld خيارات many - %ld options + %ld خيارًا other - %ld options + %ld خيار From 7113fc037ca349a88527ea3b3776cf75ed56a54f Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 9 Oct 2021 16:16:11 +0800 Subject: [PATCH 228/392] fix: reply crate duplicate mention issue. resolve #293 --- Mastodon/Scene/Compose/ComposeViewModel.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Compose/ComposeViewModel.swift b/Mastodon/Scene/Compose/ComposeViewModel.swift index f91565d38..d61be5fdd 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel.swift @@ -151,7 +151,9 @@ final class ComposeViewModel: NSObject { .sorted(by: { $0.index.intValue < $1.index.intValue }) .filter { $0.id != composeAuthor?.id } for mention in mentions { - mentionAccts.append("@" + mention.acct) + let acct = "@" + mention.acct + guard !mentionAccts.contains(acct) else { continue } + mentionAccts.append(acct) } for acct in mentionAccts { UITextChecker.learnWord(acct) From 1eb981258803e52cba72f50cf302fe6e0e55c5b1 Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 9 Oct 2021 19:01:08 +0800 Subject: [PATCH 229/392] feat: dynamic set compose post character limit. resolve #222 --- AppShared/UserDefaults+Notification.swift | 40 +++++++ AppShared/UserDefaults.swift | 31 ------ .../CoreData 2.xcdatamodel/contents | 11 +- CoreDataStack/Entity/Instance.swift | 70 ++++++++++++ .../Entity/MastodonAuthentication.swift | 11 +- Mastodon.xcodeproj/project.pbxproj | 24 +++- .../xcschemes/xcschememanagement.plist | 14 +-- .../Extension/CoreDataStack/Instance.swift | 25 +++++ .../NSDiffableDataSourceSnapshot.swift | 24 ---- .../Scene/Compose/ComposeViewController.swift | 6 +- .../Compose/ComposeViewModel+DataSource.swift | 11 +- Mastodon/Scene/Compose/ComposeViewModel.swift | 36 ++++-- .../APIService+CoreData+Instance.swift | 76 +++++++++++++ Mastodon/Service/InstanceService.swift | 103 ++++++++++++++++++ Mastodon/State/AppContext.swift | 6 + .../Entity/Mastodon+Entity+Instance.swift | 65 +++++++++++ 16 files changed, 465 insertions(+), 88 deletions(-) create mode 100644 AppShared/UserDefaults+Notification.swift create mode 100644 CoreDataStack/Entity/Instance.swift create mode 100644 Mastodon/Extension/CoreDataStack/Instance.swift delete mode 100644 Mastodon/Extension/NSDiffableDataSourceSnapshot.swift create mode 100644 Mastodon/Service/APIService/CoreData/APIService+CoreData+Instance.swift create mode 100644 Mastodon/Service/InstanceService.swift diff --git a/AppShared/UserDefaults+Notification.swift b/AppShared/UserDefaults+Notification.swift new file mode 100644 index 000000000..e743e70a0 --- /dev/null +++ b/AppShared/UserDefaults+Notification.swift @@ -0,0 +1,40 @@ +// +// UserDefaults+Notification.swift +// AppShared +// +// Created by Cirno MainasuK on 2021-10-9. +// + +import UIKit +import CryptoKit + +extension UserDefaults { + // always use hash value (SHA256) from accessToken as key + private static func deriveKey(from accessToken: String, prefix: String) -> String { + let digest = SHA256.hash(data: Data(accessToken.utf8)) + let bytes = [UInt8](digest) + let hex = bytes.toHexString() + let key = prefix + "@" + hex + return key + } + + private static let notificationCountKeyPrefix = "notification_count" + + public func getNotificationCountWithAccessToken(accessToken: String) -> Int { + let prefix = UserDefaults.notificationCountKeyPrefix + let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix) + return integer(forKey: key) + } + + public func setNotificationCountWithAccessToken(accessToken: String, value: Int) { + let prefix = UserDefaults.notificationCountKeyPrefix + let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix) + setValue(value, forKey: key) + } + + public func increaseNotificationCount(accessToken: String) { + let count = getNotificationCountWithAccessToken(accessToken: accessToken) + setNotificationCountWithAccessToken(accessToken: accessToken, value: count + 1) + } + +} diff --git a/AppShared/UserDefaults.swift b/AppShared/UserDefaults.swift index 67a3cf685..753a3284f 100644 --- a/AppShared/UserDefaults.swift +++ b/AppShared/UserDefaults.swift @@ -6,39 +6,8 @@ // import UIKit -import CryptoKit extension UserDefaults { public static let shared = UserDefaults(suiteName: AppName.groupID)! } -extension UserDefaults { - // always use hash value (SHA256) from accessToken as key - private static func deriveKey(from accessToken: String, prefix: String) -> String { - let digest = SHA256.hash(data: Data(accessToken.utf8)) - let bytes = [UInt8](digest) - let hex = bytes.toHexString() - let key = prefix + "@" + hex - return key - } - - private static let notificationCountKeyPrefix = "notification_count" - - public func getNotificationCountWithAccessToken(accessToken: String) -> Int { - let prefix = UserDefaults.notificationCountKeyPrefix - let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix) - return integer(forKey: key) - } - - public func setNotificationCountWithAccessToken(accessToken: String, value: Int) { - let prefix = UserDefaults.notificationCountKeyPrefix - let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix) - setValue(value, forKey: key) - } - - public func increaseNotificationCount(accessToken: String) { - let count = getNotificationCountWithAccessToken(accessToken: accessToken) - setNotificationCountWithAccessToken(accessToken: accessToken, value: count + 1) - } - -} diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents index c26a0bdbb..6d576ca15 100644 --- a/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents +++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData 2.xcdatamodel/contents @@ -63,6 +63,13 @@ + + + + + + + @@ -75,6 +82,7 @@ + @@ -280,7 +288,7 @@ - + @@ -293,5 +301,6 @@ + \ No newline at end of file diff --git a/CoreDataStack/Entity/Instance.swift b/CoreDataStack/Entity/Instance.swift new file mode 100644 index 000000000..8976097ef --- /dev/null +++ b/CoreDataStack/Entity/Instance.swift @@ -0,0 +1,70 @@ +// +// Instance.swift +// CoreDataStack +// +// Created by Cirno MainasuK on 2021-10-9. +// + +import Foundation +import CoreData + +public final class Instance: NSManagedObject { + @NSManaged public var domain: String + + @NSManaged public private(set) var createdAt: Date + @NSManaged public private(set) var updatedAt: Date + + @NSManaged public private(set) var configurationRaw: Data? + + // MARK: one-to-many relationships + @NSManaged public var authentications: Set +} + +extension Instance { + public override func awakeFromInsert() { + super.awakeFromInsert() + let now = Date() + setPrimitiveValue(now, forKey: #keyPath(Instance.createdAt)) + setPrimitiveValue(now, forKey: #keyPath(Instance.updatedAt)) + } + + @discardableResult + public static func insert( + into context: NSManagedObjectContext, + property: Property + ) -> Instance { + let instance: Instance = context.insertObject() + instance.domain = property.domain + return instance + } + + public func update(configurationRaw: Data?) { + self.configurationRaw = configurationRaw + } + + public func didUpdate(at networkDate: Date) { + self.updatedAt = networkDate + } +} + +extension Instance { + public struct Property { + public let domain: String + + public init(domain: String) { + self.domain = domain + } + } +} + +extension Instance: Managed { + public static var defaultSortDescriptors: [NSSortDescriptor] { + return [NSSortDescriptor(keyPath: \Instance.createdAt, ascending: false)] + } +} + +extension Instance { + public static func predicate(domain: String) -> NSPredicate { + return NSPredicate(format: "%K == %@", #keyPath(Instance.domain), domain) + } +} diff --git a/CoreDataStack/Entity/MastodonAuthentication.swift b/CoreDataStack/Entity/MastodonAuthentication.swift index 0ee0e343b..66b8ad6a9 100644 --- a/CoreDataStack/Entity/MastodonAuthentication.swift +++ b/CoreDataStack/Entity/MastodonAuthentication.swift @@ -30,6 +30,9 @@ final public class MastodonAuthentication: NSManagedObject { // one-to-one relationship @NSManaged public private(set) var user: MastodonUser + // many-to-one relationship + @NSManaged public private(set) var instance: Instance? + } extension MastodonAuthentication { @@ -97,6 +100,12 @@ extension MastodonAuthentication { } } + public func update(instance: Instance) { + if self.instance != instance { + self.instance = instance + } + } + public func didUpdate(at networkDate: Date) { self.updatedAt = networkDate } @@ -143,7 +152,7 @@ extension MastodonAuthentication: Managed { extension MastodonAuthentication { - static func predicate(domain: String) -> NSPredicate { + public static func predicate(domain: String) -> NSPredicate { return NSPredicate(format: "%K == %@", #keyPath(MastodonAuthentication.domain), domain) } diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 674821cdb..a1283ea0a 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -356,6 +356,11 @@ DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; }; DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; }; DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73B48F261F030A002E9E9F /* SafariActivity.swift */; }; + DB73BF3B2711885500781945 /* UserDefaults+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */; }; + DB73BF4127118B6D00781945 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF4027118B6D00781945 /* Instance.swift */; }; + DB73BF43271192BB00781945 /* InstanceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF42271192BB00781945 /* InstanceService.swift */; }; + DB73BF45271195AC00781945 /* APIService+CoreData+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF44271195AC00781945 /* APIService+CoreData+Instance.swift */; }; + DB73BF47271199CA00781945 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF46271199CA00781945 /* Instance.swift */; }; DB75BF1E263C1C1B00EDBF1F /* CustomScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */; }; DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */; }; DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */; }; @@ -454,7 +459,6 @@ DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */ = {isa = PBXBuildFile; productRef = DBAC6482267D0B21007FE9FD /* DifferenceKit */; }; DBAC6485267D0F9E007FE9FD /* StatusNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAC6484267D0F9E007FE9FD /* StatusNode.swift */; }; DBAC6488267D388B007FE9FD /* ASTableNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAC6487267D388B007FE9FD /* ASTableNode.swift */; }; - DBAC648A267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAC6489267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift */; }; DBAC648F267DC84D007FE9FD /* TableNodeDiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAC648E267DC84D007FE9FD /* TableNodeDiffableDataSource.swift */; }; DBAC6497267DECCB007FE9FD /* TimelineMiddleLoaderNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAC6496267DECCB007FE9FD /* TimelineMiddleLoaderNode.swift */; }; DBAC6499267DF2C4007FE9FD /* TimelineBottomLoaderNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAC6498267DF2C4007FE9FD /* TimelineBottomLoaderNode.swift */; }; @@ -1144,6 +1148,11 @@ DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = ""; }; DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = ""; }; DB73B48F261F030A002E9E9F /* SafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariActivity.swift; sourceTree = ""; }; + DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Notification.swift"; sourceTree = ""; }; + DB73BF4027118B6D00781945 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = ""; }; + DB73BF42271192BB00781945 /* InstanceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceService.swift; sourceTree = ""; }; + DB73BF44271195AC00781945 /* APIService+CoreData+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+CoreData+Instance.swift"; sourceTree = ""; }; + DB73BF46271199CA00781945 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = ""; }; DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomScheduler.swift; sourceTree = ""; }; DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewController.swift; sourceTree = ""; }; DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewModel.swift; sourceTree = ""; }; @@ -1270,7 +1279,6 @@ DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeIllustrationView.swift; sourceTree = ""; }; DBAC6484267D0F9E007FE9FD /* StatusNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusNode.swift; sourceTree = ""; }; DBAC6487267D388B007FE9FD /* ASTableNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASTableNode.swift; sourceTree = ""; }; - DBAC6489267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSDiffableDataSourceSnapshot.swift; sourceTree = ""; }; DBAC648E267DC84D007FE9FD /* TableNodeDiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableNodeDiffableDataSource.swift; sourceTree = ""; }; DBAC6496267DECCB007FE9FD /* TimelineMiddleLoaderNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMiddleLoaderNode.swift; sourceTree = ""; }; DBAC6498267DF2C4007FE9FD /* TimelineBottomLoaderNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineBottomLoaderNode.swift; sourceTree = ""; }; @@ -1771,6 +1779,7 @@ DB297B1A2679FAE200704C90 /* PlaceholderImageCacheService.swift */, DBAEDE5B267A058D00D25FF5 /* BlurhashImageCacheService.swift */, DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */, + DB73BF42271192BB00781945 /* InstanceService.swift */, ); path = Service; sourceTree = ""; @@ -2079,6 +2088,7 @@ DBAFB7342645463500371D5F /* Emojis.swift */, DBA94439265CC0FC00C537E1 /* Fields.swift */, DBA1DB7F268F84F80052DB59 /* NotificationType.swift */, + DB73BF46271199CA00781945 /* Instance.swift */, ); path = CoreDataStack; sourceTree = ""; @@ -2280,6 +2290,7 @@ 2D79E700261EA5550011E398 /* APIService+CoreData+Tag.swift */, DB6D9F56263577D2008423CD /* APIService+CoreData+Setting.swift */, 5B90C48A26259C120002E742 /* APIService+CoreData+Subscriptions.swift */, + DB73BF44271195AC00781945 /* APIService+CoreData+Instance.swift */, ); path = CoreData; sourceTree = ""; @@ -2454,6 +2465,7 @@ DB6804912637CD8700430867 /* AppName.swift */, DB6804FC2637CFEC00430867 /* AppSecret.swift */, DB6804D02637CE4700430867 /* UserDefaults.swift */, + DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */, ); path = AppShared; sourceTree = ""; @@ -2636,6 +2648,7 @@ 5B90C46D26259B2C0002E742 /* Setting.swift */, 5B90C46C26259B2C0002E742 /* Subscription.swift */, 5B90C47E26259BA90002E742 /* SubscriptionAlerts.swift */, + DB73BF4027118B6D00781945 /* Instance.swift */, ); path = Entity; sourceTree = ""; @@ -2716,7 +2729,6 @@ DB0E91E926A9675100BD2ACC /* MetaLabel.swift */, DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */, DB47229625F9EFAD00DA7F53 /* NSManagedObjectContext.swift */, - DBAC6489267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift */, DB0140CE25C42AEE00F9F3CF /* OSLog.swift */, 2D939AB425EDD8A90076FA61 /* String.swift */, DB68A06225E905E000CFDF14 /* UIApplication.swift */, @@ -3943,7 +3955,6 @@ DBBC24DC26A54BCB00398BB9 /* MastodonRegex.swift in Sources */, 2D69D00A25CAA00300C3A1B2 /* APIService+CoreData+Status.swift in Sources */, DB4481C625EE2ADA00BEFB67 /* PollSection.swift in Sources */, - DBAC648A267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift in Sources */, DBCBED1726132DB500B49291 /* UserTimelineViewModel+Diffable.swift in Sources */, DB71FD4C25F8C80E00512AE1 /* StatusPrefetchingService.swift in Sources */, 2DE0FACE2615F7AD00CDF649 /* RecommendAccountSection.swift in Sources */, @@ -3993,6 +4004,7 @@ DBAE3FAF26172FC0004B8251 /* RemoteProfileViewModel.swift in Sources */, DBE3CE0D261D767100430CC6 /* FavoriteViewController+Provider.swift in Sources */, 2D084B9326259545003AA3AF /* NotificationViewModel+LoadLatestState.swift in Sources */, + DB73BF47271199CA00781945 /* Instance.swift in Sources */, DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */, DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */, DB9E0D6F25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift in Sources */, @@ -4015,6 +4027,7 @@ 5B90C45E262599800002E742 /* SettingsViewModel.swift in Sources */, 2D82B9FF25E7863200E36F0F /* OnboardingViewControllerAppearance.swift in Sources */, 5DF1054725F8870E00D6C0D4 /* VideoPlayerViewModel.swift in Sources */, + DB73BF43271192BB00781945 /* InstanceService.swift in Sources */, DBA9443A265CC0FC00C537E1 /* Fields.swift in Sources */, 2DE0FAC12615F04D00CDF649 /* RecommendHashTagSection.swift in Sources */, DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */, @@ -4190,6 +4203,7 @@ DB0C946B26A700AB0088FB11 /* MastodonUser+Property.swift in Sources */, DB8AF54425C13647002E6C99 /* SceneCoordinator.swift in Sources */, 5DF1058525F88AE500D6C0D4 /* NeedsDependency+AVPlayerViewControllerDelegate.swift in Sources */, + DB73BF45271195AC00781945 /* APIService+CoreData+Instance.swift in Sources */, DB1D84382657B275000346B3 /* SegmentedControlNavigateable.swift in Sources */, DB447697260B439000B66B82 /* CustomEmojiPickerHeaderCollectionReusableView.swift in Sources */, DB45FAF925CA80A2005A8AC7 /* APIService+CoreData+MastodonAuthentication.swift in Sources */, @@ -4304,6 +4318,7 @@ buildActionMask = 2147483647; files = ( DB6804D12637CE4700430867 /* UserDefaults.swift in Sources */, + DB73BF3B2711885500781945 /* UserDefaults+Notification.swift in Sources */, DB4932B726F30F0700EF46D4 /* Array.swift in Sources */, DB6804922637CD8700430867 /* AppName.swift in Sources */, DB6804FD2637CFEC00430867 /* AppSecret.swift in Sources */, @@ -4324,6 +4339,7 @@ 2D927F0E25C7E9C9004F19B8 /* History.swift in Sources */, DBCC3B9B261584A00045B23D /* PrivateNote.swift in Sources */, DB89BA3725C1145C008580ED /* CoreData.xcdatamodeld in Sources */, + DB73BF4127118B6D00781945 /* Instance.swift in Sources */, DB8AF52525C131D1002E6C99 /* MastodonUser.swift in Sources */, DB89BA1B25C1107F008580ED /* Collection.swift in Sources */, DB4481AD25EE155900BEFB67 /* Poll.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b0f597fa2..b5ecab282 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 44 + 35 CoreDataStack.xcscheme_^#shared#^_ orderHint - 42 + 37 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -37,7 +37,7 @@ Mastodon - ca.xcscheme_^#shared#^_ orderHint - 16 + 18 Mastodon - de.xcscheme_^#shared#^_ @@ -67,7 +67,7 @@ Mastodon - jp.xcscheme_^#shared#^_ orderHint - 14 + 15 Mastodon - nl.xcscheme_^#shared#^_ @@ -87,7 +87,7 @@ Mastodon - zh_Hans.xcscheme_^#shared#^_ orderHint - 15 + 16 Mastodon.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 41 + 36 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 43 + 38 SuppressBuildableAutocreation diff --git a/Mastodon/Extension/CoreDataStack/Instance.swift b/Mastodon/Extension/CoreDataStack/Instance.swift new file mode 100644 index 000000000..6cacd9db9 --- /dev/null +++ b/Mastodon/Extension/CoreDataStack/Instance.swift @@ -0,0 +1,25 @@ +// +// Instance.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-9. +// + +import UIKit +import CoreDataStack +import MastodonSDK + +extension Instance { + var configuration: Mastodon.Entity.Instance.Configuration? { + guard let configurationRaw = configurationRaw else { return nil } + guard let configuration = try? JSONDecoder().decode(Mastodon.Entity.Instance.Configuration.self, from: configurationRaw) else { + return nil + } + + return configuration + } + + static func encode(configuration: Mastodon.Entity.Instance.Configuration) -> Data? { + return try? JSONEncoder().encode(configuration) + } +} diff --git a/Mastodon/Extension/NSDiffableDataSourceSnapshot.swift b/Mastodon/Extension/NSDiffableDataSourceSnapshot.swift deleted file mode 100644 index c2ff341d9..000000000 --- a/Mastodon/Extension/NSDiffableDataSourceSnapshot.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// NSDiffableDataSourceSnapshot.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021-6-19. -// - -import UIKit - -//extension NSDiffableDataSourceSnapshot { -// func itemIdentifier(for indexPath: IndexPath) -> ItemIdentifierType? { -// guard 0..() @@ -38,6 +37,24 @@ final class ComposeViewModel: NSObject { var isViewAppeared = false // output + let instanceConfiguration: Mastodon.Entity.Instance.Configuration? + var composeContentLimit: Int { + guard let maxCharacters = instanceConfiguration?.statuses?.maxCharacters else { return 500 } + return max(1, maxCharacters) + } + var maxMediaAttachments: Int { + guard let maxMediaAttachments = instanceConfiguration?.statuses?.maxMediaAttachments else { + return 4 + } + // FIXME: update timeline media preview UI + return min(4, max(1, maxMediaAttachments)) + // return max(1, maxMediaAttachments) + } + var maxPollOptions: Int { + guard let maxOptions = instanceConfiguration?.polls?.maxOptions else { return 4 } + return max(2, maxOptions) + } + let composeStatusContentTableViewCell = ComposeStatusContentTableViewCell() let composeStatusAttachmentTableViewCell = ComposeStatusAttachmentTableViewCell() let composeStatusPollTableViewCell = ComposeStatusPollTableViewCell() @@ -128,8 +145,12 @@ final class ComposeViewModel: NSObject { } return CurrentValueSubject(visibility) }() - self.activeAuthentication = CurrentValueSubject(context.authenticationService.activeMastodonAuthentication.value) + let _activeAuthentication = context.authenticationService.activeMastodonAuthentication.value + self.activeAuthentication = CurrentValueSubject(_activeAuthentication) self.activeAuthenticationBox = CurrentValueSubject(context.authenticationService.activeMastodonAuthenticationBox.value) + // set limit + let _instanceConfiguration = _activeAuthentication?.instance?.configuration + self.instanceConfiguration = _instanceConfiguration super.init() // end init @@ -243,8 +264,9 @@ final class ComposeViewModel: NSObject { let isComposeContentEmpty = composeStatusAttribute.composeContent .map { ($0 ?? "").isEmpty } let isComposeContentValid = characterCount - .map { characterCount -> Bool in - return characterCount <= ComposeViewModel.composeContentLimit + .compactMap { [weak self] characterCount -> Bool in + guard let self = self else { return characterCount <= 500 } + return characterCount <= self.composeContentLimit } let isMediaEmpty = attachmentServices .map { $0.isEmpty } @@ -381,7 +403,7 @@ final class ComposeViewModel: NSObject { .receive(on: DispatchQueue.main) .sink(receiveValue: { [weak self] isPollComposing, attachmentServices in guard let self = self else { return } - let shouldMediaDisable = isPollComposing || attachmentServices.count >= 4 + let shouldMediaDisable = isPollComposing || attachmentServices.count >= self.maxMediaAttachments let shouldPollDisable = attachmentServices.count > 0 self.isMediaToolbarButtonEnabled.value = !shouldMediaDisable @@ -455,7 +477,7 @@ extension ComposeViewModel { extension ComposeViewModel { func createNewPollOptionIfPossible() { - guard pollOptionAttributes.value.count < 4 else { return } + guard pollOptionAttributes.value.count < maxPollOptions else { return } let attribute = ComposeStatusPollItem.PollOptionAttribute() pollOptionAttributes.value = pollOptionAttributes.value + [attribute] @@ -488,7 +510,7 @@ extension ComposeViewModel { // check exclusive limit: // - up to 1 video - // - up to 4 photos + // - up to N photos func checkAttachmentPrecondition() throws { let attachmentServices = self.attachmentServices.value guard !attachmentServices.isEmpty else { return } diff --git a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Instance.swift b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Instance.swift new file mode 100644 index 000000000..614d098aa --- /dev/null +++ b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Instance.swift @@ -0,0 +1,76 @@ +// +// APIService+CoreData+Instance.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-9. +// + +import os.log +import Foundation +import CoreData +import CoreDataStack +import MastodonSDK + +extension APIService.CoreData { + + static func createOrMergeInstance( + into managedObjectContext: NSManagedObjectContext, + domain: String, + entity: Mastodon.Entity.Instance, + networkDate: Date, + log: OSLog + ) -> (instance: Instance, isCreated: Bool) { + // fetch old mastodon user + let old: Instance? = { + let request = Instance.sortedFetchRequest + request.predicate = Instance.predicate(domain: domain) + request.fetchLimit = 1 + request.returnsObjectsAsFaults = false + do { + return try managedObjectContext.fetch(request).first + } catch { + assertionFailure(error.localizedDescription) + return nil + } + }() + + if let old = old { + // merge old + APIService.CoreData.merge( + instance: old, + entity: entity, + domain: domain, + networkDate: networkDate + ) + return (old, false) + } else { + let instance = Instance.insert( + into: managedObjectContext, + property: Instance.Property(domain: domain) + ) + let configurationRaw = entity.configuration.flatMap { Instance.encode(configuration: $0) } + instance.update(configurationRaw: configurationRaw) + + return (instance, true) + } + } + +} + +extension APIService.CoreData { + + static func merge( + instance: Instance, + entity: Mastodon.Entity.Instance, + domain: String, + networkDate: Date + ) { + guard networkDate > instance.updatedAt else { return } + + let configurationRaw = entity.configuration.flatMap { Instance.encode(configuration: $0) } + instance.update(configurationRaw: configurationRaw) + + instance.didUpdate(at: networkDate) + } + +} diff --git a/Mastodon/Service/InstanceService.swift b/Mastodon/Service/InstanceService.swift new file mode 100644 index 000000000..4fb6309fd --- /dev/null +++ b/Mastodon/Service/InstanceService.swift @@ -0,0 +1,103 @@ +// +// InstanceService.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-9. +// + +import os.log +import Foundation +import Combine +import CoreData +import CoreDataStack +import MastodonSDK + +final class InstanceService { + + var disposeBag = Set() + + let logger = Logger(subsystem: "InstanceService", category: "Logic") + + // input + let backgroundManagedObjectContext: NSManagedObjectContext + weak var apiService: APIService? + weak var authenticationService: AuthenticationService? + + // output + + init( + apiService: APIService, + authenticationService: AuthenticationService + ) { + self.backgroundManagedObjectContext = apiService.backgroundManagedObjectContext + self.apiService = apiService + self.authenticationService = authenticationService + + authenticationService.activeMastodonAuthenticationBox + .receive(on: DispatchQueue.main) + .compactMap { $0?.domain } + .removeDuplicates() // prevent infinity loop + .sink { [weak self] domain in + guard let self = self else { return } + self.updateInstance(domain: domain) + } + .store(in: &disposeBag) + } + +} + +extension InstanceService { + func updateInstance(domain: String) { + guard let apiService = self.apiService else { return } + apiService.instance(domain: domain) + .flatMap { response -> AnyPublisher, Error> in + let managedObjectContext = self.backgroundManagedObjectContext + return managedObjectContext.performChanges { + // get instance + let (instance, _) = APIService.CoreData.createOrMergeInstance( + into: managedObjectContext, + domain: domain, + entity: response.value, + networkDate: response.networkDate, + log: OSLog.api + ) + + // update relationship + let request = MastodonAuthentication.sortedFetchRequest + request.predicate = MastodonAuthentication.predicate(domain: domain) + request.returnsObjectsAsFaults = false + do { + let authentications = try managedObjectContext.fetch(request) + for authentication in authentications { + authentication.update(instance: instance) + } + } catch { + assertionFailure(error.localizedDescription) + } + } + .setFailureType(to: Error.self) + .tryMap { result -> Mastodon.Response.Content in + switch result { + case .success: + return response + case .failure(let error): + throw error + } + } + .eraseToAnyPublisher() + } + .sink { [weak self] completion in + guard let self = self else { return } + switch completion { + case .failure(let error): + self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update instance failure: \(error.localizedDescription)") + case .finished: + self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update instance for domain: \(domain)") + } + } receiveValue: { [weak self] response in + guard let self = self else { return } + // do nothing + } + .store(in: &disposeBag) + } +} diff --git a/Mastodon/State/AppContext.swift b/Mastodon/State/AppContext.swift index d4682ed5e..d7c08d47f 100644 --- a/Mastodon/State/AppContext.swift +++ b/Mastodon/State/AppContext.swift @@ -31,6 +31,7 @@ class AppContext: ObservableObject { let statusPublishService = StatusPublishService() let notificationService: NotificationService let settingService: SettingService + let instanceService: InstanceService let blockDomainService: BlockDomainService let statusFilterService: StatusFilterService @@ -87,6 +88,11 @@ class AppContext: ObservableObject { notificationService: _notificationService ) + instanceService = InstanceService( + apiService: _apiService, + authenticationService: _authenticationService + ) + blockDomainService = BlockDomainService( backgroundManagedObjectContext: _backgroundManagedObjectContext, authenticationService: _authenticationService diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift index 226af40f8..d0d16ee4a 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift @@ -34,6 +34,9 @@ extension Mastodon.Entity { public let thumbnail: String? public let contactAccount: Account? public let rules: [Rule]? + + // https://github.com/mastodon/mastodon/pull/16485 + public let configuration: Configuration? enum CodingKeys: String, CodingKey { case uri @@ -52,6 +55,8 @@ extension Mastodon.Entity { case thumbnail case contactAccount = "contact_account" case rules + + case configuration } } } @@ -86,3 +91,63 @@ extension Mastodon.Entity.Instance { public let text: String } } + +extension Mastodon.Entity.Instance { + public struct Configuration: Codable { + public let statuses: Statuses? + public let mediaAttachments: MediaAttachments? + public let polls: Polls? + + enum CodingKeys: String, CodingKey { + case statuses + case mediaAttachments = "media_attachments" + case polls + } + } +} + +extension Mastodon.Entity.Instance.Configuration { + public struct Statuses: Codable { + public let maxCharacters: Int + public let maxMediaAttachments: Int + public let charactersReservedPerURL: Int + + enum CodingKeys: String, CodingKey { + case maxCharacters = "max_characters" + case maxMediaAttachments = "max_media_attachments" + case charactersReservedPerURL = "characters_reserved_per_url" + } + } + + public struct MediaAttachments: Codable { + public let supportedMIMETypes: [String] + public let imageSizeLimit: Int + public let imageMatrixLimit: Int + public let videoSizeLimit: Int + public let videoFrameRateLimit: Int + public let videoMatrixLimit: Int + + enum CodingKeys: String, CodingKey { + case supportedMIMETypes = "supported_mime_types" + case imageSizeLimit = "image_size_limit" + case imageMatrixLimit = "image_matrix_limit" + case videoSizeLimit = "video_size_limit" + case videoFrameRateLimit = "video_frame_rate_limit" + case videoMatrixLimit = "video_matrix_limit" + } + } + + public struct Polls: Codable { + public let maxOptions: Int + public let maxCharactersPerOption: Int + public let minExpiration: Int + public let maxExpiration: Int + + enum CodingKeys: String, CodingKey { + case maxOptions = "max_options" + case maxCharactersPerOption = "max_characters_per_option" + case minExpiration = "min_expiration" + case maxExpiration = "max_expiration" + } + } +} From 1bcf4cfd2fc45d3377f0bc58c504e6d5e390e73e Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 9 Oct 2021 19:15:04 +0800 Subject: [PATCH 230/392] chore: update i18n assets --- Mastodon/Resources/ar.lproj/InfoPlist.strings | 4 +- .../Resources/ar.lproj/Localizable.strings | 98 +++--- .../ar.lproj/Localizable.stringsdict | 286 +++++++++--------- .../Resources/de.lproj/Localizable.strings | 6 +- .../de.lproj/Localizable.stringsdict | 4 +- .../Resources/th.lproj/Localizable.strings | 12 +- .../th.lproj/Localizable.stringsdict | 2 +- 7 files changed, 206 insertions(+), 206 deletions(-) diff --git a/Mastodon/Resources/ar.lproj/InfoPlist.strings b/Mastodon/Resources/ar.lproj/InfoPlist.strings index 5ced1e74f..c3b26f14a 100644 --- a/Mastodon/Resources/ar.lproj/InfoPlist.strings +++ b/Mastodon/Resources/ar.lproj/InfoPlist.strings @@ -1,4 +1,4 @@ -"NSCameraUsageDescription" = "Used to take photo for post status"; -"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NSCameraUsageDescription" = "يُستخدم لالتقاط الصورة عِندَ نشر الحالات"; +"NSPhotoLibraryAddUsageDescription" = "يُستخدم لحِفظ الصورة في مكتبة الصور"; "NewPostShortcutItemTitle" = "منشور جديد"; "SearchShortcutItemTitle" = "البحث"; \ No newline at end of file diff --git a/Mastodon/Resources/ar.lproj/Localizable.strings b/Mastodon/Resources/ar.lproj/Localizable.strings index 3dfe057ed..98d8c09cb 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.strings +++ b/Mastodon/Resources/ar.lproj/Localizable.strings @@ -1,14 +1,14 @@ "Common.Alerts.BlockDomain.BlockEntireDomain" = "حظر النطاق"; "Common.Alerts.BlockDomain.Title" = "Are you really, really sure you want to block the entire %@? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed."; -"Common.Alerts.CleanCache.Message" = "تم تنظيف ذاكرة التخزين المؤقت %@ بنجاح."; -"Common.Alerts.CleanCache.Title" = "تنظيف ذاكرة التخزين المؤقت"; -"Common.Alerts.Common.PleaseTryAgain" = "الرجاء المحاولة مرة أخرى."; -"Common.Alerts.Common.PleaseTryAgainLater" = "الرجاء المحاولة مرة أخرى لاحقاً."; +"Common.Alerts.CleanCache.Message" = "تمَّ مَحو ذاكرة التخزين المؤقت %@ بنجاح."; +"Common.Alerts.CleanCache.Title" = "مَحو ذاكرة التخزين المؤقت"; +"Common.Alerts.Common.PleaseTryAgain" = "يُرجى المحاولة مرة أُخرى."; +"Common.Alerts.Common.PleaseTryAgainLater" = "يُرجى المحاولة مرة أُخرى لاحقاً."; "Common.Alerts.DeletePost.Delete" = "احذف"; "Common.Alerts.DeletePost.Title" = "هل أنت متأكد من أنك تريد حذف هذا المنشور؟"; "Common.Alerts.DiscardPostContent.Message" = "Confirm to discard composed post content."; "Common.Alerts.DiscardPostContent.Title" = "تجاهل المسودة"; -"Common.Alerts.EditProfileFailure.Message" = "لا يمكن تعديل الملف الشخصي. الرجاء المحاولة مرة أخرى."; +"Common.Alerts.EditProfileFailure.Message" = "لا يمكن تعديل الملف الشخصي. يُرجى المحاولة مرة أُخرى."; "Common.Alerts.EditProfileFailure.Title" = "Edit Profile Error"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images."; @@ -33,7 +33,7 @@ Please check your internet connection."; "Common.Controls.Actions.CopyPhoto" = "نسخ الصورة"; "Common.Controls.Actions.Delete" = "احذف"; "Common.Controls.Actions.Discard" = "تجاهل"; -"Common.Controls.Actions.Done" = "تم"; +"Common.Controls.Actions.Done" = "تمّ"; "Common.Controls.Actions.Edit" = "تعديل"; "Common.Controls.Actions.FindPeople" = "ابحث عن أشخاص لمتابعتهم"; "Common.Controls.Actions.ManuallySearch" = "البحث يدوياً بدلاً من ذلك"; @@ -53,11 +53,11 @@ Please check your internet connection."; "Common.Controls.Actions.Share" = "شارك"; "Common.Controls.Actions.SharePost" = "شارك المنشور"; "Common.Controls.Actions.ShareUser" = "شارك %@"; -"Common.Controls.Actions.SignIn" = "لِج"; -"Common.Controls.Actions.SignUp" = "انشئ حسابًا"; +"Common.Controls.Actions.SignIn" = "تسجيل الدخول"; +"Common.Controls.Actions.SignUp" = "إنشاء حِساب"; "Common.Controls.Actions.Skip" = "تخطي"; "Common.Controls.Actions.TakePhoto" = "التقط صورة"; -"Common.Controls.Actions.TryAgain" = "حاول مرة أخرى"; +"Common.Controls.Actions.TryAgain" = "المُحاولة مرة أُخرى"; "Common.Controls.Actions.UnblockDomain" = "إلغاء حظر %@"; "Common.Controls.Friendship.Block" = "حظر"; "Common.Controls.Friendship.BlockDomain" = "حظر %@"; @@ -69,8 +69,8 @@ Please check your internet connection."; "Common.Controls.Friendship.Mute" = "أكتم"; "Common.Controls.Friendship.MuteUser" = "أكتم %@"; "Common.Controls.Friendship.Muted" = "مكتوم"; -"Common.Controls.Friendship.Pending" = "Pending"; -"Common.Controls.Friendship.Request" = "Request"; +"Common.Controls.Friendship.Pending" = "قيد المُراجعة"; +"Common.Controls.Friendship.Request" = "إرسال طَلَب"; "Common.Controls.Friendship.Unblock" = "إلغاء الحَظر"; "Common.Controls.Friendship.UnblockUser" = "إلغاء حظر %@"; "Common.Controls.Friendship.Unmute" = "إلغاء الكتم"; @@ -109,13 +109,13 @@ Please check your internet connection."; "Common.Controls.Status.Tag.Link" = "الرابط"; "Common.Controls.Status.Tag.Mention" = "أشر إلى"; "Common.Controls.Status.Tag.Url" = "عنوان URL"; -"Common.Controls.Status.UserReblogged" = "%@ reblogged"; +"Common.Controls.Status.UserReblogged" = "أعادَ %@ تدوينها"; "Common.Controls.Status.UserRepliedTo" = "رد على %@"; "Common.Controls.Tabs.Home" = "الخيط الرئيسي"; "Common.Controls.Tabs.Notification" = "الإشعارات"; "Common.Controls.Tabs.Profile" = "الملف التعريفي"; "Common.Controls.Tabs.Search" = "بحث"; -"Common.Controls.Timeline.Filtered" = "Filtered"; +"Common.Controls.Timeline.Filtered" = "مُصفَّى"; "Common.Controls.Timeline.Header.BlockedWarning" = "You can’t view this user’s profile until they unblock you."; "Common.Controls.Timeline.Header.BlockingWarning" = "You can’t view this user's profile @@ -129,14 +129,14 @@ until they unblock you."; until you unblock them. Your profile looks like this to them."; "Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@’s account has been suspended."; -"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Load missing posts"; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "تحميل المنشورات المَفقودة"; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "تحميل المزيد من المنشورات..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "إظهار المزيد من الردود"; "Common.Controls.Timeline.Timestamp.Now" = "الأن"; -"Scene.AccountList.AddAccount" = "Add Account"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.AddAccount" = "إضافة حساب"; +"Scene.AccountList.DismissAccountSwitcher" = "تجاهُل مبدِّل الحساب"; "Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; -"Scene.Compose.Accessibility.AppendAttachment" = "Add Attachment"; +"Scene.Compose.Accessibility.AppendAttachment" = "إضافة مُرفَق"; "Scene.Compose.Accessibility.AppendPoll" = "اضافة استطلاع رأي"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "منتقي مخصص للإيموجي"; "Scene.Compose.Accessibility.DisableContentWarning" = "تعطيل تحذير الحتوى"; @@ -151,14 +151,14 @@ uploaded to Mastodon."; "Scene.Compose.Attachment.Video" = "فيديو"; "Scene.Compose.AutoComplete.SpaceToAdd" = "Space to add"; "Scene.Compose.ComposeAction" = "انشر"; -"Scene.Compose.ContentInputPlaceholder" = "ما الذي يجول ببالك"; +"Scene.Compose.ContentInputPlaceholder" = "أخبِرنا بِما يَجُولُ فِي ذِهنَك"; "Scene.Compose.ContentWarning.Placeholder" = "Write an accurate warning here..."; -"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Add Attachment - %@"; -"Scene.Compose.Keyboard.DiscardPost" = "Discard Post"; -"Scene.Compose.Keyboard.PublishPost" = "Publish Post"; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "إضافة مُرفَق - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "تجاهُل المنشور"; +"Scene.Compose.Keyboard.PublishPost" = "نَشر المَنشُور"; "Scene.Compose.Keyboard.SelectVisibilityEntry" = "اختر مدى الظهور - %@"; -"Scene.Compose.Keyboard.ToggleContentWarning" = "Toggle Content Warning"; -"Scene.Compose.Keyboard.TogglePoll" = "Toggle Poll"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "تبديل تحذير المُحتوى"; +"Scene.Compose.Keyboard.TogglePoll" = "تبديل الاستطلاع"; "Scene.Compose.MediaSelection.Browse" = "تصفح"; "Scene.Compose.MediaSelection.Camera" = "التقط صورة"; "Scene.Compose.MediaSelection.PhotoLibrary" = "مكتبة الصور"; @@ -180,23 +180,23 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.Button.DontReceiveEmail" = "لم أستلم أبدًا بريدا إلكترونيا"; "Scene.ConfirmEmail.Button.OpenEmailApp" = "افتح تطبيق البريد الإلكتروني"; "Scene.ConfirmEmail.DontReceiveEmail.Description" = "Check if your email address is correct as well as your junk folder if you haven’t."; -"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Resend Email"; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "إعادة إرسال البريد الإلكتروني"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "تحقق من بريدك الإلكتروني"; "Scene.ConfirmEmail.OpenEmailApp.Description" = "We just sent you an email. Check your junk folder if you haven’t."; "Scene.ConfirmEmail.OpenEmailApp.Mail" = "البريد"; -"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Open Email Client"; -"Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "فتح عميل البريد الإلكتروني"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "تحقَّق من بريدك الوارِد."; "Scene.ConfirmEmail.Subtitle" = "لقد أرسلنا للتو رسالة بريد إلكتروني إلى %@، اضغط على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيء واحد أخير."; "Scene.Favorite.Title" = "مفضلتك"; -"Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "إظهار منشورات جديدة"; "Scene.HomeTimeline.NavigationBarState.Offline" = "غير متصل"; "Scene.HomeTimeline.NavigationBarState.Published" = "تم نشره!"; "Scene.HomeTimeline.NavigationBarState.Publishing" = "جارٍ نشر المشاركة…"; "Scene.HomeTimeline.Title" = "الخيط الرئيسي"; "Scene.Notification.Keyobard.ShowEverything" = "إظهار كل شيء"; -"Scene.Notification.Keyobard.ShowMentions" = "Show Mentions"; +"Scene.Notification.Keyobard.ShowMentions" = "إظهار الإشارات"; "Scene.Notification.Title.Everything" = "الكل"; "Scene.Notification.Title.Mentions" = "الإشارات"; "Scene.Notification.UserFavorited Your Post" = "أضاف %@ منشورك إلى مفضلته"; @@ -204,7 +204,7 @@ uploaded to Mastodon."; "Scene.Notification.UserMentionedYou" = "أشار إليك %@"; "Scene.Notification.UserRebloggedYourPost" = "أعاد %@ تدوين مشاركتك"; "Scene.Notification.UserRequestedToFollowYou" = "طلب %@ متابعتك"; -"Scene.Notification.UserYourPollHasEnded" = "%@ Your poll has ended"; +"Scene.Notification.UserYourPollHasEnded" = "%@ اِنتهى استطلاعُكَ للرأي"; "Scene.Preview.Keyboard.ClosePreview" = "إغلاق المعاينة"; "Scene.Preview.Keyboard.ShowNext" = "إظهار التالي"; "Scene.Preview.Keyboard.ShowPrevious" = "إظهار السابق"; @@ -213,7 +213,7 @@ uploaded to Mastodon."; "Scene.Profile.Dashboard.Posts" = "منشورات"; "Scene.Profile.Fields.AddRow" = "إضافة صف"; "Scene.Profile.Fields.Placeholder.Content" = "المحتوى"; -"Scene.Profile.Fields.Placeholder.Label" = "Label"; +"Scene.Profile.Fields.Placeholder.Label" = "التسمية"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Message" = "Confirm to unblock %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Title" = "إلغاء حظر الحساب"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Confirm to unmute %@"; @@ -263,7 +263,7 @@ uploaded to Mastodon."; "Scene.Search.Recommend.Accounts.Title" = "حسابات قد تعجبك"; "Scene.Search.Recommend.ButtonText" = "طالع الكل"; "Scene.Search.Recommend.HashTag.Description" = "Hashtags that are getting quite a bit of attention"; -"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ people are talking"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ أشخاص يتحدَّثوا"; "Scene.Search.Recommend.HashTag.Title" = "ذات شعبية على ماستدون"; "Scene.Search.SearchBar.Cancel" = "إلغاء"; "Scene.Search.SearchBar.Placeholder" = "البحث عن وسوم أو مستخدمين·ات"; @@ -285,7 +285,7 @@ uploaded to Mastodon."; "Scene.ServerPicker.Button.Category.Games" = "ألعاب"; "Scene.ServerPicker.Button.Category.General" = "عام"; "Scene.ServerPicker.Button.Category.Journalism" = "صحافة"; -"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Lgbt" = "مجتمع الشواذ"; "Scene.ServerPicker.Button.Category.Music" = "موسيقى"; "Scene.ServerPicker.Button.Category.Regional" = "اقليمي"; "Scene.ServerPicker.Button.Category.Tech" = "تكنولوجيا"; @@ -309,38 +309,38 @@ any server."; "Scene.Settings.Footer.MastodonDescription" = "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على غيت هب %@ (%@)"; "Scene.Settings.Keyboard.CloseSettingsWindow" = "إغلاق نافذة الإعدادات"; "Scene.Settings.Section.Appearance.Automatic" = "تلقائي"; -"Scene.Settings.Section.Appearance.Dark" = "Always Dark"; -"Scene.Settings.Section.Appearance.Light" = "Always Light"; +"Scene.Settings.Section.Appearance.Dark" = "مظلمٌ دائِمًا"; +"Scene.Settings.Section.Appearance.Light" = "مضيءٌ دائمًا"; "Scene.Settings.Section.Appearance.Title" = "المظهر"; "Scene.Settings.Section.BoringZone.AccountSettings" = "إعدادات الحساب"; "Scene.Settings.Section.BoringZone.Privacy" = "سياسة الخصوصية"; "Scene.Settings.Section.BoringZone.Terms" = "شروط الخدمة"; "Scene.Settings.Section.BoringZone.Title" = "المنطقة المملة"; -"Scene.Settings.Section.Notifications.Boosts" = "Reblogs my post"; -"Scene.Settings.Section.Notifications.Favorites" = "Favorites my post"; +"Scene.Settings.Section.Notifications.Boosts" = "إعادة تدوين منشوراتي"; +"Scene.Settings.Section.Notifications.Favorites" = "الإعجاب بِمنشوراتي"; "Scene.Settings.Section.Notifications.Follows" = "يتابعني"; -"Scene.Settings.Section.Notifications.Mentions" = "Mentions me"; +"Scene.Settings.Section.Notifications.Mentions" = "الإشارة لي"; "Scene.Settings.Section.Notifications.Title" = "الإشعارات"; -"Scene.Settings.Section.Notifications.Trigger.Anyone" = "anyone"; -"Scene.Settings.Section.Notifications.Trigger.Follow" = "anyone I follow"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "أي شخص"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "أي شخص أُتابِعُه"; "Scene.Settings.Section.Notifications.Trigger.Follower" = "مشترِك"; -"Scene.Settings.Section.Notifications.Trigger.Noone" = "no one"; -"Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when"; -"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars"; -"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "لا أحد"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "إشعاري عِندَ"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "تعطيل الصور الرمزية المتحرِّكة"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "تعطيل الرموز التعبيرية المتحرِّكَة"; "Scene.Settings.Section.Preference.Title" = "التفضيلات"; -"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode"; -"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "النمط الأسود الداكِن الحقيقي"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "اِستخدام المتصفح الافتراضي لفتح الروابط"; "Scene.Settings.Section.SpicyZone.Clear" = "مسح ذاكرة التخزين المؤقت للوسائط"; "Scene.Settings.Section.SpicyZone.Signout" = "تسجيل الخروج"; "Scene.Settings.Section.SpicyZone.Title" = "المنطقة الحارة"; "Scene.Settings.Title" = "الإعدادات"; "Scene.SuggestionAccount.FollowExplain" = "When you follow someone, you’ll see their posts in your home feed."; "Scene.SuggestionAccount.Title" = "ابحث عن أشخاص لمتابعتهم"; -"Scene.Thread.BackTitle" = "Post"; -"Scene.Thread.Title" = "Post from %@"; +"Scene.Thread.BackTitle" = "منشور"; +"Scene.Thread.Title" = "مَنشور مِن %@"; "Scene.Welcome.Slogan" = "Social networking back in your hands."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.AccessibilityHint" = "انقر نقرًا مزدوجًا لتجاهل النافذة المنبثقة"; "Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.NewInMastodon" = "جديد في ماستودون"; \ No newline at end of file diff --git a/Mastodon/Resources/ar.lproj/Localizable.stringsdict b/Mastodon/Resources/ar.lproj/Localizable.stringsdict index e6b0d5f95..e3dee0d80 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ar.lproj/Localizable.stringsdict @@ -15,21 +15,21 @@ zero %ld unread notification one - 1 unread notification + إشعار واحِد غير مقروء two - %ld unread notification + إشعاران غير مقروءان few %ld unread notification many - %ld unread notification + %ld إشعارًا غيرَ مقروء other - %ld unread notification + %ld إشعار غير مقروء a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + تمَّ تجاوز حدّ الإدخال %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -37,23 +37,23 @@ NSStringFormatValueTypeKey ld zero - %ld characters + لا حرف one - 1 character + حرفٌ واحِد two - %ld characters + حرفان اثنان few - %ld characters + %ld حُرُوف many - %ld characters + %ld حرفًا other - %ld characters + %ld حَرف a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + يتبقَّى على حدّ الإدخال %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -61,17 +61,17 @@ NSStringFormatValueTypeKey ld zero - %ld characters + لا حرف one - 1 character + حرفٌ واحِد two - %ld characters + حرفان اثنان few - %ld characters + %ld حُرُوف many - %ld characters + %ld حرفًا other - %ld characters + %ld حَرف plural.count.metric_formatted.post @@ -85,17 +85,17 @@ NSStringFormatValueTypeKey ld zero - posts + لا منشور one - post + منشور two - posts + منشوران few - posts + منشورات many - posts + منشورًا other - posts + منشور plural.count.post @@ -109,17 +109,17 @@ NSStringFormatValueTypeKey ld zero - %ld posts + لا منشور one - 1 post + منشورٌ واحِد two - %ld posts + منشورانِ اثنان few - %ld posts + %ld منشورات many - %ld posts + %ld منشورًا other - %ld posts + %ld منشور plural.count.favorite @@ -133,17 +133,17 @@ NSStringFormatValueTypeKey ld zero - %ld favorites + لا إعجاب one - 1 favorite + إعجابٌ واحِد two - %ld favorites + إعجابانِ اثنان few - %ld favorites + %ld إعجابات many - %ld favorites + %ld إعجابًا other - %ld favorites + %ld إعجاب plural.count.reblog @@ -157,17 +157,17 @@ NSStringFormatValueTypeKey ld zero - %ld reblogs + لا إعاد تدوين one - 1 reblog + إعادةُ تدوينٍ واحِدة two - %ld reblogs + إعادتا تدوين few - %ld reblogs + %ld إعاداتِ تدوين many - %ld reblogs + %ld إعادةٍ للتدوين other - %ld reblogs + %ld إعادة تدوين plural.count.vote @@ -181,17 +181,17 @@ NSStringFormatValueTypeKey ld zero - %ld votes + لا صوت one - 1 vote + صوتٌ واحِد two - %ld votes + صوتانِ اثنان few - %ld votes + %ld أصوات many - %ld votes + %ld صوتًا other - %ld votes + %ld صوت plural.count.voter @@ -205,17 +205,17 @@ NSStringFormatValueTypeKey ld zero - %ld voters + لا مُصوِّتون one - 1 voter + مُصوِّتٌ واحِد two - %ld voters + مُصوِّتانِ اثنان few - %ld voters + %ld مُصوِّتين many - %ld voters + %ld مُصوِّتًا other - %ld voters + %ld مُصوِّت plural.people_talking @@ -229,17 +229,17 @@ NSStringFormatValueTypeKey ld zero - %ld people talking + لا أحَدَ يتحدَّث one - 1 people talking + شخصٌ واحدٌ يتحدَّث two - %ld people talking + شخصانِ اثنان يتحدَّثا few - %ld people talking + %ld أشخاصٍ يتحدَّثون many - %ld people talking + %ld شخصًا يتحدَّثون other - %ld people talking + %ld شخصٍ يتحدَّثون plural.count.following @@ -253,17 +253,17 @@ NSStringFormatValueTypeKey ld zero - %ld following + لا مُتابَع one - 1 following + مُتابَعٌ واحد two - %ld following + مُتابَعانِ few - %ld following + %ld مُتابَعين many - %ld following + %ld مُتابَعًا other - %ld following + %ld مُتابَع plural.count.follower @@ -279,15 +279,15 @@ zero %ld followers one - 1 follower + مُتابِعٌ واحد two - %ld followers + مُتابِعانِ اثنان few - %ld followers + %ld مُتابِعين many - %ld followers + %ld مُتابِعًا other - %ld followers + %ld مُتابِع date.year.left @@ -301,17 +301,17 @@ NSStringFormatValueTypeKey ld zero - %ld years left + تتبقى لَحظة one - 1 year left + تتبقى سنة two - %ld years left + تتبقى سنتين few - %ld years left + تتبقى %ld سنوات many - %ld years left + تتبقى %ld سنةً other - %ld years left + تتبقى %ld سنة date.month.left @@ -325,17 +325,17 @@ NSStringFormatValueTypeKey ld zero - %ld months left + تتبقى لَحظة one - 1 months left + يتبقى شهر two - %ld months left + يتبقى شهرين few - %ld months left + يتبقى %ld أشهر many - %ld months left + يتبقى %ld شهرًا other - %ld months left + يتبقى %ld شهر date.day.left @@ -349,17 +349,17 @@ NSStringFormatValueTypeKey ld zero - %ld days left + تتبقى لحظة one - 1 day left + يتبقى يوم two - %ld days left + يتبقى يومين few - %ld days left + يتبقى %ld أيام many - %ld days left + يتبقى %ld يومًا other - %ld days left + يتبقى %ld يوم date.hour.left @@ -373,17 +373,17 @@ NSStringFormatValueTypeKey ld zero - %ld hours left + تتبقى لَحظة one - 1 hour left + تتبقى ساعة two - %ld hours left + تتبقى ساعتين few - %ld hours left + تتبقى %ld ساعات many - %ld hours left + تتبقى %ld ساعةً other - %ld hours left + تتبقى %ld ساعة date.minute.left @@ -397,17 +397,17 @@ NSStringFormatValueTypeKey ld zero - %ld minutes left + تتبقى لَحظة one - 1 minute left + تتبقى دقيقة two - %ld minutes left + تتبقى دقيقتين few - %ld minutes left + تتبقى %ld دقائق many - %ld minutes left + تتبقى %ld دقيقةً other - %ld minutes left + تتبقى %ld دقيقة date.second.left @@ -421,17 +421,17 @@ NSStringFormatValueTypeKey ld zero - %ld seconds left + تتبقى لَحظة one - 1 second left + تتبقى ثانية two - %ld seconds left + تتبقى ثانيتين few - %ld seconds left + تتبقى %ld ثوان many - %ld seconds left + تتبقى %ld ثانيةً other - %ld seconds left + تتبقى %ld ثانية date.year.ago.abbr @@ -445,17 +445,17 @@ NSStringFormatValueTypeKey ld zero - %ldy ago + مُنذُ لَحظة one - 1y ago + مُنذُ سنة two - %ldy ago + مُنذُ سنتين few - %ldy ago + مُنذُ %ld سنين many - %ldy ago + مُنذُ %ld سنةً other - %ldy ago + مُنذُ %ld سنة date.month.ago.abbr @@ -469,17 +469,17 @@ NSStringFormatValueTypeKey ld zero - %ldM ago + مُنذُ لَحظة one - 1M ago + مُنذُ شهر two - %ldM ago + مُنذُ شهرين few - %ldM ago + مُنذُ %ld أشهُر many - %ldM ago + مُنذُ %ld شهرًا other - %ldM ago + مُنذُ %ld شهر date.day.ago.abbr @@ -493,17 +493,17 @@ NSStringFormatValueTypeKey ld zero - %ldd ago + مُنذُ لَحظة one - 1d ago + مُنذُ يوم two - %ldd ago + مُنذُ يومين few - %ldd ago + مُنذُ %ld أيام many - %ldd ago + مُنذُ %ld يومًا other - %ldd ago + مُنذُ %ld يوم date.hour.ago.abbr @@ -517,17 +517,17 @@ NSStringFormatValueTypeKey ld zero - %ldh ago + مُنذُ لَحظة one - 1h ago + مُنذُ ساعة two - %ldh ago + مُنذُ ساعتين few - %ldh ago + مُنذُ %ld ساعات many - %ldh ago + مُنذُ %ld ساعةًَ other - %ldh ago + مُنذُ %ld ساعة date.minute.ago.abbr @@ -541,17 +541,17 @@ NSStringFormatValueTypeKey ld zero - %ldm ago + مُنذُ لَحظة one - 1m ago + مُنذُ دقيقة two - %ldm ago + مُنذُ دقيقتان few - %ldm ago + مُنذُ %ld دقائق many - %ldm ago + مُنذُ %ld دقيقةً other - %ldm ago + مُنذُ %ld دقيقة date.second.ago.abbr @@ -565,17 +565,17 @@ NSStringFormatValueTypeKey ld zero - %lds ago + مُنذُ لَحظة one - 1s ago + مُنذُ ثانية two - %lds ago + مُنذُ ثانيتين few - %lds ago + مُنذُ %ld ثوان many - %lds ago + مُنذُ %ld ثانية other - %lds ago + مُنذُ %ld ثانية diff --git a/Mastodon/Resources/de.lproj/Localizable.strings b/Mastodon/Resources/de.lproj/Localizable.strings index cc92b8e77..51028d7a8 100644 --- a/Mastodon/Resources/de.lproj/Localizable.strings +++ b/Mastodon/Resources/de.lproj/Localizable.strings @@ -133,7 +133,7 @@ Dein Profil sieht für diesen Benutzer auch so aus."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Lade fehlende Beiträge..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Weitere Antworten anzeigen"; "Common.Controls.Timeline.Timestamp.Now" = "Gerade"; -"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.AddAccount" = "Konto hinzufügen"; "Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; "Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Anhang hinzufügen"; @@ -340,6 +340,6 @@ beliebigen Server."; "Scene.Thread.BackTitle" = "Beitrag"; "Scene.Thread.Title" = "Beitrag von %@"; "Scene.Welcome.Slogan" = "Soziale Netzwerke wieder in deinen Händen."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.AccessibilityHint" = "Doppeltippen, um diesen Assistenten zu schließen"; "Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.NewInMastodon" = "Neu in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/de.lproj/Localizable.stringsdict b/Mastodon/Resources/de.lproj/Localizable.stringsdict index c868bdc0f..66b7f2a2d 100644 --- a/Mastodon/Resources/de.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/de.lproj/Localizable.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 ungelesene Benachrichtigung other - %ld unread notification + %ld ungelesene Benachrichtigungen a11y.plural.count.input_limit_exceeds diff --git a/Mastodon/Resources/th.lproj/Localizable.strings b/Mastodon/Resources/th.lproj/Localizable.strings index 0c586cab3..a61b1d15f 100644 --- a/Mastodon/Resources/th.lproj/Localizable.strings +++ b/Mastodon/Resources/th.lproj/Localizable.strings @@ -133,9 +133,9 @@ "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "กำลังโหลดโพสต์ที่ขาดหายไป..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "แสดงการตอบกลับเพิ่มเติม"; "Common.Controls.Timeline.Timestamp.Now" = "ตอนนี้"; -"Scene.AccountList.AddAccount" = "Add Account"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.AddAccount" = "เพิ่มบัญชี"; +"Scene.AccountList.DismissAccountSwitcher" = "ปิดตัวสลับบัญชี"; +"Scene.AccountList.TabBarHint" = "โปรไฟล์ที่เลือกในปัจจุบัน: %@ แตะสองครั้งแล้วกดค้างไว้เพื่อแสดงตัวสลับบัญชี"; "Scene.Compose.Accessibility.AppendAttachment" = "เพิ่มไฟล์แนบ"; "Scene.Compose.Accessibility.AppendPoll" = "เพิ่มการสำรวจความคิดเห็น"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "ตัวเลือกอีโมจิที่กำหนดเอง"; @@ -341,6 +341,6 @@ "Scene.Thread.Title" = "โพสต์จาก %@"; "Scene.Welcome.Slogan" = "ให้เครือข่ายสังคม กลับมาอยู่ในมือของคุณ"; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.AccessibilityHint" = "แตะสองครั้งเพื่อปิดตัวช่วยสร้างนี้"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "สลับระหว่างหลายบัญชีโดยกดปุ่มโปรไฟล์ค้างไว้"; +"Scene.Wizard.NewInMastodon" = "มาใหม่ใน Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/th.lproj/Localizable.stringsdict b/Mastodon/Resources/th.lproj/Localizable.stringsdict index 1d6ff10bc..8971821f6 100644 --- a/Mastodon/Resources/th.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/th.lproj/Localizable.stringsdict @@ -13,7 +13,7 @@ NSStringFormatValueTypeKey ld other - %ld unread notification + %ld การแจ้งเตือนที่ยังไม่ได้อ่าน a11y.plural.count.input_limit_exceeds From 3b7e52edfa6328ec5f502f42eee543ea4a8313c7 Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 9 Oct 2021 19:25:42 +0800 Subject: [PATCH 231/392] chore: update version to 1.2.0 (73) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- .../xcshareddata/swiftpm/Package.resolved | 9 --- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 12 files changed, 45 insertions(+), 54 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index d332d8527..d6c057eb7 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index d332d8527..d6c057eb7 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index d332d8527..d6c057eb7 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a1283ea0a..009fbb446 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4776,7 +4776,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4805,7 +4805,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4913,11 +4913,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4944,11 +4944,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4973,11 +4973,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5003,11 +5003,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5070,7 +5070,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5095,7 +5095,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5120,7 +5120,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5145,7 +5145,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5170,7 +5170,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5195,7 +5195,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5220,7 +5220,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5245,7 +5245,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5336,7 +5336,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5403,11 +5403,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5452,7 +5452,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5477,11 +5477,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5573,7 +5573,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5640,11 +5640,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5689,7 +5689,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5714,11 +5714,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 72; + DYLIB_CURRENT_VERSION = 73; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5744,7 +5744,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5768,7 +5768,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b5ecab282..915ce8a0f 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 35 + 42 CoreDataStack.xcscheme_^#shared#^_ orderHint - 37 + 41 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 36 + 43 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 38 + 44 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index e118002a8..43a0036bd 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -216,15 +216,6 @@ "revision": "dad97167bf1be16aeecd109130900995dd01c515", "version": "2.6.0" } - }, - { - "package": "UITextView+Placeholder", - "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder", - "state": { - "branch": null, - "revision": "20f513ded04a040cdf5467f0891849b1763ede3b", - "version": "1.4.1" - } } ] }, diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 601a346dd..64cf3e07b 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 72 + 73 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index cfbcd88df..298c2a3d4 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index d332d8527..d6c057eb7 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index d332d8527..d6c057eb7 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index f5175f013..b9054fc14 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 03a3f83e5..de78b7103 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 72 + 73 NSExtension NSExtensionAttributes From 051a8f40e313367655d341186287e4e1fb9366d9 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 11:07:42 +0800 Subject: [PATCH 232/392] fix: logic error prevent status action menu display intro in 80ea6ac --- Mastodon/Protocol/UserProvider/UserProviderFacade.swift | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Mastodon/Protocol/UserProvider/UserProviderFacade.swift b/Mastodon/Protocol/UserProvider/UserProviderFacade.swift index 47490c2d8..f85881943 100644 --- a/Mastodon/Protocol/UserProvider/UserProviderFacade.swift +++ b/Mastodon/Protocol/UserProvider/UserProviderFacade.swift @@ -221,8 +221,6 @@ extension UserProviderFacade { state: .off ) { [weak provider, weak sourceView, weak barButtonItem] _ in guard let provider = provider else { return } - guard let sourceView = sourceView else { return } - guard let barButtonItem = barButtonItem else { return } let activityViewController = createActivityViewControllerForMastodonUser(mastodonUser: shareUser, dependency: provider) provider.coordinator.present( scene: .activityViewController( @@ -247,8 +245,6 @@ extension UserProviderFacade { state: .off ) { [weak provider, weak sourceView, weak barButtonItem] _ in guard let provider = provider else { return } - guard let sourceView = sourceView else { return } - guard let barButtonItem = barButtonItem else { return } let activityViewController = createActivityViewControllerForMastodonUser(status: shareStatus, dependency: provider) provider.coordinator.present( scene: .activityViewController( @@ -273,7 +269,6 @@ extension UserProviderFacade { state: .off ) { [weak provider, weak cell] _ in guard let provider = provider else { return } - guard let cell = cell else { return } UserProviderFacade.toggleUserMuteRelationship( provider: provider, @@ -304,7 +299,6 @@ extension UserProviderFacade { state: .off ) { [weak provider, weak cell] _ in guard let provider = provider else { return } - guard let cell = cell else { return } UserProviderFacade.toggleUserBlockRelationship( provider: provider, @@ -364,7 +358,6 @@ extension UserProviderFacade { state: .off ) { [weak provider, weak cell] _ in guard let provider = provider else { return } - guard let cell = cell else { return } provider.context.blockDomainService.unblockDomain(userProvider: provider, cell: cell) } children.append(unblockDomainAction) @@ -378,14 +371,12 @@ extension UserProviderFacade { state: .off ) { [weak provider, weak cell] _ in guard let provider = provider else { return } - guard let cell = cell else { return } let alertController = UIAlertController(title: L10n.Common.Alerts.BlockDomain.title(mastodonUser.domainFromAcct), message: nil, preferredStyle: .alert) let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in } alertController.addAction(cancelAction) let blockDomainAction = UIAlertAction(title: L10n.Common.Alerts.BlockDomain.blockEntireDomain, style: .destructive) { [weak provider, weak cell] _ in guard let provider = provider else { return } - guard let cell = cell else { return } provider.context.blockDomainService.blockDomain(userProvider: provider, cell: cell) } alertController.addAction(blockDomainAction) From e5a3c4ae0ded68f40c9cea72c94434a34c483bd5 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 12:35:20 +0800 Subject: [PATCH 233/392] fix: iOS 15 new tab bar appearance not override issue --- Mastodon/Service/ThemeService/ThemeService+Appearance.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift b/Mastodon/Service/ThemeService/ThemeService+Appearance.swift index 8130942aa..cffa45c7a 100644 --- a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift +++ b/Mastodon/Service/ThemeService/ThemeService+Appearance.swift @@ -48,6 +48,11 @@ extension ThemeService { tabBarAppearance.backgroundColor = theme.tabBarBackgroundColor tabBarAppearance.selectionIndicatorTintColor = Asset.Colors.brandBlue.color UITabBar.appearance().standardAppearance = tabBarAppearance + if #available(iOS 15.0, *) { + UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance + } else { + // Fallback on earlier versions + } UITabBar.appearance().barTintColor = theme.tabBarBackgroundColor // set table view cell appearance From 7e37d2c7c93fd98ed855d79ce124acd4c8f72574 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 12:59:15 +0800 Subject: [PATCH 234/392] fix: status header icon not align on iOS 15 issue --- .../Section/Status/StatusSection.swift | 4 ++-- Mastodon/Extension/MetaLabel.swift | 18 ++++++++++++++++++ .../Compose/ComposeViewModel+DataSource.swift | 2 +- .../Scene/Compose/View/ReplicaStatusView.swift | 7 ++++--- .../Scene/Share/View/Content/StatusView.swift | 7 ++++--- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Mastodon/Diffiable/Section/Status/StatusSection.swift b/Mastodon/Diffiable/Section/Status/StatusSection.swift index 682422927..ceb0c9458 100644 --- a/Mastodon/Diffiable/Section/Status/StatusSection.swift +++ b/Mastodon/Diffiable/Section/Status/StatusSection.swift @@ -639,7 +639,7 @@ extension StatusSection { ) { if status.reblog != nil { cell.statusView.headerContainerView.isHidden = false - cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage) + cell.statusView.headerIconLabel.configure(attributedString: StatusView.iconAttributedString(image: StatusView.reblogIconImage)) let headerText: String = { let author = status.author let name = author.displayName.isEmpty ? author.username : author.displayName @@ -657,7 +657,7 @@ extension StatusSection { cell.statusView.headerInfoLabel.isAccessibilityElement = true } else if status.inReplyToID != nil { cell.statusView.headerContainerView.isHidden = false - cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage) + cell.statusView.headerIconLabel.configure(attributedString: StatusView.iconAttributedString(image: StatusView.replyIconImage)) let headerText: String = { guard let replyTo = status.replyTo else { return L10n.Common.Controls.Status.userRepliedTo("-") diff --git a/Mastodon/Extension/MetaLabel.swift b/Mastodon/Extension/MetaLabel.swift index 04b214d82..cf7d27cc0 100644 --- a/Mastodon/Extension/MetaLabel.swift +++ b/Mastodon/Extension/MetaLabel.swift @@ -111,6 +111,24 @@ extension MetaLabel { } +extension MetaLabel { + func configure(attributedString: NSAttributedString) { + let attributedString = NSMutableAttributedString(attributedString: attributedString) + + MetaText.setAttributes( + for: attributedString, + textAttributes: textAttributes, + linkAttributes: linkAttributes, + paragraphStyle: paragraphStyle, + content: PlaintextMetaContent(string: "") + ) + + textStorage.setAttributedString(attributedString) + self.attributedText = attributedString + setNeedsDisplay() + } +} + struct PlaintextMetaContent: MetaContent { let string: String let entities: [Meta.Entity] = [] diff --git a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift index 104bbde83..7fd07bf83 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift @@ -237,7 +237,7 @@ extension ComposeViewModel: UITableViewDataSource { return } cell.statusView.headerContainerView.isHidden = false - cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage) + cell.statusView.headerIconLabel.configure(attributedString: StatusView.iconAttributedString(image: StatusView.replyIconImage)) let headerText: String = { let author = replyTo.author let name = author.displayName.isEmpty ? author.username : author.displayName diff --git a/Mastodon/Scene/Compose/View/ReplicaStatusView.swift b/Mastodon/Scene/Compose/View/ReplicaStatusView.swift index cb34f3ded..6f0527d55 100644 --- a/Mastodon/Scene/Compose/View/ReplicaStatusView.swift +++ b/Mastodon/Scene/Compose/View/ReplicaStatusView.swift @@ -45,9 +45,10 @@ final class ReplicaStatusView: UIView { return attributedString } - let headerIconLabel: UILabel = { - let label = UILabel() - label.attributedText = ReplicaStatusView.iconAttributedString(image: ReplicaStatusView.reblogIconImage) + let headerIconLabel: MetaLabel = { + let label = MetaLabel(style: .statusHeader) + let attributedString = StatusView.iconAttributedString(image: StatusView.reblogIconImage) + label.configure(attributedString: attributedString) return label }() diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift index 9a6907d1c..a2788f524 100644 --- a/Mastodon/Scene/Share/View/Content/StatusView.swift +++ b/Mastodon/Scene/Share/View/Content/StatusView.swift @@ -73,9 +73,10 @@ final class StatusView: UIView { return attributedString } - let headerIconLabel: UILabel = { - let label = UILabel() - label.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage) + let headerIconLabel: MetaLabel = { + let label = MetaLabel(style: .statusHeader) + let attributedString = StatusView.iconAttributedString(image: StatusView.reblogIconImage) + label.configure(attributedString: attributedString) return label }() From cba963a81eb84f0c70c8978f147267a181a0c450 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 14:11:10 +0800 Subject: [PATCH 235/392] chore: update snapshot update logic for iOS 15 new default behavior --- Mastodon.xcodeproj/project.pbxproj | 8 ++++ .../UICollectionViewDiffableDataSource.swift | 40 +++++++++++++++++++ .../UITableViewDiffableDataSource.swift | 40 +++++++++++++++++++ .../HashtagTimelineViewModel+Diffable.swift | 2 +- .../HomeTimelineViewModel+Diffable.swift | 2 +- .../PublicTimelineViewModel.swift | 2 +- .../Thread/ThreadViewModel+Diffable.swift | 2 +- 7 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 Mastodon/Extension/UICollectionViewDiffableDataSource.swift create mode 100644 Mastodon/Extension/UITableViewDiffableDataSource.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 009fbb446..7d72f0397 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -361,6 +361,8 @@ DB73BF43271192BB00781945 /* InstanceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF42271192BB00781945 /* InstanceService.swift */; }; DB73BF45271195AC00781945 /* APIService+CoreData+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF44271195AC00781945 /* APIService+CoreData+Instance.swift */; }; DB73BF47271199CA00781945 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF46271199CA00781945 /* Instance.swift */; }; + DB73BF4927140BA300781945 /* UICollectionViewDiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */; }; + DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */; }; DB75BF1E263C1C1B00EDBF1F /* CustomScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */; }; DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */; }; DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */; }; @@ -1153,6 +1155,8 @@ DB73BF42271192BB00781945 /* InstanceService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceService.swift; sourceTree = ""; }; DB73BF44271195AC00781945 /* APIService+CoreData+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+CoreData+Instance.swift"; sourceTree = ""; }; DB73BF46271199CA00781945 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = ""; }; + DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UICollectionViewDiffableDataSource.swift; sourceTree = ""; }; + DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewDiffableDataSource.swift; sourceTree = ""; }; DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomScheduler.swift; sourceTree = ""; }; DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewController.swift; sourceTree = ""; }; DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewModel.swift; sourceTree = ""; }; @@ -2748,6 +2752,8 @@ DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */, DBCC3B2F261440A50045B23D /* UITabBarController.swift */, DBCC3B35261440BA0045B23D /* UINavigationController.swift */, + DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */, + DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */, ); path = Extension; sourceTree = ""; @@ -4014,6 +4020,7 @@ DB59F11825EFA35B001F1DAB /* StripProgressView.swift in Sources */, DB59F10425EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift in Sources */, DBF9814C265E339500E4BA07 /* ProfileFieldAddEntryCollectionViewCell.swift in Sources */, + DB73BF4927140BA300781945 /* UICollectionViewDiffableDataSource.swift in Sources */, DBA5E7AB263BD3F5004598BB /* TimelineTableViewCellContextMenuConfiguration.swift in Sources */, DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */, DB6D1B44263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift in Sources */, @@ -4110,6 +4117,7 @@ DB1E346825F518E20079D7DF /* CategoryPickerSection.swift in Sources */, 2D61254D262547C200299647 /* APIService+Notification.swift in Sources */, DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */, + DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */, DBB525642612C988002F1F29 /* MeProfileViewModel.swift in Sources */, 5BB04FE9262EFC300043BFF6 /* ReportedStatusTableviewCell.swift in Sources */, DBAE3F822615DDA3004B8251 /* ProfileViewController+UserProvider.swift in Sources */, diff --git a/Mastodon/Extension/UICollectionViewDiffableDataSource.swift b/Mastodon/Extension/UICollectionViewDiffableDataSource.swift new file mode 100644 index 000000000..07d2fbd12 --- /dev/null +++ b/Mastodon/Extension/UICollectionViewDiffableDataSource.swift @@ -0,0 +1,40 @@ +// +// UICollectionViewDiffableDataSource.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-11. +// + +import UIKit + +// ref: https://www.jessesquires.com/blog/2021/07/08/diffable-data-source-behavior-changes-and-reconfiguring-cells-in-ios-15/ +extension UICollectionViewDiffableDataSource { + func reloadData( + snapshot: NSDiffableDataSourceSnapshot, + completion: (() -> Void)? = nil + ) { + if #available(iOS 15.0, *) { + self.applySnapshotUsingReloadData(snapshot, completion: completion) + } else { + self.apply(snapshot, animatingDifferences: false, completion: completion) + } + } + + func applySnapshot( + _ snapshot: NSDiffableDataSourceSnapshot, + animated: Bool, + completion: (() -> Void)? = nil) { + + if #available(iOS 15.0, *) { + self.apply(snapshot, animatingDifferences: animated, completion: completion) + } else { + if animated { + self.apply(snapshot, animatingDifferences: true, completion: completion) + } else { + UIView.performWithoutAnimation { + self.apply(snapshot, animatingDifferences: true, completion: completion) + } + } + } + } +} diff --git a/Mastodon/Extension/UITableViewDiffableDataSource.swift b/Mastodon/Extension/UITableViewDiffableDataSource.swift new file mode 100644 index 000000000..5006417a4 --- /dev/null +++ b/Mastodon/Extension/UITableViewDiffableDataSource.swift @@ -0,0 +1,40 @@ +// +// UITableViewDiffableDataSource.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-11. +// + +import UIKit + +// ref: https://www.jessesquires.com/blog/2021/07/08/diffable-data-source-behavior-changes-and-reconfiguring-cells-in-ios-15/ +extension UITableViewDiffableDataSource { + func reloadData( + snapshot: NSDiffableDataSourceSnapshot, + completion: (() -> Void)? = nil + ) { + if #available(iOS 15.0, *) { + self.applySnapshotUsingReloadData(snapshot, completion: completion) + } else { + self.apply(snapshot, animatingDifferences: false, completion: completion) + } + } + + func applySnapshot( + _ snapshot: NSDiffableDataSourceSnapshot, + animated: Bool, + completion: (() -> Void)? = nil) { + + if #available(iOS 15.0, *) { + self.apply(snapshot, animatingDifferences: animated, completion: completion) + } else { + if animated { + self.apply(snapshot, animatingDifferences: true, completion: completion) + } else { + UIView.performWithoutAnimation { + self.apply(snapshot, animatingDifferences: true, completion: completion) + } + } + } + } +} diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift index 23ed744fc..a601eb927 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift @@ -89,7 +89,7 @@ extension HashtagTimelineViewModel { } DispatchQueue.main.async { - diffableDataSource.apply(newSnapshot, animatingDifferences: false) { + diffableDataSource.reloadData(snapshot: newSnapshot) { tableView.scrollToRow(at: difference.targetIndexPath, at: .top, animated: false) tableView.contentOffset.y = tableView.contentOffset.y - difference.offset self.isFetchingLatestTimeline.value = false diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift index 73d2c1739..e87cab1c1 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift @@ -119,7 +119,7 @@ extension HomeTimelineViewModel: NSFetchedResultsControllerDelegate { return } - diffableDataSource.apply(newSnapshot, animatingDifferences: false) { + diffableDataSource.reloadData(snapshot: newSnapshot) { tableView.scrollToRow(at: difference.targetIndexPath, at: .top, animated: false) tableView.contentOffset.y = tableView.contentOffset.y - difference.offset self.isFetchingLatestTimeline.value = false diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift index c3b1a3d4b..6d6ecbd34 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift @@ -102,7 +102,7 @@ class PublicTimelineViewModel: NSObject { return } - diffableDataSource.apply(snapshot, animatingDifferences: false) { + diffableDataSource.reloadData(snapshot: snapshot) { tableView.scrollToRow(at: difference.targetIndexPath, at: .top, animated: false) tableView.contentOffset.y = tableView.contentOffset.y - difference.offset self.isFetchingLatestTimeline.value = false diff --git a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift index 5bbc383e4..853bee9da 100644 --- a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift +++ b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift @@ -135,7 +135,7 @@ extension ThreadViewModel { // save height before cell reuse let oldRootCellHeight = oldRootCell?.frame.height - diffableDataSource.apply(newSnapshot, animatingDifferences: false) { + diffableDataSource.reloadData(snapshot: newSnapshot) { guard let _ = rootItem else { return } From 084524eb75e877841ac8d51a3817e25a57fe4790 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 14:32:34 +0800 Subject: [PATCH 236/392] fix: home screen quick actions crash on iPad issue --- Mastodon/Coordinator/SceneCoordinator.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 3178a2cb7..00a245bad 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -14,11 +14,11 @@ final public class SceneCoordinator { private weak var scene: UIScene! private weak var sceneDelegate: SceneDelegate! private weak var appContext: AppContext! - private(set) weak var tabBarController: MainTabBarController! let id = UUID().uuidString - weak var splitViewController: RootSplitViewController? + private(set) weak var tabBarController: MainTabBarController! + private(set) weak var splitViewController: RootSplitViewController? private(set) var secondaryStackHashValues = Set() @@ -124,6 +124,7 @@ extension SceneCoordinator { default: let splitViewController = RootSplitViewController(context: appContext, coordinator: self) self.splitViewController = splitViewController + self.tabBarController = splitViewController.mainTabBarController sceneDelegate.window?.rootViewController = splitViewController } } @@ -253,7 +254,7 @@ extension SceneCoordinator { } func switchToTabBar(tab: MainTabBarController.Tab) { - tabBarController.selectedIndex = tab.rawValue + tabBarController.currentTab.value = tab } } From 575035daaf22508b789902bb9b9cf0bced603099 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 15:25:21 +0800 Subject: [PATCH 237/392] fix: ShareExtension UI hack not works on iOS 15 issue --- .../Scene/View/ComposeView.swift | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/ShareActionExtension/Scene/View/ComposeView.swift b/ShareActionExtension/Scene/View/ComposeView.swift index 25adf4c5a..a688d6492 100644 --- a/ShareActionExtension/Scene/View/ComposeView.swift +++ b/ShareActionExtension/Scene/View/ComposeView.swift @@ -85,6 +85,7 @@ public struct ComposeView: View { .frame(height: viewModel.toolbarHeight + 20) .listRow(backgroundColor: Color(viewModel.backgroundColor)) } // end List + .listStyle(.plain) .introspectTableView(customize: { tableView in // tableView.keyboardDismissMode = .onDrag tableView.verticalScrollIndicatorInsets.bottom = viewModel.toolbarHeight @@ -101,7 +102,7 @@ public struct ComposeView: View { .introspectTableView(customize: { tableView in tableView.backgroundColor = .clear }) - .background(Color(viewModel.backgroundColor).ignoresSafeArea()) + .overrideBackground(color: Color(viewModel.backgroundColor)) } // end GeometryReader } // end body } @@ -112,10 +113,26 @@ struct ComposeListViewFramePreferenceKey: PreferenceKey { } extension View { + // hack for separator line + @ViewBuilder func listRow(backgroundColor: Color) -> some View { - self.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) - .listRowInsets(EdgeInsets(top: -1, leading: -1, bottom: -1, trailing: -1)) - .background(backgroundColor) + // expand list row to edge (set inset) + // then hide the separator + if #available(iOS 15, *) { + frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) + .listRowInsets(EdgeInsets(top: -1, leading: -1, bottom: -1, trailing: -1)) + .background(backgroundColor) + .listRowSeparator(.hidden) // new API + } else { + frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) + .listRowInsets(EdgeInsets(top: -1, leading: -1, bottom: -1, trailing: -1)) // separator line hidden magic + .background(backgroundColor) + } + } + + @ViewBuilder + func overrideBackground(color: Color) -> some View { + background(color.ignoresSafeArea()) } } From eaa2ef40839f248a9f5bcb3493b0f8997dc8019e Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 19:19:27 +0800 Subject: [PATCH 238/392] feat: [WIP] handle notification for multiple accounts --- .../Entity/MastodonAuthentication.swift | 4 + Mastodon/Coordinator/SceneCoordinator.swift | 92 +++++++++++++++++++ .../Scene/Account/AccountViewController.swift | 4 +- ...meTimelineViewController+DebugAction.swift | 78 ++++++++++++++++ .../Profile/RemoteProfileViewModel.swift | 48 ++++++++++ .../Root/MainTab/MainTabBarController.swift | 10 -- .../Scene/Thread/RemoteThreadViewModel.swift | 1 - Mastodon/Service/AuthenticationService.swift | 27 +++++- Mastodon/Service/NotificationService.swift | 2 +- Mastodon/Supporting Files/AppDelegate.swift | 4 +- .../MastodonNotification.swift | 20 +++- 11 files changed, 272 insertions(+), 18 deletions(-) diff --git a/CoreDataStack/Entity/MastodonAuthentication.swift b/CoreDataStack/Entity/MastodonAuthentication.swift index 66b8ad6a9..7aafd65a4 100644 --- a/CoreDataStack/Entity/MastodonAuthentication.swift +++ b/CoreDataStack/Entity/MastodonAuthentication.swift @@ -167,4 +167,8 @@ extension MastodonAuthentication { ]) } + public static func predicate(userAccessToken: String) -> NSPredicate { + return NSPredicate(format: "%K == %@", #keyPath(MastodonAuthentication.userAccessToken), userAccessToken) + } + } diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 00a245bad..87e97a536 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -5,12 +5,16 @@ // Created by Cirno MainasuK on 2021-1-27. import UIKit +import Combine import SafariServices import CoreDataStack +import MastodonSDK import PanModal final public class SceneCoordinator { + private var disposeBag = Set() + private weak var scene: UIScene! private weak var sceneDelegate: SceneDelegate! private weak var appContext: AppContext! @@ -28,6 +32,93 @@ final public class SceneCoordinator { self.appContext = appContext scene.session.sceneCoordinator = self + + appContext.notificationService.requestRevealNotificationPublisher + .receive(on: DispatchQueue.main) + .compactMap { [weak self] pushNotification -> AnyPublisher in + guard let self = self else { return Just(nil).eraseToAnyPublisher() } + // skip if no available account + guard let currentActiveAuthenticationBox = appContext.authenticationService.activeMastodonAuthenticationBox.value else { + return Just(nil).eraseToAnyPublisher() + } + + let accessToken = pushNotification._accessToken // use raw accessToken value without normalize + if currentActiveAuthenticationBox.userAuthorization.accessToken == accessToken { + // do nothing if notification for current account + return Just(pushNotification).eraseToAnyPublisher() + } else { + // switch to notification's account + let request = MastodonAuthentication.sortedFetchRequest + request.predicate = MastodonAuthentication.predicate(userAccessToken: accessToken) + request.returnsObjectsAsFaults = false + request.fetchLimit = 1 + do { + guard let authentication = try appContext.managedObjectContext.fetch(request).first else { + return Just(nil).eraseToAnyPublisher() + } + let domain = authentication.domain + let userID = authentication.userID + return appContext.authenticationService.activeMastodonUser(domain: domain, userID: userID) + .receive(on: DispatchQueue.main) + .map { [weak self] result -> MastodonPushNotification? in + guard let self = self else { return nil } + switch result { + case .success: + // reset view hierarchy + self.setup() + return pushNotification + case .failure: + return nil + } + } + .delay(for: 1, scheduler: DispatchQueue.main) // set delay to slow transition (not must) + .eraseToAnyPublisher() + } catch { + assertionFailure(error.localizedDescription) + return Just(nil).eraseToAnyPublisher() + } + } + } + .switchToLatest() + .receive(on: DispatchQueue.main) + .sink { [weak self] pushNotification in + guard let self = self else { return } + guard let pushNotification = pushNotification else { return } + + // redirect to notification tab + self.switchToTabBar(tab: .notification) + + + // Delay in next run loop + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + // Note: + // show (push) on phone + // showDetail in .secondary in UISplitViewController on pad + let from = self.splitViewController?.topMost ?? self.tabBarController.topMost + + // show notification related content + guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return } + let notificationID = String(pushNotification.notificationID) + + switch type { + case .follow: + let profileViewModel = RemoteProfileViewModel(context: appContext, notificationID: notificationID) + self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show) + case .followRequest: + // do nothing + break + case .mention, .reblog, .favourite, .poll, .status: + let threadViewModel = RemoteThreadViewModel(context: appContext, notificationID: notificationID) + self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show) + case ._other: + assertionFailure() + break + } + } + } + .store(in: &disposeBag) } } @@ -254,6 +345,7 @@ extension SceneCoordinator { } func switchToTabBar(tab: MainTabBarController.Tab) { + tabBarController.selectedIndex = tab.rawValue tabBarController.currentTab.value = tab } } diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index 2898b9b5f..4f2ece253 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -111,8 +111,10 @@ extension AccountListViewController { viewModel.dataSourceDidUpdate .receive(on: DispatchQueue.main) - .sink { [weak self] in + .sink { [weak self, weak presentingViewController] in guard let self = self else { return } + // the presentingViewController may deinit + guard let _ = presentingViewController else { return } self.hasLoaded = true self.panModalSetNeedsLayoutUpdate() self.panModalTransition(to: .shortForm) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index fbc221c7a..6d79d0603 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -14,6 +14,7 @@ import CoreDataStack import FLEX import SwiftUI import MastodonUI +import MastodonSDK extension HomeTimelineViewController { var debugMenu: UIMenu { @@ -27,6 +28,7 @@ extension HomeTimelineViewController { moveMenu, dropMenu, miscMenu, + notificationMenu, UIAction(title: "Settings", image: UIImage(systemName: "gear"), attributes: []) { [weak self] action in guard let self = self else { return } self.showSettings(action) @@ -175,6 +177,25 @@ extension HomeTimelineViewController { ) } + var notificationMenu: UIMenu { + return UIMenu( + title: "Notification…", + image: UIImage(systemName: "bell.badge"), + identifier: nil, + options: [], + children: [ + UIAction(title: "Profile", image: UIImage(systemName: "person.badge.plus"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showNotification(action, notificationType: .follow) + }, + UIAction(title: "Status", image: UIImage(systemName: "list.bullet.rectangle"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showNotification(action, notificationType: .mention) + }, + ] + ) + } + } extension HomeTimelineViewController { @@ -412,6 +433,63 @@ extension HomeTimelineViewController { coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil)) } + private func showNotification(_ sender: UIAction, notificationType: Mastodon.Entity.Notification.NotificationType) { + guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { return } + + let alertController = UIAlertController(title: "Enter notification ID", message: nil, preferredStyle: .alert) + alertController.addTextField() + + let showAction = UIAlertAction(title: "Show", style: .default) { [weak self, weak alertController] _ in + guard let self = self else { return } + guard let textField = alertController?.textFields?.first, + let text = textField.text, + let notificationID = Int(text) + else { return } + + let pushNotification = MastodonPushNotification( + _accessToken: authenticationBox.userAuthorization.accessToken, + notificationID: notificationID, + notificationType: notificationType.rawValue, + preferredLocale: nil, + icon: nil, + title: "", + body: "" + ) + self.context.notificationService.requestRevealNotificationPublisher.send(pushNotification) + } + alertController.addAction(showAction) + + // for multiple accounts debug + let boxes = self.context.authenticationService.mastodonAuthenticationBoxes.value // already sorted + if boxes.count >= 2 { + let accessToken = boxes[1].userAuthorization.accessToken + let showForSecondaryAction = UIAlertAction(title: "Show for Secondary", style: .default) { [weak self, weak alertController] _ in + guard let self = self else { return } + guard let textField = alertController?.textFields?.first, + let text = textField.text, + let notificationID = Int(text) + else { return } + + let pushNotification = MastodonPushNotification( + _accessToken: accessToken, + notificationID: notificationID, + notificationType: notificationType.rawValue, + preferredLocale: nil, + icon: nil, + title: "", + body: "" + ) + self.context.notificationService.requestRevealNotificationPublisher.send(pushNotification) + } + alertController.addAction(showForSecondaryAction) + } + + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) + alertController.addAction(cancelAction) + + self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil)) + } + @objc private func showSettings(_ sender: UIAction) { guard let currentSetting = context.settingService.currentSetting.value else { return } let settingsViewModel = SettingsViewModel(context: context, setting: currentSetting) diff --git a/Mastodon/Scene/Profile/RemoteProfileViewModel.swift b/Mastodon/Scene/Profile/RemoteProfileViewModel.swift index 153f50998..ef04d5811 100644 --- a/Mastodon/Scene/Profile/RemoteProfileViewModel.swift +++ b/Mastodon/Scene/Profile/RemoteProfileViewModel.swift @@ -7,6 +7,7 @@ import os.log import Foundation +import Combine import CoreDataStack import MastodonSDK @@ -49,4 +50,51 @@ final class RemoteProfileViewModel: ProfileViewModel { .store(in: &disposeBag) } + init(context: AppContext, notificationID: Mastodon.Entity.Notification.ID) { + super.init(context: context, optionalMastodonUser: nil) + + guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { + return + } + let domain = activeMastodonAuthenticationBox.domain + let authorization = activeMastodonAuthenticationBox.userAuthorization + + context.apiService.notification( + notificationID: notificationID, + mastodonAuthenticationBox: activeMastodonAuthenticationBox + ) + .compactMap { [weak self] response -> AnyPublisher, Error>? in + let userID = response.value.account.id + // TODO: use .account directly + return context.apiService.accountInfo( + domain: domain, + userID: userID, + authorization: authorization + ) + } + .switchToLatest() + .retry(3) + .sink { completion in + switch completion { + case .failure(let error): + // TODO: handle error + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: remote notification %s user fetch failed: %s", ((#file as NSString).lastPathComponent), #line, #function, notificationID, error.localizedDescription) + case .finished: + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: remote notification %s user fetched", ((#file as NSString).lastPathComponent), #line, #function, notificationID) + } + } receiveValue: { [weak self] response in + guard let self = self else { return } + let managedObjectContext = context.managedObjectContext + let request = MastodonUser.sortedFetchRequest + request.fetchLimit = 1 + request.predicate = MastodonUser.predicate(domain: domain, id: response.value.id) + guard let mastodonUser = managedObjectContext.safeFetch(request).first else { + assertionFailure() + return + } + self.mastodonUser.value = mastodonUser + } + .store(in: &disposeBag) + } + } diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index d24a67c4a..d34c85531 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -226,16 +226,6 @@ extension MainTabBarController { } .store(in: &disposeBag) - context.notificationService.requestRevealNotificationPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] notificationID in - guard let self = self else { return } - self.coordinator.switchToTabBar(tab: .notification) - let threadViewModel = RemoteThreadViewModel(context: self.context, notificationID: notificationID) - self.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show) - } - .store(in: &disposeBag) - layoutAvatarButton() context.authenticationService.activeMastodonAuthentication .receive(on: DispatchQueue.main) diff --git a/Mastodon/Scene/Thread/RemoteThreadViewModel.swift b/Mastodon/Scene/Thread/RemoteThreadViewModel.swift index e6e111018..f8f5d3e7e 100644 --- a/Mastodon/Scene/Thread/RemoteThreadViewModel.swift +++ b/Mastodon/Scene/Thread/RemoteThreadViewModel.swift @@ -48,7 +48,6 @@ final class RemoteThreadViewModel: ThreadViewModel { .store(in: &disposeBag) } - // FIXME: multiple account supports init(context: AppContext, notificationID: Mastodon.Entity.Notification.ID) { super.init(context: context, optionalStatus: nil) diff --git a/Mastodon/Service/AuthenticationService.swift b/Mastodon/Service/AuthenticationService.swift index 0b3c3fa11..9e27caab6 100644 --- a/Mastodon/Service/AuthenticationService.swift +++ b/Mastodon/Service/AuthenticationService.swift @@ -95,8 +95,11 @@ extension AuthenticationService { func activeMastodonUser(domain: String, userID: MastodonUser.ID) -> AnyPublisher, Never> { var isActive = false + var _mastodonAuthentication: MastodonAuthentication? - return backgroundManagedObjectContext.performChanges { + return backgroundManagedObjectContext.performChanges { [weak self] in + guard let self = self else { return } + let request = MastodonAuthentication.sortedFetchRequest request.predicate = MastodonAuthentication.predicate(domain: domain, userID: userID) request.fetchLimit = 1 @@ -104,9 +107,29 @@ extension AuthenticationService { return } mastodonAuthentication.update(activedAt: Date()) + _mastodonAuthentication = mastodonAuthentication isActive = true + } - .map { result in + .receive(on: DispatchQueue.main) + .map { [weak self] result in + switch result { + case .success: + if let self = self, + let mastodonAuthentication = _mastodonAuthentication + { + // force set to avoid delay + self.activeMastodonAuthentication.value = mastodonAuthentication + self.activeMastodonAuthenticationBox.value = MastodonAuthenticationBox( + domain: mastodonAuthentication.domain, + userID: mastodonAuthentication.userID, + appAuthorization: Mastodon.API.OAuth.Authorization(accessToken: mastodonAuthentication.appAccessToken), + userAuthorization: Mastodon.API.OAuth.Authorization(accessToken: mastodonAuthentication.userAccessToken) + ) + } + case .failure: + break + } return result.map { isActive } } .eraseToAnyPublisher() diff --git a/Mastodon/Service/NotificationService.swift b/Mastodon/Service/NotificationService.swift index 463a2def8..6eb3120c7 100644 --- a/Mastodon/Service/NotificationService.swift +++ b/Mastodon/Service/NotificationService.swift @@ -30,7 +30,7 @@ final class NotificationService { /// [Token: NotificationViewModel] let notificationSubscriptionDict: [String: NotificationViewModel] = [:] let unreadNotificationCountDidUpdate = CurrentValueSubject(Void()) - let requestRevealNotificationPublisher = PassthroughSubject() + let requestRevealNotificationPublisher = PassthroughSubject() init( apiService: APIService, diff --git a/Mastodon/Supporting Files/AppDelegate.swift b/Mastodon/Supporting Files/AppDelegate.swift index 192f201d1..87d16241a 100644 --- a/Mastodon/Supporting Files/AppDelegate.swift +++ b/Mastodon/Supporting Files/AppDelegate.swift @@ -109,7 +109,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate { completionHandler([.sound]) } - // response to user action for notification + // response to user action for notification (e.g. redirect to post) func userNotificationCenter( _ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, @@ -125,7 +125,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate { let notificationID = String(mastodonPushNotification.notificationID) os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Push Notification] notification %s", ((#file as NSString).lastPathComponent), #line, #function, notificationID) appContext.notificationService.handle(mastodonPushNotification: mastodonPushNotification) - appContext.notificationService.requestRevealNotificationPublisher.send(notificationID) + appContext.notificationService.requestRevealNotificationPublisher.send(mastodonPushNotification) completionHandler() } diff --git a/NotificationService/MastodonNotification.swift b/NotificationService/MastodonNotification.swift index f3941b12d..7d6fb034d 100644 --- a/NotificationService/MastodonNotification.swift +++ b/NotificationService/MastodonNotification.swift @@ -9,7 +9,7 @@ import Foundation struct MastodonPushNotification: Codable { - private let _accessToken: String + let _accessToken: String var accessToken: String { return String.normalize(base64String: _accessToken) } @@ -32,4 +32,22 @@ struct MastodonPushNotification: Codable { case body } + public init( + _accessToken: String, + notificationID: Int, + notificationType: String, + preferredLocale: String?, + icon: String?, + title: String, + body: String + ) { + self._accessToken = _accessToken + self.notificationID = notificationID + self.notificationType = notificationType + self.preferredLocale = preferredLocale + self.icon = icon + self.title = title + self.body = body + } + } From cafd4cc3f2ebc9a9a15a201ec3ee785375f94040 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 20:01:54 +0800 Subject: [PATCH 239/392] feat: implement notification for multiple accounts handler --- .../xcschemes/xcschememanagement.plist | 8 ++++---- Mastodon/Coordinator/SceneCoordinator.swift | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 915ce8a0f..21e265788 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 42 + 36 CoreDataStack.xcscheme_^#shared#^_ orderHint - 41 + 35 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 43 + 38 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 44 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 87e97a536..5df6f7e98 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -94,9 +94,21 @@ final public class SceneCoordinator { guard let self = self else { return } // Note: - // show (push) on phone - // showDetail in .secondary in UISplitViewController on pad - let from = self.splitViewController?.topMost ?? self.tabBarController.topMost + // show (push) on phone or pad (compact) + // showDetail in .secondary in UISplitViewController on pad (expand) + let from: UIViewController? = { + if let splitViewController = self.splitViewController { + if splitViewController.mainTabBarController.topMost?.view.window != nil { + // compact + return splitViewController.mainTabBarController.topMost + } else { + // expand + return splitViewController.viewController(for: .supplementary) + } + } else { + return self.tabBarController.topMost + } + }() // show notification related content guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return } From 75bcbdb7a87aa4f9622da0a7a1e60503189a2a50 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Oct 2021 20:03:55 +0800 Subject: [PATCH 240/392] chore: update version to 1.2.0 (74) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 6 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 47 insertions(+), 47 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index d6c057eb7..222a7a1db 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index d6c057eb7..222a7a1db 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index d6c057eb7..222a7a1db 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 7d72f0397..4337bdc7d 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4784,7 +4784,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4813,7 +4813,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4921,11 +4921,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4952,11 +4952,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4981,11 +4981,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5011,11 +5011,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5078,7 +5078,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5103,7 +5103,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5128,7 +5128,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5153,7 +5153,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5178,7 +5178,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5203,7 +5203,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5228,7 +5228,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5253,7 +5253,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5344,7 +5344,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5411,11 +5411,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5460,7 +5460,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5485,11 +5485,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5581,7 +5581,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5648,11 +5648,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5697,7 +5697,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5722,11 +5722,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 73; + DYLIB_CURRENT_VERSION = 74; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5752,7 +5752,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5776,7 +5776,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 73; + CURRENT_PROJECT_VERSION = 74; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 21e265788..beafe8c8e 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 36 + 43 CoreDataStack.xcscheme_^#shared#^_ orderHint - 35 + 44 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 38 + 42 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 41 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 64cf3e07b..dd63aea2b 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -2,8 +2,6 @@ - UIViewControllerBasedStatusBarAppearance - CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion @@ -32,7 +30,7 @@ CFBundleVersion - 73 + 74 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes @@ -113,5 +111,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIViewControllerBasedStatusBarAppearance + diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 298c2a3d4..6b409db94 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index d6c057eb7..222a7a1db 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index d6c057eb7..222a7a1db 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index b9054fc14..e0a35aca8 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index de78b7103..3cc7eaedd 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 73 + 74 NSExtension NSExtensionAttributes From 8c57da25222f957b212118a89c6212e38433c5cb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 08:07:55 +0200 Subject: [PATCH 241/392] New translations Localizable.stringsdict (Catalan) --- .../input/ca_ES/Localizable.stringsdict | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict index cc7312938..140185bad 100644 --- a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict @@ -21,7 +21,7 @@ a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - El límit d’entrada supera a %#@character_count@ + El límit de la entrada supera a %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -37,7 +37,7 @@ a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - El límit d’entrada continua sent %#@character_count@ + El límit de la entrada continua sent %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -111,7 +111,7 @@ one 1 impuls other - %ld impuls + %ld impulsos plural.count.vote @@ -301,9 +301,9 @@ NSStringFormatValueTypeKey ld one - fa 1a + fa 1 any other - fa %ldy anys + fa %ld anys date.month.ago.abbr @@ -317,9 +317,9 @@ NSStringFormatValueTypeKey ld one - fa 1M + fa 1 mes other - fa %ldM mesos + fa %ld mesos date.day.ago.abbr @@ -333,9 +333,9 @@ NSStringFormatValueTypeKey ld one - fa 1d + fa 1 día other - fa %ldd dies + fa %ld dies date.hour.ago.abbr @@ -351,7 +351,7 @@ one fa 1h other - fa %ldh hores + fa %ld hores date.minute.ago.abbr @@ -365,9 +365,9 @@ NSStringFormatValueTypeKey ld one - fa 1m + fa 1 minut other - fa %ldm minuts + fa %ld minuts date.second.ago.abbr @@ -381,9 +381,9 @@ NSStringFormatValueTypeKey ld one - fa 1s + fa 1 segon other - fa %lds seg + fa %ld segons From 5377adb39fcdea868e1e69e53b0b6277025d6ad9 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Oct 2021 17:41:43 +0800 Subject: [PATCH 242/392] feat: update trends UI with chart --- Mastodon.xcodeproj/project.pbxproj | 4 + ...earchRecommendTagsCollectionViewCell.swift | 59 +++---- .../Search/Search/SearchViewController.swift | 3 - .../Search/Search/View/LineChartView.swift | 151 ++++++++++++++++++ .../Entity/Mastodon+Entity+Tag.swift | 1 + 5 files changed, 182 insertions(+), 36 deletions(-) create mode 100644 Mastodon/Scene/Search/Search/View/LineChartView.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 4337bdc7d..555329be9 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -347,6 +347,7 @@ DB6D9F9726367249008423CD /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F9626367249008423CD /* SettingsViewController.swift */; }; DB6F5E35264E78E7009108F4 /* AutoCompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */; }; DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */; }; + DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CA271D5A0300BE3819 /* LineChartView.swift */; }; DB71FD2C25F86A5100512AE1 /* AvatarStackContainerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */; }; DB71FD3625F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */; }; DB71FD3C25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD3B25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift */; }; @@ -1141,6 +1142,7 @@ DB6D9F9626367249008423CD /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewController.swift; sourceTree = ""; }; DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteTopChevronView.swift; sourceTree = ""; }; + DB71C7CA271D5A0300BE3819 /* LineChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartView.swift; sourceTree = ""; }; DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStackContainerButton.swift; sourceTree = ""; }; DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Persist+PersistMemo.swift"; sourceTree = ""; }; DB71FD3B25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Persist+PersistCache.swift"; sourceTree = ""; }; @@ -1954,6 +1956,7 @@ isa = PBXGroup; children = ( 2DCB73FC2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift */, + DB71C7CA271D5A0300BE3819 /* LineChartView.swift */, ); path = View; sourceTree = ""; @@ -4162,6 +4165,7 @@ DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */, DB44384F25E8C1FA008912A2 /* CALayer.swift in Sources */, 2D34D9CB261489930081BFC0 /* SearchViewController+Recommend.swift in Sources */, + DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */, DB938F1526241FDF00E5B6C1 /* APIService+Thread.swift in Sources */, DB482A45261335BA008AE74C /* UserTimelineViewController+Provider.swift in Sources */, 2D206B8625F5FB0900143C56 /* Double.swift in Sources */, diff --git a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift index e555e1fac..a538d30bf 100644 --- a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift +++ b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift @@ -17,7 +17,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell { let hashtagTitleLabel: UILabel = { let label = UILabel() - label.textColor = .white + label.textColor = .label label.font = .systemFont(ofSize: 20, weight: .semibold) label.lineBreakMode = .byTruncatingTail return label @@ -25,18 +25,12 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell { let peopleLabel: UILabel = { let label = UILabel() - label.textColor = .white + label.textColor = .label label.font = .preferredFont(forTextStyle: .body) return label }() - let flameIconView: UIImageView = { - let imageView = UIImageView() - let image = UIImage(systemName: "flame.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .semibold))!.withRenderingMode(.alwaysTemplate) - imageView.image = image - imageView.tintColor = .white - return imageView - }() + let lineChartView = LineChartView() override func prepareForReuse() { super.prepareForReuse() @@ -54,7 +48,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell { override var isHighlighted: Bool { didSet { - backgroundColor = isHighlighted ? Asset.Colors.brandBlueDarken20.color : Asset.Colors.brandBlue.color + backgroundColor = isHighlighted ? .systemBackground.withAlphaComponent(0.8) : .systemBackground } } } @@ -68,7 +62,7 @@ extension SearchRecommendTagsCollectionViewCell { } private func configure() { - backgroundColor = Asset.Colors.brandBlue.color + backgroundColor = .systemBackground layer.cornerRadius = 10 layer.cornerCurve = .continuous clipsToBounds = false @@ -98,41 +92,40 @@ extension SearchRecommendTagsCollectionViewCell { containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), containerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor) ]) - - - let horizontalStackView = UIStackView() - horizontalStackView.axis = .horizontal - horizontalStackView.translatesAutoresizingMaskIntoConstraints = false - horizontalStackView.distribution = .fill - hashtagTitleLabel.translatesAutoresizingMaskIntoConstraints = false - hashtagTitleLabel.setContentHuggingPriority(.defaultLow - 1, for: .horizontal) - horizontalStackView.addArrangedSubview(hashtagTitleLabel) - horizontalStackView.setContentHuggingPriority(.required - 1, for: .vertical) - - flameIconView.translatesAutoresizingMaskIntoConstraints = false - horizontalStackView.addArrangedSubview(flameIconView) - flameIconView.setContentHuggingPriority(.required - 1, for: .horizontal) - - containerStackView.addArrangedSubview(horizontalStackView) - peopleLabel.translatesAutoresizingMaskIntoConstraints = false - peopleLabel.setContentHuggingPriority(.defaultLow - 1, for: .vertical) + containerStackView.addArrangedSubview(hashtagTitleLabel) containerStackView.addArrangedSubview(peopleLabel) - containerStackView.setCustomSpacing(SearchViewController.hashtagPeopleTalkingLabelTop, after: horizontalStackView) + + lineChartView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(lineChartView) + NSLayoutConstraint.activate([ + lineChartView.topAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 8), + lineChartView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), + contentView.trailingAnchor.constraint(equalTo: lineChartView.trailingAnchor, constant: 16), + contentView.bottomAnchor.constraint(equalTo: lineChartView.bottomAnchor, constant: 16), + ]) } func config(with tag: Mastodon.Entity.Tag) { hashtagTitleLabel.text = "# " + tag.name - guard let historys = tag.history else { + guard let history = tag.history else { peopleLabel.text = "" return } - let recentHistory = historys.prefix(2) + let recentHistory = history.prefix(2) let peopleAreTalking = recentHistory.compactMap({ Int($0.accounts) }).reduce(0, +) let string = L10n.Scene.Search.Recommend.HashTag.peopleTalking(String(peopleAreTalking)) peopleLabel.text = string - + + lineChartView.data = history + .sorted(by: { $0.day < $1.day }) // latest last + .map { entry in + guard let point = Int(entry.accounts) else { + return .zero + } + return CGFloat(point) + } } } diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index 8dcf9cd3b..c72945927 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -23,9 +23,6 @@ final class SearchViewController: UIViewController, NeedsDependency { public static var hashtagCardHeight: CGFloat { get { - if UIScreen.main.bounds.size.height > 736 { - return 186 - } return 130 } } diff --git a/Mastodon/Scene/Search/Search/View/LineChartView.swift b/Mastodon/Scene/Search/Search/View/LineChartView.swift new file mode 100644 index 000000000..5b35bbc4f --- /dev/null +++ b/Mastodon/Scene/Search/Search/View/LineChartView.swift @@ -0,0 +1,151 @@ +// +// LineChartView.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-18. +// + +import UIKit +import Accelerate +import simd + +final class LineChartView: UIView { + + var data: [CGFloat] = [] { + didSet { + setNeedsLayout() + } + } + + let lineShapeLayer = CAShapeLayer() + let gradientLayer = CAGradientLayer() + let dotShapeLayer = CAShapeLayer() + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension LineChartView { + private func _init() { + lineShapeLayer.frame = bounds + gradientLayer.frame = bounds + dotShapeLayer.frame = bounds + layer.addSublayer(lineShapeLayer) + layer.addSublayer(gradientLayer) + layer.addSublayer(dotShapeLayer) + + gradientLayer.colors = [ + Asset.Colors.brandBlue.color.withAlphaComponent(0.5).cgColor, + Asset.Colors.brandBlue.color.withAlphaComponent(0).cgColor, + ] + gradientLayer.startPoint = CGPoint(x: 0.5, y: 0) + gradientLayer.endPoint = CGPoint(x: 0.5, y: 1) + } + + override func layoutSubviews() { + super.layoutSubviews() + + lineShapeLayer.frame = bounds + gradientLayer.frame = bounds + dotShapeLayer.frame = bounds + + guard data.count > 1 else { + lineShapeLayer.path = nil + dotShapeLayer.path = nil + gradientLayer.isHidden = true + return + } + gradientLayer.isHidden = false + + // Draw smooth chart + // use vDSP scale the data with line interpolation method + var data = data.map { Float($0) } + // duplicate first and last value to prevent interpolation at edge data + data.insert(data[0], at: 0) + if let last = data.last { + data.append(last) + } + + let n = vDSP_Length(128) + let stride = vDSP_Stride(1) + + // generate fine control with smoothing (simd_smoothstep(_:_:_:)) + let denominator = Float(n) / Float(data.count - 1) + let control: [Float] = (0...n).map { + let x = Float($0) / denominator + return floor(x) + simd_smoothstep(0, 1, simd_fract(x)) + } + + var points = [Float](repeating: 0, count: Int(n)) + vDSP_vlint(data, + control, stride, + &points, stride, + n, + vDSP_Length(data.count)) + + guard let maxDataPoint = data.max() else { + return + } + func calculateY(for point: Float, in frame: CGRect) -> CGFloat { + guard maxDataPoint > 0 else { return .zero } + return (1 - CGFloat(point / maxDataPoint)) * frame.height + } + + let segmentCount = points.count - 1 + let segmentWidth = bounds.width / CGFloat(segmentCount) + + let linePath = UIBezierPath() + let dotPath = UIBezierPath() + + // move to first data point + var x: CGFloat = 0 + let y = calculateY(for: points[0], in: bounds) + linePath.move(to: CGPoint(x: x, y: y)) + for point in points.dropFirst() { + x += segmentWidth + linePath.addLine(to: CGPoint( + x: x, + y: calculateY(for: point, in: bounds) + )) + } + + if let last = points.last { + let y = calculateY(for: last, in: bounds) + let center = CGPoint(x: bounds.maxX, y: y) + dotPath.addArc(withCenter: center, radius: 3, startAngle: 0, endAngle: 2 * .pi, clockwise: true) + } + + // this not works + // linePath.lineJoinStyle = .round + // lineShapeLayer.lineJoin = .round + + lineShapeLayer.lineWidth = 3 + lineShapeLayer.strokeColor = Asset.Colors.brandBlue.color.cgColor + lineShapeLayer.fillColor = UIColor.clear.cgColor + lineShapeLayer.lineCap = .round + lineShapeLayer.path = linePath.cgPath + + let maskPath = UIBezierPath(cgPath: linePath.cgPath) + maskPath.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY)) + maskPath.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY)) + maskPath.close() + let maskLayer = CAShapeLayer() + maskLayer.path = maskPath.cgPath + maskLayer.fillColor = UIColor.red.cgColor + maskLayer.strokeColor = UIColor.clear.cgColor + maskLayer.lineWidth = 0.0 + gradientLayer.mask = maskLayer + + dotShapeLayer.lineWidth = 3 + dotShapeLayer.fillColor = Asset.Colors.brandBlue.color.cgColor + dotShapeLayer.path = dotPath.cgPath + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift index e7f095eb3..740001572 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift @@ -22,6 +22,7 @@ extension Mastodon.Entity { public let url: String public let history: [History]? + enum CodingKeys: String, CodingKey { case name case url From 68a5c6d4fd7a59d7ffb3c3e8bac9f06b81f01933 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Oct 2021 17:43:44 +0800 Subject: [PATCH 243/392] chore: update version to 1.2.0 (75) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 +- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 222a7a1db..aae7af223 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 222a7a1db..aae7af223 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 222a7a1db..aae7af223 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 555329be9..6fc33a114 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4788,7 +4788,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4817,7 +4817,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4925,11 +4925,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4956,11 +4956,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4985,11 +4985,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5015,11 +5015,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5082,7 +5082,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5107,7 +5107,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5132,7 +5132,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5157,7 +5157,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5182,7 +5182,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5207,7 +5207,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5232,7 +5232,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5257,7 +5257,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5348,7 +5348,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5415,11 +5415,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5464,7 +5464,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5489,11 +5489,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5585,7 +5585,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5652,11 +5652,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5701,7 +5701,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5726,11 +5726,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 74; + DYLIB_CURRENT_VERSION = 75; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5756,7 +5756,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5780,7 +5780,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 74; + CURRENT_PROJECT_VERSION = 75; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index beafe8c8e..30ec23f52 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 43 + 41 CoreDataStack.xcscheme_^#shared#^_ orderHint - 44 + 43 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 41 + 44 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index dd63aea2b..44e29d479 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 74 + 75 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 6b409db94..b5cbd7591 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 222a7a1db..aae7af223 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 222a7a1db..aae7af223 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index e0a35aca8..c5b18a9c1 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 3cc7eaedd..c35420f84 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 74 + 75 NSExtension NSExtensionAttributes From faff2004c1110c0710560e6fec652add7000132d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 12:20:39 +0200 Subject: [PATCH 244/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 549 ++++++++++++++++++ 1 file changed, 549 insertions(+) create mode 100644 Localization/StringsConvertor/input/kmr_TR/app.json diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json new file mode 100644 index 000000000..3ec77cf10 --- /dev/null +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -0,0 +1,549 @@ +{ + "common": { + "alerts": { + "common": { + "please_try_again": "Please try again.", + "please_try_again_later": "Please try again later." + }, + "sign_up_failure": { + "title": "Sign Up Failure" + }, + "server_error": { + "title": "Server Error" + }, + "vote_failure": { + "title": "Vote Failure", + "poll_ended": "The poll has ended" + }, + "discard_post_content": { + "title": "Discard Draft", + "message": "Confirm to discard composed post content." + }, + "publish_post_failure": { + "title": "Publish Failure", + "message": "Failed to publish the post.\nPlease check your internet connection.", + "attachments_message": { + "video_attach_with_photo": "Cannot attach a video to a post that already contains images.", + "more_than_one_video": "Cannot attach more than one video." + } + }, + "edit_profile_failure": { + "title": "Edit Profile Error", + "message": "Cannot edit profile. Please try again." + }, + "sign_out": { + "title": "Sign Out", + "message": "Are you sure you want to sign out?", + "confirm": "Sign Out" + }, + "block_domain": { + "title": "Are you really, really sure you want to block the entire %s? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed.", + "block_entire_domain": "Block Domain" + }, + "save_photo_failure": { + "title": "Save Photo Failure", + "message": "Please enable the photo library access permission to save the photo." + }, + "delete_post": { + "title": "Are you sure you want to delete this post?", + "delete": "Delete" + }, + "clean_cache": { + "title": "Clean Cache", + "message": "Successfully cleaned %s cache." + } + }, + "controls": { + "actions": { + "back": "Back", + "next": "Next", + "previous": "Previous", + "open": "Open", + "add": "Add", + "remove": "Remove", + "edit": "Edit", + "save": "Save", + "ok": "OK", + "done": "Done", + "confirm": "Confirm", + "continue": "Continue", + "cancel": "Cancel", + "discard": "Discard", + "try_again": "Try Again", + "take_photo": "Take Photo", + "save_photo": "Save Photo", + "copy_photo": "Copy Photo", + "sign_in": "Sign In", + "sign_up": "Sign Up", + "see_more": "See More", + "preview": "Preview", + "share": "Share", + "share_user": "Share %s", + "share_post": "Share Post", + "open_in_safari": "Open in Safari", + "find_people": "Find people to follow", + "manually_search": "Manually search instead", + "skip": "Skip", + "reply": "Reply", + "report_user": "Report %s", + "block_domain": "Block %s", + "unblock_domain": "Unblock %s", + "settings": "Settings", + "delete": "Delete" + }, + "tabs": { + "home": "Home", + "search": "Search", + "notification": "Notification", + "profile": "Profile" + }, + "keyboard": { + "common": { + "switch_to_tab": "Switch to %s", + "compose_new_post": "Compose New Post", + "show_favorites": "Show Favorites", + "open_settings": "Open Settings" + }, + "timeline": { + "previous_status": "Previous Post", + "next_status": "Next Post", + "open_status": "Open Post", + "open_author_profile": "Open Author's Profile", + "open_reblogger_profile": "Open Reblogger's Profile", + "reply_status": "Reply to Post", + "toggle_reblog": "Toggle Reblog on Post", + "toggle_favorite": "Toggle Favorite on Post", + "toggle_content_warning": "Toggle Content Warning", + "preview_image": "Preview Image" + }, + "segmented_control": { + "previous_section": "Previous Section", + "next_section": "Next Section" + } + }, + "status": { + "user_reblogged": "%s reblogged", + "user_replied_to": "Replied to %s", + "show_post": "Show Post", + "show_user_profile": "Show user profile", + "content_warning": "Content Warning", + "media_content_warning": "Tap anywhere to reveal", + "poll": { + "vote": "Vote", + "closed": "Closed" + }, + "actions": { + "reply": "Reply", + "reblog": "Reblog", + "unreblog": "Undo reblog", + "favorite": "Favorite", + "unfavorite": "Unfavorite", + "menu": "Menu" + }, + "tag": { + "url": "URL", + "mention": "Mention", + "link": "Link", + "hashtag": "Hashtag", + "email": "Email", + "emoji": "Emoji" + } + }, + "friendship": { + "follow": "Follow", + "following": "Following", + "request": "Request", + "pending": "Pending", + "block": "Block", + "block_user": "Block %s", + "block_domain": "Block %s", + "unblock": "Unblock", + "unblock_user": "Unblock %s", + "blocked": "Blocked", + "mute": "Mute", + "mute_user": "Mute %s", + "unmute": "Unmute", + "unmute_user": "Unmute %s", + "muted": "Muted", + "edit_info": "Edit Info" + }, + "timeline": { + "filtered": "Filtered", + "timestamp": { + "now": "Now" + }, + "loader": { + "load_missing_posts": "Load missing posts", + "loading_missing_posts": "Loading missing posts...", + "show_more_replies": "Show more replies" + }, + "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." + } + } + } + }, + "scene": { + "welcome": { + "slogan": "Social networking\nback in your hands." + }, + "server_picker": { + "title": "Pick a server,\nany server.", + "button": { + "category": { + "all": "All", + "all_accessiblity_description": "Category: All", + "academia": "academia", + "activism": "activism", + "food": "food", + "furry": "furry", + "games": "games", + "general": "general", + "journalism": "journalism", + "lgbt": "lgbt", + "regional": "regional", + "art": "art", + "music": "music", + "tech": "tech" + }, + "see_less": "See Less", + "see_more": "See More" + }, + "label": { + "language": "LANGUAGE", + "users": "USERS", + "category": "CATEGORY" + }, + "input": { + "placeholder": "Find a server or join your own..." + }, + "empty_state": { + "finding_servers": "Finding available servers...", + "bad_network": "Something went wrong while loading the data. Check your internet connection.", + "no_results": "No results" + } + }, + "register": { + "title": "Tell us about you.", + "input": { + "avatar": { + "delete": "Delete" + }, + "username": { + "placeholder": "username", + "duplicate_prompt": "This username is taken." + }, + "display_name": { + "placeholder": "display name" + }, + "email": { + "placeholder": "email" + }, + "password": { + "placeholder": "password", + "hint": "Your password needs at least eight characters" + }, + "invite": { + "registration_user_invite_request": "Why do you want to join?" + } + }, + "error": { + "item": { + "username": "Username", + "email": "Email", + "password": "Password", + "agreement": "Agreement", + "locale": "Locale", + "reason": "Reason" + }, + "reason": { + "blocked": "%s contains a disallowed email provider", + "unreachable": "%s does not seem to exist", + "taken": "%s is already in use", + "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" + }, + "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)" + } + } + }, + "server_rules": { + "title": "Some ground rules.", + "subtitle": "These rules are set by the admins of %s.", + "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", + "button": { + "confirm": "I Agree" + } + }, + "confirm_email": { + "title": "One last thing.", + "subtitle": "We just sent an email to %s,\ntap the link to confirm your account.", + "button": { + "open_email_app": "Open Email App", + "dont_receive_email": "I never got an email" + }, + "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" + }, + "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" + } + }, + "home_timeline": { + "title": "Home", + "navigation_bar_state": { + "offline": "Offline", + "new_posts": "See new posts", + "published": "Published!", + "Publishing": "Publishing post..." + } + }, + "suggestion_account": { + "title": "Find People to Follow", + "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + }, + "compose": { + "title": { + "new_post": "New Post", + "new_reply": "New Reply" + }, + "media_selection": { + "camera": "Take Photo", + "photo_library": "Photo Library", + "browse": "Browse" + }, + "content_input_placeholder": "Type or paste what’s on your mind", + "compose_action": "Publish", + "replying_to_user": "replying to %s", + "attachment": { + "photo": "photo", + "video": "video", + "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..." + }, + "poll": { + "duration_time": "Duration: %s", + "thirty_minutes": "30 minutes", + "one_hour": "1 Hour", + "six_hours": "6 Hours", + "one_day": "1 Day", + "three_days": "3 Days", + "seven_days": "7 Days", + "option_number": "Option %ld" + }, + "content_warning": { + "placeholder": "Write an accurate warning here..." + }, + "visibility": { + "public": "Public", + "unlisted": "Unlisted", + "private": "Followers only", + "direct": "Only people I mention" + }, + "auto_complete": { + "space_to_add": "Space to add" + }, + "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" + }, + "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" + } + }, + "profile": { + "dashboard": { + "posts": "posts", + "following": "following", + "followers": "followers" + }, + "fields": { + "add_row": "Add Row", + "placeholder": { + "label": "Label", + "content": "Content" + } + }, + "segmented_control": { + "posts": "Posts", + "replies": "Replies", + "media": "Media" + }, + "relationship_action_alert": { + "confirm_unmute_user": { + "title": "Unmute Account", + "message": "Confirm to unmute %s" + }, + "confirm_unblock_usre": { + "title": "Unblock Account", + "message": "Confirm to unblock %s" + } + } + }, + "search": { + "title": "Search", + "search_bar": { + "placeholder": "Search hashtags and users", + "cancel": "Cancel" + }, + "recommend": { + "button_text": "See All", + "hash_tag": { + "title": "Trending on Mastodon", + "description": "Hashtags that are getting quite a bit of attention", + "people_talking": "%s people are talking" + }, + "accounts": { + "title": "Accounts you might like", + "description": "You may like to follow these accounts", + "follow": "Follow" + } + }, + "searching": { + "segment": { + "all": "All", + "people": "People", + "hashtags": "Hashtags", + "posts": "Posts" + }, + "empty_state": { + "no_results": "No results" + }, + "recent_search": "Recent searches", + "clear": "Clear" + } + }, + "favorite": { + "title": "Your Favorites" + }, + "notification": { + "title": { + "Everything": "Everything", + "Mentions": "Mentions" + }, + "user_followed_you": "%s followed you", + "user_favorited your post": "%s favorited your post", + "user_reblogged_your_post": "%s reblogged your post", + "user_mentioned_you": "%s mentioned you", + "user_requested_to_follow_you": "%s requested to follow you", + "user_your_poll_has_ended": "%s Your poll has ended", + "keyobard": { + "show_everything": "Show Everything", + "show_mentions": "Show Mentions" + } + }, + "thread": { + "back_title": "Post", + "title": "Post from %s" + }, + "settings": { + "title": "Settings", + "section": { + "appearance": { + "title": "Appearance", + "automatic": "Automatic", + "light": "Always Light", + "dark": "Always Dark" + }, + "notifications": { + "title": "Notifications", + "favorites": "Favorites my post", + "follows": "Follows me", + "boosts": "Reblogs my post", + "mentions": "Mentions me", + "trigger": { + "anyone": "anyone", + "follower": "a follower", + "follow": "anyone I follow", + "noone": "no one", + "title": "Notify me when" + } + }, + "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" + }, + "boring_zone": { + "title": "The Boring Zone", + "account_settings": "Account Settings", + "terms": "Terms of Service", + "privacy": "Privacy Policy" + }, + "spicy_zone": { + "title": "The Spicy Zone", + "clear": "Clear Media Cache", + "signout": "Sign Out" + } + }, + "footer": { + "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)" + }, + "keyboard": { + "close_settings_window": "Close Settings Window" + } + }, + "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?", + "send": "Send Report", + "skip_to_send": "Send without comment", + "text_placeholder": "Type or paste additional comments" + }, + "preview": { + "keyboard": { + "close_preview": "Close Preview", + "show_next": "Show Next", + "show_previous": "Show Previous" + } + }, + "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" + }, + "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" + } + } +} \ No newline at end of file From 9c5e01149d78703be62c0eefb8a31e0989d71756 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 12:20:40 +0200 Subject: [PATCH 245/392] New translations ios-infoPlist.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/ios-infoPlist.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json diff --git a/Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json b/Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json new file mode 100644 index 000000000..c6db73de0 --- /dev/null +++ b/Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json @@ -0,0 +1,6 @@ +{ + "NSCameraUsageDescription": "Used to take photo for post status", + "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", + "NewPostShortcutItemTitle": "New Post", + "SearchShortcutItemTitle": "Search" +} From 5dddeb318255bb4a1050823fad6b3e0319d3b0a2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 12:20:41 +0200 Subject: [PATCH 246/392] New translations Localizable.stringsdict (Kurmanji (Kurdish)) --- .../input/kmr_TR/Localizable.stringsdict | 390 ++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict diff --git a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict new file mode 100644 index 000000000..730e2902a --- /dev/null +++ b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict @@ -0,0 +1,390 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Input limit exceeds %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 character + other + %ld characters + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Input limit remains %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 character + other + %ld characters + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + post + other + posts + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 post + other + %ld posts + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 favorite + other + %ld favorites + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reblog + other + %ld reblogs + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 vote + other + %ld votes + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 voter + other + %ld voters + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 people talking + other + %ld people talking + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 following + other + %ld following + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 follower + other + %ld followers + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 year left + other + %ld years left + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 months left + other + %ld months left + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 day left + other + %ld days left + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 hour left + other + %ld hours left + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 minute left + other + %ld minutes left + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 second left + other + %ld seconds left + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1y ago + other + %ldy ago + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1M ago + other + %ldM ago + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1d ago + other + %ldd ago + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1h ago + other + %ldh ago + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1m ago + other + %ldm ago + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1s ago + other + %lds ago + + + + From 7aa634cce8faf9eac3de98040cf56da4a5a68166 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 12:20:42 +0200 Subject: [PATCH 247/392] New translations Intents.strings (Kurmanji (Kurdish)) --- .../Intents/input/kmr_TR/Intents.strings | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings new file mode 100644 index 000000000..6877490ba --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Post on Mastodon"; + +"751xkl" = "Text Content"; + +"CsR7G2" = "Post on Mastodon"; + +"HZSGTr" = "What content to post?"; + +"HdGikU" = "Posting failed"; + +"KDNTJ4" = "Failure Reason"; + +"RHxKOw" = "Send Post with text content"; + +"RxSqsb" = "Post"; + +"WCIR3D" = "Post ${content} on Mastodon"; + +"ZKJSNu" = "Post"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibility"; + +"Zo4jgJ" = "Post Visibility"; + +"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; + +"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; + +"ayoYEb-dYQ5NN" = "${content}, Public"; + +"ayoYEb-ehFLjY" = "${content}, Followers Only"; + +"dUyuGg" = "Post on Mastodon"; + +"dYQ5NN" = "Public"; + +"ehFLjY" = "Followers Only"; + +"gfePDu" = "Posting failed. ${failureReason}"; + +"k7dbKQ" = "Post was sent successfully."; + +"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; + +"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Post was sent successfully. "; From 86926a360bd172126822313139ad546a26d8ac53 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 12:20:43 +0200 Subject: [PATCH 248/392] New translations Intents.stringsdict (Kurmanji (Kurdish)) --- .../Intents/input/kmr_TR/Intents.stringsdict | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict new file mode 100644 index 000000000..18422c772 --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict @@ -0,0 +1,38 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + one + 1 option + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + one + 1 option + other + %ld options + + + + From 0f55d80e2031ac737acdc6e6bbcdbc54c51655a8 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Oct 2021 18:35:19 +0800 Subject: [PATCH 249/392] chore: update trends line chart style --- Mastodon.xcodeproj/project.pbxproj | 4 ++ .../Search/Search/View/LineChartView.swift | 60 +++++-------------- Mastodon/Vender/CurveAlgorithm.swift | 47 +++++++++++++++ 3 files changed, 67 insertions(+), 44 deletions(-) create mode 100644 Mastodon/Vender/CurveAlgorithm.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 6fc33a114..e1586f23f 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -348,6 +348,7 @@ DB6F5E35264E78E7009108F4 /* AutoCompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */; }; DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */; }; DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CA271D5A0300BE3819 /* LineChartView.swift */; }; + DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */; }; DB71FD2C25F86A5100512AE1 /* AvatarStackContainerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */; }; DB71FD3625F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */; }; DB71FD3C25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD3B25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift */; }; @@ -1143,6 +1144,7 @@ DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewController.swift; sourceTree = ""; }; DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteTopChevronView.swift; sourceTree = ""; }; DB71C7CA271D5A0300BE3819 /* LineChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartView.swift; sourceTree = ""; }; + DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurveAlgorithm.swift; sourceTree = ""; }; DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStackContainerButton.swift; sourceTree = ""; }; DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Persist+PersistMemo.swift"; sourceTree = ""; }; DB71FD3B25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Persist+PersistCache.swift"; sourceTree = ""; }; @@ -1752,6 +1754,7 @@ 2D5A3D0125CF8640002347D6 /* Vender */ = { isa = PBXGroup; children = ( + DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */, 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */, DB51D170262832380062B7A1 /* BlurHashDecode.swift */, DB51D171262832380062B7A1 /* BlurHashEncode.swift */, @@ -4234,6 +4237,7 @@ DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */, DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */, 2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */, + DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */, DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */, DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */, DBAC6499267DF2C4007FE9FD /* TimelineBottomLoaderNode.swift in Sources */, diff --git a/Mastodon/Scene/Search/Search/View/LineChartView.swift b/Mastodon/Scene/Search/Search/View/LineChartView.swift index 5b35bbc4f..51164034e 100644 --- a/Mastodon/Scene/Search/Search/View/LineChartView.swift +++ b/Mastodon/Scene/Search/Search/View/LineChartView.swift @@ -66,61 +66,33 @@ extension LineChartView { gradientLayer.isHidden = false // Draw smooth chart - // use vDSP scale the data with line interpolation method - var data = data.map { Float($0) } - // duplicate first and last value to prevent interpolation at edge data - data.insert(data[0], at: 0) - if let last = data.last { - data.append(last) - } - - let n = vDSP_Length(128) - let stride = vDSP_Stride(1) - - // generate fine control with smoothing (simd_smoothstep(_:_:_:)) - let denominator = Float(n) / Float(data.count - 1) - let control: [Float] = (0...n).map { - let x = Float($0) / denominator - return floor(x) + simd_smoothstep(0, 1, simd_fract(x)) - } - - var points = [Float](repeating: 0, count: Int(n)) - vDSP_vlint(data, - control, stride, - &points, stride, - n, - vDSP_Length(data.count)) - guard let maxDataPoint = data.max() else { return } - func calculateY(for point: Float, in frame: CGRect) -> CGFloat { + func calculateY(for point: CGFloat, in frame: CGRect) -> CGFloat { guard maxDataPoint > 0 else { return .zero } - return (1 - CGFloat(point / maxDataPoint)) * frame.height + return (1 - point / maxDataPoint) * frame.height } - let segmentCount = points.count - 1 + let segmentCount = data.count - 1 let segmentWidth = bounds.width / CGFloat(segmentCount) - let linePath = UIBezierPath() + let points: [CGPoint] = { + var points: [CGPoint] = [] + var x: CGFloat = 0 + for value in data { + let point = CGPoint(x: x, y: calculateY(for: value, in: bounds)) + points.append(point) + x += segmentWidth + } + return points + }() + + guard let linePath = CurveAlgorithm.shared.createCurvedPath(points) else { return } let dotPath = UIBezierPath() - // move to first data point - var x: CGFloat = 0 - let y = calculateY(for: points[0], in: bounds) - linePath.move(to: CGPoint(x: x, y: y)) - for point in points.dropFirst() { - x += segmentWidth - linePath.addLine(to: CGPoint( - x: x, - y: calculateY(for: point, in: bounds) - )) - } - if let last = points.last { - let y = calculateY(for: last, in: bounds) - let center = CGPoint(x: bounds.maxX, y: y) - dotPath.addArc(withCenter: center, radius: 3, startAngle: 0, endAngle: 2 * .pi, clockwise: true) + dotPath.addArc(withCenter: last, radius: 3, startAngle: 0, endAngle: 2 * .pi, clockwise: true) } // this not works diff --git a/Mastodon/Vender/CurveAlgorithm.swift b/Mastodon/Vender/CurveAlgorithm.swift new file mode 100644 index 000000000..00db06048 --- /dev/null +++ b/Mastodon/Vender/CurveAlgorithm.swift @@ -0,0 +1,47 @@ +// +// CurveAlgorithm.swift +// +// Ref: https://github.com/nhatminh12369/LineChart/blob/master/LineChart/CurveAlgorithm.swift + +import UIKit + +struct CurvedSegment { + var controlPoint1: CGPoint + var controlPoint2: CGPoint +} + +class CurveAlgorithm { + static let shared = CurveAlgorithm() + + private func controlPointsFrom(points: [CGPoint]) -> [CurvedSegment] { + var result: [CurvedSegment] = [] + + let delta: CGFloat = 0.4 + + // only use horizontal control point + for i in 1.. UIBezierPath? { + let path = UIBezierPath() + path.move(to: dataPoints[0]) + + var curveSegments: [CurvedSegment] = [] + curveSegments = controlPointsFrom(points: dataPoints) + + for i in 1.. Date: Mon, 18 Oct 2021 18:49:15 +0800 Subject: [PATCH 250/392] chore: update version to 1.2.0 (76) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index aae7af223..d4f88f0be 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index aae7af223..d4f88f0be 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index aae7af223..d4f88f0be 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index e1586f23f..a4fe60399 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4792,7 +4792,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4821,7 +4821,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4929,11 +4929,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4960,11 +4960,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4989,11 +4989,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5019,11 +5019,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5086,7 +5086,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5111,7 +5111,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5136,7 +5136,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5161,7 +5161,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5186,7 +5186,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5211,7 +5211,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5236,7 +5236,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5261,7 +5261,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5352,7 +5352,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5419,11 +5419,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5468,7 +5468,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5493,11 +5493,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5589,7 +5589,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5656,11 +5656,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5705,7 +5705,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5730,11 +5730,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 75; + DYLIB_CURRENT_VERSION = 76; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5760,7 +5760,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5784,7 +5784,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 75; + CURRENT_PROJECT_VERSION = 76; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 30ec23f52..751f88d54 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 41 + 53 CoreDataStack.xcscheme_^#shared#^_ orderHint - 43 + 50 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 42 + 52 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 44 + 51 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 44e29d479..5a0b24aec 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 75 + 76 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index b5cbd7591..5a2f9e2ff 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index aae7af223..d4f88f0be 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index aae7af223..d4f88f0be 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index c5b18a9c1..ee858ed64 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index c35420f84..a7ea5b685 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 75 + 76 NSExtension NSExtensionAttributes From 3e9290c5a608687f1212d623d33a456c4040d3e7 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Oct 2021 19:00:55 +0800 Subject: [PATCH 251/392] chore: set path line join style --- Mastodon/Scene/Search/Search/View/LineChartView.swift | 7 ++----- Mastodon/Vender/CurveAlgorithm.swift | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Mastodon/Scene/Search/Search/View/LineChartView.swift b/Mastodon/Scene/Search/Search/View/LineChartView.swift index 51164034e..2fb8ac733 100644 --- a/Mastodon/Scene/Search/Search/View/LineChartView.swift +++ b/Mastodon/Scene/Search/Search/View/LineChartView.swift @@ -94,14 +94,11 @@ extension LineChartView { if let last = points.last { dotPath.addArc(withCenter: last, radius: 3, startAngle: 0, endAngle: 2 * .pi, clockwise: true) } - - // this not works - // linePath.lineJoinStyle = .round - // lineShapeLayer.lineJoin = .round - + lineShapeLayer.lineWidth = 3 lineShapeLayer.strokeColor = Asset.Colors.brandBlue.color.cgColor lineShapeLayer.fillColor = UIColor.clear.cgColor + lineShapeLayer.lineJoin = .round lineShapeLayer.lineCap = .round lineShapeLayer.path = linePath.cgPath diff --git a/Mastodon/Vender/CurveAlgorithm.swift b/Mastodon/Vender/CurveAlgorithm.swift index 00db06048..0ca4c8734 100644 --- a/Mastodon/Vender/CurveAlgorithm.swift +++ b/Mastodon/Vender/CurveAlgorithm.swift @@ -16,7 +16,7 @@ class CurveAlgorithm { private func controlPointsFrom(points: [CGPoint]) -> [CurvedSegment] { var result: [CurvedSegment] = [] - let delta: CGFloat = 0.4 + let delta: CGFloat = 0.2 // only use horizontal control point for i in 1.. Date: Mon, 18 Oct 2021 19:01:49 +0800 Subject: [PATCH 252/392] chore: update version to 1.2.0 (77) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index d4f88f0be..009534d8f 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index d4f88f0be..009534d8f 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index d4f88f0be..009534d8f 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a4fe60399..dab0ea3cc 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4792,7 +4792,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4821,7 +4821,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4929,11 +4929,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4960,11 +4960,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4989,11 +4989,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5019,11 +5019,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5086,7 +5086,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5111,7 +5111,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5136,7 +5136,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5161,7 +5161,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5186,7 +5186,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5211,7 +5211,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5236,7 +5236,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5261,7 +5261,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5352,7 +5352,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5419,11 +5419,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5468,7 +5468,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5493,11 +5493,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5589,7 +5589,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5656,11 +5656,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5705,7 +5705,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5730,11 +5730,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 76; + DYLIB_CURRENT_VERSION = 77; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5760,7 +5760,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5784,7 +5784,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 76; + CURRENT_PROJECT_VERSION = 77; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 751f88d54..e6f225e6d 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 53 + 54 CoreDataStack.xcscheme_^#shared#^_ orderHint - 50 + 53 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 52 + 55 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 51 + 56 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 5a0b24aec..a371b7f41 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 76 + 77 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 5a2f9e2ff..9179ceb0c 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index d4f88f0be..009534d8f 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index d4f88f0be..009534d8f 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index ee858ed64..642d2f561 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index a7ea5b685..fa46a9679 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 76 + 77 NSExtension NSExtensionAttributes From 107e6437174738c8e5b125790dfd73ce409c8254 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 13:33:27 +0200 Subject: [PATCH 253/392] New translations Intents.strings (Kurmanji (Kurdish)) --- .../Intents/input/kmr_TR/Intents.strings | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings index 6877490ba..944f91c46 100644 --- a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings @@ -1,8 +1,8 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Di Mastodon de biweşîne"; -"751xkl" = "Text Content"; +"751xkl" = "Naveroka nivîsê"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Di Mastodon de biweşîne"; "HZSGTr" = "What content to post?"; @@ -12,17 +12,17 @@ "RHxKOw" = "Send Post with text content"; -"RxSqsb" = "Post"; +"RxSqsb" = "Şandî"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "${content} biweşîne di Mastodon de"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Şandî"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Xuyanî"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Xuyaniya şandiyê"; "apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; From cda40437e053ce0f819b8d56da8cc3b82224cd8c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Oct 2021 13:33:28 +0200 Subject: [PATCH 254/392] New translations Intents.stringsdict (Kurmanji (Kurdish)) --- .../StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict index 18422c772..fb10126c0 100644 --- a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict @@ -13,9 +13,9 @@ NSStringFormatValueTypeKey %ld one - 1 option + 1 vebijêrk other - %ld options + %ld vebijêrk There are ${count} options matching ‘${visibility}’. From 78a50049984ff2e34561e3e1e100b69ef6f15e5e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 03:24:14 +0200 Subject: [PATCH 255/392] New translations Localizable.stringsdict (Kurmanji (Kurdish)) --- .../input/kmr_TR/Localizable.stringsdict | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict index 730e2902a..8efdda094 100644 --- a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict @@ -13,15 +13,15 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 agahdariya nexwendî other - %ld unread notification + %ld agahdariyên nexwendî a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Sînorê têketinê derbas kir %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - post + şandî other - posts + şandî plural.count.post @@ -77,9 +77,9 @@ NSStringFormatValueTypeKey ld one - 1 post + 1 şandî other - %ld posts + %ld şandî plural.count.favorite @@ -93,9 +93,9 @@ NSStringFormatValueTypeKey ld one - 1 favorite + 1 hezkirin other - %ld favorites + %ld hezkirin plural.count.reblog @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 vote + 1 deng other - %ld votes + %ld deng plural.count.voter @@ -141,9 +141,9 @@ NSStringFormatValueTypeKey ld one - 1 voter + 1 hilbijêr other - %ld voters + %ld hilbijêr plural.people_talking @@ -301,9 +301,9 @@ NSStringFormatValueTypeKey ld one - 1y ago + 1 sal berê other - %ldy ago + %ld sal berê date.month.ago.abbr @@ -317,9 +317,9 @@ NSStringFormatValueTypeKey ld one - 1M ago + 1 xulek berê other - %ldM ago + %ld xulek berê date.day.ago.abbr @@ -333,9 +333,9 @@ NSStringFormatValueTypeKey ld one - 1d ago + 1 roj berê other - %ldd ago + %ld roj berê date.hour.ago.abbr @@ -349,9 +349,9 @@ NSStringFormatValueTypeKey ld one - 1h ago + 1 demjimêr berê other - %ldh ago + %ld demjimêr berê date.minute.ago.abbr @@ -365,9 +365,9 @@ NSStringFormatValueTypeKey ld one - 1m ago + 1 xulek berê other - %ldm ago + %ld xulek berê date.second.ago.abbr @@ -381,9 +381,9 @@ NSStringFormatValueTypeKey ld one - 1s ago + 1 çirke berê other - %lds ago + %ld çirke berê From 35af570bdbdccf5fc524e96643e57cae350bc0cd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 07:10:52 +0200 Subject: [PATCH 256/392] New translations ios-infoPlist.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/ios-infoPlist.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json b/Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json index c6db73de0..cdb286c00 100644 --- a/Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/kmr_TR/ios-infoPlist.json @@ -1,6 +1,6 @@ { - "NSCameraUsageDescription": "Used to take photo for post status", - "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", - "NewPostShortcutItemTitle": "New Post", - "SearchShortcutItemTitle": "Search" + "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" } From ce23fa4b78f83e2f9e9260257d39e9a7d55b0766 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 07:10:54 +0200 Subject: [PATCH 257/392] New translations Localizable.stringsdict (Kurmanji (Kurdish)) --- .../input/kmr_TR/Localizable.stringsdict | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict index 8efdda094..064b8bf2b 100644 --- a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict @@ -29,15 +29,15 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 tîp other - %ld characters + %ld tîp a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Sînorê têketinê %#@character_count@ maye character_count NSStringFormatSpecTypeKey @@ -45,9 +45,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 tîp other - %ld characters + %ld tîp plural.count.metric_formatted.post @@ -157,9 +157,9 @@ NSStringFormatValueTypeKey ld one - 1 people talking + 1 mirov diaxive other - %ld people talking + %ld mirov diaxive plural.count.following @@ -173,9 +173,9 @@ NSStringFormatValueTypeKey ld one - 1 following + 1 dişopîne other - %ld following + %ld dişopîne plural.count.follower @@ -189,9 +189,9 @@ NSStringFormatValueTypeKey ld one - 1 follower + 1 şopîner other - %ld followers + %ld şopîner date.year.left @@ -205,9 +205,9 @@ NSStringFormatValueTypeKey ld one - 1 year left + 1 sal berê other - %ld years left + %ld sal berê date.month.left @@ -221,9 +221,9 @@ NSStringFormatValueTypeKey ld one - 1 months left + 1 meh berê other - %ld months left + %ld meh berê date.day.left @@ -237,9 +237,9 @@ NSStringFormatValueTypeKey ld one - 1 day left + 1 roj berê other - %ld days left + %ld roj berê date.hour.left @@ -253,9 +253,9 @@ NSStringFormatValueTypeKey ld one - 1 hour left + 1 demjimêr berê other - %ld hours left + %ld demjimêr berê date.minute.left @@ -269,9 +269,9 @@ NSStringFormatValueTypeKey ld one - 1 minute left + 1 xulek berê other - %ld minutes left + %ld xulek berê date.second.left @@ -285,9 +285,9 @@ NSStringFormatValueTypeKey ld one - 1 second left + 1 çirke berê other - %ld seconds left + %ld çirke berê date.year.ago.abbr From 4e3275120ebafe0541ea0adf31ef164f3d06c5c4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 19:19:48 +0200 Subject: [PATCH 258/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 3ec77cf10..6dffb38bb 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -46,7 +46,7 @@ }, "delete_post": { "title": "Are you sure you want to delete this post?", - "delete": "Delete" + "delete": "Jê bibe" }, "clean_cache": { "title": "Clean Cache", @@ -55,31 +55,31 @@ }, "controls": { "actions": { - "back": "Back", - "next": "Next", - "previous": "Previous", - "open": "Open", - "add": "Add", - "remove": "Remove", - "edit": "Edit", - "save": "Save", - "ok": "OK", - "done": "Done", - "confirm": "Confirm", - "continue": "Continue", - "cancel": "Cancel", - "discard": "Discard", - "try_again": "Try Again", + "back": "Vegere", + "next": "Pêş", + "previous": "Paş", + "open": "Veke", + "add": "Tevlî bike", + "remove": "Rake", + "edit": "Serrast bike", + "save": "Tomar bike", + "ok": "BAŞ E", + "done": "Qediya", + "confirm": "Bipejirîne", + "continue": "Bidomîne", + "cancel": "Dev jê berde", + "discard": "Biavêje", + "try_again": "Dîsa biceribîne", "take_photo": "Take Photo", "save_photo": "Save Photo", "copy_photo": "Copy Photo", - "sign_in": "Sign In", - "sign_up": "Sign Up", - "see_more": "See More", - "preview": "Preview", - "share": "Share", - "share_user": "Share %s", - "share_post": "Share Post", + "sign_in": "Têkeve", + "sign_up": "Tomar bibe", + "see_more": "Bêtir bibîne", + "preview": "Pêşdîtin", + "share": "Parve bike", + "share_user": "%s parve bike", + "share_post": "Şandiyê parve bike", "open_in_safari": "Open in Safari", "find_people": "Find people to follow", "manually_search": "Manually search instead", @@ -110,7 +110,7 @@ "open_status": "Open Post", "open_author_profile": "Open Author's Profile", "open_reblogger_profile": "Open Reblogger's Profile", - "reply_status": "Reply to Post", + "reply_status": "Bersivê bide şandiyê", "toggle_reblog": "Toggle Reblog on Post", "toggle_favorite": "Toggle Favorite on Post", "toggle_content_warning": "Toggle Content Warning", From a6a782517668a7a43645a13a457b2c28746b4e86 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 19:19:49 +0200 Subject: [PATCH 259/392] New translations Intents.strings (Kurmanji (Kurdish)) --- .../StringsConvertor/Intents/input/kmr_TR/Intents.strings | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings index 944f91c46..22b6300dc 100644 --- a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings @@ -34,9 +34,9 @@ "dUyuGg" = "Post on Mastodon"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Gelemperî"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Tenê şopîneran"; "gfePDu" = "Posting failed. ${failureReason}"; @@ -46,6 +46,6 @@ "oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; -"rM6dvp" = "URL"; +"rM6dvp" = "Girêdan"; "ryJLwG" = "Post was sent successfully. "; From 301a53f2228276478bdc6c9e118e7bd3b0c9fba2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 20:20:38 +0200 Subject: [PATCH 260/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 130 +++++++++--------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 6dffb38bb..09f992590 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -2,50 +2,50 @@ "common": { "alerts": { "common": { - "please_try_again": "Please try again.", - "please_try_again_later": "Please try again later." + "please_try_again": "Ji kerema xwe dîsa biceribîne.", + "please_try_again_later": "Ji kerema xwe paşê dîsa biceribîne." }, "sign_up_failure": { - "title": "Sign Up Failure" + "title": "Tomarkirin têkçû" }, "server_error": { - "title": "Server Error" + "title": "Çewtiya rajekar" }, "vote_failure": { - "title": "Vote Failure", - "poll_ended": "The poll has ended" + "title": "Dengdayîn têkçû", + "poll_ended": "Rapirsîya qediya" }, "discard_post_content": { "title": "Discard Draft", "message": "Confirm to discard composed post content." }, "publish_post_failure": { - "title": "Publish Failure", - "message": "Failed to publish the post.\nPlease check your internet connection.", + "title": "Weşandin têkçû", + "message": "Weşandina şandiyê têkçû.\nJkx girêdana înternetê xwe kontrol bike.", "attachments_message": { - "video_attach_with_photo": "Cannot attach a video to a post that already contains images.", - "more_than_one_video": "Cannot attach more than one video." + "video_attach_with_photo": "Nikare vîdyoyekê tevlî şandiyê ku berê wêne tê de heye bike.", + "more_than_one_video": "Nikare ji bêtirî yek vîdyoyekê tevlî şandiyê bike." } }, "edit_profile_failure": { "title": "Edit Profile Error", - "message": "Cannot edit profile. Please try again." + "message": "Nikare profîlê serrast bike. Jkx dîsa biceribîne." }, "sign_out": { - "title": "Sign Out", - "message": "Are you sure you want to sign out?", - "confirm": "Sign Out" + "title": "Derkeve", + "message": "Ma tu dixwazî ku derkevî?", + "confirm": "Derkeve" }, "block_domain": { - "title": "Are you really, really sure you want to block the entire %s? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed.", - "block_entire_domain": "Block Domain" + "title": "Tu ji xwe bawerî, bi rastî tu dixwazî hemû %s asteng bikî? Di gelek rewşan de asteng kirin an jî bêdeng kirin têrê dike û tê tercîh kirin. Tu nikarî naveroka vê navperê di demnameyê an jî agahdariyên xwe de bibînî. Şopînerên te yê di vê navperê were jêbirin.", + "block_entire_domain": "Navperê asteng bike" }, "save_photo_failure": { - "title": "Save Photo Failure", + "title": "Tomarkirina wêneyê têkçû", "message": "Please enable the photo library access permission to save the photo." }, "delete_post": { - "title": "Are you sure you want to delete this post?", + "title": "Ma tu dixwazî vê şandiyê jê bibî?", "delete": "Jê bibe" }, "clean_cache": { @@ -80,35 +80,35 @@ "share": "Parve bike", "share_user": "%s parve bike", "share_post": "Şandiyê parve bike", - "open_in_safari": "Open in Safari", + "open_in_safari": "Di Safariyê de veke", "find_people": "Find people to follow", - "manually_search": "Manually search instead", - "skip": "Skip", - "reply": "Reply", - "report_user": "Report %s", - "block_domain": "Block %s", - "unblock_domain": "Unblock %s", - "settings": "Settings", - "delete": "Delete" + "manually_search": "Ji devlê i destan lêgerînê bike", + "skip": "Derbas bike", + "reply": "Bersivê bide", + "report_user": "%s ragihîne", + "block_domain": "%s asteng bike", + "unblock_domain": "%s asteng neke", + "settings": "Sazkarî", + "delete": "Jê bibe" }, "tabs": { - "home": "Home", - "search": "Search", - "notification": "Notification", - "profile": "Profile" + "home": "Serrûpel", + "search": "Bigere", + "notification": "Agahdarî", + "profile": "Profîl" }, "keyboard": { "common": { - "switch_to_tab": "Switch to %s", - "compose_new_post": "Compose New Post", - "show_favorites": "Show Favorites", - "open_settings": "Open Settings" + "switch_to_tab": "Biguherîne bo %s", + "compose_new_post": "Şandiyeke nû binivsîne", + "show_favorites": "Bijarteyan nîşan bide", + "open_settings": "Sazkariyan Veke" }, "timeline": { - "previous_status": "Previous Post", - "next_status": "Next Post", - "open_status": "Open Post", - "open_author_profile": "Open Author's Profile", + "previous_status": "Şandeya paş", + "next_status": "Şandiya pêş", + "open_status": "Şandiyê veke", + "open_author_profile": "Profîla nivîskaran veke", "open_reblogger_profile": "Open Reblogger's Profile", "reply_status": "Bersivê bide şandiyê", "toggle_reblog": "Toggle Reblog on Post", @@ -124,8 +124,8 @@ "status": { "user_reblogged": "%s reblogged", "user_replied_to": "Replied to %s", - "show_post": "Show Post", - "show_user_profile": "Show user profile", + "show_post": "Şandiyê nîşan bide", + "show_user_profile": "Profîla bikarhêner nîşan bide", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", "poll": { @@ -152,33 +152,33 @@ "friendship": { "follow": "Follow", "following": "Following", - "request": "Request", - "pending": "Pending", - "block": "Block", - "block_user": "Block %s", - "block_domain": "Block %s", - "unblock": "Unblock", - "unblock_user": "Unblock %s", - "blocked": "Blocked", - "mute": "Mute", - "mute_user": "Mute %s", - "unmute": "Unmute", - "unmute_user": "Unmute %s", + "request": "Daxwazên şopandinê", + "pending": "Tê nirxandin", + "block": "Asteng bike", + "block_user": "%s asteng bike", + "block_domain": "%s asteng bike", + "unblock": "Astengiyê rake", + "unblock_user": "%s asteng neke", + "blocked": "Astengkirî", + "mute": "Bêdeng bike", + "mute_user": "%s bêdeng bike", + "unmute": "Bêdeng neke", + "unmute_user": "%s bêdeng neke", "muted": "Muted", - "edit_info": "Edit Info" + "edit_info": "Zanyariyan serrast bike" }, "timeline": { "filtered": "Filtered", "timestamp": { - "now": "Now" + "now": "Niha" }, "loader": { "load_missing_posts": "Load missing posts", "loading_missing_posts": "Loading missing posts...", - "show_more_replies": "Show more replies" + "show_more_replies": "Bêtir bersivan nîşan bide" }, "header": { - "no_status_found": "No Post Found", + "no_status_found": "Şandî nehate dîtin", "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.", @@ -197,15 +197,15 @@ "title": "Pick a server,\nany server.", "button": { "category": { - "all": "All", - "all_accessiblity_description": "Category: All", - "academia": "academia", - "activism": "activism", - "food": "food", + "all": "Hemû", + "all_accessiblity_description": "Beş: Hemû", + "academia": "akademî", + "activism": "çalakî", + "food": "xwarin", "furry": "furry", - "games": "games", - "general": "general", - "journalism": "journalism", + "games": "lîsk", + "general": "giştî", + "journalism": "rojnamevanî", "lgbt": "lgbt", "regional": "regional", "art": "art", From 86e83a3f31a89b7712b2dd5286d7530c405fb537 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 22:09:00 +0200 Subject: [PATCH 261/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 09f992590..0c465cb25 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -16,8 +16,8 @@ "poll_ended": "Rapirsîya qediya" }, "discard_post_content": { - "title": "Discard Draft", - "message": "Confirm to discard composed post content." + "title": "Reşnivîs jêbibe", + "message": "Piştrast bikin ku naveroka posteyê ya hatîye nivîsandin jê bibin." }, "publish_post_failure": { "title": "Weşandin têkçû", @@ -28,7 +28,7 @@ } }, "edit_profile_failure": { - "title": "Edit Profile Error", + "title": "Çewtiya profîlê biguherîne", "message": "Nikare profîlê serrast bike. Jkx dîsa biceribîne." }, "sign_out": { @@ -42,15 +42,15 @@ }, "save_photo_failure": { "title": "Tomarkirina wêneyê têkçû", - "message": "Please enable the photo library access permission to save the photo." + "message": "Ji kerema xwe destûra gihîştina pirtûkxaneya wêneyê çalak bikin da ku wêneyê hilînin." }, "delete_post": { "title": "Ma tu dixwazî vê şandiyê jê bibî?", "delete": "Jê bibe" }, "clean_cache": { - "title": "Clean Cache", - "message": "Successfully cleaned %s cache." + "title": "Pêşbîrê paqij bike", + "message": "Pêşbîra %s biserketî hate paqijkirin." } }, "controls": { @@ -70,9 +70,9 @@ "cancel": "Dev jê berde", "discard": "Biavêje", "try_again": "Dîsa biceribîne", - "take_photo": "Take Photo", - "save_photo": "Save Photo", - "copy_photo": "Copy Photo", + "take_photo": "Wêne bikişîne", + "save_photo": "Wêneyê hilîne", + "copy_photo": "Wêne kopî bikin", "sign_in": "Têkeve", "sign_up": "Tomar bibe", "see_more": "Bêtir bibîne", @@ -81,7 +81,7 @@ "share_user": "%s parve bike", "share_post": "Şandiyê parve bike", "open_in_safari": "Di Safariyê de veke", - "find_people": "Find people to follow", + "find_people": "Kesên ku bişopînin bibînin", "manually_search": "Ji devlê i destan lêgerînê bike", "skip": "Derbas bike", "reply": "Bersivê bide", @@ -109,24 +109,24 @@ "next_status": "Şandiya pêş", "open_status": "Şandiyê veke", "open_author_profile": "Profîla nivîskaran veke", - "open_reblogger_profile": "Open Reblogger's Profile", + "open_reblogger_profile": "Profîla nivîskaran veke", "reply_status": "Bersivê bide şandiyê", "toggle_reblog": "Toggle Reblog on Post", - "toggle_favorite": "Toggle Favorite on Post", - "toggle_content_warning": "Toggle Content Warning", - "preview_image": "Preview Image" + "toggle_favorite": "Di postê da Bijartin veke/bigire", + "toggle_content_warning": "Hişyariya naverokê veke/bigire", + "preview_image": "Wêneya pêşdîtinê" }, "segmented_control": { - "previous_section": "Previous Section", - "next_section": "Next Section" + "previous_section": "Beşa berê", + "next_section": "Beşa paşê" } }, "status": { - "user_reblogged": "%s reblogged", - "user_replied_to": "Replied to %s", + "user_reblogged": "%s ji nû ve hat blogkirin", + "user_replied_to": "Bersiv da %s", "show_post": "Şandiyê nîşan bide", "show_user_profile": "Profîla bikarhêner nîşan bide", - "content_warning": "Content Warning", + "content_warning": "Hişyariya naverokê", "media_content_warning": "Tap anywhere to reveal", "poll": { "vote": "Vote", From 0fb360aca88d4f27b7715789469a4f168e69f88e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 19 Oct 2021 23:06:46 +0200 Subject: [PATCH 262/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 0c465cb25..cc2fdd329 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -127,31 +127,31 @@ "show_post": "Şandiyê nîşan bide", "show_user_profile": "Profîla bikarhêner nîşan bide", "content_warning": "Hişyariya naverokê", - "media_content_warning": "Tap anywhere to reveal", + "media_content_warning": "Ji bo aşkerakirinê derekî bitikîne", "poll": { - "vote": "Vote", - "closed": "Closed" + "vote": "Deng", + "closed": "Girtî" }, "actions": { - "reply": "Reply", - "reblog": "Reblog", - "unreblog": "Undo reblog", - "favorite": "Favorite", - "unfavorite": "Unfavorite", - "menu": "Menu" + "reply": "Bersivê bide", + "reblog": "Ji nû ve blog", + "unreblog": "Ji nû ve blogkirin betal bikin", + "favorite": "Bijartî", + "unfavorite": "Nebijare", + "menu": "Menû" }, "tag": { "url": "URL", - "mention": "Mention", - "link": "Link", - "hashtag": "Hashtag", - "email": "Email", - "emoji": "Emoji" + "mention": "Behs", + "link": "Girêdan", + "hashtag": "Etîket", + "email": "E-name", + "emoji": "E-name" } }, "friendship": { - "follow": "Follow", - "following": "Following", + "follow": "Bişopîne", + "following": "Dişopîne", "request": "Daxwazên şopandinê", "pending": "Tê nirxandin", "block": "Asteng bike", @@ -164,37 +164,37 @@ "mute_user": "%s bêdeng bike", "unmute": "Bêdeng neke", "unmute_user": "%s bêdeng neke", - "muted": "Muted", + "muted": "Bêdengkirî", "edit_info": "Zanyariyan serrast bike" }, "timeline": { - "filtered": "Filtered", + "filtered": "Parzûnkirî", "timestamp": { "now": "Niha" }, "loader": { - "load_missing_posts": "Load missing posts", - "loading_missing_posts": "Loading missing posts...", + "load_missing_posts": "Barkirina posteyên kêm", + "loading_missing_posts": "Barkirina posteyên kêm...", "show_more_replies": "Bêtir bersivan nîşan bide" }, "header": { "no_status_found": "Şandî nehate dîtin", - "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." + "blocking_warning": "Tu nikarî profîla vî bikarhênerî bibînî\nHeta ku tu wan asteng bikî.\nProfîla te ji wan ra wiha xuya dike.", + "user_blocking_warning": "Tu nikarî profîla %s bibînî\nHeta ku tu wan asteng bikî.\nProfîla te ji wan ra wiha xuya dike.", + "blocked_warning": "Tu nikarî profîla vî bikarhênerî bibînî\nheta ku astengîya te rakin.", + "user_blocked_warning": "Tu nikarî profîla %s bibînî\nHeta ku astengîya te rakin.", + "suspended_warning": "Ev bikarhêner hat sekinandin.", + "user_suspended_warning": "Hesaba %s hat sekinandin." } } } }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands." + "slogan": "Tevna civakî\nvegerrîna di destê te da." }, "server_picker": { - "title": "Pick a server,\nany server.", + "title": "Pêşkêşkarekê hilbijêre,\nher pêşkêşvanek.", "button": { "category": { "all": "Hemû", From 084a41b5039664a30f4726ee1a063641d613ba37 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 21 Oct 2021 04:36:43 +0200 Subject: [PATCH 263/392] New translations app.json (Kurmanji (Kurdish)) --- Localization/StringsConvertor/input/kmr_TR/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index cc2fdd329..eaa584de0 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -194,7 +194,7 @@ "slogan": "Tevna civakî\nvegerrîna di destê te da." }, "server_picker": { - "title": "Pêşkêşkarekê hilbijêre,\nher pêşkêşvanek.", + "title": "Rajekarekê hilbijêre,\nHer kîjan rajekar be.", "button": { "category": { "all": "Hemû", From d640be9cbe4c805ba27f02b447efa1b3d6a5f878 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 21 Oct 2021 05:38:59 +0200 Subject: [PATCH 264/392] New translations app.json (Kurmanji (Kurdish)) --- Localization/StringsConvertor/input/kmr_TR/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index eaa584de0..b2db1adb3 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -191,7 +191,7 @@ }, "scene": { "welcome": { - "slogan": "Tevna civakî\nvegerrîna di destê te da." + "slogan": "Torên civakî\ndi destên te de." }, "server_picker": { "title": "Rajekarekê hilbijêre,\nHer kîjan rajekar be.", From 2b1a7e7d399b6a72857f3cce27a2aa63d5e652a7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 21 Oct 2021 05:39:00 +0200 Subject: [PATCH 265/392] New translations Intents.strings (Kurmanji (Kurdish)) --- .../StringsConvertor/Intents/input/kmr_TR/Intents.strings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings index 22b6300dc..687cac69f 100644 --- a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings @@ -4,13 +4,13 @@ "CsR7G2" = "Di Mastodon de biweşîne"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Kîjan naverok bila bê şandin?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Şandin têkçû"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Sedema têkçûnê"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Bi naveroka nivîsî şandiyan bişîne"; "RxSqsb" = "Şandî"; From 87722f172e03fdc0a653780348557a0de038b9c7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 21 Oct 2021 05:39:01 +0200 Subject: [PATCH 266/392] New translations Intents.stringsdict (Kurmanji (Kurdish)) --- .../Intents/input/kmr_TR/Intents.stringsdict | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict index fb10126c0..2f001aaa9 100644 --- a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + %#@count_option@ heye ku bi ‘${content}’ re têkildar e. count_option NSStringFormatSpecTypeKey @@ -21,7 +21,7 @@ There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + %#@count_option@ heye ku bi ‘${visibility}’ re têkildar e. count_option NSStringFormatSpecTypeKey @@ -29,9 +29,9 @@ NSStringFormatValueTypeKey %ld one - 1 option + 1 vebijêrk other - %ld options + %ld vebijêrk From 61f839ff0a0a64cf23de7a7b6270cd843f168792 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 22 Oct 2021 20:23:55 +0800 Subject: [PATCH 267/392] chore: update SDWebImage to 5.12.1 --- .../xcschemes/xcschememanagement.plist | 14 +++++++------- .../xcshareddata/swiftpm/Package.resolved | 13 +++++++++++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index e6f225e6d..5a5418919 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 54 + 37 CoreDataStack.xcscheme_^#shared#^_ orderHint - 53 + 36 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -37,7 +37,7 @@ Mastodon - ca.xcscheme_^#shared#^_ orderHint - 18 + 16 Mastodon - de.xcscheme_^#shared#^_ @@ -67,7 +67,7 @@ Mastodon - jp.xcscheme_^#shared#^_ orderHint - 15 + 14 Mastodon - nl.xcscheme_^#shared#^_ @@ -87,7 +87,7 @@ Mastodon - zh_Hans.xcscheme_^#shared#^_ orderHint - 16 + 15 Mastodon.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 55 + 35 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 56 + 38 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 43a0036bd..26ba58d55 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -141,8 +141,8 @@ "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", "state": { "branch": null, - "revision": "d6367439527663d2038ca445a3c3c4e4bac40d60", - "version": "5.12.0" + "revision": "a72df4849408da7e5d3c1b586797b7c601c41d1b", + "version": "5.12.1" } }, { @@ -216,6 +216,15 @@ "revision": "dad97167bf1be16aeecd109130900995dd01c515", "version": "2.6.0" } + }, + { + "package": "UITextView+Placeholder", + "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder", + "state": { + "branch": null, + "revision": "20f513ded04a040cdf5467f0891849b1763ede3b", + "version": "1.4.1" + } } ] }, From de86e5eab1225a0b1d3100c678c97d193e6138c8 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 22 Oct 2021 20:31:11 +0800 Subject: [PATCH 268/392] fix: user profile timeline not deselect item sometimes when cancel swipe issue --- .../Paging/ProfilePagingViewController.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift b/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift index 16dcbbeb6..23630741f 100644 --- a/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift +++ b/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift @@ -21,6 +21,19 @@ final class ProfilePagingViewController: TabmanViewController { // MARK: - PageboyViewControllerDelegate + override func pageboyViewController(_ pageboyViewController: PageboyViewController, didCancelScrollToPageAt index: PageboyViewController.PageIndex, returnToPageAt previousIndex: PageboyViewController.PageIndex) { + super.pageboyViewController(pageboyViewController, didCancelScrollToPageAt: index, returnToPageAt: previousIndex) + + // Fix the SDK bug for table view get row selected during swipe but cancel paging + guard previousIndex < viewModel.viewControllers.count else { return } + let viewController = viewModel.viewControllers[previousIndex] + + if let tableView = viewController.scrollView as? UITableView { + for cell in tableView.visibleCells { + cell.setHighlighted(false, animated: false) + } + } + } override func pageboyViewController(_ pageboyViewController: PageboyViewController, didScrollToPageAt index: TabmanViewController.PageIndex, direction: PageboyViewController.NavigationDirection, animated: Bool) { super.pageboyViewController(pageboyViewController, didScrollToPageAt: index, direction: direction, animated: animated) From 510199aad3ce98e583ddeb2f81bad03363b262b1 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 22 Oct 2021 20:31:30 +0800 Subject: [PATCH 269/392] chore: update version to 1.2.0 (78) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 009534d8f..1958eb540 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 009534d8f..1958eb540 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 009534d8f..1958eb540 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index dab0ea3cc..600d1f4bb 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4792,7 +4792,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4821,7 +4821,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4929,11 +4929,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4960,11 +4960,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4989,11 +4989,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5019,11 +5019,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5086,7 +5086,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5111,7 +5111,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5136,7 +5136,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5161,7 +5161,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5186,7 +5186,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5211,7 +5211,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5236,7 +5236,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5261,7 +5261,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5352,7 +5352,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5419,11 +5419,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5468,7 +5468,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5493,11 +5493,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5589,7 +5589,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5656,11 +5656,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5705,7 +5705,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5730,11 +5730,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 77; + DYLIB_CURRENT_VERSION = 78; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5760,7 +5760,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5784,7 +5784,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 78; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 5a5418919..424b6b090 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 37 + 44 CoreDataStack.xcscheme_^#shared#^_ orderHint - 36 + 43 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 35 + 42 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 38 + 41 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index a371b7f41..f8987fab7 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 77 + 78 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 9179ceb0c..1f4cb4c62 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 009534d8f..1958eb540 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 009534d8f..1958eb540 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 642d2f561..f1f14ae01 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index fa46a9679..9edd32f6a 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 77 + 78 NSExtension NSExtensionAttributes From 532e10e466f7a673af73f8c1c0b7c14dbcc3959d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 25 Oct 2021 10:40:39 +0200 Subject: [PATCH 270/392] New translations app.json (Japanese) --- Localization/StringsConvertor/input/ja_JP/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/ja_JP/app.json b/Localization/StringsConvertor/input/ja_JP/app.json index 2f1aec4ec..1c7d408f5 100644 --- a/Localization/StringsConvertor/input/ja_JP/app.json +++ b/Localization/StringsConvertor/input/ja_JP/app.json @@ -191,7 +191,7 @@ }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands." + "slogan": "ソーシャルネットワーキングを、あなたの手の中に." }, "server_picker": { "title": "サーバーを選択", @@ -538,11 +538,11 @@ "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" + "add_account": "アカウントを追加" }, "wizard": { - "new_in_mastodon": "New in Mastodon", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "new_in_mastodon": "Mastodon の新機能", + "multiple_account_switch_intro_description": "プロフィールボタンを押して複数のアカウントを切り替えます。", "accessibility_hint": "Double tap to dismiss this wizard" } } From 30110d1560b594aab1069dbd4bc6cbcd8eb7f593 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 25 Oct 2021 10:40:40 +0200 Subject: [PATCH 271/392] New translations Localizable.stringsdict (Japanese) --- .../input/ja_JP/Localizable.stringsdict | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict index 0300d9dc3..c51a9a29d 100644 --- a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict @@ -13,7 +13,7 @@ NSStringFormatValueTypeKey ld other - %ld unread notification + %ld 件の未読通知 a11y.plural.count.input_limit_exceeds @@ -27,7 +27,7 @@ NSStringFormatValueTypeKey ld other - %ld characters + %ld 文字 a11y.plural.count.input_limit_remains @@ -41,7 +41,7 @@ NSStringFormatValueTypeKey ld other - %ld characters + %ld 文字 plural.count.metric_formatted.post @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld votes + %ld票 plural.count.voter @@ -195,7 +195,7 @@ NSStringFormatValueTypeKey ld other - %ld months left + %ldか月前 date.day.left @@ -279,7 +279,7 @@ NSStringFormatValueTypeKey ld other - %ldM ago + %ld分前 date.day.ago.abbr From 6b12adb9c56d0fb4a257742dd0c27bf7b21d10e3 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 25 Oct 2021 16:59:31 +0800 Subject: [PATCH 272/392] fix: auto complete in Compose scene not trigger delegate issue. resolve #300 --- Mastodon/Scene/Compose/ComposeViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index ec8a20e3f..5968df428 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -1275,7 +1275,6 @@ extension ComposeViewController: AutoCompleteViewControllerDelegate { case .bottomLoader: return nil } - text.append(" ") return text }() guard let replacedText = _replacedText else { return } @@ -1286,6 +1285,9 @@ extension ComposeViewController: AutoCompleteViewControllerDelegate { let range = NSRange(info.toHighlightEndRange, in: text) textEditorView.textStorage.replaceCharacters(in: range, with: replacedText) + DispatchQueue.main.async { + textEditorView.textView.insertText(" ") // trigger textView delegate update + } viewModel.autoCompleteInfo.value = nil switch item { From eaff3632430de2f9592d9b8b6afa4efc91bf552f Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 25 Oct 2021 17:00:36 +0800 Subject: [PATCH 273/392] fix: auto complete list cell title UI is user interaction enabled issue --- .../Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift b/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift index 7492753fe..c1e7ab6a4 100644 --- a/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift +++ b/Mastodon/Scene/Compose/AutoComplete/Cell/AutoCompleteTableViewCell.swift @@ -33,6 +33,7 @@ final class AutoCompleteTableViewCell: UITableViewCell { let titleLabel: MetaLabel = { let label = MetaLabel(style: .autoCompletion) + label.isUserInteractionEnabled = false return label }() From 829c3f4cd232367525c43d2a5aa02f14f03475e5 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 25 Oct 2021 17:24:44 +0800 Subject: [PATCH 274/392] fix: hashtag icon in search history record cell can not adaptive update appearance issue --- .../Section/Search/SearchHistorySection.swift | 18 +----- .../SearchResultTableViewCell.swift | 55 ++++++++++++++----- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/Mastodon/Diffiable/Section/Search/SearchHistorySection.swift b/Mastodon/Diffiable/Section/Search/SearchHistorySection.swift index 8f39eb6bd..b5c5cd8cc 100644 --- a/Mastodon/Diffiable/Section/Search/SearchHistorySection.swift +++ b/Mastodon/Diffiable/Section/Search/SearchHistorySection.swift @@ -32,24 +32,8 @@ extension SearchHistorySection { } return cell case .status: + // Should not show status in the history list return UITableViewCell() -// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell -// if let status = try? dependency.context.managedObjectContext.existingObject(with: statusObjectID) as? Status { -// let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value -// let requestUserID = activeMastodonAuthenticationBox?.userID ?? "" -// StatusSection.configure( -// cell: cell, -// tableView: tableView, -// timelineContext: .search, -// dependency: dependency, -// readableLayoutFrame: tableView.readableContentGuide.layoutFrame, -// status: status, -// requestUserID: requestUserID, -// statusItemAttribute: attribute -// ) -// } -// cell.delegate = statusTableViewCellDelegate -// return cell } // end switch } // end UITableViewDiffableDataSource } // end func diff --git a/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift b/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift index a872fca43..0c919e7d5 100644 --- a/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift +++ b/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift @@ -16,7 +16,7 @@ import MastodonMeta final class SearchResultTableViewCell: UITableViewCell { - let _imageView: AvatarImageView = { + let avatarImageView: AvatarImageView = { let imageView = AvatarImageView() imageView.tintColor = Asset.Colors.Label.primary.color imageView.layer.cornerRadius = 4 @@ -24,6 +24,13 @@ final class SearchResultTableViewCell: UITableViewCell { return imageView }() + let hashtagImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(systemName: "number.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 34, weight: .regular))!.withRenderingMode(.alwaysTemplate) + imageView.tintColor = Asset.Colors.Label.primary.color + return imageView + }() + let _titleLabel = MetaLabel(style: .statusName) let _subTitleLabel: UILabel = { @@ -43,7 +50,8 @@ final class SearchResultTableViewCell: UITableViewCell { override func prepareForReuse() { super.prepareForReuse() - _imageView.af.cancelImageRequest() + avatarImageView.af.cancelImageRequest() + setDisplayAvatarImage() } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -74,11 +82,20 @@ extension SearchResultTableViewCell { containerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) ]) - _imageView.translatesAutoresizingMaskIntoConstraints = false - containerStackView.addArrangedSubview(_imageView) + avatarImageView.translatesAutoresizingMaskIntoConstraints = false + containerStackView.addArrangedSubview(avatarImageView) NSLayoutConstraint.activate([ - _imageView.widthAnchor.constraint(equalToConstant: 42).priority(.required - 1), - _imageView.heightAnchor.constraint(equalToConstant: 42).priority(.required - 1), + avatarImageView.widthAnchor.constraint(equalToConstant: 42).priority(.required - 1), + avatarImageView.heightAnchor.constraint(equalToConstant: 42).priority(.required - 1), + ]) + + hashtagImageView.translatesAutoresizingMaskIntoConstraints = false + containerStackView.addSubview(hashtagImageView) + NSLayoutConstraint.activate([ + hashtagImageView.centerXAnchor.constraint(equalTo: avatarImageView.centerXAnchor), + hashtagImageView.centerYAnchor.constraint(equalTo: avatarImageView.centerYAnchor), + hashtagImageView.widthAnchor.constraint(equalToConstant: 42).priority(.required - 1), + hashtagImageView.heightAnchor.constraint(equalToConstant: 42).priority(.required - 1), ]) let textStackView = UIStackView() @@ -107,7 +124,9 @@ extension SearchResultTableViewCell { _titleLabel.isUserInteractionEnabled = false _subTitleLabel.isUserInteractionEnabled = false - _imageView.isUserInteractionEnabled = false + avatarImageView.isUserInteractionEnabled = false + + setDisplayAvatarImage() } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { @@ -182,8 +201,7 @@ extension SearchResultTableViewCell { func config(with tag: Mastodon.Entity.Tag) { configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: nil)) - let image = UIImage(systemName: "number.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 34, weight: .regular))!.withRenderingMode(.alwaysTemplate) - _imageView.image = image + setDisplayHashtagImage() let metaContent = PlaintextMetaContent(string: "#" + tag.name) _titleLabel.configure(content: metaContent) guard let histories = tag.history else { @@ -198,8 +216,7 @@ extension SearchResultTableViewCell { func config(with tag: Tag) { configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: nil)) - let image = UIImage(systemName: "number.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 34, weight: .regular))!.withRenderingMode(.alwaysTemplate) - _imageView.image = image + setDisplayHashtagImage() let metaContent = PlaintextMetaContent(string: "#" + tag.name) _titleLabel.configure(content: metaContent) guard let histories = tag.histories?.sorted(by: { @@ -215,11 +232,23 @@ extension SearchResultTableViewCell { } } +extension SearchResultTableViewCell { + func setDisplayAvatarImage() { + avatarImageView.alpha = 1 + hashtagImageView.alpha = 0 + } + + func setDisplayHashtagImage() { + avatarImageView.alpha = 0 + hashtagImageView.alpha = 1 + } +} + // MARK: - AvatarStackedImageView extension SearchResultTableViewCell: AvatarConfigurableView { static var configurableAvatarImageSize: CGSize { CGSize(width: 42, height: 42) } static var configurableAvatarImageCornerRadius: CGFloat { 4 } - var configurableAvatarImageView: FLAnimatedImageView? { _imageView } + var configurableAvatarImageView: FLAnimatedImageView? { avatarImageView } } #if canImport(SwiftUI) && DEBUG @@ -231,7 +260,7 @@ struct SearchResultTableViewCell_Previews: PreviewProvider { UIViewPreview { let cell = SearchResultTableViewCell() cell.backgroundColor = .white - cell._imageView.image = UIImage(systemName: "number.circle.fill") + cell.setDisplayHashtagImage() cell._titleLabel.text = "Electronic Frontier Foundation" cell._subTitleLabel.text = "@eff@mastodon.social" return cell From 1b74df7f27c28d08895e3fba4df8807c3a88477b Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 25 Oct 2021 18:08:33 +0800 Subject: [PATCH 275/392] chore: update trends card UI --- ...earchRecommendTagsCollectionViewCell.swift | 32 +++++++++++++------ .../Search/Search/SearchViewController.swift | 3 ++ .../Search/Search/View/LineChartView.swift | 22 ++++++------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift index a538d30bf..3734bc8a4 100644 --- a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift +++ b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift @@ -17,7 +17,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell { let hashtagTitleLabel: UILabel = { let label = UILabel() - label.textColor = .label + label.textColor = .white label.font = .systemFont(ofSize: 20, weight: .semibold) label.lineBreakMode = .byTruncatingTail return label @@ -25,7 +25,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell { let peopleLabel: UILabel = { let label = UILabel() - label.textColor = .label + label.textColor = .white label.font = .preferredFont(forTextStyle: .body) return label }() @@ -48,7 +48,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell { override var isHighlighted: Bool { didSet { - backgroundColor = isHighlighted ? .systemBackground.withAlphaComponent(0.8) : .systemBackground + backgroundColor = isHighlighted ? Asset.Colors.brandBlueDarken20.color : Asset.Colors.brandBlue.color } } } @@ -62,7 +62,7 @@ extension SearchRecommendTagsCollectionViewCell { } private func configure() { - backgroundColor = .systemBackground + backgroundColor = Asset.Colors.brandBlue.color layer.cornerRadius = 10 layer.cornerCurve = .continuous clipsToBounds = false @@ -96,14 +96,26 @@ extension SearchRecommendTagsCollectionViewCell { containerStackView.addArrangedSubview(hashtagTitleLabel) containerStackView.addArrangedSubview(peopleLabel) - lineChartView.translatesAutoresizingMaskIntoConstraints = false - contentView.addSubview(lineChartView) + let lineChartContainer = UIView() + lineChartContainer.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(lineChartContainer) NSLayoutConstraint.activate([ - lineChartView.topAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 8), - lineChartView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), - contentView.trailingAnchor.constraint(equalTo: lineChartView.trailingAnchor, constant: 16), - contentView.bottomAnchor.constraint(equalTo: lineChartView.bottomAnchor, constant: 16), + lineChartContainer.topAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 12), + lineChartContainer.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + contentView.trailingAnchor.constraint(equalTo: lineChartContainer.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: lineChartContainer.bottomAnchor, constant: 12), ]) + lineChartContainer.layer.masksToBounds = true + + lineChartView.translatesAutoresizingMaskIntoConstraints = false + lineChartContainer.addSubview(lineChartView) + NSLayoutConstraint.activate([ + lineChartView.topAnchor.constraint(equalTo: lineChartContainer.topAnchor, constant: 4), + lineChartView.leadingAnchor.constraint(equalTo: lineChartContainer.leadingAnchor), + lineChartView.trailingAnchor.constraint(equalTo: lineChartContainer.trailingAnchor), + lineChartContainer.bottomAnchor.constraint(equalTo: lineChartView.bottomAnchor, constant: 4), + ]) + } func config(with tag: Mastodon.Entity.Tag) { diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index c72945927..8dcf9cd3b 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -23,6 +23,9 @@ final class SearchViewController: UIViewController, NeedsDependency { public static var hashtagCardHeight: CGFloat { get { + if UIScreen.main.bounds.size.height > 736 { + return 186 + } return 130 } } diff --git a/Mastodon/Scene/Search/Search/View/LineChartView.swift b/Mastodon/Scene/Search/Search/View/LineChartView.swift index 2fb8ac733..a64aa270d 100644 --- a/Mastodon/Scene/Search/Search/View/LineChartView.swift +++ b/Mastodon/Scene/Search/Search/View/LineChartView.swift @@ -19,7 +19,7 @@ final class LineChartView: UIView { let lineShapeLayer = CAShapeLayer() let gradientLayer = CAGradientLayer() - let dotShapeLayer = CAShapeLayer() +// let dotShapeLayer = CAShapeLayer() override init(frame: CGRect) { super.init(frame: frame) @@ -37,14 +37,14 @@ extension LineChartView { private func _init() { lineShapeLayer.frame = bounds gradientLayer.frame = bounds - dotShapeLayer.frame = bounds +// dotShapeLayer.frame = bounds layer.addSublayer(lineShapeLayer) layer.addSublayer(gradientLayer) - layer.addSublayer(dotShapeLayer) +// layer.addSublayer(dotShapeLayer) gradientLayer.colors = [ - Asset.Colors.brandBlue.color.withAlphaComponent(0.5).cgColor, - Asset.Colors.brandBlue.color.withAlphaComponent(0).cgColor, + UIColor.white.withAlphaComponent(0.5).cgColor, + UIColor.white.withAlphaComponent(0).cgColor, ] gradientLayer.startPoint = CGPoint(x: 0.5, y: 0) gradientLayer.endPoint = CGPoint(x: 0.5, y: 1) @@ -55,11 +55,11 @@ extension LineChartView { lineShapeLayer.frame = bounds gradientLayer.frame = bounds - dotShapeLayer.frame = bounds +// dotShapeLayer.frame = bounds guard data.count > 1 else { lineShapeLayer.path = nil - dotShapeLayer.path = nil +// dotShapeLayer.path = nil gradientLayer.isHidden = true return } @@ -96,7 +96,7 @@ extension LineChartView { } lineShapeLayer.lineWidth = 3 - lineShapeLayer.strokeColor = Asset.Colors.brandBlue.color.cgColor + lineShapeLayer.strokeColor = UIColor.white.cgColor lineShapeLayer.fillColor = UIColor.clear.cgColor lineShapeLayer.lineJoin = .round lineShapeLayer.lineCap = .round @@ -113,8 +113,8 @@ extension LineChartView { maskLayer.lineWidth = 0.0 gradientLayer.mask = maskLayer - dotShapeLayer.lineWidth = 3 - dotShapeLayer.fillColor = Asset.Colors.brandBlue.color.cgColor - dotShapeLayer.path = dotPath.cgPath +// dotShapeLayer.lineWidth = 3 +// dotShapeLayer.fillColor = Asset.Colors.brandBlue.color.cgColor +// dotShapeLayer.path = dotPath.cgPath } } From 825447ef69d1fea4c311fa290b991b80f12cb2b5 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 25 Oct 2021 18:11:37 +0800 Subject: [PATCH 276/392] fix: name label in user recommend card is user interaction enabled issue --- .../SearchRecommendAccountsCollectionViewCell.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift index 365c1ee72..2b0c4736d 100644 --- a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift +++ b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift @@ -167,6 +167,8 @@ extension SearchRecommendAccountsCollectionViewCell { containerStackView.addArrangedSubview(followButton) followButton.addTarget(self, action: #selector(SearchRecommendAccountsCollectionViewCell.followButtonDidPressed(_:)), for: .touchUpInside) + + displayNameLabel.isUserInteractionEnabled = false } } From b2e8eb18a0daace77b000b86e561008391afc7e3 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 25 Oct 2021 18:11:52 +0800 Subject: [PATCH 277/392] chore: update version to 1.2.0 (79) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 +- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 1958eb540..7f509a3fe 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 1958eb540..7f509a3fe 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 1958eb540..7f509a3fe 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 600d1f4bb..3c44f617b 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4792,7 +4792,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4821,7 +4821,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4929,11 +4929,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4960,11 +4960,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4989,11 +4989,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5019,11 +5019,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5086,7 +5086,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5111,7 +5111,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5136,7 +5136,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5161,7 +5161,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5186,7 +5186,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5211,7 +5211,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5236,7 +5236,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5261,7 +5261,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5352,7 +5352,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5419,11 +5419,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5468,7 +5468,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5493,11 +5493,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5589,7 +5589,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5656,11 +5656,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5705,7 +5705,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5730,11 +5730,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 78; + DYLIB_CURRENT_VERSION = 79; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5760,7 +5760,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5784,7 +5784,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 78; + CURRENT_PROJECT_VERSION = 79; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 424b6b090..62b4c7f21 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ AppShared.xcscheme_^#shared#^_ orderHint - 44 + 42 CoreDataStack.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 42 + 41 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 41 + 44 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index f8987fab7..43ae9e6d0 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 78 + 79 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 1f4cb4c62..714ba3106 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 1958eb540..7f509a3fe 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 1958eb540..7f509a3fe 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index f1f14ae01..b5ee7a305 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 9edd32f6a..5643d878f 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 78 + 79 NSExtension NSExtensionAttributes From 4640ac80eb2851c1a47641e7bc990bbfcb8a87d3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 25 Oct 2021 23:36:20 +0200 Subject: [PATCH 278/392] New translations app.json (German) --- Localization/StringsConvertor/input/de_DE/app.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/de_DE/app.json b/Localization/StringsConvertor/input/de_DE/app.json index ff29e8d64..43d8ed70a 100644 --- a/Localization/StringsConvertor/input/de_DE/app.json +++ b/Localization/StringsConvertor/input/de_DE/app.json @@ -536,13 +536,13 @@ } }, "account_list": { - "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", + "tab_bar_hint": "Aktuell ausgewähltes Profil: %s. Doppeltippen dann gedrückt halten, um den Kontoschalter anzuzeigen", "dismiss_account_switcher": "Dismiss Account Switcher", "add_account": "Konto hinzufügen" }, "wizard": { "new_in_mastodon": "Neu in Mastodon", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "multiple_account_switch_intro_description": "Wechsel zwischen mehreren Konten durch drücken der Profil-Schaltfläche.", "accessibility_hint": "Doppeltippen, um diesen Assistenten zu schließen" } } From dfd3516f013d9ef8925186d8160759f9ef876037 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 26 Oct 2021 05:47:36 +0200 Subject: [PATCH 279/392] New translations Intents.strings (Arabic) --- .../StringsConvertor/Intents/input/ar_SA/Intents.strings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings index bf3e77ed2..220b144ab 100644 --- a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings @@ -1,10 +1,10 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "النَشر على ماستودون"; "751xkl" = "محتوى نصي"; "CsR7G2" = "انشر على ماستدون"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "ما المُحتوى المُراد نشره؟"; "HdGikU" = "Posting failed"; @@ -12,11 +12,11 @@ "RHxKOw" = "Send Post with text content"; -"RxSqsb" = "Post"; +"RxSqsb" = "مَنشور"; "WCIR3D" = "Post ${content} on Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "مَنشور"; "ZS1XaK" = "${content}"; From 831b19aedd1dc4fdeaa7746faa7e27b13b1aa8d3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 26 Oct 2021 06:52:24 +0200 Subject: [PATCH 280/392] New translations Intents.strings (Arabic) --- .../Intents/input/ar_SA/Intents.strings | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings index 220b144ab..cde27dc97 100644 --- a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings @@ -6,15 +6,15 @@ "HZSGTr" = "ما المُحتوى المُراد نشره؟"; -"HdGikU" = "Posting failed"; +"HdGikU" = "فَشَلَ النشر"; "KDNTJ4" = "سبب الإخفاق"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "إرسال مَنشور يَحوي نص"; "RxSqsb" = "مَنشور"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "نَشر ${content} على ماستودون"; "ZKJSNu" = "مَنشور"; @@ -24,13 +24,13 @@ "Zo4jgJ" = "مدى ظهور المنشور"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "هُناك عدد ${count} خِيار مُطابق لِـ\"عام\"."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "هُناك عدد ${count} خِيار مُطابق لِـ\"المُتابِعُون فقط\"."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}، عام"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}، المُتابِعُون فقط"; "dUyuGg" = "النشر على ماستدون"; @@ -38,13 +38,13 @@ "ehFLjY" = "لمتابعيك فقط"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "فَشَلَ النشر، ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "تمَّ إرسال المنشور بِنجاح."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "للتأكيد، هل تَريد \"عام\"؟"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "للتأكيد، هل تُريد \"للمُتابِعين فقط\"؟"; "rM6dvp" = "عنوان URL"; From 478004d3cd7a55073068fe69c3409791c5a638da Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 26 Oct 2021 06:52:25 +0200 Subject: [PATCH 281/392] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index ef009776c..4bf55d918 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -28,7 +28,7 @@ } }, "edit_profile_failure": { - "title": "Edit Profile Error", + "title": "خطأ في تَحرير الملف الشخصي", "message": "لا يمكن تعديل الملف الشخصي. يُرجى المحاولة مرة أُخرى." }, "sign_out": { @@ -194,12 +194,12 @@ "slogan": "Social networking\nback in your hands." }, "server_picker": { - "title": "Pick a server,\nany server.", + "title": "اِختر خادِم،\nأي خادِم.", "button": { "category": { "all": "الكل", "all_accessiblity_description": "الفئة: الكل", - "academia": "academia", + "academia": "أكاديمي", "activism": "للنشطاء", "food": "الطعام", "furry": "فروي", From 8d6d075140c660f2efa93acceba67f31ac5ed1c3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 26 Oct 2021 18:44:41 +0200 Subject: [PATCH 282/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index b2db1adb3..1514332e8 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -207,72 +207,72 @@ "general": "giştî", "journalism": "rojnamevanî", "lgbt": "lgbt", - "regional": "regional", - "art": "art", - "music": "music", - "tech": "tech" + "regional": "herêmî", + "art": "huner", + "music": "muzîk", + "tech": "teknolojî" }, - "see_less": "See Less", - "see_more": "See More" + "see_less": "Kêmtir bibîne", + "see_more": "Bêtir bibîne" }, "label": { - "language": "LANGUAGE", - "users": "USERS", - "category": "CATEGORY" + "language": "ZIMAN", + "users": "BIKARHÊNER", + "category": "KATEGORÎ" }, "input": { - "placeholder": "Find a server or join your own..." + "placeholder": "Serverek bibînin an jî beşdarî ya xwe bibin..." }, "empty_state": { - "finding_servers": "Finding available servers...", - "bad_network": "Something went wrong while loading the data. Check your internet connection.", - "no_results": "No results" + "finding_servers": "Dîtina serverên berdest...", + "bad_network": "Di dema barkirina daneyan da tiştek xelet derket. Girêdana xwe ya înternetê kontrol bike.", + "no_results": "Encam nade" } }, "register": { - "title": "Tell us about you.", + "title": "Ji me re hinekî qala xwe bike.", "input": { "avatar": { - "delete": "Delete" + "delete": "Jê bibe" }, "username": { - "placeholder": "username", - "duplicate_prompt": "This username is taken." + "placeholder": "navê bikarhêner", + "duplicate_prompt": "Navê vê bikarhêner tê girtin." }, "display_name": { - "placeholder": "display name" + "placeholder": "navê nîşanê" }, "email": { - "placeholder": "email" + "placeholder": "e-name" }, "password": { - "placeholder": "password", - "hint": "Your password needs at least eight characters" + "placeholder": "şîfre", + "hint": "Şîfreya we herî kêm heşt tîpan hewce dike" }, "invite": { - "registration_user_invite_request": "Why do you want to join?" + "registration_user_invite_request": "Tu çima dixwazî beşdar bibî?" } }, "error": { "item": { - "username": "Username", - "email": "Email", - "password": "Password", - "agreement": "Agreement", - "locale": "Locale", - "reason": "Reason" + "username": "Navê bikarhêner", + "email": "E-name", + "password": "Şîfre", + "agreement": "Lihevhatin", + "locale": "Herêm", + "reason": "Sedem" }, "reason": { - "blocked": "%s contains a disallowed email provider", - "unreachable": "%s does not seem to exist", - "taken": "%s is already in use", - "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" + "blocked": "%s peydekerê e-nameya bêdestûr dihewîne", + "unreachable": "%s xuya nake", + "taken": "%s jixwe tê bikaranîn", + "reserved": "%s peyveke mifteya veqetandî ye", + "accepted": "%s divê were qebûlkirin", + "blank": "%s pêwist e", + "invalid": "%s ne derbasdar e", + "too_long": "%s gelekî dirêj e", + "too_short": "%s pir kurt e", + "inclusion": "%s nirxeke ku tê destekirin nîn e" }, "special": { "username_invalid": "Username must only contain alphanumeric characters and underscores", From 4c893a168d6c73c1dc7e31ea758a6ca0d7abb84b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 26 Oct 2021 19:55:32 +0200 Subject: [PATCH 283/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 1514332e8..926002627 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -275,25 +275,25 @@ "inclusion": "%s nirxeke ku tê destekirin nîn e" }, "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": "Navê bikarhêner divê tenê tîpên alfanumerîk û binxet hebe", + "username_too_long": "Navê bikarhêner pir dirêj e (ji 30 tîpan dirêjtir nabe)", + "email_invalid": "Ev ne navnîşana e-nameyek derbasdar e", + "password_too_short": "Şîfre pir kurt e (divê herî kêm 8 tîpan be)" } } }, "server_rules": { - "title": "Some ground rules.", - "subtitle": "These rules are set by the admins of %s.", - "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": "Hin qaîdeyên bingehîn.", + "subtitle": "Ev rêzik ji aliyê rêvebirên %s ve tên sazkirin.", + "prompt": "Bi berdewamî, hûn ji bo %s di bin şertên polîtîkaya xizmet û nepenîtiyê da ne.", + "terms_of_service": "şert û mercên xizmetê", + "privacy_policy": "polîtîkaya nepenîtiyê", "button": { - "confirm": "I Agree" + "confirm": "Ez tev dibim" } }, "confirm_email": { - "title": "One last thing.", + "title": "Tiştekî dawî.", "subtitle": "We just sent an email to %s,\ntap the link to confirm your account.", "button": { "open_email_app": "Open Email App", @@ -372,101 +372,101 @@ "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" + "disable_content_warning": "Hişyariya naverokê neçalak bike", + "post_visibility_menu": "Menuya Xuyabûna Şandiyê" }, "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": "Şandî bihelîne", + "publish_post": "Şandiye bide weşan", + "toggle_poll": "Anketê veke/bigire", + "toggle_content_warning": "Hişyariya naverokê veke/bigire", + "append_attachment_entry": "Pêvek lê zêde bike - %s", + "select_visibility_entry": "Xuyanîbûn hilbijêre - %s" } }, "profile": { "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "posts": "şandîyan", + "following": "dişopîne", + "followers": "şopîneran" }, "fields": { - "add_row": "Add Row", + "add_row": "Rêzê lê zêde bike", "placeholder": { - "label": "Label", - "content": "Content" + "label": "Nîşan", + "content": "Naverok" } }, "segmented_control": { - "posts": "Posts", - "replies": "Replies", - "media": "Media" + "posts": "Şandîyan", + "replies": "Bersivan", + "media": "Medya" }, "relationship_action_alert": { "confirm_unmute_user": { - "title": "Unmute Account", - "message": "Confirm to unmute %s" + "title": "Hesabê ji bê deng rake", + "message": "Ji bo vekirina bê dengkirinê bipejirin %s" }, "confirm_unblock_usre": { - "title": "Unblock Account", - "message": "Confirm to unblock %s" + "title": "Hesabê ji bloke rake", + "message": "Ji bo rakirina blokê bipejirin %s" } } }, "search": { - "title": "Search", + "title": "Bigere", "search_bar": { - "placeholder": "Search hashtags and users", - "cancel": "Cancel" + "placeholder": "Li etîketan û bikarhêneran bigerin", + "cancel": "Betal kirin" }, "recommend": { - "button_text": "See All", + "button_text": "Hemûyé bibîne", "hash_tag": { - "title": "Trending on Mastodon", - "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "title": "Trend li ser Mastodon", + "description": "Etîketên ku pir balê dikişînin", + "people_talking": "%s kes diaxivin" }, "accounts": { - "title": "Accounts you might like", - "description": "You may like to follow these accounts", - "follow": "Follow" + "title": "Hesabên ku hûn dikarin hez bikin", + "description": "Dibe ku tu bixwazî van hesaban bişopînî", + "follow": "Bişopîne" } }, "searching": { "segment": { - "all": "All", - "people": "People", - "hashtags": "Hashtags", - "posts": "Posts" + "all": "Hemû", + "people": "Mirov", + "hashtags": "Etîketan", + "posts": "Şandîyan" }, "empty_state": { - "no_results": "No results" + "no_results": "Encam tune" }, - "recent_search": "Recent searches", - "clear": "Clear" + "recent_search": "Lêgerînên dawî", + "clear": "Paqij bike" } }, "favorite": { - "title": "Your Favorites" + "title": "Bijareyên te" }, "notification": { "title": { - "Everything": "Everything", - "Mentions": "Mentions" + "Everything": "Her tişt", + "Mentions": "Behs" }, - "user_followed_you": "%s followed you", - "user_favorited your post": "%s favorited your post", - "user_reblogged_your_post": "%s reblogged your post", - "user_mentioned_you": "%s mentioned you", - "user_requested_to_follow_you": "%s requested to follow you", - "user_your_poll_has_ended": "%s Your poll has ended", + "user_followed_you": "%s te şopand", + "user_favorited your post": "%s posta we bijarte", + "user_reblogged_your_post": "%s posta we ji nû ve tomar kir", + "user_mentioned_you": "%s behsa te kir", + "user_requested_to_follow_you": "%s daxwaza şopandina te kir", + "user_your_poll_has_ended": "%s Anketa te qediya", "keyobard": { - "show_everything": "Show Everything", - "show_mentions": "Show Mentions" + "show_everything": "Her tiştî nîşan bide", + "show_mentions": "Behskirîya nîşan bike" } }, "thread": { - "back_title": "Post", + "back_title": "Şandî", "title": "Post from %s" }, "settings": { From 49955a638625ae65f9989726246af226e72b3822 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 26 Oct 2021 19:55:33 +0200 Subject: [PATCH 284/392] New translations Intents.strings (Kurmanji (Kurdish)) --- .../Intents/input/kmr_TR/Intents.strings | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings index 687cac69f..3e1c69fc3 100644 --- a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings @@ -24,28 +24,28 @@ "Zo4jgJ" = "Xuyaniya şandiyê"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Vebijarkên ${count} hene ku li gorî 'Giştî' ne."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Vebijarkên ${count} hene ku li gorî 'Tenê Şopandin' hene."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, Giştî"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, Tenê şopînêr"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Li ser Mastodon bişînin"; "dYQ5NN" = "Gelemperî"; "ehFLjY" = "Tenê şopîneran"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Weşandin bi ser neket. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Şandî bi serkeftî hate şandin."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Tenê ji bo pejirandinê, we 'Giştî' dixwest?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Tenê ji bo piştrastkirinê, we 'Tenê Şopdarên' dixwest?"; "rM6dvp" = "Girêdan"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "Bi serkeftî hat şandin. "; From 8d9ac28d810cd2d3b2906883ac1e62b004086063 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 27 Oct 2021 12:17:22 +0200 Subject: [PATCH 285/392] New translations app.json (Scottish Gaelic) --- Localization/StringsConvertor/input/gd_GB/app.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index 35f551fea..a73925bba 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -536,14 +536,14 @@ } }, "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": "A’ phròifil air a taghadh: %s. Thoir gnogag dhùbailte is cùm sìos a ghearradh leum gu cunntas eile", + "dismiss_account_switcher": "Leig seachad taghadh a’ chunntais", + "add_account": "Cuir cunntas ris" }, "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": "Na tha ùr ann am Mastodon", + "multiple_account_switch_intro_description": "Geàrr leum eadar iomadh cunntas le cumail sìos putan na pròifil.", + "accessibility_hint": "Thoir gnogag dhùbailte a’ leigeil seachad an draoidh seo" } } } \ No newline at end of file From c13d1e2c0d0fe9041f590d8ec09f778b185a5c87 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 27 Oct 2021 12:17:24 +0200 Subject: [PATCH 286/392] New translations Localizable.stringsdict (Scottish Gaelic) --- .../StringsConvertor/input/gd_GB/Localizable.stringsdict | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict index 41e592a5e..7a54f553e 100644 --- a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + %ld bhrath nach deach a leughadh two - %ld unread notification + %ld bhrath nach deach a leughadh few - %ld unread notification + %ld brathan nach deach a leughadh other - %ld unread notification + %ld brath nach deach a leughadh a11y.plural.count.input_limit_exceeds From f778d37ea20f2b4ba31323c15b2c9eaeb298332a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 27 Oct 2021 16:26:41 +0200 Subject: [PATCH 287/392] New translations app.json (Kurmanji (Kurdish)) --- Localization/StringsConvertor/input/kmr_TR/app.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 926002627..a2b990128 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -296,13 +296,13 @@ "title": "Tiştekî dawî.", "subtitle": "We just sent an email to %s,\ntap the link to confirm your account.", "button": { - "open_email_app": "Open Email App", - "dont_receive_email": "I never got an email" + "open_email_app": "Sepana e-nameyê veke", + "dont_receive_email": "Min hîç e-nameyeke nesitand" }, "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": "E-nameyê xwe kontrol bike", + "description": "Kontrol bike ka navnîşana e-nameya te rast e û her wiha peldanka xwe ya spam.", + "resend_email": "E-namyê yê dîsa bişîne" }, "open_email_app": { "title": "Check your inbox.", From 62a932825e1958f984623c224d6dcc73251f9695 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 27 Oct 2021 17:23:26 +0200 Subject: [PATCH 288/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index a2b990128..45c224fa4 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -307,69 +307,69 @@ "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" + "mail": "E-name", + "open_email_client": "Rajegirê e-nameyê veke" } }, "home_timeline": { - "title": "Home", + "title": "Serrûpel", "navigation_bar_state": { - "offline": "Offline", - "new_posts": "See new posts", - "published": "Published!", - "Publishing": "Publishing post..." + "offline": "Derhêl", + "new_posts": "Şandiyên nû bibîne", + "published": "Hate weşandin!", + "Publishing": "Şandî tê weşandin..." } }, "suggestion_account": { - "title": "Find People to Follow", - "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + "title": "Kesên bo ku bişopînî bibîne", + "follow_explain": "Gava tu kesekî dişopînî, tu yê şandiyê wan di serrûpelê de bibîne." }, "compose": { "title": { - "new_post": "New Post", - "new_reply": "New Reply" + "new_post": "Şandiya nû", + "new_reply": "Bersiva nû" }, "media_selection": { - "camera": "Take Photo", - "photo_library": "Photo Library", - "browse": "Browse" + "camera": "Wêne bikişîne", + "photo_library": "Wênegeh", + "browse": "Bigere" }, "content_input_placeholder": "Type or paste what’s on your mind", - "compose_action": "Publish", - "replying_to_user": "replying to %s", + "compose_action": "Biweşîne", + "replying_to_user": "bersiv bide %s", "attachment": { - "photo": "photo", - "video": "video", - "attachment_broken": "This %s is broken and can’t be\nuploaded to Mastodon.", + "photo": "wêne", + "video": "vîdyo", + "attachment_broken": "Ev %s naxebite û nayê barkirin\n li ser Mastodon.", "description_photo": "Describe the photo for the visually-impaired...", "description_video": "Describe the video for the visually-impaired..." }, "poll": { - "duration_time": "Duration: %s", - "thirty_minutes": "30 minutes", - "one_hour": "1 Hour", - "six_hours": "6 Hours", - "one_day": "1 Day", - "three_days": "3 Days", - "seven_days": "7 Days", - "option_number": "Option %ld" + "duration_time": "Dirêjî: %s", + "thirty_minutes": "30 xulek", + "one_hour": "1 Demjimêr", + "six_hours": "6 Demjimêr", + "one_day": "1 Roj", + "three_days": "3 Roj", + "seven_days": "7 Roj", + "option_number": "Vebijêrk %ld" }, "content_warning": { "placeholder": "Write an accurate warning here..." }, "visibility": { - "public": "Public", - "unlisted": "Unlisted", - "private": "Followers only", - "direct": "Only people I mention" + "public": "Gelemperî", + "unlisted": "Nerêzokkirî", + "private": "Tenê şopîneran", + "direct": "Tenê mirovên ku min qalkirî" }, "auto_complete": { "space_to_add": "Space to add" }, "accessibility": { - "append_attachment": "Add Attachment", - "append_poll": "Add Poll", - "remove_poll": "Remove Poll", + "append_attachment": "Pêvek tevlî bike", + "append_poll": "Rapirsî tevlî bike", + "remove_poll": "Rapirsî rake", "custom_emoji_picker": "Custom Emoji Picker", "enable_content_warning": "Enable Content Warning", "disable_content_warning": "Hişyariya naverokê neçalak bike", From 59faa09fe2268dd20ff378d110c4e7bab26f298d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 27 Oct 2021 19:02:52 +0200 Subject: [PATCH 289/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 45c224fa4..5821049bb 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -470,30 +470,30 @@ "title": "Post from %s" }, "settings": { - "title": "Settings", + "title": "Sazkarî", "section": { "appearance": { - "title": "Appearance", - "automatic": "Automatic", - "light": "Always Light", - "dark": "Always Dark" + "title": "Xuyang", + "automatic": "Xweber", + "light": "Her dem ronî", + "dark": "Her dem tarî" }, "notifications": { - "title": "Notifications", - "favorites": "Favorites my post", - "follows": "Follows me", + "title": "Agahdarî", + "favorites": "Şandiyên min hez kir", + "follows": "Min şopand", "boosts": "Reblogs my post", - "mentions": "Mentions me", + "mentions": "Qale min kir", "trigger": { - "anyone": "anyone", - "follower": "a follower", - "follow": "anyone I follow", - "noone": "no one", - "title": "Notify me when" + "anyone": "her kes", + "follower": "şopînerek", + "follow": "her kesê ku dişopînim", + "noone": "ne yek", + "title": "Min agahdar bike gava" } }, "preference": { - "title": "Preferences", + "title": "Hilbijarte", "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", From bc10d782870450f67b437fa7d8673dd53bc910ee Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 27 Oct 2021 20:16:43 +0200 Subject: [PATCH 290/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 5821049bb..9798c86c2 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -519,30 +519,30 @@ } }, "report": { - "title": "Report %s", - "step1": "Step 1 of 2", - "step2": "Step 2 of 2", + "title": "%s ragihîne", + "step1": "Gav 1 ji 2", + "step2": "Gav 2 ji 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?", - "send": "Send Report", - "skip_to_send": "Send without comment", + "send": "Ragihandinê bişîne", + "skip_to_send": "Bêyî şirove bişîne", "text_placeholder": "Type or paste additional comments" }, "preview": { "keyboard": { - "close_preview": "Close Preview", - "show_next": "Show Next", - "show_previous": "Show Previous" + "close_preview": "Pêşdîtin bigire", + "show_next": "A pêş nîşan bide", + "show_previous": "A paş nîşan bide" } }, "account_list": { - "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", + "tab_bar_hint": "Profîla hilbijartî ya niha: %s. Du caran bitikîne û paşê dest bide ser da ku guhêrbara ajimêr were nîşandan", "dismiss_account_switcher": "Dismiss Account Switcher", - "add_account": "Add Account" + "add_account": "Ajimêr tevlî bike" }, "wizard": { - "new_in_mastodon": "New in Mastodon", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "new_in_mastodon": "Nû di Mastodon de", + "multiple_account_switch_intro_description": "Dest bide ser bişkoja profîlê da ku di navbera gelek ajimêrann de biguherînî.", "accessibility_hint": "Double tap to dismiss this wizard" } } From 19db0afa3eb5bb09f79772b0e4e2d86e0067afdd Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 28 Oct 2021 19:17:41 +0800 Subject: [PATCH 291/392] feat: update for new iPad UI --- Mastodon.xcodeproj/project.pbxproj | 8 + .../xcschemes/xcschememanagement.plist | 8 +- Mastodon/Coordinator/SceneCoordinator.swift | 105 ++++--- Mastodon/Generated/Assets.swift | 20 +- .../Sidebar}/Contents.json | 0 .../Scene/Sidebar/logo.imageset/Contents.json | 15 + .../Scene/Sidebar/logo.imageset/logo.pdf | 108 +++++++ .../Contents.json | 6 +- .../sidebar.background.colorset/Contents.json | 6 +- .../Background/danger.colorset/Contents.json | 20 -- .../Contents.json | 20 -- .../Contents.json | 38 --- .../Contents.json | 38 --- .../system.background.colorset/Contents.json | 38 --- .../Contents.json | 38 --- .../Contents.json | 38 --- .../Contents.json | 38 --- .../Contents.json | 38 --- .../_Deprecated/Compose/Contents.json | 9 - .../Compose/background.colorset/Contents.json | 38 --- .../toolbar.background.colorset/Contents.json | 38 --- .../Assets.xcassets/_Deprecated/Contents.json | 9 - .../HomeTimelineViewController.swift | 30 +- .../HomeTimeline/HomeTimelineViewModel.swift | 3 +- .../Root/ContentSplitViewController.swift | 92 ++++++ .../MainTab/MainTabBarController+Wizard.swift | 3 + .../Scene/Root/RootSplitViewController.swift | 274 +++++++--------- .../Root/Sidebar/SidebarViewController.swift | 200 +++++++----- .../Scene/Root/Sidebar/SidebarViewModel.swift | 295 +++++------------- .../View/SidebarListCollectionViewCell.swift | 15 - .../Sidebar/View/SidebarListContentView.swift | 149 ++------- .../Sidebar/View/SidebarListHeaderView.swift | 42 +++ .../View/Button/CircleAvatarButton.swift | 7 +- .../Service/ThemeService/SystemTheme.swift | 2 +- 34 files changed, 705 insertions(+), 1083 deletions(-) rename Mastodon/Resources/Assets.xcassets/{_Deprecated/Background => Scene/Sidebar}/Contents.json (100%) create mode 100644 Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/Contents.json create mode 100644 Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/logo.pdf delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/danger.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/onboarding.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.grouped.system.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.system.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.elevated.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.grouped.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.grouped.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/toolbar.background.colorset/Contents.json delete mode 100644 Mastodon/Resources/Assets.xcassets/_Deprecated/Contents.json create mode 100644 Mastodon/Scene/Root/ContentSplitViewController.swift create mode 100644 Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 3c44f617b..1ab4b2559 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -187,6 +187,8 @@ DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB029E94266A20430062874E /* MastodonAuthenticationController.swift */; }; DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */; }; DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */; }; + DB03A793272A7E5700EE37C5 /* SidebarListHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A792272A7E5700EE37C5 /* SidebarListHeaderView.swift */; }; + DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A794272A981400EE37C5 /* ContentSplitViewController.swift */; }; DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */; }; DB03F7F52689B782007B274C /* ComposeTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F42689B782007B274C /* ComposeTableView.swift */; }; DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB040ED026538E3C00BEE9D8 /* Trie.swift */; }; @@ -958,6 +960,8 @@ DB029E94266A20430062874E /* MastodonAuthenticationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAuthenticationController.swift; sourceTree = ""; }; DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadReplyLoaderTableViewCell.swift; sourceTree = ""; }; DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveUserInterfaceStyleBarButtonItem.swift; sourceTree = ""; }; + DB03A792272A7E5700EE37C5 /* SidebarListHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListHeaderView.swift; sourceTree = ""; }; + DB03A794272A981400EE37C5 /* ContentSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSplitViewController.swift; sourceTree = ""; }; DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeRepliedToStatusContentTableViewCell.swift; sourceTree = ""; }; DB03F7F42689B782007B274C /* ComposeTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeTableView.swift; sourceTree = ""; }; DB040ED026538E3C00BEE9D8 /* Trie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = ""; }; @@ -2125,6 +2129,7 @@ DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */, DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */, DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */, + DB03A792272A7E5700EE37C5 /* SidebarListHeaderView.swift */, ); path = View; sourceTree = ""; @@ -2587,6 +2592,7 @@ isa = PBXGroup; children = ( DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */, + DB03A794272A981400EE37C5 /* ContentSplitViewController.swift */, DB852D1A26FAED0100FC9D81 /* Sidebar */, DB8AF54E25C13703002E6C99 /* MainTab */, ); @@ -3873,6 +3879,7 @@ DBA94440265D137600C537E1 /* Mastodon+Entity+Field.swift in Sources */, DB49A61425FF2C5600B98345 /* EmojiService.swift in Sources */, DBBF1DC7265251D400E5B703 /* AutoCompleteViewModel+State.swift in Sources */, + DB03A793272A7E5700EE37C5 /* SidebarListHeaderView.swift in Sources */, DB4FFC2B269EC39600D62E92 /* SearchToSearchDetailViewControllerAnimatedTransitioning.swift in Sources */, DBCC3B9526157E6E0045B23D /* APIService+Relationship.swift in Sources */, 2D7631B325C159F700929FB9 /* Item.swift in Sources */, @@ -3935,6 +3942,7 @@ DB71FD4625F8C6D200512AE1 /* StatusProvider+UITableViewDataSourcePrefetching.swift in Sources */, DB297B1B2679FAE200704C90 /* PlaceholderImageCacheService.swift in Sources */, 2D8FCA082637EABB00137F46 /* APIService+FollowRequest.swift in Sources */, + DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */, 2D152A8C25C295CC009AA50C /* StatusView.swift in Sources */, DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */, DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 62b4c7f21..e6093a218 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 42 + 35 CoreDataStack.xcscheme_^#shared#^_ orderHint - 43 + 38 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 41 + 36 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 44 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 5df6f7e98..23c2a6f44 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -90,45 +90,45 @@ final public class SceneCoordinator { // Delay in next run loop - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - - // Note: - // show (push) on phone or pad (compact) - // showDetail in .secondary in UISplitViewController on pad (expand) - let from: UIViewController? = { - if let splitViewController = self.splitViewController { - if splitViewController.mainTabBarController.topMost?.view.window != nil { - // compact - return splitViewController.mainTabBarController.topMost - } else { - // expand - return splitViewController.viewController(for: .supplementary) - } - } else { - return self.tabBarController.topMost - } - }() - - // show notification related content - guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return } - let notificationID = String(pushNotification.notificationID) - - switch type { - case .follow: - let profileViewModel = RemoteProfileViewModel(context: appContext, notificationID: notificationID) - self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show) - case .followRequest: - // do nothing - break - case .mention, .reblog, .favourite, .poll, .status: - let threadViewModel = RemoteThreadViewModel(context: appContext, notificationID: notificationID) - self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show) - case ._other: - assertionFailure() - break - } - } +// DispatchQueue.main.async { [weak self] in +// guard let self = self else { return } +// +// // Note: +// // show (push) on phone or pad (compact) +// // showDetail in .secondary in UISplitViewController on pad (expand) +// let from: UIViewController? = { +// if let splitViewController = self.splitViewController { +// if splitViewController.mainTabBarController.topMost?.view.window != nil { +// // compact +// return splitViewController.mainTabBarController.topMost +// } else { +// // expand +// return splitViewController.viewController(for: .supplementary) +// } +// } else { +// return self.tabBarController.topMost +// } +// }() +// +// // show notification related content +// guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return } +// let notificationID = String(pushNotification.notificationID) +// +// switch type { +// case .follow: +// let profileViewModel = RemoteProfileViewModel(context: appContext, notificationID: notificationID) +// self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show) +// case .followRequest: +// // do nothing +// break +// case .mention, .reblog, .favourite, .poll, .status: +// let threadViewModel = RemoteThreadViewModel(context: appContext, notificationID: notificationID) +// self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show) +// case ._other: +// assertionFailure() +// break +// } +// } // end DispatchQueue.main.async } .store(in: &disposeBag) } @@ -227,7 +227,7 @@ extension SceneCoordinator { default: let splitViewController = RootSplitViewController(context: appContext, coordinator: self) self.splitViewController = splitViewController - self.tabBarController = splitViewController.mainTabBarController + self.tabBarController = splitViewController.contentSplitViewController.mainTabBarController sceneDelegate.window?.rootViewController = splitViewController } } @@ -282,18 +282,19 @@ extension SceneCoordinator { switch transition { case .show: - if let splitViewController = splitViewController, !splitViewController.isCollapsed, - let supplementaryViewController = splitViewController.viewController(for: .supplementary) as? UINavigationController, - (supplementaryViewController === presentingViewController || supplementaryViewController.viewControllers.contains(presentingViewController)) || - (presentingViewController is UserTimelineViewController && presentingViewController.view.isDescendant(of: supplementaryViewController.view)) - { - fallthrough - } else { - if secondaryStackHashValues.contains(presentingViewController.hashValue) { - secondaryStackHashValues.insert(viewController.hashValue) - } - presentingViewController.show(viewController, sender: sender) - } +// if let splitViewController = splitViewController, !splitViewController.isCollapsed, +// let supplementaryViewController = splitViewController.viewController(for: .supplementary) as? UINavigationController, +// (supplementaryViewController === presentingViewController || supplementaryViewController.viewControllers.contains(presentingViewController)) || +// (presentingViewController is UserTimelineViewController && presentingViewController.view.isDescendant(of: supplementaryViewController.view)) +// { +// fallthrough +// } else { +// if secondaryStackHashValues.contains(presentingViewController.hashValue) { +// secondaryStackHashValues.insert(viewController.hashValue) +// } +// presentingViewController.show(viewController, sender: sender) +// } + presentingViewController.show(viewController, sender: sender) case .showDetail: secondaryStackHashValues.insert(viewController.hashValue) let navigationController = AdaptiveStatusBarStyleNavigationController(rootViewController: viewController) diff --git a/Mastodon/Generated/Assets.swift b/Mastodon/Generated/Assets.swift index 96fe0fca8..906dd74e2 100644 --- a/Mastodon/Generated/Assets.swift +++ b/Mastodon/Generated/Assets.swift @@ -96,6 +96,9 @@ internal enum Asset { internal static let usernameGray = ColorAsset(name: "Scene/Profile/Banner/username.gray") } } + internal enum Sidebar { + internal static let logo = ImageAsset(name: "Scene/Sidebar/logo") + } internal enum Welcome { internal enum Illustration { internal static let backgroundCyan = ColorAsset(name: "Scene/Welcome/illustration/background.cyan") @@ -160,23 +163,6 @@ internal enum Asset { internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/system/tab.bar.item.inactive.icon.color") } } - internal enum Deprecated { - internal enum Background { - internal static let danger = ColorAsset(name: "_Deprecated/Background/danger") - internal static let onboardingBackground = ColorAsset(name: "_Deprecated/Background/onboarding.background") - internal static let secondaryGroupedSystemBackground = ColorAsset(name: "_Deprecated/Background/secondary.grouped.system.background") - internal static let secondarySystemBackground = ColorAsset(name: "_Deprecated/Background/secondary.system.background") - internal static let systemBackground = ColorAsset(name: "_Deprecated/Background/system.background") - internal static let systemElevatedBackground = ColorAsset(name: "_Deprecated/Background/system.elevated.background") - internal static let systemGroupedBackground = ColorAsset(name: "_Deprecated/Background/system.grouped.background") - internal static let tertiarySystemBackground = ColorAsset(name: "_Deprecated/Background/tertiary.system.background") - internal static let tertiarySystemGroupedBackground = ColorAsset(name: "_Deprecated/Background/tertiary.system.grouped.background") - } - internal enum Compose { - internal static let background = ColorAsset(name: "_Deprecated/Compose/background") - internal static let toolbarBackground = ColorAsset(name: "_Deprecated/Compose/toolbar.background") - } - } } // swiftlint:enable identifier_name line_length nesting type_body_length type_name diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/Contents.json b/Mastodon/Resources/Assets.xcassets/Scene/Sidebar/Contents.json similarity index 100% rename from Mastodon/Resources/Assets.xcassets/_Deprecated/Background/Contents.json rename to Mastodon/Resources/Assets.xcassets/Scene/Sidebar/Contents.json diff --git a/Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/Contents.json new file mode 100644 index 000000000..4f547d09b --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "logo.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/logo.pdf b/Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/logo.pdf new file mode 100644 index 000000000..908727a57 --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Scene/Sidebar/logo.imageset/logo.pdf @@ -0,0 +1,108 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 -0.103455 cm +0.168627 0.564706 0.850980 scn +27.796436 10.091343 m +33.035133 10.719734 37.596470 13.962151 38.169762 16.924883 c +39.073063 21.591980 38.998501 28.314186 38.998501 28.314186 c +38.998501 37.425270 33.056084 40.095867 33.056084 40.095867 c +30.059872 41.478233 24.914881 42.059555 19.569633 42.103455 c +19.438305 42.103455 l +14.093056 42.059555 8.951445 41.478233 5.955006 40.095867 c +5.955006 40.095867 0.012361 37.425270 0.012361 28.314186 c +0.012361 27.761837 0.009520 27.180878 0.006561 26.576080 c +-0.001656 24.896429 -0.010772 23.032921 0.037591 21.087820 c +0.253392 12.177679 1.663759 3.396290 9.864657 1.215820 c +13.645910 0.210445 16.892391 0.000000 19.507011 0.144371 c +24.248556 0.408443 26.910255 1.844212 26.910255 1.844212 c +26.753922 5.300014 l +26.753922 5.300014 23.365528 4.226753 19.560173 4.357544 c +15.789957 4.487431 11.809797 4.765984 11.200012 9.415886 c +11.143697 9.824329 11.115539 10.261055 11.115539 10.719732 c +11.115539 10.719732 14.816599 9.810978 19.507011 9.595104 c +22.375050 9.462955 25.064680 9.763912 27.796436 10.091343 c +h +31.989010 16.575367 m +31.989010 27.607372 l +31.989010 29.862061 31.417519 31.653776 30.269808 32.979347 c +29.085829 34.304916 27.535576 34.984444 25.611385 34.984444 c +23.384670 34.984444 21.698582 34.124794 20.583984 32.405266 c +19.500023 30.580288 l +18.416286 32.405266 l +17.301464 34.124794 15.615376 34.984444 13.388884 34.984444 c +11.464469 34.984444 9.914215 34.304916 8.730462 32.979347 c +7.582527 31.653776 7.011036 29.862061 7.011036 27.607372 c +7.011036 16.575367 l +11.361976 16.575367 l +11.361976 27.283108 l +11.361976 29.540287 12.307401 30.685961 14.198477 30.685961 c +16.289360 30.685961 17.337505 29.326900 17.337505 26.639557 c +17.337505 20.778585 l +21.662764 20.778585 l +21.662764 26.639557 l +21.662764 29.326900 22.710684 30.685961 24.801567 30.685961 c +26.692642 30.685961 27.638069 29.540287 27.638069 27.283108 c +27.638069 16.575367 l +31.989010 16.575367 l +h +f* +n +Q + +endstream +endobj + +3 0 obj + 2035 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 39.000000 42.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Type /Catalog + /Pages 5 0 R + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002125 00000 n +0000002148 00000 n +0000002321 00000 n +0000002395 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2454 +%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/Theme/system/Background/secondary.system.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/system/Background/secondary.system.background.colorset/Contents.json index b9a69ec7d..77d24b11d 100644 --- a/Mastodon/Resources/Assets.xcassets/Theme/system/Background/secondary.system.background.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Theme/system/Background/secondary.system.background.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "46", - "green" : "44", - "red" : "44" + "blue" : "0x2E", + "green" : "0x2C", + "red" : "0x2C" } }, "idiom" : "universal" diff --git a/Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json index e30d6cabe..ee5b1c373 100644 --- a/Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Theme/system/Background/sidebar.background.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.263", - "green" : "0.208", - "red" : "0.192" + "blue" : "0x2E", + "green" : "0x2C", + "red" : "0x2C" } }, "idiom" : "universal" diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/danger.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/danger.colorset/Contents.json deleted file mode 100644 index dabccc33e..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/danger.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.353", - "green" : "0.251", - "red" : "0.875" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/onboarding.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/onboarding.background.colorset/Contents.json deleted file mode 100644 index 0e4687fb4..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/onboarding.background.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.910", - "green" : "0.882", - "red" : "0.851" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.grouped.system.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.grouped.system.background.colorset/Contents.json deleted file mode 100644 index ef6c7f7b1..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.grouped.system.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.996", - "green" : "1.000", - "red" : "0.996" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.263", - "green" : "0.208", - "red" : "0.192" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.system.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.system.background.colorset/Contents.json deleted file mode 100644 index c915c8911..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/secondary.system.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.910", - "green" : "0.882", - "red" : "0.851" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.133", - "green" : "0.106", - "red" : "0.098" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.background.colorset/Contents.json deleted file mode 100644 index 4572c2409..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.996", - "green" : "1.000", - "red" : "0.996" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.216", - "green" : "0.173", - "red" : "0.157" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.elevated.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.elevated.background.colorset/Contents.json deleted file mode 100644 index 33b71ef90..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.elevated.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "1.000", - "green" : "1.000", - "red" : "1.000" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.216", - "green" : "0.173", - "red" : "0.157" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.grouped.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.grouped.background.colorset/Contents.json deleted file mode 100644 index c915c8911..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/system.grouped.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.910", - "green" : "0.882", - "red" : "0.851" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.133", - "green" : "0.106", - "red" : "0.098" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.background.colorset/Contents.json deleted file mode 100644 index 4572c2409..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.996", - "green" : "1.000", - "red" : "0.996" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.216", - "green" : "0.173", - "red" : "0.157" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.grouped.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.grouped.background.colorset/Contents.json deleted file mode 100644 index 98dd7bbde..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Background/tertiary.system.grouped.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.910", - "green" : "0.882", - "red" : "0.851" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.263", - "green" : "0.208", - "red" : "0.192" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/Contents.json deleted file mode 100644 index 6e965652d..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/background.colorset/Contents.json deleted file mode 100644 index 33b71ef90..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "1.000", - "green" : "1.000", - "red" : "1.000" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.216", - "green" : "0.173", - "red" : "0.157" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/toolbar.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/toolbar.background.colorset/Contents.json deleted file mode 100644 index da7b76069..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Compose/toolbar.background.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.871", - "green" : "0.847", - "red" : "0.839" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "0.920", - "blue" : "0.125", - "green" : "0.125", - "red" : "0.125" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/_Deprecated/Contents.json b/Mastodon/Resources/Assets.xcassets/_Deprecated/Contents.json deleted file mode 100644 index 6e965652d..000000000 --- a/Mastodon/Resources/Assets.xcassets/_Deprecated/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index dbd552d97..55bf544ca 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -114,6 +114,24 @@ extension HomeTimelineViewController { #endif } .store(in: &disposeBag) + #if DEBUG + // long press to trigger debug menu + settingBarButtonItem.menu = debugMenu + #else + settingBarButtonItem.target = self + settingBarButtonItem.action = #selector(HomeTimelineViewController.settingBarButtonItemPressed(_:)) + #endif + + viewModel.displayComposeBarButtonItem + .receive(on: DispatchQueue.main) + .sink { [weak self] displayComposeBarButtonItem in + guard let self = self else { return } + self.navigationItem.rightBarButtonItem = displayComposeBarButtonItem ? self.composeBarButtonItem : nil + } + .store(in: &disposeBag) + composeBarButtonItem.target = self + composeBarButtonItem.action = #selector(HomeTimelineViewController.composeBarButtonItemPressed(_:)) + navigationItem.titleView = titleView titleView.delegate = self @@ -126,18 +144,6 @@ extension HomeTimelineViewController { } .store(in: &disposeBag) - #if DEBUG - // long press to trigger debug menu - settingBarButtonItem.menu = debugMenu - #else - settingBarButtonItem.target = self - settingBarButtonItem.action = #selector(HomeTimelineViewController.settingBarButtonItemPressed(_:)) - #endif - - navigationItem.rightBarButtonItem = composeBarButtonItem - composeBarButtonItem.target = self - composeBarButtonItem.action = #selector(HomeTimelineViewController.composeBarButtonItemPressed(_:)) - tableView.refreshControl = refreshControl refreshControl.addTarget(self, action: #selector(HomeTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index a3fbcbd74..c4681b40b 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -30,6 +30,8 @@ final class HomeTimelineViewModel: NSObject { let homeTimelineNavigationBarTitleViewModel: HomeTimelineNavigationBarTitleViewModel let lastAutomaticFetchTimestamp = CurrentValueSubject(nil) let scrollPositionRecord = CurrentValueSubject(nil) + let displaySettingBarButtonItem = CurrentValueSubject(true) + let displayComposeBarButtonItem = CurrentValueSubject(true) weak var contentOffsetAdjustableTimelineViewControllerDelegate: ContentOffsetAdjustableTimelineViewControllerDelegate? weak var tableView: UITableView? @@ -70,7 +72,6 @@ final class HomeTimelineViewModel: NSObject { let loadMiddleSateMachineList = CurrentValueSubject<[NSManagedObjectID: GKStateMachine], Never>([:]) // TimelineIndex.objectID : middle loading state machine var diffableDataSource: UITableViewDiffableDataSource? var cellFrameCache = NSCache() - let displaySettingBarButtonItem = CurrentValueSubject(true) init(context: AppContext) { self.context = context diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift new file mode 100644 index 000000000..42ce3afc3 --- /dev/null +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -0,0 +1,92 @@ +// +// ContentSplitViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-28. +// + +import os.log +import UIKit +import Combine +import CoreDataStack + +final class ContentSplitViewController: UIViewController, NeedsDependency { + + var disposeBag = Set() + + static let sidebarWidth: CGFloat = 89 + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + private(set) lazy var sidebarViewController: SidebarViewController = { + let sidebarViewController = SidebarViewController() + sidebarViewController.context = context + sidebarViewController.coordinator = coordinator + sidebarViewController.viewModel = SidebarViewModel(context: context) + sidebarViewController.delegate = self + return sidebarViewController + }() + + @Published var currentSupplementaryTab: MainTabBarController.Tab = .home + private(set) lazy var mainTabBarController: MainTabBarController = { + let mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) + return mainTabBarController + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension ContentSplitViewController { + override func viewDidLoad() { + super.viewDidLoad() + + navigationController?.setNavigationBarHidden(true, animated: false) + + addChild(sidebarViewController) + sidebarViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(sidebarViewController.view) + sidebarViewController.didMove(toParent: self) + NSLayoutConstraint.activate([ + sidebarViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + sidebarViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + sidebarViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + sidebarViewController.view.widthAnchor.constraint(equalToConstant: ContentSplitViewController.sidebarWidth), + ]) + + addChild(mainTabBarController) + mainTabBarController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(mainTabBarController.view) + sidebarViewController.didMove(toParent: self) + NSLayoutConstraint.activate([ + mainTabBarController.view.topAnchor.constraint(equalTo: view.topAnchor), + mainTabBarController.view.leadingAnchor.constraint(equalTo: sidebarViewController.view.trailingAnchor), + mainTabBarController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + mainTabBarController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + $currentSupplementaryTab + .removeDuplicates() + .sink(receiveValue: { [weak self] tab in + guard let self = self else { return } + self.mainTabBarController.selectedIndex = tab.rawValue + self.mainTabBarController.currentTab.value = tab + }) + .store(in: &disposeBag) + } +} + +// MARK: - SidebarViewControllerDelegate +extension ContentSplitViewController: SidebarViewControllerDelegate { + + func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) { + guard let _ = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { + assertionFailure() + return + } + currentSupplementaryTab = tab + } +} diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift index 8f3f2eea4..b69a6b786 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift @@ -70,6 +70,9 @@ extension MainTabBarController.Wizard { func setup(in view: UIView) { assert(delegate != nil, "need set delegate before use") + + guard !items.isEmpty else { return } + backgroundView.frame = view.bounds backgroundView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(backgroundView) diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 15464c9db..4f818ea9d 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -14,57 +14,44 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { var disposeBag = Set() + static let sidebarWidth: CGFloat = 89 + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } - private(set) lazy var sidebarViewController: SidebarViewController = { - let sidebarViewController = SidebarViewController() - sidebarViewController.context = context - sidebarViewController.coordinator = coordinator - sidebarViewController.viewModel = SidebarViewModel(context: context) - sidebarViewController.delegate = self - return sidebarViewController + private(set) lazy var contentSplitViewController: ContentSplitViewController = { + let contentSplitViewController = ContentSplitViewController() + contentSplitViewController.context = context + contentSplitViewController.coordinator = coordinator + return contentSplitViewController }() - - var currentSupplementaryTab: MainTabBarController.Tab = .home - private(set) lazy var supplementaryViewControllers: [UIViewController] = { - let viewControllers = MainTabBarController.Tab.allCases.map { tab in - tab.viewController(context: context, coordinator: coordinator) - } - for viewController in viewControllers { - guard let navigationController = viewController as? UINavigationController else { - assertionFailure() - continue - } - if let homeViewController = navigationController.topViewController as? HomeTimelineViewController { - homeViewController.viewModel.displaySettingBarButtonItem.value = false - } - } - return viewControllers - }() - - private(set) lazy var mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) init(context: AppContext, coordinator: SceneCoordinator) { self.context = context self.coordinator = coordinator - super.init(style: .tripleColumn) + super.init(style: .doubleColumn) + primaryEdge = .trailing primaryBackgroundStyle = .sidebar - preferredDisplayMode = .oneBesideSecondary + preferredDisplayMode = .twoBesideSecondary preferredSplitBehavior = .tile delegate = self + // disable edge swipe gesture + presentsWithGesture = false + if #available(iOS 14.5, *) { - displayModeButtonVisibility = .always + displayModeButtonVisibility = .never } else { // Fallback on earlier versions } - setViewController(sidebarViewController, for: .primary) - setViewController(supplementaryViewControllers[0], for: .supplementary) - setViewController(SecondaryPlaceholderViewController(), for: .secondary) - setViewController(mainTabBarController, for: .compact) + setViewController(UIViewController(), for: .primary) + setViewController(contentSplitViewController, for: .secondary) + + contentSplitViewController.sidebarViewController.view.layer.zPosition = 100 + contentSplitViewController.mainTabBarController.view.layer.zPosition = 90 + view.layer.zPosition = 80 } required init?(coder: NSCoder) { @@ -83,16 +70,11 @@ extension RootSplitViewController { super.viewDidLoad() updateBehavior(size: view.frame.size) - - mainTabBarController.currentTab + contentSplitViewController.$currentSupplementaryTab .receive(on: DispatchQueue.main) - .sink { [weak self] tab in + .sink { [weak self] _ in guard let self = self else { return } - guard tab != self.currentSupplementaryTab else { return } - guard let index = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { return } - self.currentSupplementaryTab = tab - self.setViewController(self.supplementaryViewControllers[index], for: .supplementary) - + self.updateBehavior(size: self.view.frame.size) } .store(in: &disposeBag) } @@ -100,133 +82,111 @@ extension RootSplitViewController { override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - updateBehavior(size: size) + coordinator.animate { [weak self] context in + guard let self = self else { return } + self.updateBehavior(size: size) + } completion: { context in + // do nothing + } } private func updateBehavior(size: CGSize) { - // fix secondary too small on iPad mini issue - if size.width > 960 { - preferredDisplayMode = .oneBesideSecondary - preferredSplitBehavior = .tile - } else { - preferredDisplayMode = .oneBesideSecondary - preferredSplitBehavior = .displace - } - } - -} - -// MARK: - SidebarViewControllerDelegate -extension RootSplitViewController: SidebarViewControllerDelegate { - - func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) { - - guard let index = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { - assertionFailure() - return - } - currentSupplementaryTab = tab - setViewController(supplementaryViewControllers[index], for: .supplementary) - } - - func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectSearchHistory searchHistoryViewModel: SidebarViewModel.SearchHistoryViewModel) { - // self.sidebarViewController(sidebarViewController, didSelectTab: .search) - - let supplementaryViewController = viewController(for: .supplementary) - let managedObjectContext = context.managedObjectContext - managedObjectContext.perform { - let searchHistory = managedObjectContext.object(with: searchHistoryViewModel.searchHistoryObjectID) as! SearchHistory - if let account = searchHistory.account { - DispatchQueue.main.async { - let profileViewModel = CachedProfileViewModel(context: self.context, mastodonUser: account) - self.coordinator.present(scene: .profile(viewModel: profileViewModel), from: supplementaryViewController, transition: .show) - } - } else if let hashtag = searchHistory.hashtag { - DispatchQueue.main.async { - let hashtagTimelineViewModel = HashtagTimelineViewModel(context: self.context, hashtag: hashtag.name) - self.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: supplementaryViewController, transition: .show) - } + switch contentSplitViewController.currentSupplementaryTab { + case .search: + hide(.primary) + default: + if size.width > 960 { + show(.primary) } else { - assertionFailure() + hide(.primary) } } } - + } // MARK: - UISplitViewControllerDelegate extension RootSplitViewController: UISplitViewControllerDelegate { - // .regular to .compact - // move navigation stack from .supplementary & .secondary to .compact - func splitViewController( - _ svc: UISplitViewController, - topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column - ) -> UISplitViewController.Column { - switch proposedTopColumn { - case .compact: - guard let index = MainTabBarController.Tab.allCases.firstIndex(of: currentSupplementaryTab) else { - assertionFailure() - break - } - mainTabBarController.selectedIndex = index - mainTabBarController.currentTab.value = currentSupplementaryTab - - guard let navigationController = mainTabBarController.selectedViewController as? UINavigationController else { break } - navigationController.popToRootViewController(animated: false) - var viewControllers = navigationController.viewControllers // init navigation stack with topMost - - if let supplementaryNavigationController = viewController(for: .supplementary) as? UINavigationController { - // append supplementary - viewControllers.append(contentsOf: supplementaryNavigationController.popToRootViewController(animated: true) ?? []) - } - if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { - // append secondary - viewControllers.append(contentsOf: secondaryNavigationController.popToRootViewController(animated: true) ?? []) - } - // set navigation stack - navigationController.setViewControllers(viewControllers, animated: false) - - default: - assertionFailure() - } - - return proposedTopColumn - } - - // .compact to .regular - // restore navigation stack to .supplementary & .secondary - func splitViewController( - _ svc: UISplitViewController, - displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode - ) -> UISplitViewController.DisplayMode { - let compactNavigationController = mainTabBarController.selectedViewController as? UINavigationController - - if let topMost = compactNavigationController?.topMost, - topMost is AccountListViewController { - topMost.dismiss(animated: false, completion: nil) - } - - let viewControllers = compactNavigationController?.popToRootViewController(animated: true) ?? [] - - var supplementaryViewControllers: [UIViewController] = [] - var secondaryViewControllers: [UIViewController] = [] - for viewController in viewControllers { - if coordinator.secondaryStackHashValues.contains(viewController.hashValue) { - secondaryViewControllers.append(viewController) - } else { - supplementaryViewControllers.append(viewController) - } - - } - if let supplementary = viewController(for: .supplementary) as? UINavigationController { - supplementary.setViewControllers(supplementary.viewControllers + supplementaryViewControllers, animated: false) - } - if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { - secondaryNavigationController.setViewControllers(secondaryNavigationController.viewControllers + secondaryViewControllers, animated: false) - } - - return proposedDisplayMode - } +// // .regular to .compact +// // move navigation stack from .supplementary & .secondary to .compact +// func splitViewController( +// _ svc: UISplitViewController, +// topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column +// ) -> UISplitViewController.Column { +// switch proposedTopColumn { +// case .compact: +// guard let index = MainTabBarController.Tab.allCases.firstIndex(of: currentSupplementaryTab) else { +// assertionFailure() +// break +// } +// mainTabBarController.selectedIndex = index +// mainTabBarController.currentTab.value = currentSupplementaryTab +// +// guard let navigationController = mainTabBarController.selectedViewController as? UINavigationController else { break } +// navigationController.popToRootViewController(animated: false) +// var viewControllers = navigationController.viewControllers // init navigation stack with topMost +// +// if let supplementaryNavigationController = viewController(for: .supplementary) as? UINavigationController { +// // append supplementary +// viewControllers.append(contentsOf: supplementaryNavigationController.popToRootViewController(animated: true) ?? []) +// } +// if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { +// // append secondary +// viewControllers.append(contentsOf: secondaryNavigationController.popToRootViewController(animated: true) ?? []) +// } +// // set navigation stack +// navigationController.setViewControllers(viewControllers, animated: false) +// +// default: +// assertionFailure() +// } +// +// return proposedTopColumn +// } +// +// // .compact to .regular +// // restore navigation stack to .supplementary & .secondary +// func splitViewController( +// _ svc: UISplitViewController, +// displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode +// ) -> UISplitViewController.DisplayMode { +// let compactNavigationController = mainTabBarController.selectedViewController as? UINavigationController +// +// if let topMost = compactNavigationController?.topMost, +// topMost is AccountListViewController { +// topMost.dismiss(animated: false, completion: nil) +// } +// +// let viewControllers = compactNavigationController?.popToRootViewController(animated: true) ?? [] +// +// var supplementaryViewControllers: [UIViewController] = [] +// var secondaryViewControllers: [UIViewController] = [] +// for viewController in viewControllers { +// if coordinator.secondaryStackHashValues.contains(viewController.hashValue) { +// secondaryViewControllers.append(viewController) +// } else { +// supplementaryViewControllers.append(viewController) +// } +// +// } +// if let supplementary = viewController(for: .supplementary) as? UINavigationController { +// supplementary.setViewControllers(supplementary.viewControllers + supplementaryViewControllers, animated: false) +// } +// if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { +// secondaryNavigationController.setViewControllers(secondaryNavigationController.viewControllers + secondaryViewControllers, animated: false) +// } +// +// return proposedDisplayMode +// } } + +//extension UIView { +// func setNeedsLayoutForSubviews() { +// self.subviews.forEach({ +// $0.setNeedsLayout() +// $0.setNeedsLayoutForSubviews() +// }) +// } +//} diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 69d9f55c8..060091922 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -12,7 +12,6 @@ import CoreDataStack protocol SidebarViewControllerDelegate: AnyObject { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) - func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectSearchHistory searchHistoryViewModel: SidebarViewModel.SearchHistoryViewModel) } final class SidebarViewController: UIViewController, NeedsDependency { @@ -21,28 +20,46 @@ final class SidebarViewController: UIViewController, NeedsDependency { weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var disposeBag = Set() + var observations = Set() var viewModel: SidebarViewModel! weak var delegate: SidebarViewControllerDelegate? - - let settingBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem() - barButtonItem.tintColor = Asset.Colors.brandBlue.color - barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate) - return barButtonItem - }() static func createLayout() -> UICollectionViewLayout { let layout = UICollectionViewCompositionalLayout() { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in var configuration = UICollectionLayoutListConfiguration(appearance: .sidebar) configuration.backgroundColor = .clear - if sectionIndex == SidebarViewModel.Section.tab.rawValue { - // with indentation - configuration.headerMode = .none - } else { - // remove indentation - configuration.headerMode = .firstItemInSection + configuration.showsSeparators = false + let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment) + switch sectionIndex { + case 0: + let header = NSCollectionLayoutBoundarySupplementaryItem( + layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), + heightDimension: .estimated(100)), + elementKind: UICollectionView.elementKindSectionHeader, + alignment: .top + ) + section.boundarySupplementaryItems = [header] + default: + break } + return section + } + return layout + } + + let collectionView: UICollectionView = { + let layout = SidebarViewController.createLayout() + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.alwaysBounceVertical = false + collectionView.backgroundColor = .clear + return collectionView + }() + + static func createSecondaryLayout() -> UICollectionViewLayout { + let layout = UICollectionViewCompositionalLayout() { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in + var configuration = UICollectionLayoutListConfiguration(appearance: .sidebar) + configuration.backgroundColor = .clear configuration.showsSeparators = false let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment) return section @@ -50,12 +67,15 @@ final class SidebarViewController: UIViewController, NeedsDependency { return layout } - let collectionView: UICollectionView = { - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: SidebarViewController.createLayout()) + let secondaryCollectionView: UICollectionView = { + let layout = SidebarViewController.createSecondaryLayout() + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.isScrollEnabled = false + collectionView.alwaysBounceVertical = false collectionView.backgroundColor = .clear return collectionView }() - + var secondaryCollectionViewHeightLayoutConstraint: NSLayoutConstraint! } extension SidebarViewController { @@ -63,23 +83,7 @@ extension SidebarViewController { override func viewDidLoad() { super.viewDidLoad() - viewModel.context.authenticationService.activeMastodonAuthenticationBox - .receive(on: DispatchQueue.main) - .sink { [weak self] activeMastodonAuthenticationBox in - guard let self = self else { return } - let domain = activeMastodonAuthenticationBox?.domain - self.navigationItem.backBarButtonItem = { - let barButtonItem = UIBarButtonItem() - barButtonItem.image = UIImage(systemName: "sidebar.leading") - return barButtonItem - }() - self.navigationItem.title = domain - } - .store(in: &disposeBag) - navigationItem.rightBarButtonItem = settingBarButtonItem - settingBarButtonItem.target = self - settingBarButtonItem.action = #selector(SidebarViewController.settingBarButtonItemPressed(_:)) - navigationController?.navigationBar.prefersLargeTitles = true + navigationController?.setNavigationBarHidden(true, animated: false) setupBackground(theme: ThemeService.shared.currentTheme.value) ThemeService.shared.currentTheme @@ -99,65 +103,101 @@ extension SidebarViewController { collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) + secondaryCollectionView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(secondaryCollectionView) + secondaryCollectionViewHeightLayoutConstraint = secondaryCollectionView.heightAnchor.constraint(equalToConstant: 44).priority(.required - 1) + NSLayoutConstraint.activate([ + secondaryCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + secondaryCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + view.bottomAnchor.constraint(equalTo: secondaryCollectionView.bottomAnchor), + secondaryCollectionViewHeightLayoutConstraint, + ]) + collectionView.delegate = self - viewModel.setupDiffableDataSource(collectionView: collectionView) + secondaryCollectionView.delegate = self + viewModel.setupDiffableDataSource( + collectionView: collectionView, + secondaryCollectionView: secondaryCollectionView + ) + + secondaryCollectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] secondaryCollectionView, _ in + guard let self = self else { return } + let height = secondaryCollectionView.contentSize.height + self.secondaryCollectionViewHeightLayoutConstraint.constant = height + self.collectionView.contentInset.bottom = height + } + .store(in: &observations) } private func setupBackground(theme: Theme) { let color: UIColor = theme.sidebarBackgroundColor - let barAppearance = UINavigationBarAppearance() - barAppearance.configureWithOpaqueBackground() - barAppearance.backgroundColor = color - barAppearance.shadowColor = .clear - barAppearance.shadowImage = UIImage() // remove separator line - navigationItem.standardAppearance = barAppearance - navigationItem.compactAppearance = barAppearance - navigationItem.scrollEdgeAppearance = barAppearance - if #available(iOS 15.0, *) { - navigationItem.compactScrollEdgeAppearance = barAppearance - } else { - // Fallback on earlier versions - } - view.backgroundColor = color - collectionView.backgroundColor = color + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + coordinator.animate { context in + self.collectionView.collectionViewLayout.invalidateLayout() +// // do nothing + } completion: { [weak self] context in +// guard let self = self else { return } + } + } } -extension SidebarViewController { - @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, setting: setting) - coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil)) - } -} - // MARK: - UICollectionViewDelegate extension SidebarViewController: UICollectionViewDelegate { + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let diffableDataSource = viewModel.diffableDataSource else { return } - guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } - switch item { - case .tab(let tab): - delegate?.sidebarViewController(self, didSelectTab: tab) - case .searchHistory(let viewModel): - delegate?.sidebarViewController(self, didSelectSearchHistory: viewModel) - case .header: - break - case .account(let viewModel): - assert(Thread.isMainThread) - let authentication = context.managedObjectContext.object(with: viewModel.authenticationObjectID) as! MastodonAuthentication - context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID) - .receive(on: DispatchQueue.main) - .sink { [weak self] result in - guard let self = self else { return } - self.coordinator.setup() - } - .store(in: &disposeBag) - case .addAccount: - coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil)) + switch collectionView { + case self.collectionView: + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } + switch item { + case .tab(let tab): + delegate?.sidebarViewController(self, didSelectTab: tab) + case .setting: + guard let setting = context.settingService.currentSetting.value else { return } + let settingsViewModel = SettingsViewModel(context: context, setting: setting) + coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil)) + case .compose: + assertionFailure() + } + case secondaryCollectionView: + guard let diffableDataSource = viewModel.secondaryDiffableDataSource else { return } + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } + switch item { + case .compose: + let composeViewModel = ComposeViewModel(context: context, composeKind: .post) + coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil)) + default: + assertionFailure() + } + default: + assertionFailure() } +// switch item { +// case .tab(let tab): +// delegate?.sidebarViewController(self, didSelectTab: tab) +// case .searchHistory(let viewModel): +// delegate?.sidebarViewController(self, didSelectSearchHistory: viewModel) +// case .header: +// break +// case .account(let viewModel): +// assert(Thread.isMainThread) +// let authentication = context.managedObjectContext.object(with: viewModel.authenticationObjectID) as! MastodonAuthentication +// context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID) +// .receive(on: DispatchQueue.main) +// .sink { [weak self] result in +// guard let self = self else { return } +// self.coordinator.setup() +// } +// .store(in: &disposeBag) +// case .addAccount: +// coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil)) +// } } } diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index d7ec5b717..6dd46d08c 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -22,6 +22,8 @@ final class SidebarViewModel { // output var diffableDataSource: UICollectionViewDiffableDataSource? + var secondaryDiffableDataSource: UICollectionViewDiffableDataSource? + let activeMastodonAuthenticationObjectID = CurrentValueSubject(nil) init(context: AppContext) { @@ -47,38 +49,22 @@ final class SidebarViewModel { extension SidebarViewModel { enum Section: Int, Hashable, CaseIterable { - case tab - case account + case main + case secondary } enum Item: Hashable { case tab(MainTabBarController.Tab) - case searchHistory(SearchHistoryViewModel) - case header(HeaderViewModel) - case account(AccountViewModel) - case addAccount + case setting + case compose } - struct SearchHistoryViewModel: Hashable { - let searchHistoryObjectID: NSManagedObjectID - } - - struct HeaderViewModel: Hashable { - let title: String - } - - struct AccountViewModel: Hashable { - let authenticationObjectID: NSManagedObjectID - } - - struct AddAccountViewModel: Hashable { - let id = UUID() - } } extension SidebarViewModel { func setupDiffableDataSource( - collectionView: UICollectionView + collectionView: UICollectionView, + secondaryCollectionView: UICollectionView ) { let tabCellRegistration = UICollectionView.CellRegistration { [weak self] cell, indexPath, item in guard let self = self else { return } @@ -92,23 +78,10 @@ extension SidebarViewModel { return nil } }() - let headline: MetaContent = { - switch item { - case .me: - return PlaintextMetaContent(string: item.title) - // TODO: - // return PlaintextMetaContent(string: "Myself") - default: - return PlaintextMetaContent(string: item.title) - } - }() - let needsOutlineDisclosure = item == .search cell.item = SidebarListContentView.Item( + title: item.title, image: item.sidebarImage, - imageURL: imageURL, - headline: headline, - subheadline: nil, - needsOutlineDisclosure: needsOutlineDisclosure + imageURL: imageURL ) cell.setNeedsUpdateConfiguration() @@ -135,209 +108,91 @@ extension SidebarViewModel { } } - let searchHistoryCellRegistration = UICollectionView.CellRegistration { [weak self] cell, indexPath, item in + let cellRegistration = UICollectionView.CellRegistration { [weak self] cell, indexPath, item in guard let self = self else { return } - let managedObjectContext = self.searchHistoryFetchedResultController.fetchedResultsController.managedObjectContext - - guard let searchHistory = try? managedObjectContext.existingObject(with: item.searchHistoryObjectID) as? SearchHistory else { return } - - if let account = searchHistory.account { - let headline: MetaContent = { - do { - let content = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojiMeta) - return try MastodonMetaContent.convert(document: content) - } catch { - return PlaintextMetaContent(string: account.displayNameWithFallback) - } - }() - cell.item = SidebarListContentView.Item( - image: .placeholder(color: .systemFill), - imageURL: account.avatarImageURL(), - headline: headline, - subheadline: PlaintextMetaContent(string: "@" + account.acctWithDomain), - needsOutlineDisclosure: false - ) - } else if let hashtag = searchHistory.hashtag { - let image = UIImage(systemName: "number.square.fill")!.withRenderingMode(.alwaysTemplate) - let headline = PlaintextMetaContent(string: "#" + hashtag.name) - cell.item = SidebarListContentView.Item( - image: image, - imageURL: nil, - headline: headline, - subheadline: nil, - needsOutlineDisclosure: false - ) - } else { - assertionFailure() - } - + cell.item = item cell.setNeedsUpdateConfiguration() } - let headerRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in - var content = UIListContentConfiguration.sidebarHeader() - content.text = item.title - cell.contentConfiguration = content - cell.accessories = [.outlineDisclosure()] - } - - let accountRegistration = UICollectionView.CellRegistration { [weak self] (cell, indexPath, item) in - guard let self = self else { return } - - // accounts maybe already sign-out - // check isDeleted before using - guard let authentication = try? AppContext.shared.managedObjectContext.existingObject(with: item.authenticationObjectID) as? MastodonAuthentication, - !authentication.isDeleted else { - return - } - let user = authentication.user - let imageURL = user.avatarImageURL() - let headline: MetaContent = { - do { - let content = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojiMeta) - return try MastodonMetaContent.convert(document: content) - } catch { - return PlaintextMetaContent(string: user.displayNameWithFallback) - } - }() - cell.item = SidebarListContentView.Item( - image: .placeholder(color: .systemFill), - imageURL: imageURL, - headline: headline, - subheadline: PlaintextMetaContent(string: "@" + user.acctWithDomain), - needsOutlineDisclosure: false - ) - cell.setNeedsUpdateConfiguration() - - // FIXME: use notification, not timer - let accessToken = authentication.userAccessToken - AppContext.shared.timestampUpdatePublisher - .map { _ in UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken) } - .removeDuplicates() - .receive(on: DispatchQueue.main) - .sink { [weak cell] count in - guard let cell = cell else { return } - cell._contentView?.badgeButton.setBadge(number: count) - } - .store(in: &cell.disposeBag) - - let authenticationObjectID = item.authenticationObjectID - self.activeMastodonAuthenticationObjectID - .receive(on: DispatchQueue.main) - .sink { [weak cell] objectID in - guard let cell = cell else { return } - cell._contentView?.checkmarkImageView.isHidden = authenticationObjectID != objectID - } - .store(in: &cell.disposeBag) - } - - let addAccountRegistration = UICollectionView.CellRegistration { (cell, indexPath, item) in - var content = UIListContentConfiguration.sidebarCell() - content.text = L10n.Scene.AccountList.addAccount - content.image = UIImage(systemName: "plus.square.fill")! - - cell.contentConfiguration = content - cell.accessories = [] + // header + let headerRegistration = UICollectionView.SupplementaryRegistration(elementKind: UICollectionView.elementKindSectionHeader) { supplementaryView, elementKind, indexPath in + // do nothing } let _diffableDataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, item in switch item { case .tab(let tab): return collectionView.dequeueConfiguredReusableCell(using: tabCellRegistration, for: indexPath, item: tab) - case .searchHistory(let viewModel): - return collectionView.dequeueConfiguredReusableCell(using: searchHistoryCellRegistration, for: indexPath, item: viewModel) - case .header(let viewModel): - return collectionView.dequeueConfiguredReusableCell(using: headerRegistration, for: indexPath, item: viewModel) - case .account(let viewModel): - return collectionView.dequeueConfiguredReusableCell(using: accountRegistration, for: indexPath, item: viewModel) - case .addAccount: - return collectionView.dequeueConfiguredReusableCell(using: addAccountRegistration, for: indexPath, item: AddAccountViewModel()) + case .setting: + let item = SidebarListContentView.Item( + title: L10n.Common.Controls.Actions.settings, + image: UIImage(systemName: "gear")!, + imageURL: nil + ) + return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) + case .compose: + let item = SidebarListContentView.Item( + title: "Compose", // FIXME: + image: UIImage(systemName: "square.and.pencil")!, + imageURL: nil + ) + return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) + } + } + _diffableDataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in + switch elementKind { + case UICollectionView.elementKindSectionHeader: + return collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath) + default: + assertionFailure() + return UICollectionReusableView() } } diffableDataSource = _diffableDataSource var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections(Section.allCases) - _diffableDataSource.apply(snapshot) + snapshot.appendSections([.main]) - for section in Section.allCases { - switch section { - case .tab: - var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() - let items: [Item] = [ - .tab(.home), - .tab(.search), - .tab(.notification), - .tab(.me), - ] - sectionSnapshot.append(items, to: nil) - _diffableDataSource.apply(sectionSnapshot, to: section) - case .account: - var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() - let headerItem = Item.header(HeaderViewModel(title: "Accounts")) - sectionSnapshot.append([headerItem], to: nil) - sectionSnapshot.append([], to: headerItem) - sectionSnapshot.append([.addAccount], to: headerItem) - sectionSnapshot.expand([headerItem]) - _diffableDataSource.apply(sectionSnapshot, to: section) + var sectionSnapshot = NSDiffableDataSourceSectionSnapshot() + let items: [Item] = [ + .tab(.home), + .tab(.search), + .tab(.notification), + .tab(.me), + .setting, + ] + sectionSnapshot.append(items, to: nil) + _diffableDataSource.apply(sectionSnapshot, to: .main) + + + // secondary + let _secondaryDiffableDataSource = UICollectionViewDiffableDataSource(collectionView: secondaryCollectionView) { collectionView, indexPath, item in + guard case .compose = item else { + assertionFailure() + return UICollectionViewCell() } + + let item = SidebarListContentView.Item( + title: "Compose", // FIXME: + image: UIImage(systemName: "square.and.pencil")!, + imageURL: nil + ) + return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) } +// _secondaryDiffableDataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in +// return nil +// } + secondaryDiffableDataSource = _secondaryDiffableDataSource - // update .search tab - searchHistoryFetchedResultController.objectIDs - .removeDuplicates() - .receive(on: DispatchQueue.main) - .sink { [weak self] objectIDs in - guard let self = self else { return } - guard let diffableDataSource = self.diffableDataSource else { return } + var secondarySnapshot = NSDiffableDataSourceSnapshot() + secondarySnapshot.appendSections([.secondary]) - // update .search tab - var sectionSnapshot = diffableDataSource.snapshot(for: .tab) - - // remove children - let searchHistorySnapshot = sectionSnapshot.snapshot(of: .tab(.search)) - sectionSnapshot.delete(searchHistorySnapshot.items) - - // append children - let managedObjectContext = self.searchHistoryFetchedResultController.fetchedResultsController.managedObjectContext - let items: [Item] = objectIDs.compactMap { objectID -> Item? in - guard let searchHistory = try? managedObjectContext.existingObject(with: objectID) as? SearchHistory else { return nil } - guard searchHistory.account != nil || searchHistory.hashtag != nil else { return nil } - let viewModel = SearchHistoryViewModel(searchHistoryObjectID: objectID) - return Item.searchHistory(viewModel) - } - sectionSnapshot.append(Array(items.prefix(5)), to: .tab(.search)) - sectionSnapshot.expand([.tab(.search)]) - - // apply snapshot - diffableDataSource.apply(sectionSnapshot, to: .tab, animatingDifferences: false) - } - .store(in: &disposeBag) - - // update .me tab and .account section - context.authenticationService.mastodonAuthentications - .receive(on: DispatchQueue.main) - .sink { [weak self] authentications in - guard let self = self else { return } - guard let diffableDataSource = self.diffableDataSource else { return } - // tab - var snapshot = diffableDataSource.snapshot() - snapshot.reloadItems([.tab(.me)]) - diffableDataSource.apply(snapshot) - - // account - var accountSectionSnapshot = NSDiffableDataSourceSectionSnapshot() - let headerItem = Item.header(HeaderViewModel(title: "Accounts")) - accountSectionSnapshot.append([headerItem], to: nil) - let accountItems = authentications.map { authentication in - Item.account(AccountViewModel(authenticationObjectID: authentication.objectID)) - } - accountSectionSnapshot.append(accountItems, to: headerItem) - accountSectionSnapshot.append([.addAccount], to: headerItem) - accountSectionSnapshot.expand([headerItem]) - diffableDataSource.apply(accountSectionSnapshot, to: .account) - } - .store(in: &disposeBag) + var secondarySectionSnapshot = NSDiffableDataSourceSectionSnapshot() + let secondarySectionItems: [Item] = [ + .compose, + ] + secondarySectionSnapshot.append(secondarySectionItems, to: nil) + _secondaryDiffableDataSource.apply(secondarySectionSnapshot, to: .secondary) } } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift index 1bb76f59e..dc71eadfb 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift @@ -60,21 +60,6 @@ extension SidebarListCollectionViewCell { newBackgroundConfiguration.backgroundColorTransformer = .init { $0.withAlphaComponent(0.8) } } - backgroundConfiguration = newBackgroundConfiguration - - let needsOutlineDisclosure = item?.needsOutlineDisclosure ?? false - if !needsOutlineDisclosure { - accessories = [] - } else { - let tintColor: UIColor = state.isHighlighted || state.isSelected ? .white : Asset.Colors.brandBlue.color - accessories = [ - UICellAccessory.outlineDisclosure( - displayed: .always, - options: UICellAccessory.OutlineDisclosureOptions(tintColor: tintColor), - actionHandler: nil - ) - ] - } } } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift index 62b188325..dedd47b88 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -15,15 +15,10 @@ final class SidebarListContentView: UIView, UIContentView { let logger = Logger(subsystem: "SidebarListContentView", category: "UI") let imageView = UIImageView() - let animationImageView = FLAnimatedImageView() // for animation image - let headlineLabel = MetaLabel(style: .sidebarHeadline(isSelected: false)) - let subheadlineLabel = MetaLabel(style: .sidebarSubheadline(isSelected: false)) - let badgeButton = BadgeButton() - let checkmarkImageView: UIImageView = { - let image = UIImage(systemName: "checkmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .semibold)) - let imageView = UIImageView(image: image) - imageView.tintColor = .label - return imageView + let avatarButton: CircleAvatarButton = { + let button = CircleAvatarButton() + button.borderWidth = 2 + return button }() private var currentConfiguration: ContentConfiguration! @@ -53,93 +48,31 @@ final class SidebarListContentView: UIView, UIContentView { extension SidebarListContentView { private func _init() { - let imageViewContainer = UIView() - imageViewContainer.translatesAutoresizingMaskIntoConstraints = false - addSubview(imageViewContainer) - NSLayoutConstraint.activate([ - imageViewContainer.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor), - imageViewContainer.centerYAnchor.constraint(equalTo: centerYAnchor), - ]) - imageViewContainer.setContentHuggingPriority(.defaultLow, for: .horizontal) - imageViewContainer.setContentHuggingPriority(.defaultLow, for: .vertical) - - animationImageView.translatesAutoresizingMaskIntoConstraints = false - imageViewContainer.addSubview(animationImageView) - NSLayoutConstraint.activate([ - animationImageView.centerXAnchor.constraint(equalTo: imageViewContainer.centerXAnchor), - animationImageView.centerYAnchor.constraint(equalTo: imageViewContainer.centerYAnchor), - animationImageView.widthAnchor.constraint(equalTo: imageViewContainer.widthAnchor, multiplier: 1.0).priority(.required - 1), - animationImageView.heightAnchor.constraint(equalTo: imageViewContainer.heightAnchor, multiplier: 1.0).priority(.required - 1), - ]) - animationImageView.setContentHuggingPriority(.defaultLow - 10, for: .vertical) - animationImageView.setContentHuggingPriority(.defaultLow - 10, for: .horizontal) - imageView.translatesAutoresizingMaskIntoConstraints = false - imageViewContainer.addSubview(imageView) + addSubview(imageView) NSLayoutConstraint.activate([ - imageView.centerXAnchor.constraint(equalTo: imageViewContainer.centerXAnchor), - imageView.centerYAnchor.constraint(equalTo: imageViewContainer.centerYAnchor), - imageView.widthAnchor.constraint(equalTo: imageViewContainer.widthAnchor, multiplier: 1.0).priority(.required - 1), - imageView.heightAnchor.constraint(equalTo: imageViewContainer.heightAnchor, multiplier: 1.0).priority(.required - 1), + imageView.topAnchor.constraint(equalTo: topAnchor, constant: 16), + imageView.centerXAnchor.constraint(equalTo: centerXAnchor), + bottomAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 16), + imageView.widthAnchor.constraint(equalToConstant: 40).priority(.required - 1), + imageView.heightAnchor.constraint(equalToConstant: 40).priority(.required - 1), ]) - imageView.setContentHuggingPriority(.defaultLow - 10, for: .vertical) - imageView.setContentHuggingPriority(.defaultLow - 10, for: .horizontal) - - let textContainer = UIStackView() - textContainer.axis = .vertical - textContainer.translatesAutoresizingMaskIntoConstraints = false - addSubview(textContainer) + + avatarButton.translatesAutoresizingMaskIntoConstraints = false + addSubview(avatarButton) NSLayoutConstraint.activate([ - textContainer.topAnchor.constraint(equalTo: topAnchor, constant: 10), - textContainer.leadingAnchor.constraint(equalTo: imageViewContainer.trailingAnchor, constant: 10), - // textContainer.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), - bottomAnchor.constraint(equalTo: textContainer.bottomAnchor, constant: 12), + avatarButton.centerXAnchor.constraint(equalTo: imageView.centerXAnchor), + 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), ]) - - textContainer.addArrangedSubview(headlineLabel) - textContainer.addArrangedSubview(subheadlineLabel) - headlineLabel.setContentHuggingPriority(.required - 9, for: .vertical) - headlineLabel.setContentCompressionResistancePriority(.required - 9, for: .vertical) - subheadlineLabel.setContentHuggingPriority(.required - 10, for: .vertical) - subheadlineLabel.setContentCompressionResistancePriority(.required - 10, for: .vertical) - - badgeButton.translatesAutoresizingMaskIntoConstraints = false - addSubview(badgeButton) - NSLayoutConstraint.activate([ - badgeButton.leadingAnchor.constraint(equalTo: textContainer.trailingAnchor, constant: 4), - badgeButton.centerYAnchor.constraint(equalTo: centerYAnchor), - badgeButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 16).priority(.required - 1), - badgeButton.widthAnchor.constraint(equalTo: badgeButton.heightAnchor, multiplier: 1.0).priority(.required - 1), - ]) - badgeButton.setContentHuggingPriority(.required - 10, for: .horizontal) - badgeButton.setContentCompressionResistancePriority(.required - 10, for: .horizontal) - - NSLayoutConstraint.activate([ - imageViewContainer.heightAnchor.constraint(equalTo: headlineLabel.heightAnchor, multiplier: 1.0).priority(.required - 1), - imageViewContainer.widthAnchor.constraint(equalTo: imageViewContainer.heightAnchor, multiplier: 1.0).priority(.required - 1), - ]) - - checkmarkImageView.translatesAutoresizingMaskIntoConstraints = false - addSubview(checkmarkImageView) - NSLayoutConstraint.activate([ - checkmarkImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - checkmarkImageView.leadingAnchor.constraint(equalTo: badgeButton.trailingAnchor, constant: 16), - checkmarkImageView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor), - ]) - checkmarkImageView.setContentHuggingPriority(.required - 9, for: .horizontal) - checkmarkImageView.setContentCompressionResistancePriority(.required - 9, for: .horizontal) - - animationImageView.isUserInteractionEnabled = false - headlineLabel.isUserInteractionEnabled = false - subheadlineLabel.isUserInteractionEnabled = false - + avatarButton.setContentHuggingPriority(.defaultLow - 10, for: .vertical) + avatarButton.setContentHuggingPriority(.defaultLow - 10, for: .horizontal) + imageView.contentMode = .scaleAspectFit - animationImageView.contentMode = .scaleAspectFit + avatarButton.contentMode = .scaleAspectFit imageView.tintColor = Asset.Colors.brandBlue.color - animationImageView.tintColor = Asset.Colors.brandBlue.color - - badgeButton.setBadge(number: 0) - checkmarkImageView.isHidden = true + avatarButton.tintColor = Asset.Colors.brandBlue.color } private func apply(configuration: ContentConfiguration) { @@ -152,31 +85,20 @@ extension SidebarListContentView { // configure state imageView.tintColor = item.isSelected ? .white : Asset.Colors.brandBlue.color - animationImageView.tintColor = item.isSelected ? .white : Asset.Colors.brandBlue.color - headlineLabel.setup(style: .sidebarHeadline(isSelected: item.isSelected)) - subheadlineLabel.setup(style: .sidebarSubheadline(isSelected: item.isSelected)) + avatarButton.tintColor = item.isSelected ? .white : Asset.Colors.brandBlue.color // configure model imageView.isHidden = item.imageURL != nil - animationImageView.isHidden = item.imageURL == nil + avatarButton.isHidden = item.imageURL == nil imageView.image = item.image.withRenderingMode(.alwaysTemplate) - animationImageView.setImage( + avatarButton.avatarImageView.setImage( url: item.imageURL, - placeholder: animationImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink + placeholder: avatarButton.avatarImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink scaleToSize: nil ) - animationImageView.layer.masksToBounds = true - animationImageView.layer.cornerCurve = .continuous - animationImageView.layer.cornerRadius = 4 - - headlineLabel.configure(content: item.headline) - - if let subheadline = item.subheadline { - subheadlineLabel.configure(content: subheadline) - subheadlineLabel.isHidden = false - } else { - subheadlineLabel.isHidden = true - } + avatarButton.layer.masksToBounds = true + avatarButton.layer.cornerCurve = .continuous + avatarButton.layer.cornerRadius = 4 } } @@ -186,27 +108,22 @@ extension SidebarListContentView { var isSelected: Bool = false // model + let title: String let image: UIImage let imageURL: URL? - let headline: MetaContent - let subheadline: MetaContent? - - let needsOutlineDisclosure: Bool - + static func == (lhs: SidebarListContentView.Item, rhs: SidebarListContentView.Item) -> Bool { return lhs.isSelected == rhs.isSelected + && lhs.title == rhs.title && lhs.image == rhs.image && lhs.imageURL == rhs.imageURL - && lhs.headline.string == rhs.headline.string - && lhs.subheadline?.string == rhs.subheadline?.string } func hash(into hasher: inout Hasher) { hasher.combine(isSelected) + hasher.combine(title) hasher.combine(image) imageURL.flatMap { hasher.combine($0) } - hasher.combine(headline.string) - subheadline.flatMap { hasher.combine($0.string) } } } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift new file mode 100644 index 000000000..2056c5dcd --- /dev/null +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift @@ -0,0 +1,42 @@ +// +// SidebarListHeaderView.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-10-28. +// + +import UIKit + +final class SidebarListHeaderView: UICollectionReusableView { + + let imageView: UIImageView = { + let imageView = UIImageView() + imageView.image = Asset.Scene.Sidebar.logo.image + return imageView + }() + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension SidebarListHeaderView { + private func _init() { + imageView.translatesAutoresizingMaskIntoConstraints = false + addSubview(imageView) + NSLayoutConstraint.activate([ + imageView.topAnchor.constraint(equalTo: topAnchor, constant: 8), + imageView.centerXAnchor.constraint(equalTo: centerXAnchor), + bottomAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 16), + imageView.widthAnchor.constraint(equalToConstant: 44).priority(.required - 1), + imageView.heightAnchor.constraint(equalToConstant: 44).priority(.required - 1), + ]) + } +} diff --git a/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift b/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift index 40272d290..0bc2aeefd 100644 --- a/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift +++ b/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift @@ -9,12 +9,15 @@ import UIKit final class CircleAvatarButton: AvatarButton { + var borderColor: CGColor = UIColor.systemFill.cgColor + var borderWidth: CGFloat = 1.0 + override func layoutSubviews() { super.layoutSubviews() layer.masksToBounds = true layer.cornerRadius = frame.width * 0.5 - layer.borderColor = UIColor.systemFill.cgColor - layer.borderWidth = 1 + layer.borderColor = borderColor + layer.borderWidth = borderWidth } } diff --git a/Mastodon/Service/ThemeService/SystemTheme.swift b/Mastodon/Service/ThemeService/SystemTheme.swift index 2e3b290db..1ea923979 100644 --- a/Mastodon/Service/ThemeService/SystemTheme.swift +++ b/Mastodon/Service/ThemeService/SystemTheme.swift @@ -23,7 +23,7 @@ struct SystemTheme: Theme { let navigationBarBackgroundColor = Asset.Theme.System.navigationBarBackground.color - let sidebarBackgroundColor = Asset.Theme.Mastodon.sidebarBackground.color + let sidebarBackgroundColor = Asset.Theme.System.sidebarBackground.color let tabBarBackgroundColor = Asset.Theme.System.tabBarBackground.color let tabBarItemSelectedIconColor = Asset.Colors.brandBlue.color From b1f3729f56450fde3a56b99d7341c488b63f63d9 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 28 Oct 2021 19:33:29 +0800 Subject: [PATCH 292/392] chore: update version to 1.2.0 (80) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- .../xcshareddata/swiftpm/Package.resolved | 9 --- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 12 files changed, 45 insertions(+), 54 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 7f509a3fe..cf50d3ac4 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 7f509a3fe..cf50d3ac4 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 7f509a3fe..cf50d3ac4 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 1ab4b2559..f7b373f59 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4800,7 +4800,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4829,7 +4829,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4937,11 +4937,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4968,11 +4968,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4997,11 +4997,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5027,11 +5027,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5094,7 +5094,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5119,7 +5119,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5144,7 +5144,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5169,7 +5169,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5194,7 +5194,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5219,7 +5219,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5244,7 +5244,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5269,7 +5269,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5360,7 +5360,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5427,11 +5427,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5476,7 +5476,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5501,11 +5501,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5597,7 +5597,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5664,11 +5664,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5713,7 +5713,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5738,11 +5738,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 79; + DYLIB_CURRENT_VERSION = 80; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5768,7 +5768,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5792,7 +5792,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 79; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index e6093a218..cb88c3960 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 35 + 42 CoreDataStack.xcscheme_^#shared#^_ orderHint - 38 + 43 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 36 + 44 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 41 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 26ba58d55..b305c8156 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -216,15 +216,6 @@ "revision": "dad97167bf1be16aeecd109130900995dd01c515", "version": "2.6.0" } - }, - { - "package": "UITextView+Placeholder", - "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder", - "state": { - "branch": null, - "revision": "20f513ded04a040cdf5467f0891849b1763ede3b", - "version": "1.4.1" - } } ] }, diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 43ae9e6d0..1c89f12a2 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 79 + 80 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 714ba3106..062a4bf1a 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 7f509a3fe..cf50d3ac4 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 7f509a3fe..cf50d3ac4 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index b5ee7a305..fb52c9dce 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 5643d878f..8870b320d 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 79 + 80 NSExtension NSExtensionAttributes From c6fc5cc09dd48f43017cad33f00c1dee87af51df Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 14:58:09 +0800 Subject: [PATCH 293/392] feat: update to new UI tint style --- .../Scene/Compose/View/ComposeToolbarView.swift | 2 +- .../HashtagTimelineViewController.swift | 2 +- .../HomeTimeline/HomeTimelineViewController.swift | 4 ++-- Mastodon/Scene/Report/ReportViewController.swift | 2 +- .../View/SidebarListCollectionViewCell.swift | 10 ++-------- .../Sidebar/View/SidebarListContentView.swift | 15 ++++++++------- .../Scene/Share/View/Content/StatusView.swift | 2 +- .../Scene/Share/View/Content/ThreadMetaView.swift | 8 ++++---- .../ThreadReplyLoaderTableViewCell.swift | 2 +- .../TimelineLoaderTableViewCell.swift | 4 ++-- Mastodon/Service/ThemeService/MastodonTheme.swift | 2 +- Mastodon/Service/ThemeService/SystemTheme.swift | 2 +- .../ThemeService/ThemeService+Appearance.swift | 6 +++--- Mastodon/Service/ThemeService/ThemeService.swift | 2 ++ Mastodon/Supporting Files/SceneDelegate.swift | 2 +- .../Scene/View/ComposeToolbarView.swift | 2 +- 16 files changed, 32 insertions(+), 35 deletions(-) diff --git a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift index 373ce1a15..6b06973a2 100644 --- a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift +++ b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift @@ -262,7 +262,7 @@ extension ComposeToolbarView { } private static func configureToolbarButtonAppearance(button: UIButton) { - button.tintColor = Asset.Colors.brandBlue.color + button.tintColor = ThemeService.tintColor button.setBackgroundImage(.placeholder(size: ComposeToolbarView.toolbarButtonSize, color: .systemFill), for: .highlighted) button.layer.masksToBounds = true button.layer.cornerRadius = 5 diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift index 9801d701a..72f084fad 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift @@ -24,7 +24,7 @@ class HashtagTimelineViewController: UIViewController, NeedsDependency, MediaPre let composeBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() - barButtonItem.tintColor = Asset.Colors.brandBlue.color + // barButtonItem.tintColor = Asset.Colors.brandBlue.color barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate) return barButtonItem }() diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 55bf544ca..6b5476885 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -46,14 +46,14 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media let settingBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() - barButtonItem.tintColor = Asset.Colors.brandBlue.color + barButtonItem.tintColor = ThemeService.tintColor barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate) return barButtonItem }() let composeBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() - barButtonItem.tintColor = Asset.Colors.brandBlue.color + barButtonItem.tintColor = ThemeService.tintColor barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate) return barButtonItem }() diff --git a/Mastodon/Scene/Report/ReportViewController.swift b/Mastodon/Scene/Report/ReportViewController.swift index efaa533e1..6a7161c91 100644 --- a/Mastodon/Scene/Report/ReportViewController.swift +++ b/Mastodon/Scene/Report/ReportViewController.swift @@ -251,7 +251,7 @@ class ReportViewController: UIViewController, NeedsDependency { = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.cancel, target: self, action: #selector(doneButtonDidClick)) - navigationItem.rightBarButtonItem?.tintColor = Asset.Colors.brandBlue.color + navigationItem.rightBarButtonItem?.tintColor = ThemeService.tintColor // fetch old mastodon user let beReportedUser: MastodonUser? = { diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift index dc71eadfb..998d3f9e2 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListCollectionViewCell.swift @@ -51,15 +51,9 @@ extension SidebarListCollectionViewCell { newConfiguration.item = item contentConfiguration = newConfiguration + // remove background var newBackgroundConfiguration = UIBackgroundConfiguration.listSidebarCell().updated(for: state) - // Customize the background color to use the tint color when the cell is highlighted or selected. - if state.isSelected || state.isHighlighted { - newBackgroundConfiguration.backgroundColor = Asset.Colors.brandBlue.color - } - if state.isHighlighted { - newBackgroundConfiguration.backgroundColorTransformer = .init { $0.withAlphaComponent(0.8) } - } - + newBackgroundConfiguration.backgroundColor = .clear backgroundConfiguration = newBackgroundConfiguration } } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift index dedd47b88..8c013efda 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -71,8 +71,6 @@ extension SidebarListContentView { imageView.contentMode = .scaleAspectFit avatarButton.contentMode = .scaleAspectFit - imageView.tintColor = Asset.Colors.brandBlue.color - avatarButton.tintColor = Asset.Colors.brandBlue.color } private func apply(configuration: ContentConfiguration) { @@ -84,8 +82,9 @@ extension SidebarListContentView { guard let item = configuration.item else { return } // configure state - imageView.tintColor = item.isSelected ? .white : Asset.Colors.brandBlue.color - avatarButton.tintColor = item.isSelected ? .white : Asset.Colors.brandBlue.color + let tintColor = item.isHighlighted ? ThemeService.tintColor.withAlphaComponent(0.5) : ThemeService.tintColor + imageView.tintColor = tintColor + avatarButton.tintColor = tintColor // configure model imageView.isHidden = item.imageURL != nil @@ -96,9 +95,6 @@ extension SidebarListContentView { placeholder: avatarButton.avatarImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink scaleToSize: nil ) - avatarButton.layer.masksToBounds = true - avatarButton.layer.cornerCurve = .continuous - avatarButton.layer.cornerRadius = 4 } } @@ -106,6 +102,7 @@ extension SidebarListContentView { struct Item: Hashable { // state var isSelected: Bool = false + var isHighlighted: Bool = false // model let title: String @@ -114,6 +111,7 @@ extension SidebarListContentView { static func == (lhs: SidebarListContentView.Item, rhs: SidebarListContentView.Item) -> Bool { return lhs.isSelected == rhs.isSelected + && lhs.isHighlighted == rhs.isHighlighted && lhs.title == rhs.title && lhs.image == rhs.image && lhs.imageURL == rhs.imageURL @@ -121,6 +119,7 @@ extension SidebarListContentView { func hash(into hasher: inout Hasher) { hasher.combine(isSelected) + hasher.combine(isHighlighted) hasher.combine(title) hasher.combine(image) imageURL.flatMap { hasher.combine($0) } @@ -143,9 +142,11 @@ extension SidebarListContentView { if let state = state as? UICellConfigurationState { updatedConfiguration.item?.isSelected = state.isHighlighted || state.isSelected + updatedConfiguration.item?.isHighlighted = state.isHighlighted } else { assertionFailure() updatedConfiguration.item?.isSelected = false + updatedConfiguration.item?.isHighlighted = false } return updatedConfiguration diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift index a2788f524..957764fa7 100644 --- a/Mastodon/Scene/Share/View/Content/StatusView.swift +++ b/Mastodon/Scene/Share/View/Content/StatusView.swift @@ -126,7 +126,7 @@ final class StatusView: UIView { let revealContentWarningButton: UIButton = { let button = HighlightDimmableButton() button.setImage(UIImage(systemName: "eye", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .medium)), for: .normal) - button.tintColor = Asset.Colors.brandBlue.color + // button.tintColor = Asset.Colors.brandBlue.color return button }() diff --git a/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift b/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift index 4bda525ae..c339654f5 100644 --- a/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift +++ b/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift @@ -23,8 +23,8 @@ final class ThreadMetaView: UIView { let button = UIButton() button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) button.setTitle("0 reblog", for: .normal) - button.setTitleColor(Asset.Colors.brandBlue.color, for: .normal) - button.setTitleColor(Asset.Colors.brandBlue.color.withAlphaComponent(0.5), for: .highlighted) + button.setTitleColor(ThemeService.tintColor, for: .normal) + button.setTitleColor(ThemeService.tintColor.withAlphaComponent(0.5), for: .highlighted) return button }() @@ -32,8 +32,8 @@ final class ThreadMetaView: UIView { let button = UIButton() button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) button.setTitle("0 favorite", for: .normal) - button.setTitleColor(Asset.Colors.brandBlue.color, for: .normal) - button.setTitleColor(Asset.Colors.brandBlue.color.withAlphaComponent(0.5), for: .highlighted) + button.setTitleColor(ThemeService.tintColor, for: .normal) + button.setTitleColor(ThemeService.tintColor.withAlphaComponent(0.5), for: .highlighted) return button }() diff --git a/Mastodon/Scene/Share/View/TableviewCell/ThreadReplyLoaderTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/ThreadReplyLoaderTableViewCell.swift index 5e5ac88d7..a819f301c 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/ThreadReplyLoaderTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/ThreadReplyLoaderTableViewCell.swift @@ -23,7 +23,7 @@ final class ThreadReplyLoaderTableViewCell: UITableViewCell { let loadMoreButton: UIButton = { let button = HighlightDimmableButton() button.titleLabel?.font = TimelineLoaderTableViewCell.labelFont - button.setTitleColor(Asset.Colors.brandBlue.color, for: .normal) + button.setTitleColor(ThemeService.tintColor, for: .normal) button.setTitle(L10n.Common.Controls.Timeline.Loader.showMoreReplies, for: .normal) return button }() diff --git a/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift index 8c329d31e..da0b80fb4 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift @@ -24,7 +24,7 @@ class TimelineLoaderTableViewCell: UITableViewCell { let loadMoreButton: UIButton = { let button = HighlightDimmableButton() button.titleLabel?.font = TimelineLoaderTableViewCell.labelFont - button.setTitleColor(Asset.Colors.brandBlue.color, for: .normal) + button.setTitleColor(ThemeService.tintColor, for: .normal) button.setTitle(L10n.Common.Controls.Timeline.Loader.loadMissingPosts, for: .normal) button.setTitle("", for: .disabled) return button @@ -68,7 +68,7 @@ class TimelineLoaderTableViewCell: UITableViewCell { func stopAnimating() { activityIndicatorView.stopAnimating() self.loadMoreButton.isEnabled = true - self.loadMoreLabel.textColor = Asset.Colors.brandBlue.color + self.loadMoreLabel.textColor = ThemeService.tintColor self.loadMoreLabel.text = "" } diff --git a/Mastodon/Service/ThemeService/MastodonTheme.swift b/Mastodon/Service/ThemeService/MastodonTheme.swift index 85b0d42db..1f0fd4e38 100644 --- a/Mastodon/Service/ThemeService/MastodonTheme.swift +++ b/Mastodon/Service/ThemeService/MastodonTheme.swift @@ -26,7 +26,7 @@ struct MastodonTheme: Theme { let sidebarBackgroundColor = Asset.Theme.Mastodon.sidebarBackground.color let tabBarBackgroundColor = Asset.Theme.Mastodon.tabBarBackground.color - let tabBarItemSelectedIconColor = Asset.Colors.brandBlue.color + let tabBarItemSelectedIconColor = ThemeService.tintColor let tabBarItemFocusedIconColor = Asset.Theme.Mastodon.tabBarItemInactiveIconColor.color let tabBarItemNormalIconColor = Asset.Theme.Mastodon.tabBarItemInactiveIconColor.color let tabBarItemDisabledIconColor = Asset.Theme.Mastodon.tabBarItemInactiveIconColor.color diff --git a/Mastodon/Service/ThemeService/SystemTheme.swift b/Mastodon/Service/ThemeService/SystemTheme.swift index 1ea923979..26673d57d 100644 --- a/Mastodon/Service/ThemeService/SystemTheme.swift +++ b/Mastodon/Service/ThemeService/SystemTheme.swift @@ -26,7 +26,7 @@ struct SystemTheme: Theme { let sidebarBackgroundColor = Asset.Theme.System.sidebarBackground.color let tabBarBackgroundColor = Asset.Theme.System.tabBarBackground.color - let tabBarItemSelectedIconColor = Asset.Colors.brandBlue.color + let tabBarItemSelectedIconColor = ThemeService.tintColor let tabBarItemFocusedIconColor = Asset.Theme.System.tabBarItemInactiveIconColor.color let tabBarItemNormalIconColor = Asset.Theme.System.tabBarItemInactiveIconColor.color let tabBarItemDisabledIconColor = Asset.Theme.System.tabBarItemInactiveIconColor.color diff --git a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift b/Mastodon/Service/ThemeService/ThemeService+Appearance.swift index cffa45c7a..896ed888e 100644 --- a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift +++ b/Mastodon/Service/ThemeService/ThemeService+Appearance.swift @@ -46,7 +46,7 @@ extension ThemeService { tabBarAppearance.compactInlineLayoutAppearance = tabBarItemAppearance tabBarAppearance.backgroundColor = theme.tabBarBackgroundColor - tabBarAppearance.selectionIndicatorTintColor = Asset.Colors.brandBlue.color + tabBarAppearance.selectionIndicatorTintColor = ThemeService.tintColor UITabBar.appearance().standardAppearance = tabBarAppearance if #available(iOS 15.0, *) { UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance @@ -61,9 +61,9 @@ extension ThemeService { UITableViewCell.appearance().selectionColor = theme.tableViewCellSelectionBackgroundColor // set search bar appearance - UISearchBar.appearance().tintColor = Asset.Colors.brandBlue.color + UISearchBar.appearance().tintColor = ThemeService.tintColor UISearchBar.appearance().barTintColor = theme.navigationBarBackgroundColor - let cancelButtonAttributes: [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor: Asset.Colors.brandBlue.color] + let cancelButtonAttributes: [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor: ThemeService.tintColor] UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes(cancelButtonAttributes, for: .normal) } } diff --git a/Mastodon/Service/ThemeService/ThemeService.swift b/Mastodon/Service/ThemeService/ThemeService.swift index 35d5b3491..e3bd7c4ab 100644 --- a/Mastodon/Service/ThemeService/ThemeService.swift +++ b/Mastodon/Service/ThemeService/ThemeService.swift @@ -10,6 +10,8 @@ import Combine // ref: https://zamzam.io/protocol-oriented-themes-for-ios-apps/ final class ThemeService { + + static let tintColor: UIColor = .label // MARK: - Singleton public static let shared = ThemeService() diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift index 6c5752c4c..4809fe5f9 100644 --- a/Mastodon/Supporting Files/SceneDelegate.swift +++ b/Mastodon/Supporting Files/SceneDelegate.swift @@ -37,7 +37,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { self.window = window // set tint color - window.tintColor = Asset.Colors.brandBlue.color + window.tintColor = UIColor.label ThemeService.shared.currentTheme .receive(on: RunLoop.main) diff --git a/ShareActionExtension/Scene/View/ComposeToolbarView.swift b/ShareActionExtension/Scene/View/ComposeToolbarView.swift index e6842c744..d88bb018c 100644 --- a/ShareActionExtension/Scene/View/ComposeToolbarView.swift +++ b/ShareActionExtension/Scene/View/ComposeToolbarView.swift @@ -190,7 +190,7 @@ extension ComposeToolbarView { extension ComposeToolbarView { private static func configureToolbarButtonAppearance(button: UIButton) { - button.tintColor = Asset.Colors.brandBlue.color + button.tintColor = ThemeService.tintColor button.setBackgroundImage(.placeholder(size: ComposeToolbarView.toolbarButtonSize, color: .systemFill), for: .highlighted) button.layer.masksToBounds = true button.layer.cornerRadius = 5 From 0ec20c6c88784028549829171dec410823f693ad Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 14:58:59 +0800 Subject: [PATCH 294/392] feat: add split view layout update handler --- .../Root/ContentSplitViewController.swift | 2 +- .../Scene/Root/RootSplitViewController.swift | 133 +++++++----------- 2 files changed, 54 insertions(+), 81 deletions(-) diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 42ce3afc3..6f5e294cd 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -47,7 +47,7 @@ extension ContentSplitViewController { navigationController?.setNavigationBarHidden(true, animated: false) addChild(sidebarViewController) - sidebarViewController.view.translatesAutoresizingMaskIntoConstraints = false + sidebarViewController.view.translatesAutoresizingMaskIntoConstraints = false view.addSubview(sidebarViewController.view) sidebarViewController.didMove(toParent: self) NSLayoutConstraint.activate([ diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 4f818ea9d..fc1e7a4f7 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -26,6 +26,8 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { return contentSplitViewController }() + lazy var compactMainTabBarViewController = MainTabBarController(context: context, coordinator: coordinator) + init(context: AppContext, coordinator: SceneCoordinator) { self.context = context self.coordinator = coordinator @@ -48,6 +50,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { setViewController(UIViewController(), for: .primary) setViewController(contentSplitViewController, for: .secondary) + setViewController(compactMainTabBarViewController, for: .compact) contentSplitViewController.sidebarViewController.view.layer.zPosition = 100 contentSplitViewController.mainTabBarController.view.layer.zPosition = 90 @@ -108,85 +111,55 @@ extension RootSplitViewController { // MARK: - UISplitViewControllerDelegate extension RootSplitViewController: UISplitViewControllerDelegate { -// // .regular to .compact -// // move navigation stack from .supplementary & .secondary to .compact -// func splitViewController( -// _ svc: UISplitViewController, -// topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column -// ) -> UISplitViewController.Column { -// switch proposedTopColumn { -// case .compact: -// guard let index = MainTabBarController.Tab.allCases.firstIndex(of: currentSupplementaryTab) else { -// assertionFailure() -// break -// } -// mainTabBarController.selectedIndex = index -// mainTabBarController.currentTab.value = currentSupplementaryTab -// -// guard let navigationController = mainTabBarController.selectedViewController as? UINavigationController else { break } -// navigationController.popToRootViewController(animated: false) -// var viewControllers = navigationController.viewControllers // init navigation stack with topMost -// -// if let supplementaryNavigationController = viewController(for: .supplementary) as? UINavigationController { -// // append supplementary -// viewControllers.append(contentsOf: supplementaryNavigationController.popToRootViewController(animated: true) ?? []) -// } -// if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { -// // append secondary -// viewControllers.append(contentsOf: secondaryNavigationController.popToRootViewController(animated: true) ?? []) -// } -// // set navigation stack -// navigationController.setViewControllers(viewControllers, animated: false) -// -// default: -// assertionFailure() -// } -// -// return proposedTopColumn -// } -// -// // .compact to .regular -// // restore navigation stack to .supplementary & .secondary -// func splitViewController( -// _ svc: UISplitViewController, -// displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode -// ) -> UISplitViewController.DisplayMode { -// let compactNavigationController = mainTabBarController.selectedViewController as? UINavigationController -// -// if let topMost = compactNavigationController?.topMost, -// topMost is AccountListViewController { -// topMost.dismiss(animated: false, completion: nil) -// } -// -// let viewControllers = compactNavigationController?.popToRootViewController(animated: true) ?? [] -// -// var supplementaryViewControllers: [UIViewController] = [] -// var secondaryViewControllers: [UIViewController] = [] -// for viewController in viewControllers { -// if coordinator.secondaryStackHashValues.contains(viewController.hashValue) { -// secondaryViewControllers.append(viewController) -// } else { -// supplementaryViewControllers.append(viewController) -// } -// -// } -// if let supplementary = viewController(for: .supplementary) as? UINavigationController { -// supplementary.setViewControllers(supplementary.viewControllers + supplementaryViewControllers, animated: false) -// } -// if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { -// secondaryNavigationController.setViewControllers(secondaryNavigationController.viewControllers + secondaryViewControllers, animated: false) -// } -// -// return proposedDisplayMode -// } + private static func transform(from: UITabBarController, to: UITabBarController) { + let sourceNavigationControllers = from.viewControllers ?? [] + let targetNavigationControllers = to.viewControllers ?? [] + + for (source, target) in zip(sourceNavigationControllers, targetNavigationControllers) { + guard let source = source as? UINavigationController, + let target = target as? UINavigationController + else { continue } + let viewControllers = source.popToRootViewController(animated: false) ?? [] + _ = target.popToRootViewController(animated: false) + target.viewControllers.append(contentsOf: viewControllers) + } + + to.selectedIndex = from.selectedIndex + } + + // .regular to .compact + func splitViewController( + _ svc: UISplitViewController, + topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column + ) -> UISplitViewController.Column { + switch proposedTopColumn { + case .compact: + RootSplitViewController.transform(from: contentSplitViewController.mainTabBarController, to: compactMainTabBarViewController) + compactMainTabBarViewController.currentTab.value = contentSplitViewController.currentSupplementaryTab + + default: + assertionFailure() + } + + return proposedTopColumn + } + + // .compact to .regular + func splitViewController( + _ svc: UISplitViewController, + displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode + ) -> UISplitViewController.DisplayMode { + let compactNavigationController = compactMainTabBarViewController.selectedViewController as? UINavigationController + + if let topMost = compactNavigationController?.topMost, + topMost is AccountListViewController { + topMost.dismiss(animated: false, completion: nil) + } + + RootSplitViewController.transform(from: compactMainTabBarViewController, to: contentSplitViewController.mainTabBarController) + contentSplitViewController.currentSupplementaryTab = compactMainTabBarViewController.currentTab.value + + return proposedDisplayMode + } } - -//extension UIView { -// func setNeedsLayoutForSubviews() { -// self.subviews.forEach({ -// $0.setNeedsLayout() -// $0.setNeedsLayoutForSubviews() -// }) -// } -//} From bcddcf226b8e6527e30cd2b45600c3b89a4f36fc Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 17:26:26 +0800 Subject: [PATCH 295/392] feat: add account switcher for iPad sidebar --- .../xcschemes/xcschememanagement.plist | 8 ++-- Mastodon/Coordinator/SceneCoordinator.swift | 6 ++- .../Cell/AddAccountTableViewCell.swift | 26 ++++++++++- .../Root/ContentSplitViewController.swift | 18 +++++++- .../Scene/Root/RootSplitViewController.swift | 33 +++++++++++--- .../Root/Sidebar/SidebarViewController.swift | 44 ++++++++++--------- .../Sidebar/View/SidebarListContentView.swift | 4 ++ 7 files changed, 106 insertions(+), 33 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index cb88c3960..879d91053 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 42 + 35 CoreDataStack.xcscheme_^#shared#^_ orderHint - 43 + 36 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 44 + 37 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 41 + 38 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 23c2a6f44..696b211bc 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -139,6 +139,7 @@ extension SceneCoordinator { case show // push case showDetail // replace case modal(animated: Bool, completion: (() -> Void)? = nil) + case popover(sourceView: UIView) case panModal case custom(transitioningDelegate: UIViewControllerTransitioningDelegate) case customPush @@ -326,7 +327,10 @@ extension SceneCoordinator { panModalPresentable.transitioningDelegate = PanModalPresentationDelegate.default presentingViewController.present(panModalPresentable, animated: true, completion: nil) //presentingViewController.presentPanModal(panModalPresentable) - + case .popover(let sourceView): + viewController.modalPresentationStyle = .popover + viewController.popoverPresentationController?.sourceView = sourceView + (splitViewController ?? presentingViewController)?.present(viewController, animated: true, completion: nil) case .custom(let transitioningDelegate): viewController.modalPresentationStyle = .custom viewController.transitioningDelegate = transitioningDelegate diff --git a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift index 743ad1dc2..722896641 100644 --- a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift @@ -9,7 +9,7 @@ import UIKit import MetaTextKit final class AddAccountTableViewCell: UITableViewCell { - + let iconImageView: UIImageView = { let image = UIImage(systemName: "plus.circle.fill")! let imageView = UIImageView(image: image) @@ -51,6 +51,28 @@ extension AddAccountTableViewCell { ]) iconImageView.setContentHuggingPriority(.defaultLow, for: .horizontal) iconImageView.setContentHuggingPriority(.defaultLow, for: .vertical) + + // layout the same placeholder UI from `AccountListTableViewCell` + let placeholderLabelContainerStackView = UIStackView() + placeholderLabelContainerStackView.axis = .vertical + placeholderLabelContainerStackView.distribution = .equalCentering + placeholderLabelContainerStackView.spacing = 2 + placeholderLabelContainerStackView.distribution = .fillProportionally + placeholderLabelContainerStackView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(placeholderLabelContainerStackView) + NSLayoutConstraint.activate([ + placeholderLabelContainerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), + placeholderLabelContainerStackView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 10), + contentView.bottomAnchor.constraint(equalTo: placeholderLabelContainerStackView.bottomAnchor, constant: 10), + iconImageView.heightAnchor.constraint(equalTo: placeholderLabelContainerStackView.heightAnchor, multiplier: 0.8).priority(.required - 10), + ]) + let _nameLabel = MetaLabel(style: .accountListName) + _nameLabel.configure(content: PlaintextMetaContent(string: " ")) + let _usernameLabel = MetaLabel(style: .accountListUsername) + _usernameLabel.configure(content: PlaintextMetaContent(string: " ")) + placeholderLabelContainerStackView.addArrangedSubview(_nameLabel) + placeholderLabelContainerStackView.addArrangedSubview(_usernameLabel) + placeholderLabelContainerStackView.isHidden = true titleLabel.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(titleLabel) @@ -58,7 +80,7 @@ extension AddAccountTableViewCell { titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 15), titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 10), contentView.bottomAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15), - iconImageView.heightAnchor.constraint(equalTo: titleLabel.heightAnchor, multiplier: 1.0).priority(.required - 10), + // iconImageView.heightAnchor.constraint(equalTo: titleLabel.heightAnchor, multiplier: 1.0).priority(.required - 10), titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), ]) diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 6f5e294cd..6e595f2ee 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -63,7 +63,7 @@ extension ContentSplitViewController { sidebarViewController.didMove(toParent: self) NSLayoutConstraint.activate([ mainTabBarController.view.topAnchor.constraint(equalTo: view.topAnchor), - mainTabBarController.view.leadingAnchor.constraint(equalTo: sidebarViewController.view.trailingAnchor), + mainTabBarController.view.leadingAnchor.constraint(equalTo: sidebarViewController.view.trailingAnchor, constant: UIView.separatorLineHeight(of: view)), mainTabBarController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), mainTabBarController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) @@ -87,6 +87,22 @@ extension ContentSplitViewController: SidebarViewControllerDelegate { assertionFailure() return } + let previousTab = currentSupplementaryTab currentSupplementaryTab = tab + + if previousTab == tab, + let navigationController = mainTabBarController.selectedViewController as? UINavigationController + { + navigationController.popToRootViewController(animated: true) + } } + + func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView) { + guard case let .tab(tab) = item, tab == .me else { return } + + let accountListViewController = coordinator.present(scene: .accountList, from: nil, transition: .popover(sourceView: sourceView)) as! AccountListViewController + accountListViewController.dragIndicatorView.barView.isHidden = true + accountListViewController.preferredContentSize = CGSize(width: 300, height: 320) + } + } diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index fc1e7a4f7..22354751d 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -26,8 +26,17 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { return contentSplitViewController }() + private(set) lazy var searchViewController: SearchViewController = { + let searchViewController = SearchViewController() + searchViewController.context = context + searchViewController.coordinator = coordinator + return searchViewController + }() + lazy var compactMainTabBarViewController = MainTabBarController(context: context, coordinator: coordinator) + let separatorLine = UIView.separatorLine + init(context: AppContext, coordinator: SceneCoordinator) { self.context = context self.coordinator = coordinator @@ -48,13 +57,9 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { // Fallback on earlier versions } - setViewController(UIViewController(), for: .primary) + setViewController(searchViewController, for: .primary) setViewController(contentSplitViewController, for: .secondary) setViewController(compactMainTabBarViewController, for: .compact) - - contentSplitViewController.sidebarViewController.view.layer.zPosition = 100 - contentSplitViewController.mainTabBarController.view.layer.zPosition = 90 - view.layer.zPosition = 80 } required init?(coder: NSCoder) { @@ -80,6 +85,15 @@ extension RootSplitViewController { self.updateBehavior(size: self.view.frame.size) } .store(in: &disposeBag) + + setupBackground(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupBackground(theme: theme) + } + .store(in: &disposeBag) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { @@ -108,6 +122,15 @@ extension RootSplitViewController { } +extension RootSplitViewController { + + private func setupBackground(theme: Theme) { + // this set column separator line color + view.backgroundColor = theme.separator + } + +} + // MARK: - UISplitViewControllerDelegate extension RootSplitViewController: UISplitViewControllerDelegate { diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 060091922..7958c5080 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -12,10 +12,13 @@ import CoreDataStack protocol SidebarViewControllerDelegate: AnyObject { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) + func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView) } final class SidebarViewController: UIViewController, NeedsDependency { + let logger = Logger(subsystem: "SidebarViewController", category: "ViewController") + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -127,6 +130,10 @@ extension SidebarViewController { self.collectionView.contentInset.bottom = height } .store(in: &observations) + + let sidebarLongPressGestureRecognizer = UILongPressGestureRecognizer() + sidebarLongPressGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarLongPressGestureRecognizerHandler(_:))) + collectionView.addGestureRecognizer(sidebarLongPressGestureRecognizer) } private func setupBackground(theme: Theme) { @@ -148,6 +155,23 @@ extension SidebarViewController { } +extension SidebarViewController { + @objc private func sidebarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) { + guard sender.state == .began 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, didLongPressItem: item, sourceView: cell) + } + +} + // MARK: - UICollectionViewDelegate extension SidebarViewController: UICollectionViewDelegate { @@ -179,25 +203,5 @@ extension SidebarViewController: UICollectionViewDelegate { default: assertionFailure() } -// switch item { -// case .tab(let tab): -// delegate?.sidebarViewController(self, didSelectTab: tab) -// case .searchHistory(let viewModel): -// delegate?.sidebarViewController(self, didSelectSearchHistory: viewModel) -// case .header: -// break -// case .account(let viewModel): -// assert(Thread.isMainThread) -// let authentication = context.managedObjectContext.object(with: viewModel.authenticationObjectID) as! MastodonAuthentication -// context.authenticationService.activeMastodonUser(domain: authentication.domain, userID: authentication.userID) -// .receive(on: DispatchQueue.main) -// .sink { [weak self] result in -// guard let self = self else { return } -// self.coordinator.setup() -// } -// .store(in: &disposeBag) -// case .addAccount: -// coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil)) -// } } } diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift index 8c013efda..d85d3a8be 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -18,6 +18,7 @@ final class SidebarListContentView: UIView, UIContentView { let avatarButton: CircleAvatarButton = { let button = CircleAvatarButton() button.borderWidth = 2 + button.borderColor = UIColor.label.cgColor return button }() @@ -71,6 +72,9 @@ extension SidebarListContentView { imageView.contentMode = .scaleAspectFit avatarButton.contentMode = .scaleAspectFit + + imageView.isUserInteractionEnabled = false + avatarButton.isUserInteractionEnabled = false } private func apply(configuration: ContentConfiguration) { From e8e655ff5c7225657ac53e96b26f45199dca297b Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 18:08:47 +0800 Subject: [PATCH 296/392] feat: add accessibility supports for iPad sidebar --- Localization/app.json | 1 + Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Localization/app.json b/Localization/app.json index 3ec77cf10..3d0e36d03 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 6dd46d08c..83abf4e6b 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -84,6 +84,8 @@ extension SidebarViewModel { imageURL: imageURL ) cell.setNeedsUpdateConfiguration() + cell.isAccessibilityElement = true + cell.accessibilityLabel = item.title switch item { case .notification: @@ -103,6 +105,10 @@ extension SidebarViewModel { cell._contentView?.imageView.image = image } .store(in: &cell.disposeBag) + case .me: + guard let authentication = self.context.authenticationService.activeMastodonAuthentication.value else { break } + let currentUserDisplayName = authentication.user.displayNameWithFallback ?? "no user" + cell.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName) default: break } @@ -112,6 +118,8 @@ extension SidebarViewModel { guard let self = self else { return } cell.item = item cell.setNeedsUpdateConfiguration() + cell.isAccessibilityElement = true + cell.accessibilityLabel = item.title } // header @@ -132,7 +140,7 @@ extension SidebarViewModel { return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) case .compose: let item = SidebarListContentView.Item( - title: "Compose", // FIXME: + title: "Compose", // TODO: update i18n image: UIImage(systemName: "square.and.pencil")!, imageURL: nil ) From bb79e574124fa772859a5362c5eae0def750b189 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 18:14:51 +0800 Subject: [PATCH 297/392] chore: set Home page navigation item hidden on iPad --- Mastodon/Scene/Root/ContentSplitViewController.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 6e595f2ee..577f8d6a4 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -31,6 +31,10 @@ final class ContentSplitViewController: UIViewController, NeedsDependency { @Published var currentSupplementaryTab: MainTabBarController.Tab = .home private(set) lazy var mainTabBarController: MainTabBarController = { let mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) + if let homeTimelineViewController = mainTabBarController.viewController(of: HomeTimelineViewController.self) { + homeTimelineViewController.viewModel.displayComposeBarButtonItem.value = false + homeTimelineViewController.viewModel.displaySettingBarButtonItem.value = false + } return mainTabBarController }() From 2f0b321fd9023a6806d1ce5f3953e30a0489ad57 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 18:35:02 +0800 Subject: [PATCH 298/392] chore: update tab bar inactive color --- .../Contents.json | 12 ++++++------ .../Contents.json | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/tab.bar.item.inactive.icon.color.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/tab.bar.item.inactive.icon.color.colorset/Contents.json index 1accfacdf..bfc2a11b2 100644 --- a/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/tab.bar.item.inactive.icon.color.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/tab.bar.item.inactive.icon.color.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.549", - "green" : "0.510", - "red" : "0.431" + "blue" : "0x99", + "green" : "0x99", + "red" : "0x99" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "200", - "green" : "174", - "red" : "155" + "blue" : "0x99", + "green" : "0x99", + "red" : "0x99" } }, "idiom" : "universal" diff --git a/Mastodon/Resources/Assets.xcassets/Theme/system/tab.bar.item.inactive.icon.color.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/system/tab.bar.item.inactive.icon.color.colorset/Contents.json index ece9000aa..bfc2a11b2 100644 --- a/Mastodon/Resources/Assets.xcassets/Theme/system/tab.bar.item.inactive.icon.color.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Theme/system/tab.bar.item.inactive.icon.color.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.549", - "green" : "0.510", - "red" : "0.431" + "blue" : "0x99", + "green" : "0x99", + "red" : "0x99" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "140", - "green" : "130", - "red" : "110" + "blue" : "0x99", + "green" : "0x99", + "red" : "0x99" } }, "idiom" : "universal" From e669d17d4922452dfda65ce0ce5161f60fd42d72 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 18:56:58 +0800 Subject: [PATCH 299/392] feat: make notification coordinator works --- Mastodon/Coordinator/SceneCoordinator.swift | 94 +++++++++---------- .../Header/ProfileHeaderViewController.swift | 23 +++-- .../Scene/Profile/ProfileViewController.swift | 3 + 3 files changed, 62 insertions(+), 58 deletions(-) diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 696b211bc..10d6fb84f 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -90,45 +90,44 @@ final public class SceneCoordinator { // Delay in next run loop -// DispatchQueue.main.async { [weak self] in -// guard let self = self else { return } -// -// // Note: -// // show (push) on phone or pad (compact) -// // showDetail in .secondary in UISplitViewController on pad (expand) -// let from: UIViewController? = { -// if let splitViewController = self.splitViewController { -// if splitViewController.mainTabBarController.topMost?.view.window != nil { -// // compact -// return splitViewController.mainTabBarController.topMost -// } else { -// // expand -// return splitViewController.viewController(for: .supplementary) -// } -// } else { -// return self.tabBarController.topMost -// } -// }() -// -// // show notification related content -// guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return } -// let notificationID = String(pushNotification.notificationID) -// -// switch type { -// case .follow: -// let profileViewModel = RemoteProfileViewModel(context: appContext, notificationID: notificationID) -// self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show) -// case .followRequest: -// // do nothing -// break -// case .mention, .reblog, .favourite, .poll, .status: -// let threadViewModel = RemoteThreadViewModel(context: appContext, notificationID: notificationID) -// self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show) -// case ._other: -// assertionFailure() -// break -// } -// } // end DispatchQueue.main.async + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + // Note: + // show (push) on phone and pad + let from: UIViewController? = { + if let splitViewController = self.splitViewController { + if splitViewController.compactMainTabBarViewController.topMost?.view.window != nil { + // compact + return splitViewController.compactMainTabBarViewController.topMost + } else { + // expand + return splitViewController.contentSplitViewController.mainTabBarController.topMost + } + } else { + return self.tabBarController.topMost + } + }() + + // show notification related content + guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return } + let notificationID = String(pushNotification.notificationID) + + switch type { + case .follow: + let profileViewModel = RemoteProfileViewModel(context: appContext, notificationID: notificationID) + self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show) + case .followRequest: + // do nothing + break + case .mention, .reblog, .favourite, .poll, .status: + let threadViewModel = RemoteThreadViewModel(context: appContext, notificationID: notificationID) + self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show) + case ._other: + assertionFailure() + break + } + } // end DispatchQueue.main.async } .store(in: &disposeBag) } @@ -283,18 +282,6 @@ extension SceneCoordinator { switch transition { case .show: -// if let splitViewController = splitViewController, !splitViewController.isCollapsed, -// let supplementaryViewController = splitViewController.viewController(for: .supplementary) as? UINavigationController, -// (supplementaryViewController === presentingViewController || supplementaryViewController.viewControllers.contains(presentingViewController)) || -// (presentingViewController is UserTimelineViewController && presentingViewController.view.isDescendant(of: supplementaryViewController.view)) -// { -// fallthrough -// } else { -// if secondaryStackHashValues.contains(presentingViewController.hashValue) { -// secondaryStackHashValues.insert(viewController.hashValue) -// } -// presentingViewController.show(viewController, sender: sender) -// } presentingViewController.show(viewController, sender: sender) case .showDetail: secondaryStackHashValues.insert(viewController.hashValue) @@ -362,6 +349,11 @@ extension SceneCoordinator { } func switchToTabBar(tab: MainTabBarController.Tab) { + splitViewController?.contentSplitViewController.currentSupplementaryTab = tab + + splitViewController?.compactMainTabBarViewController.selectedIndex = tab.rawValue + splitViewController?.compactMainTabBarViewController.currentTab.value = tab + tabBarController.selectedIndex = tab.rawValue tabBarController.currentTab.value = tab } diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift index 716b62307..34716dde5 100644 --- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift +++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift @@ -44,10 +44,11 @@ final class ProfileHeaderViewController: UIViewController { let profileHeaderView = ProfileHeaderView() let pageSegmentedControl: UISegmentedControl = { - let segmenetedControl = UISegmentedControl(items: ["A", "B"]) - segmenetedControl.selectedSegmentIndex = 0 - return segmenetedControl + let segmentedControl = UISegmentedControl(items: ["A", "B"]) + segmentedControl.selectedSegmentIndex = 0 + return segmentedControl }() + var pageSegmentedControlLeadingLayoutConstraint: NSLayoutConstraint! private var isBannerPinned = false private var bottomShadowAlpha: CGFloat = 0.0 @@ -118,9 +119,10 @@ extension ProfileHeaderViewController { pageSegmentedControl.translatesAutoresizingMaskIntoConstraints = false view.addSubview(pageSegmentedControl) + pageSegmentedControlLeadingLayoutConstraint = pageSegmentedControl.leadingAnchor.constraint(equalTo: view.leadingAnchor) NSLayoutConstraint.activate([ pageSegmentedControl.topAnchor.constraint(equalTo: profileHeaderView.bottomAnchor, constant: ProfileHeaderViewController.segmentedControlMarginHeight), - pageSegmentedControl.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor), + pageSegmentedControlLeadingLayoutConstraint, // Fix iPad layout issue pageSegmentedControl.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor), view.bottomAnchor.constraint(equalTo: pageSegmentedControl.bottomAnchor, constant: ProfileHeaderViewController.segmentedControlMarginHeight), pageSegmentedControl.heightAnchor.constraint(equalToConstant: ProfileHeaderViewController.segmentedControlHeight).priority(.defaultHigh), @@ -133,10 +135,10 @@ extension ProfileHeaderViewController { viewModel.isTitleViewContentOffsetSet.eraseToAnyPublisher() ) .receive(on: DispatchQueue.main) - .sink { [weak self] viewDidAppear, isTitleViewContentOffsetDidSetted in + .sink { [weak self] viewDidAppear, isTitleViewContentOffsetDidSet in guard let self = self else { return } - self.titleView.titleLabel.alpha = viewDidAppear && isTitleViewContentOffsetDidSetted ? 1 : 0 - self.titleView.subtitleLabel.alpha = viewDidAppear && isTitleViewContentOffsetDidSetted ? 1 : 0 + self.titleView.titleLabel.alpha = viewDidAppear && isTitleViewContentOffsetDidSet ? 1 : 0 + self.titleView.subtitleLabel.alpha = viewDidAppear && isTitleViewContentOffsetDidSet ? 1 : 0 } .store(in: &disposeBag) @@ -283,6 +285,13 @@ extension ProfileHeaderViewController { setupBottomShadow() } + override func viewLayoutMarginsDidChange() { + super.viewLayoutMarginsDidChange() + + let margin = view.frame.maxX - view.readableContentGuide.layoutFrame.maxX + pageSegmentedControlLeadingLayoutConstraint.constant = margin + } + } extension ProfileHeaderViewController { diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 434836ab4..b864fc94c 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -517,6 +517,7 @@ extension ProfileViewController { .assign(to: \.value, on: profileHeaderViewController.viewModel.displayProfileInfo.note) .store(in: &disposeBag) viewModel.statusesCount + .receive(on: DispatchQueue.main) .sink { [weak self] count in guard let self = self else { return } let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" @@ -526,6 +527,7 @@ extension ProfileViewController { } .store(in: &disposeBag) viewModel.followingCount + .receive(on: DispatchQueue.main) .sink { [weak self] count in guard let self = self else { return } let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" @@ -535,6 +537,7 @@ extension ProfileViewController { } .store(in: &disposeBag) viewModel.followersCount + .receive(on: DispatchQueue.main) .sink { [weak self] count in guard let self = self else { return } let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" From 9e2566e2a7e8c172c187f0e8b049827ddcef1dc3 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 19:00:23 +0800 Subject: [PATCH 300/392] chore: update i18n resources --- .../Resources/ar.lproj/Localizable.strings | 8 ++--- .../ca.lproj/Localizable.stringsdict | 28 ++++++++--------- .../Resources/de.lproj/Localizable.strings | 4 +-- .../Resources/gd-GB.lproj/Localizable.strings | 12 ++++---- .../gd-GB.lproj/Localizable.stringsdict | 8 ++--- .../Resources/ja.lproj/Localizable.strings | 9 +++--- .../ja.lproj/Localizable.stringsdict | 12 ++++---- MastodonIntent/ar.lproj/Intents.strings | 30 +++++++++---------- 8 files changed, 55 insertions(+), 56 deletions(-) diff --git a/Mastodon/Resources/ar.lproj/Localizable.strings b/Mastodon/Resources/ar.lproj/Localizable.strings index 98d8c09cb..5950546a9 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.strings +++ b/Mastodon/Resources/ar.lproj/Localizable.strings @@ -9,7 +9,7 @@ "Common.Alerts.DiscardPostContent.Message" = "Confirm to discard composed post content."; "Common.Alerts.DiscardPostContent.Title" = "تجاهل المسودة"; "Common.Alerts.EditProfileFailure.Message" = "لا يمكن تعديل الملف الشخصي. يُرجى المحاولة مرة أُخرى."; -"Common.Alerts.EditProfileFailure.Title" = "Edit Profile Error"; +"Common.Alerts.EditProfileFailure.Title" = "خطأ في تَحرير الملف الشخصي"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images."; "Common.Alerts.PublishPostFailure.Message" = "Failed to publish the post. @@ -275,7 +275,7 @@ uploaded to Mastodon."; "Scene.Search.Searching.Segment.People" = "الأشخاص"; "Scene.Search.Searching.Segment.Posts" = "المنشورات"; "Scene.Search.Title" = "بحث"; -"Scene.ServerPicker.Button.Category.Academia" = "academia"; +"Scene.ServerPicker.Button.Category.Academia" = "أكاديمي"; "Scene.ServerPicker.Button.Category.Activism" = "للنشطاء"; "Scene.ServerPicker.Button.Category.All" = "الكل"; "Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "الفئة: الكل"; @@ -298,8 +298,8 @@ uploaded to Mastodon."; "Scene.ServerPicker.Label.Category" = "الفئة"; "Scene.ServerPicker.Label.Language" = "اللغة"; "Scene.ServerPicker.Label.Users" = "مستخدمون·ات"; -"Scene.ServerPicker.Title" = "Pick a server, -any server."; +"Scene.ServerPicker.Title" = "اِختر خادِم، +أي خادِم."; "Scene.ServerRules.Button.Confirm" = "انا أوافق"; "Scene.ServerRules.PrivacyPolicy" = "سياسة الخصوصية"; "Scene.ServerRules.Prompt" = "إن اخترت المواصلة، فإنك تخضع لشروط الخدمة وسياسة الخصوصية لـ %@."; diff --git a/Mastodon/Resources/ca.lproj/Localizable.stringsdict b/Mastodon/Resources/ca.lproj/Localizable.stringsdict index cc7312938..140185bad 100644 --- a/Mastodon/Resources/ca.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ca.lproj/Localizable.stringsdict @@ -21,7 +21,7 @@ a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - El límit d’entrada supera a %#@character_count@ + El límit de la entrada supera a %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -37,7 +37,7 @@ a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - El límit d’entrada continua sent %#@character_count@ + El límit de la entrada continua sent %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -111,7 +111,7 @@ one 1 impuls other - %ld impuls + %ld impulsos plural.count.vote @@ -301,9 +301,9 @@ NSStringFormatValueTypeKey ld one - fa 1a + fa 1 any other - fa %ldy anys + fa %ld anys date.month.ago.abbr @@ -317,9 +317,9 @@ NSStringFormatValueTypeKey ld one - fa 1M + fa 1 mes other - fa %ldM mesos + fa %ld mesos date.day.ago.abbr @@ -333,9 +333,9 @@ NSStringFormatValueTypeKey ld one - fa 1d + fa 1 día other - fa %ldd dies + fa %ld dies date.hour.ago.abbr @@ -351,7 +351,7 @@ one fa 1h other - fa %ldh hores + fa %ld hores date.minute.ago.abbr @@ -365,9 +365,9 @@ NSStringFormatValueTypeKey ld one - fa 1m + fa 1 minut other - fa %ldm minuts + fa %ld minuts date.second.ago.abbr @@ -381,9 +381,9 @@ NSStringFormatValueTypeKey ld one - fa 1s + fa 1 segon other - fa %lds seg + fa %ld segons diff --git a/Mastodon/Resources/de.lproj/Localizable.strings b/Mastodon/Resources/de.lproj/Localizable.strings index 51028d7a8..2780723ed 100644 --- a/Mastodon/Resources/de.lproj/Localizable.strings +++ b/Mastodon/Resources/de.lproj/Localizable.strings @@ -135,7 +135,7 @@ Dein Profil sieht für diesen Benutzer auch so aus."; "Common.Controls.Timeline.Timestamp.Now" = "Gerade"; "Scene.AccountList.AddAccount" = "Konto hinzufügen"; "Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.TabBarHint" = "Aktuell ausgewähltes Profil: %@. Doppeltippen dann gedrückt halten, um den Kontoschalter anzuzeigen"; "Scene.Compose.Accessibility.AppendAttachment" = "Anhang hinzufügen"; "Scene.Compose.Accessibility.AppendPoll" = "Umfrage hinzufügen"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Benutzerdefinierter Emojiwähler"; @@ -341,5 +341,5 @@ beliebigen Server."; "Scene.Thread.Title" = "Beitrag von %@"; "Scene.Welcome.Slogan" = "Soziale Netzwerke wieder in deinen Händen."; "Scene.Wizard.AccessibilityHint" = "Doppeltippen, um diesen Assistenten zu schließen"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Wechsel zwischen mehreren Konten durch drücken der Profil-Schaltfläche."; "Scene.Wizard.NewInMastodon" = "Neu in Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/gd-GB.lproj/Localizable.strings b/Mastodon/Resources/gd-GB.lproj/Localizable.strings index f24bd24e9..6c01adb0a 100644 --- a/Mastodon/Resources/gd-GB.lproj/Localizable.strings +++ b/Mastodon/Resources/gd-GB.lproj/Localizable.strings @@ -133,9 +133,9 @@ Seo an coltas a th’ air a’ phròifil agad dhaibh-san."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "A’ luchdadh nam post a tha a dhìth…"; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Seall barrachd freagairtean"; "Common.Controls.Timeline.Timestamp.Now" = "An-dràsta"; -"Scene.AccountList.AddAccount" = "Add Account"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.AddAccount" = "Cuir cunntas ris"; +"Scene.AccountList.DismissAccountSwitcher" = "Leig seachad taghadh a’ chunntais"; +"Scene.AccountList.TabBarHint" = "A’ phròifil air a taghadh: %@. Thoir gnogag dhùbailte is cùm sìos a ghearradh leum gu cunntas eile"; "Scene.Compose.Accessibility.AppendAttachment" = "Cuir ceanglachan ris"; "Scene.Compose.Accessibility.AppendPoll" = "Cuir cunntas-bheachd ris"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Roghnaichear nan Emoji gnàthaichte"; @@ -340,6 +340,6 @@ thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.Thread.Title" = "Post le %@"; "Scene.Welcome.Slogan" = "A’ cur nan lìonraidhean sòisealta ’nad làmhan fhèin."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.AccessibilityHint" = "Thoir gnogag dhùbailte a’ leigeil seachad an draoidh seo"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Geàrr leum eadar iomadh cunntas le cumail sìos putan na pròifil."; +"Scene.Wizard.NewInMastodon" = "Na tha ùr ann am Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict b/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict index 41e592a5e..7a54f553e 100644 --- a/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/gd-GB.lproj/Localizable.stringsdict @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + %ld bhrath nach deach a leughadh two - %ld unread notification + %ld bhrath nach deach a leughadh few - %ld unread notification + %ld brathan nach deach a leughadh other - %ld unread notification + %ld brath nach deach a leughadh a11y.plural.count.input_limit_exceeds diff --git a/Mastodon/Resources/ja.lproj/Localizable.strings b/Mastodon/Resources/ja.lproj/Localizable.strings index e83278e34..beadccf22 100644 --- a/Mastodon/Resources/ja.lproj/Localizable.strings +++ b/Mastodon/Resources/ja.lproj/Localizable.strings @@ -129,7 +129,7 @@ "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "読込中..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "リプライをもっとみる"; "Common.Controls.Timeline.Timestamp.Now" = "今"; -"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.AddAccount" = "アカウントを追加"; "Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; "Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "アタッチメントの追加"; @@ -332,8 +332,7 @@ "Scene.SuggestionAccount.Title" = "フォローする人を探す"; "Scene.Thread.BackTitle" = "投稿"; "Scene.Thread.Title" = "%@の投稿"; -"Scene.Welcome.Slogan" = "Social networking -back in your hands."; +"Scene.Welcome.Slogan" = "ソーシャルネットワーキングを、あなたの手の中に."; "Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "プロフィールボタンを押して複数のアカウントを切り替えます。"; +"Scene.Wizard.NewInMastodon" = "Mastodon の新機能"; \ No newline at end of file diff --git a/Mastodon/Resources/ja.lproj/Localizable.stringsdict b/Mastodon/Resources/ja.lproj/Localizable.stringsdict index 0300d9dc3..c51a9a29d 100644 --- a/Mastodon/Resources/ja.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ja.lproj/Localizable.stringsdict @@ -13,7 +13,7 @@ NSStringFormatValueTypeKey ld other - %ld unread notification + %ld 件の未読通知 a11y.plural.count.input_limit_exceeds @@ -27,7 +27,7 @@ NSStringFormatValueTypeKey ld other - %ld characters + %ld 文字 a11y.plural.count.input_limit_remains @@ -41,7 +41,7 @@ NSStringFormatValueTypeKey ld other - %ld characters + %ld 文字 plural.count.metric_formatted.post @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld votes + %ld票 plural.count.voter @@ -195,7 +195,7 @@ NSStringFormatValueTypeKey ld other - %ld months left + %ldか月前 date.day.left @@ -279,7 +279,7 @@ NSStringFormatValueTypeKey ld other - %ldM ago + %ld分前 date.day.ago.abbr diff --git a/MastodonIntent/ar.lproj/Intents.strings b/MastodonIntent/ar.lproj/Intents.strings index bf3e77ed2..cde27dc97 100644 --- a/MastodonIntent/ar.lproj/Intents.strings +++ b/MastodonIntent/ar.lproj/Intents.strings @@ -1,22 +1,22 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "النَشر على ماستودون"; "751xkl" = "محتوى نصي"; "CsR7G2" = "انشر على ماستدون"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "ما المُحتوى المُراد نشره؟"; -"HdGikU" = "Posting failed"; +"HdGikU" = "فَشَلَ النشر"; "KDNTJ4" = "سبب الإخفاق"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "إرسال مَنشور يَحوي نص"; -"RxSqsb" = "Post"; +"RxSqsb" = "مَنشور"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "نَشر ${content} على ماستودون"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "مَنشور"; "ZS1XaK" = "${content}"; @@ -24,13 +24,13 @@ "Zo4jgJ" = "مدى ظهور المنشور"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "هُناك عدد ${count} خِيار مُطابق لِـ\"عام\"."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "هُناك عدد ${count} خِيار مُطابق لِـ\"المُتابِعُون فقط\"."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}، عام"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}، المُتابِعُون فقط"; "dUyuGg" = "النشر على ماستدون"; @@ -38,13 +38,13 @@ "ehFLjY" = "لمتابعيك فقط"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "فَشَلَ النشر، ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "تمَّ إرسال المنشور بِنجاح."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "للتأكيد، هل تَريد \"عام\"؟"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "للتأكيد، هل تُريد \"للمُتابِعين فقط\"؟"; "rM6dvp" = "عنوان URL"; From b4c240967f0bf04e68ae89997449c518c9f92328 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 19:29:58 +0800 Subject: [PATCH 301/392] feat: add Kurmanji (Kurdish) i18n strings from Crowdin --- .../Sources/StringsConvertor/main.swift | 1 + Mastodon.xcodeproj/project.pbxproj | 11 + .../xcschemes/xcschememanagement.plist | 6 +- .../Resources/ku-TR.lproj/InfoPlist.strings | 4 + .../Resources/ku-TR.lproj/Localizable.strings | 346 ++++++++++++++++ .../ku-TR.lproj/Localizable.stringsdict | 390 ++++++++++++++++++ MastodonIntent/ku-TR.lproj/Intents.strings | 51 +++ .../ku-TR.lproj/Intents.stringsdict | 54 +++ 8 files changed, 860 insertions(+), 3 deletions(-) create mode 100644 Mastodon/Resources/ku-TR.lproj/InfoPlist.strings create mode 100644 Mastodon/Resources/ku-TR.lproj/Localizable.strings create mode 100644 Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict create mode 100644 MastodonIntent/ku-TR.lproj/Intents.strings create mode 100644 MastodonIntent/ku-TR.lproj/Intents.stringsdict diff --git a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift index 124612e5c..6507986be 100644 --- a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift +++ b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift @@ -51,6 +51,7 @@ private func map(language: String) -> String? { case "fr_FR": return "fr" // French case "de_DE": return "de" // German case "ja_JP": return "ja" // Japanese + case "kmr_TR": return "ku-TR" // Kurmanji (Kurdish) case "ru_RU": return "ru" // Russian case "gd_GB": return "gd-GB" // Scottish Gaelic case "es_ES": return "es" // Spanish diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index f7b373f59..cc98e398b 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -1365,6 +1365,11 @@ DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreference.swift; sourceTree = ""; }; DBD376B1269302A4007FEC24 /* UITableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = ""; }; DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Onboarding.swift"; sourceTree = ""; }; + DBDC1CF9272C0FD600055C3D /* ku-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ku-TR"; path = "ku-TR.lproj/Intents.strings"; sourceTree = ""; }; + DBDC1CFA272C0FD600055C3D /* ku-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "ku-TR"; path = "ku-TR.lproj/Localizable.stringsdict"; sourceTree = ""; }; + DBDC1CFB272C0FD600055C3D /* ku-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ku-TR"; path = "ku-TR.lproj/Localizable.strings"; sourceTree = ""; }; + DBDC1CFC272C0FD600055C3D /* ku-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ku-TR"; path = "ku-TR.lproj/InfoPlist.strings"; sourceTree = ""; }; + DBDC1CFD272C0FD600055C3D /* ku-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "ku-TR"; path = "ku-TR.lproj/Intents.stringsdict"; sourceTree = ""; }; DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewController.swift; sourceTree = ""; }; DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewModel.swift; sourceTree = ""; }; DBE3CDBA261C427900430CC6 /* TimelineHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineHeaderTableViewCell.swift; sourceTree = ""; }; @@ -3530,6 +3535,7 @@ ru, "gd-GB", th, + "ku-TR", ); mainGroup = DB427DC925BAA00100D1B89D; packageReferences = ( @@ -4560,6 +4566,7 @@ DB4B777F26CA4EFA00B087B3 /* ru */, DB4B778426CA500E00B087B3 /* gd-GB */, DB4B779226CA50BA00B087B3 /* th */, + DBDC1CF9272C0FD600055C3D /* ku-TR */, ); name = Intents.intentdefinition; sourceTree = ""; @@ -4580,6 +4587,7 @@ DB4B778226CA4EFA00B087B3 /* ru */, DB4B778726CA500E00B087B3 /* gd-GB */, DB4B779526CA50BA00B087B3 /* th */, + DBDC1CFC272C0FD600055C3D /* ku-TR */, ); name = InfoPlist.strings; sourceTree = ""; @@ -4600,6 +4608,7 @@ DB4B778126CA4EFA00B087B3 /* ru */, DB4B778626CA500E00B087B3 /* gd-GB */, DB4B779426CA50BA00B087B3 /* th */, + DBDC1CFB272C0FD600055C3D /* ku-TR */, ); name = Localizable.strings; sourceTree = ""; @@ -4636,6 +4645,7 @@ DB4B778026CA4EFA00B087B3 /* ru */, DB4B778526CA500E00B087B3 /* gd-GB */, DB4B779326CA50BA00B087B3 /* th */, + DBDC1CFA272C0FD600055C3D /* ku-TR */, ); name = Localizable.stringsdict; sourceTree = ""; @@ -4656,6 +4666,7 @@ DB4B779026CA504900B087B3 /* fr */, DB4B779126CA504A00B087B3 /* ja */, DB4B779626CA50BA00B087B3 /* th */, + DBDC1CFD272C0FD600055C3D /* ku-TR */, ); name = Intents.stringsdict; sourceTree = ""; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 879d91053..e0afdf7fc 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 35 + 36 CoreDataStack.xcscheme_^#shared#^_ orderHint - 36 + 35 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 37 + 40 MastodonIntents.xcscheme_^#shared#^_ diff --git a/Mastodon/Resources/ku-TR.lproj/InfoPlist.strings b/Mastodon/Resources/ku-TR.lproj/InfoPlist.strings new file mode 100644 index 000000000..669ecfacf --- /dev/null +++ b/Mastodon/Resources/ku-TR.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"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/ku-TR.lproj/Localizable.strings b/Mastodon/Resources/ku-TR.lproj/Localizable.strings new file mode 100644 index 000000000..345f10cf9 --- /dev/null +++ b/Mastodon/Resources/ku-TR.lproj/Localizable.strings @@ -0,0 +1,346 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Navperê asteng bike"; +"Common.Alerts.BlockDomain.Title" = "Tu ji xwe bawerî, bi rastî tu dixwazî hemû %@ asteng bikî? Di gelek rewşan de asteng kirin an jî bêdeng kirin têrê dike û tê tercîh kirin. Tu nikarî naveroka vê navperê di demnameyê an jî agahdariyên xwe de bibînî. Şopînerên te yê di vê navperê were jêbirin."; +"Common.Alerts.CleanCache.Message" = "Pêşbîra %@ biserketî hate paqijkirin."; +"Common.Alerts.CleanCache.Title" = "Pêşbîrê paqij bike"; +"Common.Alerts.Common.PleaseTryAgain" = "Ji kerema xwe dîsa biceribîne."; +"Common.Alerts.Common.PleaseTryAgainLater" = "Ji kerema xwe paşê dîsa biceribîne."; +"Common.Alerts.DeletePost.Delete" = "Jê bibe"; +"Common.Alerts.DeletePost.Title" = "Ma tu dixwazî vê şandiyê jê bibî?"; +"Common.Alerts.DiscardPostContent.Message" = "Piştrast bikin ku naveroka posteyê ya hatîye nivîsandin jê bibin."; +"Common.Alerts.DiscardPostContent.Title" = "Reşnivîs jêbibe"; +"Common.Alerts.EditProfileFailure.Message" = "Nikare profîlê serrast bike. Jkx dîsa biceribîne."; +"Common.Alerts.EditProfileFailure.Title" = "Çewtiya profîlê biguherîne"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Nikare ji bêtirî yek vîdyoyekê tevlî şandiyê bike."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Nikare vîdyoyekê tevlî şandiyê ku berê wêne tê de heye bike."; +"Common.Alerts.PublishPostFailure.Message" = "Weşandina şandiyê têkçû. +Jkx girêdana înternetê xwe kontrol bike."; +"Common.Alerts.PublishPostFailure.Title" = "Weşandin têkçû"; +"Common.Alerts.SavePhotoFailure.Message" = "Ji kerema xwe destûra gihîştina pirtûkxaneya wêneyê çalak bikin da ku wêneyê hilînin."; +"Common.Alerts.SavePhotoFailure.Title" = "Tomarkirina wêneyê têkçû"; +"Common.Alerts.ServerError.Title" = "Çewtiya rajekar"; +"Common.Alerts.SignOut.Confirm" = "Derkeve"; +"Common.Alerts.SignOut.Message" = "Ma tu dixwazî ku derkevî?"; +"Common.Alerts.SignOut.Title" = "Derkeve"; +"Common.Alerts.SignUpFailure.Title" = "Tomarkirin têkçû"; +"Common.Alerts.VoteFailure.PollEnded" = "Rapirsîya qediya"; +"Common.Alerts.VoteFailure.Title" = "Dengdayîn têkçû"; +"Common.Controls.Actions.Add" = "Tevlî bike"; +"Common.Controls.Actions.Back" = "Vegere"; +"Common.Controls.Actions.BlockDomain" = "%@ asteng bike"; +"Common.Controls.Actions.Cancel" = "Dev jê berde"; +"Common.Controls.Actions.Confirm" = "Bipejirîne"; +"Common.Controls.Actions.Continue" = "Bidomîne"; +"Common.Controls.Actions.CopyPhoto" = "Wêne kopî bikin"; +"Common.Controls.Actions.Delete" = "Jê bibe"; +"Common.Controls.Actions.Discard" = "Biavêje"; +"Common.Controls.Actions.Done" = "Qediya"; +"Common.Controls.Actions.Edit" = "Serrast bike"; +"Common.Controls.Actions.FindPeople" = "Kesên ku bişopînin bibînin"; +"Common.Controls.Actions.ManuallySearch" = "Ji devlê i destan lêgerînê bike"; +"Common.Controls.Actions.Next" = "Pêş"; +"Common.Controls.Actions.Ok" = "BAŞ E"; +"Common.Controls.Actions.Open" = "Veke"; +"Common.Controls.Actions.OpenInSafari" = "Di Safariyê de veke"; +"Common.Controls.Actions.Preview" = "Pêşdîtin"; +"Common.Controls.Actions.Previous" = "Paş"; +"Common.Controls.Actions.Remove" = "Rake"; +"Common.Controls.Actions.Reply" = "Bersivê bide"; +"Common.Controls.Actions.ReportUser" = "%@ ragihîne"; +"Common.Controls.Actions.Save" = "Tomar bike"; +"Common.Controls.Actions.SavePhoto" = "Wêneyê hilîne"; +"Common.Controls.Actions.SeeMore" = "Bêtir bibîne"; +"Common.Controls.Actions.Settings" = "Sazkarî"; +"Common.Controls.Actions.Share" = "Parve bike"; +"Common.Controls.Actions.SharePost" = "Şandiyê parve bike"; +"Common.Controls.Actions.ShareUser" = "%@ parve bike"; +"Common.Controls.Actions.SignIn" = "Têkeve"; +"Common.Controls.Actions.SignUp" = "Tomar bibe"; +"Common.Controls.Actions.Skip" = "Derbas bike"; +"Common.Controls.Actions.TakePhoto" = "Wêne bikişîne"; +"Common.Controls.Actions.TryAgain" = "Dîsa biceribîne"; +"Common.Controls.Actions.UnblockDomain" = "%@ asteng neke"; +"Common.Controls.Friendship.Block" = "Asteng bike"; +"Common.Controls.Friendship.BlockDomain" = "%@ asteng bike"; +"Common.Controls.Friendship.BlockUser" = "%@ asteng bike"; +"Common.Controls.Friendship.Blocked" = "Astengkirî"; +"Common.Controls.Friendship.EditInfo" = "Zanyariyan serrast bike"; +"Common.Controls.Friendship.Follow" = "Bişopîne"; +"Common.Controls.Friendship.Following" = "Dişopîne"; +"Common.Controls.Friendship.Mute" = "Bêdeng bike"; +"Common.Controls.Friendship.MuteUser" = "%@ bêdeng bike"; +"Common.Controls.Friendship.Muted" = "Bêdengkirî"; +"Common.Controls.Friendship.Pending" = "Tê nirxandin"; +"Common.Controls.Friendship.Request" = "Daxwazên şopandinê"; +"Common.Controls.Friendship.Unblock" = "Astengiyê rake"; +"Common.Controls.Friendship.UnblockUser" = "%@ asteng neke"; +"Common.Controls.Friendship.Unmute" = "Bêdeng neke"; +"Common.Controls.Friendship.UnmuteUser" = "%@ bêdeng neke"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "Şandiyeke nû binivsîne"; +"Common.Controls.Keyboard.Common.OpenSettings" = "Sazkariyan Veke"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "Bijarteyan nîşan bide"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "Biguherîne bo %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Beşa paşê"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Beşa berê"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "Şandiya pêş"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Profîla nivîskaran veke"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Profîla nivîskaran veke"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "Şandiyê veke"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Wêneya pêşdîtinê"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Şandeya paş"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Bersivê bide şandiyê"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Hişyariya naverokê veke/bigire"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Di postê da Bijartin veke/bigire"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Toggle Reblog on Post"; +"Common.Controls.Status.Actions.Favorite" = "Bijartî"; +"Common.Controls.Status.Actions.Menu" = "Menû"; +"Common.Controls.Status.Actions.Reblog" = "Ji nû ve blog"; +"Common.Controls.Status.Actions.Reply" = "Bersivê bide"; +"Common.Controls.Status.Actions.Unfavorite" = "Nebijare"; +"Common.Controls.Status.Actions.Unreblog" = "Ji nû ve blogkirin betal bikin"; +"Common.Controls.Status.ContentWarning" = "Hişyariya naverokê"; +"Common.Controls.Status.MediaContentWarning" = "Ji bo aşkerakirinê derekî bitikîne"; +"Common.Controls.Status.Poll.Closed" = "Girtî"; +"Common.Controls.Status.Poll.Vote" = "Deng"; +"Common.Controls.Status.ShowPost" = "Şandiyê nîşan bide"; +"Common.Controls.Status.ShowUserProfile" = "Profîla bikarhêner nîşan bide"; +"Common.Controls.Status.Tag.Email" = "E-name"; +"Common.Controls.Status.Tag.Emoji" = "E-name"; +"Common.Controls.Status.Tag.Hashtag" = "Etîket"; +"Common.Controls.Status.Tag.Link" = "Girêdan"; +"Common.Controls.Status.Tag.Mention" = "Behs"; +"Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.UserReblogged" = "%@ ji nû ve hat blogkirin"; +"Common.Controls.Status.UserRepliedTo" = "Bersiv da %@"; +"Common.Controls.Tabs.Home" = "Serrûpel"; +"Common.Controls.Tabs.Notification" = "Agahdarî"; +"Common.Controls.Tabs.Profile" = "Profîl"; +"Common.Controls.Tabs.Search" = "Bigere"; +"Common.Controls.Timeline.Filtered" = "Parzûnkirî"; +"Common.Controls.Timeline.Header.BlockedWarning" = "Tu nikarî profîla vî bikarhênerî bibînî +heta ku astengîya te rakin."; +"Common.Controls.Timeline.Header.BlockingWarning" = "Tu nikarî profîla vî bikarhênerî bibînî +Heta ku tu wan asteng bikî. +Profîla te ji wan ra wiha xuya dike."; +"Common.Controls.Timeline.Header.NoStatusFound" = "Şandî nehate dîtin"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "Ev bikarhêner hat sekinandin."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "Tu nikarî profîla %@ bibînî +Heta ku astengîya te rakin."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "Tu nikarî profîla %@ bibînî +Heta ku tu wan asteng bikî. +Profîla te ji wan ra wiha xuya dike."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "Hesaba %@ hat sekinandin."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Barkirina posteyên kêm"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Barkirina posteyên kêm..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Bêtir bersivan nîşan bide"; +"Common.Controls.Timeline.Timestamp.Now" = "Niha"; +"Scene.AccountList.AddAccount" = "Ajimêr tevlî bike"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Profîla hilbijartî ya niha: %@. Du caran bitikîne û paşê dest bide ser da ku guhêrbara ajimêr were nîşandan"; +"Scene.Compose.Accessibility.AppendAttachment" = "Pêvek tevlî bike"; +"Scene.Compose.Accessibility.AppendPoll" = "Rapirsî tevlî bike"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Custom Emoji Picker"; +"Scene.Compose.Accessibility.DisableContentWarning" = "Hişyariya naverokê neçalak bike"; +"Scene.Compose.Accessibility.EnableContentWarning" = "Enable Content Warning"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Menuya Xuyabûna Şandiyê"; +"Scene.Compose.Accessibility.RemovePoll" = "Rapirsî rake"; +"Scene.Compose.Attachment.AttachmentBroken" = "Ev %@ naxebite û nayê barkirin + li ser Mastodon."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Describe the photo for the visually-impaired..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Describe the video for the visually-impaired..."; +"Scene.Compose.Attachment.Photo" = "wêne"; +"Scene.Compose.Attachment.Video" = "vîdyo"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Space to add"; +"Scene.Compose.ComposeAction" = "Biweşîne"; +"Scene.Compose.ContentInputPlaceholder" = "Type or paste what’s on your mind"; +"Scene.Compose.ContentWarning.Placeholder" = "Write an accurate warning here..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Pêvek lê zêde bike - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "Şandî bihelîne"; +"Scene.Compose.Keyboard.PublishPost" = "Şandiye bide weşan"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Xuyanîbûn hilbijêre - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "Hişyariya naverokê veke/bigire"; +"Scene.Compose.Keyboard.TogglePoll" = "Anketê veke/bigire"; +"Scene.Compose.MediaSelection.Browse" = "Bigere"; +"Scene.Compose.MediaSelection.Camera" = "Wêne bikişîne"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "Wênegeh"; +"Scene.Compose.Poll.DurationTime" = "Dirêjî: %@"; +"Scene.Compose.Poll.OneDay" = "1 Roj"; +"Scene.Compose.Poll.OneHour" = "1 Demjimêr"; +"Scene.Compose.Poll.OptionNumber" = "Vebijêrk %ld"; +"Scene.Compose.Poll.SevenDays" = "7 Roj"; +"Scene.Compose.Poll.SixHours" = "6 Demjimêr"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 xulek"; +"Scene.Compose.Poll.ThreeDays" = "3 Roj"; +"Scene.Compose.ReplyingToUser" = "bersiv bide %@"; +"Scene.Compose.Title.NewPost" = "Şandiya nû"; +"Scene.Compose.Title.NewReply" = "Bersiva nû"; +"Scene.Compose.Visibility.Direct" = "Tenê mirovên ku min qalkirî"; +"Scene.Compose.Visibility.Private" = "Tenê şopîneran"; +"Scene.Compose.Visibility.Public" = "Gelemperî"; +"Scene.Compose.Visibility.Unlisted" = "Nerêzokkirî"; +"Scene.ConfirmEmail.Button.DontReceiveEmail" = "Min hîç e-nameyeke nesitand"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "Sepana e-nameyê veke"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Kontrol bike ka navnîşana e-nameya te rast e û her wiha peldanka xwe ya spam."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "E-namyê yê dîsa bişîne"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "E-nameyê xwe kontrol bike"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "We just sent you an email. Check your junk folder if you haven’t."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "E-name"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Rajegirê e-nameyê veke"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; +"Scene.ConfirmEmail.Subtitle" = "We just sent an email to %@, +tap the link to confirm your account."; +"Scene.ConfirmEmail.Title" = "Tiştekî dawî."; +"Scene.Favorite.Title" = "Bijareyên te"; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "Şandiyên nû bibîne"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "Derhêl"; +"Scene.HomeTimeline.NavigationBarState.Published" = "Hate weşandin!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Şandî tê weşandin..."; +"Scene.HomeTimeline.Title" = "Serrûpel"; +"Scene.Notification.Keyobard.ShowEverything" = "Her tiştî nîşan bide"; +"Scene.Notification.Keyobard.ShowMentions" = "Behskirîya nîşan bike"; +"Scene.Notification.Title.Everything" = "Her tişt"; +"Scene.Notification.Title.Mentions" = "Behs"; +"Scene.Notification.UserFavorited Your Post" = "%@ posta we bijarte"; +"Scene.Notification.UserFollowedYou" = "%@ te şopand"; +"Scene.Notification.UserMentionedYou" = "%@ behsa te kir"; +"Scene.Notification.UserRebloggedYourPost" = "%@ posta we ji nû ve tomar kir"; +"Scene.Notification.UserRequestedToFollowYou" = "%@ daxwaza şopandina te kir"; +"Scene.Notification.UserYourPollHasEnded" = "%@ Anketa te qediya"; +"Scene.Preview.Keyboard.ClosePreview" = "Pêşdîtin bigire"; +"Scene.Preview.Keyboard.ShowNext" = "A pêş nîşan bide"; +"Scene.Preview.Keyboard.ShowPrevious" = "A paş nîşan bide"; +"Scene.Profile.Dashboard.Followers" = "şopîneran"; +"Scene.Profile.Dashboard.Following" = "dişopîne"; +"Scene.Profile.Dashboard.Posts" = "şandîyan"; +"Scene.Profile.Fields.AddRow" = "Rêzê lê zêde bike"; +"Scene.Profile.Fields.Placeholder.Content" = "Naverok"; +"Scene.Profile.Fields.Placeholder.Label" = "Nîşan"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Message" = "Ji bo rakirina blokê bipejirin %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Title" = "Hesabê ji bloke rake"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Ji bo vekirina bê dengkirinê bipejirin %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Hesabê ji bê deng rake"; +"Scene.Profile.SegmentedControl.Media" = "Medya"; +"Scene.Profile.SegmentedControl.Posts" = "Şandîyan"; +"Scene.Profile.SegmentedControl.Replies" = "Bersivan"; +"Scene.Register.Error.Item.Agreement" = "Lihevhatin"; +"Scene.Register.Error.Item.Email" = "E-name"; +"Scene.Register.Error.Item.Locale" = "Herêm"; +"Scene.Register.Error.Item.Password" = "Şîfre"; +"Scene.Register.Error.Item.Reason" = "Sedem"; +"Scene.Register.Error.Item.Username" = "Navê bikarhêner"; +"Scene.Register.Error.Reason.Accepted" = "%@ divê were qebûlkirin"; +"Scene.Register.Error.Reason.Blank" = "%@ pêwist e"; +"Scene.Register.Error.Reason.Blocked" = "%@ peydekerê e-nameya bêdestûr dihewîne"; +"Scene.Register.Error.Reason.Inclusion" = "%@ nirxeke ku tê destekirin nîn e"; +"Scene.Register.Error.Reason.Invalid" = "%@ ne derbasdar e"; +"Scene.Register.Error.Reason.Reserved" = "%@ peyveke mifteya veqetandî ye"; +"Scene.Register.Error.Reason.Taken" = "%@ jixwe tê bikaranîn"; +"Scene.Register.Error.Reason.TooLong" = "%@ gelekî dirêj e"; +"Scene.Register.Error.Reason.TooShort" = "%@ pir kurt e"; +"Scene.Register.Error.Reason.Unreachable" = "%@ xuya nake"; +"Scene.Register.Error.Special.EmailInvalid" = "Ev ne navnîşana e-nameyek derbasdar e"; +"Scene.Register.Error.Special.PasswordTooShort" = "Şîfre pir kurt e (divê herî kêm 8 tîpan be)"; +"Scene.Register.Error.Special.UsernameInvalid" = "Navê bikarhêner divê tenê tîpên alfanumerîk û binxet hebe"; +"Scene.Register.Error.Special.UsernameTooLong" = "Navê bikarhêner pir dirêj e (ji 30 tîpan dirêjtir nabe)"; +"Scene.Register.Input.Avatar.Delete" = "Jê bibe"; +"Scene.Register.Input.DisplayName.Placeholder" = "navê nîşanê"; +"Scene.Register.Input.Email.Placeholder" = "e-name"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Tu çima dixwazî beşdar bibî?"; +"Scene.Register.Input.Password.Hint" = "Şîfreya we herî kêm heşt tîpan hewce dike"; +"Scene.Register.Input.Password.Placeholder" = "şîfre"; +"Scene.Register.Input.Username.DuplicatePrompt" = "Navê vê bikarhêner tê girtin."; +"Scene.Register.Input.Username.Placeholder" = "navê bikarhêner"; +"Scene.Register.Title" = "Ji me re hinekî qala xwe bike."; +"Scene.Report.Content1" = "Are there any other posts you’d like to add to the report?"; +"Scene.Report.Content2" = "Is there anything the moderators should know about this report?"; +"Scene.Report.Send" = "Ragihandinê bişîne"; +"Scene.Report.SkipToSend" = "Bêyî şirove bişîne"; +"Scene.Report.Step1" = "Gav 1 ji 2"; +"Scene.Report.Step2" = "Gav 2 ji 2"; +"Scene.Report.TextPlaceholder" = "Type or paste additional comments"; +"Scene.Report.Title" = "%@ ragihîne"; +"Scene.Search.Recommend.Accounts.Description" = "Dibe ku tu bixwazî van hesaban bişopînî"; +"Scene.Search.Recommend.Accounts.Follow" = "Bişopîne"; +"Scene.Search.Recommend.Accounts.Title" = "Hesabên ku hûn dikarin hez bikin"; +"Scene.Search.Recommend.ButtonText" = "Hemûyé bibîne"; +"Scene.Search.Recommend.HashTag.Description" = "Etîketên ku pir balê dikişînin"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ kes diaxivin"; +"Scene.Search.Recommend.HashTag.Title" = "Trend li ser Mastodon"; +"Scene.Search.SearchBar.Cancel" = "Betal kirin"; +"Scene.Search.SearchBar.Placeholder" = "Li etîketan û bikarhêneran bigerin"; +"Scene.Search.Searching.Clear" = "Paqij bike"; +"Scene.Search.Searching.EmptyState.NoResults" = "Encam tune"; +"Scene.Search.Searching.RecentSearch" = "Lêgerînên dawî"; +"Scene.Search.Searching.Segment.All" = "Hemû"; +"Scene.Search.Searching.Segment.Hashtags" = "Etîketan"; +"Scene.Search.Searching.Segment.People" = "Mirov"; +"Scene.Search.Searching.Segment.Posts" = "Şandîyan"; +"Scene.Search.Title" = "Bigere"; +"Scene.ServerPicker.Button.Category.Academia" = "akademî"; +"Scene.ServerPicker.Button.Category.Activism" = "çalakî"; +"Scene.ServerPicker.Button.Category.All" = "Hemû"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "Beş: Hemû"; +"Scene.ServerPicker.Button.Category.Art" = "huner"; +"Scene.ServerPicker.Button.Category.Food" = "xwarin"; +"Scene.ServerPicker.Button.Category.Furry" = "furry"; +"Scene.ServerPicker.Button.Category.Games" = "lîsk"; +"Scene.ServerPicker.Button.Category.General" = "giştî"; +"Scene.ServerPicker.Button.Category.Journalism" = "rojnamevanî"; +"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Music" = "muzîk"; +"Scene.ServerPicker.Button.Category.Regional" = "herêmî"; +"Scene.ServerPicker.Button.Category.Tech" = "teknolojî"; +"Scene.ServerPicker.Button.SeeLess" = "Kêmtir bibîne"; +"Scene.ServerPicker.Button.SeeMore" = "Bêtir bibîne"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Di dema barkirina daneyan da tiştek xelet derket. Girêdana xwe ya înternetê kontrol bike."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Dîtina serverên berdest..."; +"Scene.ServerPicker.EmptyState.NoResults" = "Encam nade"; +"Scene.ServerPicker.Input.Placeholder" = "Serverek bibînin an jî beşdarî ya xwe bibin..."; +"Scene.ServerPicker.Label.Category" = "KATEGORÎ"; +"Scene.ServerPicker.Label.Language" = "ZIMAN"; +"Scene.ServerPicker.Label.Users" = "BIKARHÊNER"; +"Scene.ServerPicker.Title" = "Rajekarekê hilbijêre, +Her kîjan rajekar be."; +"Scene.ServerRules.Button.Confirm" = "Ez tev dibim"; +"Scene.ServerRules.PrivacyPolicy" = "polîtîkaya nepenîtiyê"; +"Scene.ServerRules.Prompt" = "Bi berdewamî, hûn ji bo %@ di bin şertên polîtîkaya xizmet û nepenîtiyê da ne."; +"Scene.ServerRules.Subtitle" = "Ev rêzik ji aliyê rêvebirên %@ ve tên sazkirin."; +"Scene.ServerRules.TermsOfService" = "şert û mercên xizmetê"; +"Scene.ServerRules.Title" = "Hin qaîdeyên bingehîn."; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon is open source software. You can report issues on GitHub at %@ (%@)"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window"; +"Scene.Settings.Section.Appearance.Automatic" = "Xweber"; +"Scene.Settings.Section.Appearance.Dark" = "Her dem tarî"; +"Scene.Settings.Section.Appearance.Light" = "Her dem ronî"; +"Scene.Settings.Section.Appearance.Title" = "Xuyang"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings"; +"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy"; +"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service"; +"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone"; +"Scene.Settings.Section.Notifications.Boosts" = "Reblogs my post"; +"Scene.Settings.Section.Notifications.Favorites" = "Şandiyên min hez kir"; +"Scene.Settings.Section.Notifications.Follows" = "Min şopand"; +"Scene.Settings.Section.Notifications.Mentions" = "Qale min kir"; +"Scene.Settings.Section.Notifications.Title" = "Agahdarî"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "her kes"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "her kesê ku dişopînim"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "şopînerek"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "ne yek"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "Min agahdar bike gava"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis"; +"Scene.Settings.Section.Preference.Title" = "Hilbijarte"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links"; +"Scene.Settings.Section.SpicyZone.Clear" = "Clear Media Cache"; +"Scene.Settings.Section.SpicyZone.Signout" = "Sign Out"; +"Scene.Settings.Section.SpicyZone.Title" = "The Spicy Zone"; +"Scene.Settings.Title" = "Sazkarî"; +"Scene.SuggestionAccount.FollowExplain" = "Gava tu kesekî dişopînî, tu yê şandiyê wan di serrûpelê de bibîne."; +"Scene.SuggestionAccount.Title" = "Kesên bo ku bişopînî bibîne"; +"Scene.Thread.BackTitle" = "Şandî"; +"Scene.Thread.Title" = "Post from %@"; +"Scene.Welcome.Slogan" = "Torên civakî +di destên te de."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Dest bide ser bişkoja profîlê da ku di navbera gelek ajimêrann de biguherînî."; +"Scene.Wizard.NewInMastodon" = "Nû di Mastodon de"; \ No newline at end of file diff --git a/Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict b/Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict new file mode 100644 index 000000000..064b8bf2b --- /dev/null +++ b/Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict @@ -0,0 +1,390 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 agahdariya nexwendî + other + %ld agahdariyên nexwendî + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Sînorê têketinê derbas kir %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tîp + other + %ld tîp + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Sînorê têketinê %#@character_count@ maye + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tîp + other + %ld tîp + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + şandî + other + şandî + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 şandî + other + %ld şandî + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 hezkirin + other + %ld hezkirin + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reblog + other + %ld reblogs + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 deng + other + %ld deng + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 hilbijêr + other + %ld hilbijêr + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 mirov diaxive + other + %ld mirov diaxive + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 dişopîne + other + %ld dişopîne + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 şopîner + other + %ld şopîner + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 sal berê + other + %ld sal berê + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 meh berê + other + %ld meh berê + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 roj berê + other + %ld roj berê + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 demjimêr berê + other + %ld demjimêr berê + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 xulek berê + other + %ld xulek berê + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 çirke berê + other + %ld çirke berê + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 sal berê + other + %ld sal berê + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 xulek berê + other + %ld xulek berê + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 roj berê + other + %ld roj berê + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 demjimêr berê + other + %ld demjimêr berê + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 xulek berê + other + %ld xulek berê + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 çirke berê + other + %ld çirke berê + + + + diff --git a/MastodonIntent/ku-TR.lproj/Intents.strings b/MastodonIntent/ku-TR.lproj/Intents.strings new file mode 100644 index 000000000..3e1c69fc3 --- /dev/null +++ b/MastodonIntent/ku-TR.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Di Mastodon de biweşîne"; + +"751xkl" = "Naveroka nivîsê"; + +"CsR7G2" = "Di Mastodon de biweşîne"; + +"HZSGTr" = "Kîjan naverok bila bê şandin?"; + +"HdGikU" = "Şandin têkçû"; + +"KDNTJ4" = "Sedema têkçûnê"; + +"RHxKOw" = "Bi naveroka nivîsî şandiyan bişîne"; + +"RxSqsb" = "Şandî"; + +"WCIR3D" = "${content} biweşîne di Mastodon de"; + +"ZKJSNu" = "Şandî"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Xuyanî"; + +"Zo4jgJ" = "Xuyaniya şandiyê"; + +"apSxMG-dYQ5NN" = "Vebijarkên ${count} hene ku li gorî 'Giştî' ne."; + +"apSxMG-ehFLjY" = "Vebijarkên ${count} hene ku li gorî 'Tenê Şopandin' hene."; + +"ayoYEb-dYQ5NN" = "${content}, Giştî"; + +"ayoYEb-ehFLjY" = "${content}, Tenê şopînêr"; + +"dUyuGg" = "Li ser Mastodon bişînin"; + +"dYQ5NN" = "Gelemperî"; + +"ehFLjY" = "Tenê şopîneran"; + +"gfePDu" = "Weşandin bi ser neket. ${failureReason}"; + +"k7dbKQ" = "Şandî bi serkeftî hate şandin."; + +"oGiqmY-dYQ5NN" = "Tenê ji bo pejirandinê, we 'Giştî' dixwest?"; + +"oGiqmY-ehFLjY" = "Tenê ji bo piştrastkirinê, we 'Tenê Şopdarên' dixwest?"; + +"rM6dvp" = "Girêdan"; + +"ryJLwG" = "Bi serkeftî hat şandin. "; diff --git a/MastodonIntent/ku-TR.lproj/Intents.stringsdict b/MastodonIntent/ku-TR.lproj/Intents.stringsdict new file mode 100644 index 000000000..5a39d5e64 --- /dev/null +++ b/MastodonIntent/ku-TR.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 + + + + From d66dfccad0a253201b5861f08a1396240f550a05 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Oct 2021 19:38:21 +0800 Subject: [PATCH 302/392] chore: update to version 1.2.0 (81) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index cf50d3ac4..9da0855b7 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index cf50d3ac4..9da0855b7 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index cf50d3ac4..9da0855b7 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index cc98e398b..1e5021a31 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4811,7 +4811,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4840,7 +4840,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4948,11 +4948,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4979,11 +4979,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5008,11 +5008,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5038,11 +5038,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5105,7 +5105,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5130,7 +5130,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5155,7 +5155,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5180,7 +5180,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5205,7 +5205,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5230,7 +5230,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5255,7 +5255,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5280,7 +5280,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5371,7 +5371,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5438,11 +5438,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5487,7 +5487,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5512,11 +5512,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5608,7 +5608,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5675,11 +5675,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5724,7 +5724,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5749,11 +5749,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 80; + DYLIB_CURRENT_VERSION = 81; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5779,7 +5779,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5803,7 +5803,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 80; + CURRENT_PROJECT_VERSION = 81; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index e0afdf7fc..1e9186391 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 36 + 43 CoreDataStack.xcscheme_^#shared#^_ orderHint - 35 + 42 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 40 + 41 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 38 + 44 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 1c89f12a2..dc3e86199 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 80 + 81 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 062a4bf1a..6fabe37eb 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index cf50d3ac4..9da0855b7 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index cf50d3ac4..9da0855b7 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index fb52c9dce..43c0dff37 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 8870b320d..73d43d819 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 80 + 81 NSExtension NSExtensionAttributes From 90a24445e3e076890fb2078a1f429139776fc9da Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 29 Oct 2021 21:45:10 +0200 Subject: [PATCH 303/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 9798c86c2..5330ea480 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -111,7 +111,7 @@ "open_author_profile": "Profîla nivîskaran veke", "open_reblogger_profile": "Profîla nivîskaran veke", "reply_status": "Bersivê bide şandiyê", - "toggle_reblog": "Toggle Reblog on Post", + "toggle_reblog": "Ji vû nivîsandin di şandiyê de biguherîne", "toggle_favorite": "Di postê da Bijartin veke/bigire", "toggle_content_warning": "Hişyariya naverokê veke/bigire", "preview_image": "Wêneya pêşdîtinê" @@ -294,7 +294,7 @@ }, "confirm_email": { "title": "Tiştekî dawî.", - "subtitle": "We just sent an email to %s,\ntap the link to confirm your account.", + "subtitle": "Me tenê e-nameyek ji %s re şand,\ngirêdanê bitikne da ku ajimêra xwe bidî piştrastkirin.", "button": { "open_email_app": "Sepana e-nameyê veke", "dont_receive_email": "Min hîç e-nameyeke nesitand" @@ -305,8 +305,8 @@ "resend_email": "E-namyê yê dîsa bişîne" }, "open_email_app": { - "title": "Check your inbox.", - "description": "We just sent you an email. Check your junk folder if you haven’t.", + "title": "Nameyên xwe yên wergirtî kontrol bike.", + "description": "Me tenê ji te re e-nameyek şand. Heke nehatiye peldanka xwe ya spamê kontrol bike.", "mail": "E-name", "open_email_client": "Rajegirê e-nameyê veke" } @@ -334,15 +334,15 @@ "photo_library": "Wênegeh", "browse": "Bigere" }, - "content_input_placeholder": "Type or paste what’s on your mind", + "content_input_placeholder": "Tiştê ku di hişê te de ye binivîsin an jî pêve bike", "compose_action": "Biweşîne", "replying_to_user": "bersiv bide %s", "attachment": { "photo": "wêne", "video": "vîdyo", "attachment_broken": "Ev %s naxebite û nayê barkirin\n li ser Mastodon.", - "description_photo": "Describe the photo for the visually-impaired...", - "description_video": "Describe the video for the visually-impaired..." + "description_photo": "Wêneyê ji bo kêmbînên dîtbar bide nasîn...", + "description_video": "Vîdyoyê ji bo kêmbînên dîtbar bide nasîn..." }, "poll": { "duration_time": "Dirêjî: %s", @@ -355,7 +355,7 @@ "option_number": "Vebijêrk %ld" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "Li vir hişyariyek hûrgilî binivîsine..." }, "visibility": { "public": "Gelemperî", @@ -364,14 +364,14 @@ "direct": "Tenê mirovên ku min qalkirî" }, "auto_complete": { - "space_to_add": "Space to add" + "space_to_add": "Bicîhkirinê tevlî bike" }, "accessibility": { "append_attachment": "Pêvek tevlî bike", "append_poll": "Rapirsî tevlî bike", "remove_poll": "Rapirsî rake", - "custom_emoji_picker": "Custom Emoji Picker", - "enable_content_warning": "Enable Content Warning", + "custom_emoji_picker": "Hilbijêrê emojî yên kesanekirî", + "enable_content_warning": "Hişyariya naverokê neçalak bike", "disable_content_warning": "Hişyariya naverokê neçalak bike", "post_visibility_menu": "Menuya Xuyabûna Şandiyê" }, @@ -467,7 +467,7 @@ }, "thread": { "back_title": "Şandî", - "title": "Post from %s" + "title": "Şandî ji %s" }, "settings": { "title": "Sazkarî", @@ -482,7 +482,7 @@ "title": "Agahdarî", "favorites": "Şandiyên min hez kir", "follows": "Min şopand", - "boosts": "Reblogs my post", + "boosts": "Şandiya min ji nû ve binivîsine", "mentions": "Qale min kir", "trigger": { "anyone": "her kes", @@ -494,39 +494,39 @@ }, "preference": { "title": "Hilbijarte", - "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" + "true_black_dark_mode": "Moda tarî ya reş a rastîn", + "disable_avatar_animation": "Avatarên anîmasyonî neçalak bike", + "disable_emoji_animation": "Emojiyên anîmasyonî neçalak bike", + "using_default_browser": "Ji bo vekirina girêdanan geroka berdest bi kar bîne" }, "boring_zone": { - "title": "The Boring Zone", - "account_settings": "Account Settings", - "terms": "Terms of Service", - "privacy": "Privacy Policy" + "title": "Devera acizker", + "account_settings": "Sazkariyên ajimêr", + "terms": "Mercên bikaranînê", + "privacy": "Polîtikaya nihêniyê" }, "spicy_zone": { - "title": "The Spicy Zone", - "clear": "Clear Media Cache", - "signout": "Sign Out" + "title": "Devera germ", + "clear": "Pêşbîra medyayê pak bike", + "signout": "Derkeve" } }, "footer": { - "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)" + "mastodon_description": "Mastodon nermalava çavkaniya vekirî ye. Tu dikarî pirsgirêkan li ser GitHub-ê ragihînî di %s (%s) de" }, "keyboard": { - "close_settings_window": "Close Settings Window" + "close_settings_window": "Sazkariyên çarçoveyê bigire" } }, "report": { "title": "%s ragihîne", "step1": "Gav 1 ji 2", "step2": "Gav 2 ji 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?", + "content1": "Şandiyên din hene ku tu dixwazî tevlî ragihandinê bikî?", + "content2": "Derbarê vê ragihandinê de tiştek heye ku divê çavdêr bizanin?", "send": "Ragihandinê bişîne", "skip_to_send": "Bêyî şirove bişîne", - "text_placeholder": "Type or paste additional comments" + "text_placeholder": "Şiroveyên daxwazkirê binivîsine an jî pê ve bike" }, "preview": { "keyboard": { @@ -537,13 +537,13 @@ }, "account_list": { "tab_bar_hint": "Profîla hilbijartî ya niha: %s. Du caran bitikîne û paşê dest bide ser da ku guhêrbara ajimêr were nîşandan", - "dismiss_account_switcher": "Dismiss Account Switcher", + "dismiss_account_switcher": "Guherkera ajimêrê paş guh bike", "add_account": "Ajimêr tevlî bike" }, "wizard": { "new_in_mastodon": "Nû di Mastodon de", "multiple_account_switch_intro_description": "Dest bide ser bişkoja profîlê da ku di navbera gelek ajimêrann de biguherînî.", - "accessibility_hint": "Double tap to dismiss this wizard" + "accessibility_hint": "Du caran bitikîne da ku çarçoveyahilpekok ji holê rakî" } } } \ No newline at end of file From 061ed1b4b197614b4efb15db5ebd7f5d62b9c959 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 29 Oct 2021 21:45:11 +0200 Subject: [PATCH 304/392] New translations Localizable.stringsdict (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict index 064b8bf2b..8ae1b812a 100644 --- a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict @@ -109,9 +109,9 @@ NSStringFormatValueTypeKey ld one - 1 reblog + 1 ji nû ve nivîsandin other - %ld reblogs + %ld ji nû ve nivîsandin plural.count.vote From f0a570ea0cb6683eaa635515ede8376ec0159019 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 1 Nov 2021 19:54:07 +0800 Subject: [PATCH 305/392] feat: add follower list for user --- Mastodon.xcodeproj/project.pbxproj | 52 +++++ .../xcschemes/xcschememanagement.plist | 8 +- Mastodon/Coordinator/SceneCoordinator.swift | 5 + Mastodon/Diffiable/Item/UserItem.swift | 15 ++ Mastodon/Diffiable/Section/UserSection.swift | 63 ++++++ ...erProviderFacade+UITableViewDelegate.swift | 22 ++ .../UserProvider/UserProviderFacade.swift | 22 ++ .../FollowerListViewController+Provider.swift | 50 +++++ .../Follower/FollowerListViewController.swift | 111 ++++++++++ .../FollowerListViewModel+Diffable.swift | 58 ++++++ .../FollowerListViewModel+State.swift | 196 ++++++++++++++++++ .../Follower/FollowerListViewModel.swift | 53 +++++ .../Header/View/ProfileHeaderView.swift | 19 +- .../View/ProfileStatusDashboardView.swift | 28 ++- .../Scene/Profile/ProfileViewController.swift | 33 ++- .../Timeline/UserTimelineViewController.swift | 1 - .../TimelineFooterTableViewCell.swift | 51 +++++ .../TableviewCell/UserTableViewCell.swift | 131 ++++++++++++ .../APIService/APIService+Follower.swift | 65 ++++++ .../Mastodon+API+Account+FollowRequest.swift | 6 +- .../API/Mastodon+API+Account+Followers.swift | 81 ++++++++ 21 files changed, 1028 insertions(+), 42 deletions(-) create mode 100644 Mastodon/Diffiable/Item/UserItem.swift create mode 100644 Mastodon/Diffiable/Section/UserSection.swift create mode 100644 Mastodon/Protocol/UserProvider/UserProviderFacade+UITableViewDelegate.swift create mode 100644 Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift create mode 100644 Mastodon/Scene/Profile/Follower/FollowerListViewController.swift create mode 100644 Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift create mode 100644 Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift create mode 100644 Mastodon/Scene/Share/View/TableviewCell/TimelineFooterTableViewCell.swift create mode 100644 Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell.swift create mode 100644 Mastodon/Service/APIService/APIService+Follower.swift create mode 100644 MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 1e5021a31..11914fe75 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -333,6 +333,17 @@ DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A06225E905E000CFDF14 /* UIApplication.swift */; }; DB6B35182601FA3400DC1E11 /* MastodonAttachmentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B35172601FA3400DC1E11 /* MastodonAttachmentService.swift */; }; DB6B351E2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift */; }; + DB6B74EF272FB55000C70B6E /* FollowerListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74EE272FB55000C70B6E /* FollowerListViewController.swift */; }; + DB6B74F2272FB67600C70B6E /* FollowerListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74F1272FB67600C70B6E /* FollowerListViewModel.swift */; }; + DB6B74F4272FBAE700C70B6E /* FollowerListViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74F3272FBAE700C70B6E /* FollowerListViewModel+Diffable.swift */; }; + DB6B74F6272FBCDB00C70B6E /* FollowerListViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74F5272FBCDB00C70B6E /* FollowerListViewModel+State.swift */; }; + DB6B74F8272FBFB100C70B6E /* FollowerListViewController+Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74F7272FBFB100C70B6E /* FollowerListViewController+Provider.swift */; }; + DB6B74FA272FC2B500C70B6E /* APIService+Follower.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74F9272FC2B500C70B6E /* APIService+Follower.swift */; }; + DB6B74FC272FF55800C70B6E /* UserSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74FB272FF55800C70B6E /* UserSection.swift */; }; + DB6B74FE272FF59000C70B6E /* UserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74FD272FF59000C70B6E /* UserItem.swift */; }; + DB6B7500272FF73800C70B6E /* UserTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */; }; + DB6B75022730060700C70B6E /* UserProviderFacade+UITableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B75012730060700C70B6E /* UserProviderFacade+UITableViewDelegate.swift */; }; + DB6B750427300B4000C70B6E /* TimelineFooterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */; }; DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */; }; DB6D1B3D2636857500ACB481 /* AppearancePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */; }; DB6D1B44263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B43263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift */; }; @@ -1132,6 +1143,17 @@ DB68A06225E905E000CFDF14 /* UIApplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIApplication.swift; sourceTree = ""; }; DB6B35172601FA3400DC1E11 /* MastodonAttachmentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAttachmentService.swift; sourceTree = ""; }; DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentCollectionViewCell.swift; sourceTree = ""; }; + DB6B74EE272FB55000C70B6E /* FollowerListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowerListViewController.swift; sourceTree = ""; }; + DB6B74F1272FB67600C70B6E /* FollowerListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowerListViewModel.swift; sourceTree = ""; }; + DB6B74F3272FBAE700C70B6E /* FollowerListViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowerListViewModel+Diffable.swift"; sourceTree = ""; }; + DB6B74F5272FBCDB00C70B6E /* FollowerListViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowerListViewModel+State.swift"; sourceTree = ""; }; + DB6B74F7272FBFB100C70B6E /* FollowerListViewController+Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowerListViewController+Provider.swift"; sourceTree = ""; }; + DB6B74F9272FC2B500C70B6E /* APIService+Follower.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Follower.swift"; sourceTree = ""; }; + DB6B74FB272FF55800C70B6E /* UserSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSection.swift; sourceTree = ""; }; + DB6B74FD272FF59000C70B6E /* UserItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserItem.swift; sourceTree = ""; }; + DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTableViewCell.swift; sourceTree = ""; }; + DB6B75012730060700C70B6E /* UserProviderFacade+UITableViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserProviderFacade+UITableViewDelegate.swift"; sourceTree = ""; }; + DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineFooterTableViewCell.swift; sourceTree = ""; }; DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Entity+Error.swift"; sourceTree = ""; }; DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePreference.swift; sourceTree = ""; }; DB6D1B43263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+API+Subscriptions+Policy.swift"; sourceTree = ""; }; @@ -1866,6 +1888,7 @@ 2D4AD8A126316CD200613EFC /* SelectedAccountSection.swift */, DB6D9F7C26358ED4008423CD /* SettingsSection.swift */, DBA94433265CBB5300C537E1 /* ProfileFieldSection.swift */, + DB6B74FB272FF55800C70B6E /* UserSection.swift */, ); path = Section; sourceTree = ""; @@ -1909,8 +1932,10 @@ 2DA7D04925CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift */, 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */, DBE3CDBA261C427900430CC6 /* TimelineHeaderTableViewCell.swift */, + DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */, DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */, DB92CF7125E7BB98002C1017 /* PollOptionTableViewCell.swift */, + DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */, ); path = TableviewCell; sourceTree = ""; @@ -1919,6 +1944,7 @@ isa = PBXGroup; children = ( 2D7631B225C159F700929FB9 /* Item.swift */, + DB6B74FD272FF59000C70B6E /* UserItem.swift */, 2D198642261BF09500F0B013 /* SearchResultItem.swift */, DB4F097C26A03A5B00D62E92 /* SearchHistoryItem.swift */, 2D4AD8A726316D3500613EFC /* SelectedAccountItem.swift */, @@ -2289,6 +2315,7 @@ 2D34D9D026148D9E0081BFC0 /* APIService+Recommend.swift */, 2D34D9DA261494120081BFC0 /* APIService+Search.swift */, 0F202212261351F5000C64BF /* APIService+HashtagTimeline.swift */, + DB6B74F9272FC2B500C70B6E /* APIService+Follower.swift */, DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */, 5B24BBE1262DB19100A9381B /* APIService+Report.swift */, DBAE3F932616E28B004B8251 /* APIService+Follow.swift */, @@ -2508,6 +2535,18 @@ path = NavigationController; sourceTree = ""; }; + DB6B74F0272FB55400C70B6E /* Follower */ = { + isa = PBXGroup; + children = ( + DB6B74EE272FB55000C70B6E /* FollowerListViewController.swift */, + DB6B74F7272FBFB100C70B6E /* FollowerListViewController+Provider.swift */, + DB6B74F1272FB67600C70B6E /* FollowerListViewModel.swift */, + DB6B74F3272FBAE700C70B6E /* FollowerListViewModel+Diffable.swift */, + DB6B74F5272FBCDB00C70B6E /* FollowerListViewModel+State.swift */, + ); + path = Follower; + sourceTree = ""; + }; DB6C8C0525F0921200AAA452 /* MastodonSDK */ = { isa = PBXGroup; children = ( @@ -2862,6 +2901,7 @@ DBB525462611ED57002F1F29 /* Header */, DBB5253B2611ECF5002F1F29 /* Timeline */, DBE3CDF1261C6B3100430CC6 /* Favorite */, + DB6B74F0272FB55400C70B6E /* Follower */, DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */, DBAE3F812615DDA3004B8251 /* ProfileViewController+UserProvider.swift */, DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */, @@ -2982,6 +3022,7 @@ children = ( DBAE3F672615DD60004B8251 /* UserProvider.swift */, DBAE3F872615DDF4004B8251 /* UserProviderFacade.swift */, + DB6B75012730060700C70B6E /* UserProviderFacade+UITableViewDelegate.swift */, ); path = UserProvider; sourceTree = ""; @@ -3965,6 +4006,7 @@ DB75BF1E263C1C1B00EDBF1F /* CustomScheduler.swift in Sources */, 0FAA102725E1126A0017CCDE /* MastodonPickServerViewController.swift in Sources */, DB59F0FE25EF5D96001F1DAB /* StatusProvider+UITableViewDelegate.swift in Sources */, + DB6B74FE272FF59000C70B6E /* UserItem.swift in Sources */, DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */, DBE3CE07261D6A0E00430CC6 /* FavoriteViewModel+Diffable.swift in Sources */, 2D61335825C188A000CAE157 /* APIService+Persist+Status.swift in Sources */, @@ -4094,6 +4136,9 @@ DB9A486C26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift in Sources */, 5D0393902612D259007FE196 /* WebViewController.swift in Sources */, DB4481CC25EE2AFE00BEFB67 /* PollItem.swift in Sources */, + DB6B74FA272FC2B500C70B6E /* APIService+Follower.swift in Sources */, + DB6B74F4272FBAE700C70B6E /* FollowerListViewModel+Diffable.swift in Sources */, + DB6B74F2272FB67600C70B6E /* FollowerListViewModel.swift in Sources */, DB44767B260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift in Sources */, 0F20222D261457EE000C64BF /* HashtagTimelineViewModel+LoadOldestState.swift in Sources */, DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */, @@ -4106,6 +4151,7 @@ DB35FC1F2612F1D9006193C9 /* ProfileRelationshipActionButton.swift in Sources */, DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */, DB3667A6268AE2620027D07F /* ComposeStatusPollSection.swift in Sources */, + DB6B750427300B4000C70B6E /* TimelineFooterTableViewCell.swift in Sources */, DB59F10E25EF724F001F1DAB /* APIService+Poll.swift in Sources */, DB852D1F26FB037800FC9D81 /* SidebarViewModel.swift in Sources */, DB47229725F9EFAD00DA7F53 /* NSManagedObjectContext.swift in Sources */, @@ -4122,6 +4168,7 @@ DBF156E42702DB3F00EC00B7 /* HandleTapAction.swift in Sources */, DB023295267F0AB800031745 /* ASMetaEditableTextNode.swift in Sources */, 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, + DB6B74F6272FBCDB00C70B6E /* FollowerListViewModel+State.swift in Sources */, DB4F096C269EFA2000D62E92 /* SearchResultViewController+StatusProvider.swift in Sources */, DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */, DB9F58EF26EF491E00E7BBE9 /* AccountListViewModel.swift in Sources */, @@ -4139,6 +4186,7 @@ DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */, DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */, DBB525642612C988002F1F29 /* MeProfileViewModel.swift in Sources */, + DB6B74EF272FB55000C70B6E /* FollowerListViewController.swift in Sources */, 5BB04FE9262EFC300043BFF6 /* ReportedStatusTableviewCell.swift in Sources */, DBAE3F822615DDA3004B8251 /* ProfileViewController+UserProvider.swift in Sources */, DBBC24C426A544B900398BB9 /* Theme.swift in Sources */, @@ -4180,6 +4228,7 @@ DB49A63D25FF609300B98345 /* PlayerContainerView+MediaTypeIndicotorView.swift in Sources */, DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */, DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */, + DB6B75022730060700C70B6E /* UserProviderFacade+UITableViewDelegate.swift in Sources */, DB44384F25E8C1FA008912A2 /* CALayer.swift in Sources */, 2D34D9CB261489930081BFC0 /* SearchViewController+Recommend.swift in Sources */, DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */, @@ -4245,6 +4294,7 @@ DBE54AC62636C89F004E7C0B /* NotificationPreference.swift in Sources */, 2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */, DB98339C25C96DE600AD9700 /* APIService+Account.swift in Sources */, + DB6B74FC272FF55800C70B6E /* UserSection.swift in Sources */, 2DF75BA725D10E1000694EC8 /* APIService+Favorite.swift in Sources */, DB9D6C3825E508BE0051B173 /* Attachment.swift in Sources */, 5DFC35DF262068D20045711D /* SearchViewController+Follow.swift in Sources */, @@ -4261,6 +4311,7 @@ 0F202227261411BB000C64BF /* HashtagTimelineViewController+Provider.swift in Sources */, 2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */, 2D76316525C14BD100929FB9 /* PublicTimelineViewController.swift in Sources */, + DB6B7500272FF73800C70B6E /* UserTableViewCell.swift in Sources */, DB1D842E26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift in Sources */, DB938F1F2624382F00E5B6C1 /* ThreadViewModel+Diffable.swift in Sources */, 2D69CFF425CA9E2200C3A1B2 /* LoadMoreConfigurableTableViewContainer.swift in Sources */, @@ -4291,6 +4342,7 @@ DB647C5726F1E97300F7F82C /* MainTabBarController+Wizard.swift in Sources */, DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */, DBB525412611ED54002F1F29 /* ProfileHeaderViewController.swift in Sources */, + DB6B74F8272FBFB100C70B6E /* FollowerListViewController+Provider.swift in Sources */, DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */, DB4932B326F2054200EF46D4 /* CircleAvatarButton.swift in Sources */, 0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 1e9186391..05869c6aa 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 43 + 35 CoreDataStack.xcscheme_^#shared#^_ orderHint - 42 + 39 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 41 + 36 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 44 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 10d6fb84f..cda20255b 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -178,6 +178,7 @@ extension SceneCoordinator { case accountList case profile(viewModel: ProfileViewModel) case favorite(viewModel: FavoriteViewModel) + case follower(viewModel: FollowerListViewModel) // setting case settings(viewModel: SettingsViewModel) @@ -424,6 +425,10 @@ private extension SceneCoordinator { let _viewController = FavoriteViewController() _viewController.viewModel = viewModel viewController = _viewController + case .follower(let viewModel): + let _viewController = FollowerListViewController() + _viewController.viewModel = viewModel + viewController = _viewController case .suggestionAccount(let viewModel): let _viewController = SuggestionAccountViewController() _viewController.viewModel = viewModel diff --git a/Mastodon/Diffiable/Item/UserItem.swift b/Mastodon/Diffiable/Item/UserItem.swift new file mode 100644 index 000000000..6f3c591b1 --- /dev/null +++ b/Mastodon/Diffiable/Item/UserItem.swift @@ -0,0 +1,15 @@ +// +// UserItem.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import Foundation +import CoreData + +enum UserItem: Hashable { + case follower(objectID: NSManagedObjectID) + case bottomLoader + case bottomHeader(text: String) +} diff --git a/Mastodon/Diffiable/Section/UserSection.swift b/Mastodon/Diffiable/Section/UserSection.swift new file mode 100644 index 000000000..58e80c6e3 --- /dev/null +++ b/Mastodon/Diffiable/Section/UserSection.swift @@ -0,0 +1,63 @@ +// +// UserSection.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import os.log +import UIKit +import CoreData +import CoreDataStack +import MetaTextKit +import MastodonMeta + +enum UserSection: Hashable { + case main +} + +extension UserSection { + + static let logger = Logger(subsystem: "StatusSection", category: "logic") + + static func tableViewDiffableDataSource( + for tableView: UITableView, + dependency: NeedsDependency, + managedObjectContext: NSManagedObjectContext + ) -> UITableViewDiffableDataSource { + UITableViewDiffableDataSource(tableView: tableView) { [ + weak dependency + ] tableView, indexPath, item -> UITableViewCell? in + guard let dependency = dependency else { return UITableViewCell() } + switch item { + case .follower(let objectID): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell + managedObjectContext.performAndWait { + let user = managedObjectContext.object(with: objectID) as! MastodonUser + configure(cell: cell, user: user) + } + return cell + case .bottomLoader: + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell + cell.startAnimating() + return cell + case .bottomHeader(let text): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineFooterTableViewCell.self), for: indexPath) as! TimelineFooterTableViewCell + cell.messageLabel.text = text + return cell + } // end switch + } // end UITableViewDiffableDataSource + } // end static func tableViewDiffableDataSource { … } + +} + +extension UserSection { + + static func configure( + cell: UserTableViewCell, + user: MastodonUser + ) { + cell.configure(user: user) + } + +} diff --git a/Mastodon/Protocol/UserProvider/UserProviderFacade+UITableViewDelegate.swift b/Mastodon/Protocol/UserProvider/UserProviderFacade+UITableViewDelegate.swift new file mode 100644 index 000000000..a6e3cf215 --- /dev/null +++ b/Mastodon/Protocol/UserProvider/UserProviderFacade+UITableViewDelegate.swift @@ -0,0 +1,22 @@ +// +// UserProviderFacade+UITableViewDelegate.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import Combine +import CoreDataStack +import MastodonSDK +import os.log +import UIKit + +extension UserTableViewCellDelegate where Self: UserProvider { + + func handleTableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + guard let cell = tableView.cellForRow(at: indexPath) else { return } + let user = self.mastodonUser(for: cell) + UserProviderFacade.coordinatorToUserProfileScene(provider: self, user: user) + } + +} diff --git a/Mastodon/Protocol/UserProvider/UserProviderFacade.swift b/Mastodon/Protocol/UserProvider/UserProviderFacade.swift index f85881943..edbe311c7 100644 --- a/Mastodon/Protocol/UserProvider/UserProviderFacade.swift +++ b/Mastodon/Protocol/UserProvider/UserProviderFacade.swift @@ -440,3 +440,25 @@ extension UserProviderFacade { return activityViewController } } + +extension UserProviderFacade { + static func coordinatorToUserProfileScene(provider: UserProvider, user: Future) { + user + .sink { [weak provider] mastodonUser in + guard let provider = provider else { return } + guard let mastodonUser = mastodonUser else { return } + let profileViewModel = CachedProfileViewModel(context: provider.context, mastodonUser: mastodonUser) + DispatchQueue.main.async { + if provider.navigationController == nil { + let from = provider.presentingViewController ?? provider + provider.dismiss(animated: true) { + provider.coordinator.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show) + } + } else { + provider.coordinator.present(scene: .profile(viewModel: profileViewModel), from: provider, transition: .show) + } + } + } + .store(in: &provider.disposeBag) + } +} diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift new file mode 100644 index 000000000..627ed7772 --- /dev/null +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift @@ -0,0 +1,50 @@ +// +// FollowerListViewController+Provider.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import os.log +import UIKit +import Combine +import CoreData +import CoreDataStack + +extension FollowerListViewController: UserProvider { + + func mastodonUser() -> Future { + Future { promise in + promise(.success(nil)) + } + } + + func mastodonUser(for cell: UITableViewCell?) -> Future { + Future { [weak self] promise in + guard let self = self else { return } + guard let diffableDataSource = self.viewModel.diffableDataSource else { + assertionFailure() + promise(.success(nil)) + return + } + guard let cell = cell, + let indexPath = self.tableView.indexPath(for: cell), + let item = diffableDataSource.itemIdentifier(for: indexPath) else { + promise(.success(nil)) + return + } + + let managedObjectContext = self.viewModel.userFetchedResultsController.fetchedResultsController.managedObjectContext + + switch item { + case .follower(let objectID): + managedObjectContext.perform { + let user = managedObjectContext.object(with: objectID) as? MastodonUser + promise(.success(user)) + } + case .bottomLoader, .bottomHeader: + promise(.success(nil)) + } + } + } +} diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift new file mode 100644 index 000000000..428448666 --- /dev/null +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift @@ -0,0 +1,111 @@ +// +// FollowerListViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import os.log +import UIKit +import AVKit +import GameplayKit +import Combine + +final class FollowerListViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + var disposeBag = Set() + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var viewModel: FollowerListViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.register(UserTableViewCell.self, forCellReuseIdentifier: String(describing: UserTableViewCell.self)) + tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) + tableView.register(TimelineFooterTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineFooterTableViewCell.self)) + tableView.rowHeight = UITableView.automaticDimension + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension FollowerListViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: RunLoop.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + 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.delegate = self + viewModel.setupDiffableDataSource( + for: tableView, + dependency: self + ) + // TODO: add UserTableViewCellDelegate + + // trigger user timeline loading + Publishers.CombineLatest( + viewModel.domain.removeDuplicates().eraseToAnyPublisher(), + viewModel.userID.removeDuplicates().eraseToAnyPublisher() + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.viewModel.stateMachine.enter(FollowerListViewModel.State.Reloading.self) + } + .store(in: &disposeBag) + } + +} + +// MARK: - LoadMoreConfigurableTableViewContainer +extension FollowerListViewController: LoadMoreConfigurableTableViewContainer { + typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell + typealias LoadingState = FollowerListViewModel.State.Loading + var loadMoreConfigurableTableView: UITableView { tableView } + var loadMoreConfigurableStateMachine: GKStateMachine { viewModel.stateMachine } +} + +// MARK: - UIScrollViewDelegate +extension FollowerListViewController { + func scrollViewDidScroll(_ scrollView: UIScrollView) { + handleScrollViewDidScroll(scrollView) + } +} + + +// MARK: - UITableViewDelegate +extension FollowerListViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + handleTableView(tableView, didSelectRowAt: indexPath) + } +} + +// MARK: - UserTableViewCellDelegate +extension FollowerListViewController: UserTableViewCellDelegate { } diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift new file mode 100644 index 000000000..90b9cb311 --- /dev/null +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift @@ -0,0 +1,58 @@ +// +// FollowerListViewModel+Diffable.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import UIKit + +extension FollowerListViewModel { + func setupDiffableDataSource( + for tableView: UITableView, + dependency: NeedsDependency + ) { + diffableDataSource = UserSection.tableViewDiffableDataSource( + for: tableView, + dependency: dependency, + managedObjectContext: userFetchedResultsController.fetchedResultsController.managedObjectContext + ) + + // set empty section to make update animation top-to-bottom style + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + diffableDataSource?.apply(snapshot) + + // workaround to append loader wrong animation issue + snapshot.appendItems([.bottomLoader], toSection: .main) + diffableDataSource?.apply(snapshot) + + userFetchedResultsController.objectIDs.removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak self] objectIDs in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + let items: [UserItem] = objectIDs.map { + UserItem.follower(objectID: $0) + } + snapshot.appendItems(items, toSection: .main) + + if let currentState = self.stateMachine.currentState { + switch currentState { + case is State.Idle, is State.Loading, is State.Fail: + snapshot.appendItems([.bottomLoader], toSection: .main) + case is State.NoMore: + break + default: + break + } + } + + diffableDataSource.apply(snapshot) + } + .store(in: &disposeBag) + } +} diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift new file mode 100644 index 000000000..b012a59bb --- /dev/null +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift @@ -0,0 +1,196 @@ +// +// FollowerListViewModel+State.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import os.log +import Foundation +import GameplayKit +import MastodonSDK + +extension FollowerListViewModel { + class State: GKState { + weak var viewModel: FollowerListViewModel? + + init(viewModel: FollowerListViewModel) { + self.viewModel = viewModel + } + + override func didEnter(from previousState: GKState?) { + os_log("%{public}s[%{public}ld], %{public}s: enter %s, previous: %s", ((#file as NSString).lastPathComponent), #line, #function, self.debugDescription, previousState.debugDescription) + } + } +} + +extension FollowerListViewModel.State { + class Initial: FollowerListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + guard let viewModel = viewModel else { return false } + switch stateClass { + case is Reloading.Type: + return viewModel.userID.value != nil + default: + return false + } + } + } + + class Reloading: FollowerListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + // reset + viewModel.userFetchedResultsController.userIDs.value = [] + + stateMachine.enter(Loading.self) + } + } + + class Fail: FollowerListViewModel.State { + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading 3s later…", ((#file as NSString).lastPathComponent), #line, #function) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading", ((#file as NSString).lastPathComponent), #line, #function) + stateMachine.enter(Loading.self) + } + } + } + + class Idle: FollowerListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type, is Loading.Type: + return true + default: + return false + } + } + } + + class Loading: FollowerListViewModel.State { + + var maxID: String? + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + + if previousState is Reloading { + maxID = nil + } + + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + guard let userID = viewModel.userID.value, !userID.isEmpty else { + stateMachine.enter(Fail.self) + return + } + + guard let activeMastodonAuthenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { + stateMachine.enter(Fail.self) + return + } + + viewModel.context.apiService.followers( + userID: userID, + maxID: maxID, + authorizationBox: activeMastodonAuthenticationBox + ) + .receive(on: DispatchQueue.main) + .sink { completion in + switch completion { + case .failure(let error): + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch user timeline fail: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription) + stateMachine.enter(Fail.self) + case .finished: + break + } + } receiveValue: { response in + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + + var hasNewAppend = false + var userIDs = viewModel.userFetchedResultsController.userIDs.value + for user in response.value { + guard !userIDs.contains(user.id) else { continue } + userIDs.append(user.id) + hasNewAppend = true + } + + let maxID = response.link?.maxID + + if hasNewAppend, maxID != nil { + stateMachine.enter(Idle.self) + } else { + stateMachine.enter(NoMore.self) + } + self.maxID = maxID + viewModel.userFetchedResultsController.userIDs.value = userIDs + } + .store(in: &viewModel.disposeBag) + } // end func didEnter + } + + class NoMore: FollowerListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let _ = stateMachine else { return } + guard let diffableDataSource = viewModel.diffableDataSource else { + assertionFailure() + return + } + DispatchQueue.main.async { + var snapshot = diffableDataSource.snapshot() + snapshot.deleteItems([.bottomLoader]) + let header = UserItem.bottomHeader(text: "Followers from other servers are not displayed") + snapshot.appendItems([header], toSection: .main) + diffableDataSource.apply(snapshot, animatingDifferences: false) + } + } + } +} diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift new file mode 100644 index 000000000..f62441cf1 --- /dev/null +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift @@ -0,0 +1,53 @@ +// +// FollowerListViewModel.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import Foundation +import Combine +import Combine +import CoreData +import CoreDataStack +import GameplayKit +import MastodonSDK + +final class FollowerListViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let domain: CurrentValueSubject + let userID: CurrentValueSubject + let userFetchedResultsController: UserFetchedResultsController + + // output + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + init(context: AppContext, domain: String?, userID: String?) { + self.context = context + self.userFetchedResultsController = UserFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: domain, + additionalTweetPredicate: nil + ) + self.domain = CurrentValueSubject(domain) + self.userID = CurrentValueSubject(userID) + // super.init() + + } +} diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift index 90f2e7a11..016b31a1e 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift @@ -17,9 +17,7 @@ protocol ProfileHeaderViewDelegate: AnyObject { func profileHeaderView(_ profileHeaderView: ProfileHeaderView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) func profileHeaderView(_ profileHeaderView: ProfileHeaderView, metaTextView: MetaTextView, metaDidPressed meta: Meta) - func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) - func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, followingDashboardMeterViewDidPressed followingDashboardMeterView: ProfileStatusDashboardMeterView) - func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, followersDashboardMeterViewDidPressed followersDashboardMeterView: ProfileStatusDashboardMeterView) + func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView dashboardView: ProfileStatusDashboardView, dashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView, meter: ProfileStatusDashboardView.Meter) } final class ProfileHeaderView: UIView { @@ -443,6 +441,7 @@ extension ProfileHeaderView { bringSubviewToFront(bannerContainerView) bringSubviewToFront(nameContainerStackView) + statusDashboardView.delegate = self bioMetaText.textView.delegate = self bioMetaText.textView.linkDelegate = self @@ -549,19 +548,9 @@ extension ProfileHeaderView: MetaTextViewDelegate { // MARK: - ProfileStatusDashboardViewDelegate extension ProfileHeaderView: ProfileStatusDashboardViewDelegate { - - func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) { - delegate?.profileHeaderView(self, profileStatusDashboardView: dashboardView, postDashboardMeterViewDidPressed: dashboardMeterView) + func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, dashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView, meter: ProfileStatusDashboardView.Meter) { + delegate?.profileHeaderView(self, profileStatusDashboardView: dashboardView, dashboardMeterViewDidPressed: dashboardMeterView, meter: meter) } - - func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, followingDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) { - delegate?.profileHeaderView(self, profileStatusDashboardView: dashboardView, followingDashboardMeterViewDidPressed: dashboardMeterView) - } - - func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, followersDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) { - delegate?.profileHeaderView(self, profileStatusDashboardView: dashboardView, followersDashboardMeterViewDidPressed: dashboardMeterView) - } - } // MARK: - AvatarConfigurableView diff --git a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift b/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift index 0360421a8..c21703c08 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift @@ -9,9 +9,7 @@ import os.log import UIKit protocol ProfileStatusDashboardViewDelegate: AnyObject { - func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) - func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, followingDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) - func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, followersDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) + func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, dashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView, meter: ProfileStatusDashboardView.Meter) } final class ProfileStatusDashboardView: UIView { @@ -34,6 +32,14 @@ final class ProfileStatusDashboardView: UIView { } +extension ProfileStatusDashboardView { + enum Meter: Hashable { + case post + case following + case follower + } +} + extension ProfileStatusDashboardView { private func _init() { let containerStackView = UIStackView() @@ -67,7 +73,6 @@ extension ProfileStatusDashboardView { tapGestureRecognizer.addTarget(self, action: #selector(ProfileStatusDashboardView.tapGestureRecognizerHandler(_:))) meterView.addGestureRecognizer(tapGestureRecognizer) } - } } @@ -78,12 +83,15 @@ extension ProfileStatusDashboardView { assertionFailure() return } - if sourceView === postDashboardMeterView { - delegate?.profileStatusDashboardView(self, postDashboardMeterViewDidPressed: sourceView) - } else if sourceView === followingDashboardMeterView { - delegate?.profileStatusDashboardView(self, followingDashboardMeterViewDidPressed: sourceView) - } else if sourceView === followersDashboardMeterView { - delegate?.profileStatusDashboardView(self, followersDashboardMeterViewDidPressed: sourceView) + switch sourceView { + case postDashboardMeterView: + delegate?.profileStatusDashboardView(self, dashboardMeterViewDidPressed: sourceView, meter: .post) + case followingDashboardMeterView: + delegate?.profileStatusDashboardView(self, dashboardMeterViewDidPressed: sourceView, meter: .following) + case followersDashboardMeterView: + delegate?.profileStatusDashboardView(self, dashboardMeterViewDidPressed: sourceView, meter: .follower) + default: + assertionFailure() } } } diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index b864fc94c..04d582315 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -769,7 +769,6 @@ extension ProfileViewController: ProfilePagingViewControllerDelegate { // MARK: - ProfileHeaderViewDelegate extension ProfileViewController: ProfileHeaderViewDelegate { - func profileHeaderView(_ profileHeaderView: ProfileHeaderView, avatarImageViewDidPressed imageView: UIImageView) { guard let mastodonUser = viewModel.mastodonUser.value else { return } guard let avatar = imageView.image else { return } @@ -982,15 +981,29 @@ extension ProfileViewController: ProfileHeaderViewDelegate { } } - func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) { - - } - - func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, followingDashboardMeterViewDidPressed followingDashboardMeterView: ProfileStatusDashboardMeterView) { - - } - - func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, followersDashboardMeterViewDidPressed followersDashboardMeterView: ProfileStatusDashboardMeterView) { + func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView dashboardView: ProfileStatusDashboardView, dashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView, meter: ProfileStatusDashboardView.Meter) { + switch meter { + case .post: + // do nothing + break + case .follower: + guard let domain = viewModel.domain.value, + let userID = viewModel.userID.value + else { return } + let followerListViewModel = FollowerListViewModel( + context: context, + domain: domain, + userID: userID + ) + coordinator.present( + scene: .follower(viewModel: followerListViewModel), + from: self, + transition: .show + ) + case .following: + // TODO: + break + } } } diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift index f3803da01..42e9376cf 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift @@ -12,7 +12,6 @@ import Combine import CoreDataStack import GameplayKit -// TODO: adopt MediaPreviewableViewController final class UserTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } diff --git a/Mastodon/Scene/Share/View/TableviewCell/TimelineFooterTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/TimelineFooterTableViewCell.swift new file mode 100644 index 000000000..43dd2c6fa --- /dev/null +++ b/Mastodon/Scene/Share/View/TableviewCell/TimelineFooterTableViewCell.swift @@ -0,0 +1,51 @@ +// +// TimelineFooterTableViewCell.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import UIKit + +final class TimelineFooterTableViewCell: UITableViewCell { + + let messageLabel: UILabel = { + let label = UILabel() + label.font = .systemFont(ofSize: 17) + label.textAlignment = .center + label.textColor = Asset.Colors.Label.secondary.color + label.text = "info" + label.numberOfLines = 0 + 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 TimelineFooterTableViewCell { + + private func _init() { + selectionStyle = .none + backgroundColor = .clear + + messageLabel.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(messageLabel) + NSLayoutConstraint.activate([ + messageLabel.topAnchor.constraint(equalTo: contentView.topAnchor), + messageLabel.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + messageLabel.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), + messageLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + messageLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 68).priority(.required - 1), // same height to bottom loader + ]) + } + +} diff --git a/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell.swift new file mode 100644 index 000000000..29e28415e --- /dev/null +++ b/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell.swift @@ -0,0 +1,131 @@ +// +// UserTableViewCell.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import CoreData +import CoreDataStack +import MastodonSDK +import UIKit +import MetaTextKit +import MastodonMeta +import FLAnimatedImage + +protocol UserTableViewCellDelegate: AnyObject { } + +final class UserTableViewCell: UITableViewCell { + + weak var delegate: UserTableViewCellDelegate? + + let avatarImageView: AvatarImageView = { + let imageView = AvatarImageView() + imageView.tintColor = Asset.Colors.Label.primary.color + imageView.layer.cornerRadius = 4 + imageView.clipsToBounds = true + return imageView + }() + + let nameLabel = MetaLabel(style: .statusName) + + let usernameLabel: UILabel = { + let label = UILabel() + label.textColor = Asset.Colors.Label.secondary.color + label.font = .preferredFont(forTextStyle: .body) + return label + }() + + let separatorLine = UIView.separatorLine + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension UserTableViewCell { + + private func _init() { + let containerStackView = UIStackView() + containerStackView.axis = .horizontal + containerStackView.distribution = .fill + containerStackView.spacing = 12 + containerStackView.layoutMargins = UIEdgeInsets(top: 12, left: 0, bottom: 12, right: 0) + containerStackView.isLayoutMarginsRelativeArrangement = true + containerStackView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(containerStackView) + NSLayoutConstraint.activate([ + containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor), + containerStackView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + containerStackView.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), + containerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) + ]) + + avatarImageView.translatesAutoresizingMaskIntoConstraints = false + containerStackView.addArrangedSubview(avatarImageView) + NSLayoutConstraint.activate([ + avatarImageView.widthAnchor.constraint(equalToConstant: 42).priority(.required - 1), + avatarImageView.heightAnchor.constraint(equalToConstant: 42).priority(.required - 1), + ]) + + let textStackView = UIStackView() + textStackView.axis = .vertical + textStackView.distribution = .fill + textStackView.translatesAutoresizingMaskIntoConstraints = false + nameLabel.translatesAutoresizingMaskIntoConstraints = false + textStackView.addArrangedSubview(nameLabel) + usernameLabel.translatesAutoresizingMaskIntoConstraints = false + textStackView.addArrangedSubview(usernameLabel) + usernameLabel.setContentHuggingPriority(.defaultLow - 1, for: .vertical) + + containerStackView.addArrangedSubview(textStackView) + + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + + + nameLabel.isUserInteractionEnabled = false + usernameLabel.isUserInteractionEnabled = false + avatarImageView.isUserInteractionEnabled = false + } + +} + +// MARK: - AvatarStackedImageView +extension UserTableViewCell: AvatarConfigurableView { + static var configurableAvatarImageSize: CGSize { CGSize(width: 42, height: 42) } + static var configurableAvatarImageCornerRadius: CGFloat { 4 } + var configurableAvatarImageView: FLAnimatedImageView? { avatarImageView } +} + +extension UserTableViewCell { + func configure(user: MastodonUser) { + // avatar + configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: user.avatarImageURL())) + // name + let name = user.displayNameWithFallback + do { + let mastodonContent = MastodonContent(content: name, emojis: user.emojiMeta) + let metaContent = try MastodonMetaContent.convert(document: mastodonContent) + nameLabel.configure(content: metaContent) + } catch { + let metaContent = PlaintextMetaContent(string: name) + nameLabel.configure(content: metaContent) + } + // username + usernameLabel.text = "@" + user.acct + } +} diff --git a/Mastodon/Service/APIService/APIService+Follower.swift b/Mastodon/Service/APIService/APIService+Follower.swift new file mode 100644 index 000000000..db29a0a29 --- /dev/null +++ b/Mastodon/Service/APIService/APIService+Follower.swift @@ -0,0 +1,65 @@ +// +// APIService+Follower.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import UIKit +import Combine +import CoreData +import CoreDataStack +import CommonOSLog +import MastodonSDK + +extension APIService { + + func followers( + userID: Mastodon.Entity.Account.ID, + maxID: String?, + authorizationBox: MastodonAuthenticationBox + ) -> AnyPublisher, Error> { + let domain = authorizationBox.domain + let authorization = authorizationBox.userAuthorization + let requestMastodonUserID = authorizationBox.userID + + return Mastodon.API.Account.followers( + session: session, + domain: domain, + userID: userID, + authorization: authorization + ) + .flatMap { response -> AnyPublisher, Error> in + let managedObjectContext = self.backgroundManagedObjectContext + return managedObjectContext.performChanges { + let requestMastodonUserRequest = MastodonUser.sortedFetchRequest + requestMastodonUserRequest.predicate = MastodonUser.predicate(domain: domain, id: requestMastodonUserID) + requestMastodonUserRequest.fetchLimit = 1 + guard let requestMastodonUser = managedObjectContext.safeFetch(requestMastodonUserRequest).first else { return } + + for entity in response.value { + _ = APIService.CoreData.createOrMergeMastodonUser( + into: managedObjectContext, + for: requestMastodonUser, + in: domain, + entity: entity, + userCache: nil, + networkDate: response.networkDate, + log: .api + ) + } + } + .tryMap { result -> Mastodon.Response.Content<[Mastodon.Entity.Account]> in + switch result { + case .success: + return response + case .failure(let error): + throw error + } + } + .eraseToAnyPublisher() + } + .eraseToAnyPublisher() + } + +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+FollowRequest.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+FollowRequest.swift index 87c879ea0..7adbcdeff 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+FollowRequest.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+FollowRequest.swift @@ -12,13 +12,15 @@ import Combine extension Mastodon.API.Account { static func acceptFollowRequestEndpointURL(domain: String, userID: Mastodon.Entity.Account.ID) -> URL { - return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("follow_requests") + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("follow_requests") .appendingPathComponent(userID) .appendingPathComponent("authorize") } static func rejectFollowRequestEndpointURL(domain: String, userID: Mastodon.Entity.Account.ID) -> URL { - return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("follow_requests") + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("follow_requests") .appendingPathComponent(userID) .appendingPathComponent("reject") } diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift new file mode 100644 index 000000000..b09a5f07b --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift @@ -0,0 +1,81 @@ +// +// Mastodon+API+Account+Followers.swift +// +// +// Created by Cirno MainasuK on 2021-11-1. +// + +import Foundation +import Combine + +extension Mastodon.API.Account { + + static func followersEndpointURL(domain: String, userID: Mastodon.Entity.Account.ID) -> URL { + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("accounts") + .appendingPathComponent(userID) + .appendingPathComponent("followers") + } + + /// Followers + /// + /// Accounts which follow the given account, if network is not hidden by the account owner. + /// + /// - Since: 0.0.0 + /// - Version: 3.4.1 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/accounts/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - userID: ID of the account in the database + /// - authorization: User token + /// - Returns: `AnyPublisher` contains `[Account]` nested in the response + public static func followers( + session: URLSession, + domain: String, + userID: Mastodon.Entity.Account.ID, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: followersEndpointURL(domain: domain, userID: userID), + query: nil, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Account].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + public struct FollowerQuery: Codable, GetQuery { + + public let maxID: String? + public let limit: Int? // default 40 + + enum CodingKeys: String, CodingKey { + case maxID = "max_id" + case limit + } + + public init( + maxID: String?, + limit: Int? + ) { + self.maxID = maxID + self.limit = limit + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + maxID.flatMap { items.append(URLQueryItem(name: "max_id", value: $0)) } + limit.flatMap { items.append(URLQueryItem(name: "limit", value: String($0))) } + guard !items.isEmpty else { return nil } + return items + } + + } + +} From 14236c27b8c58791e2cfc34d8ecbc2ed66aa22af Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 1 Nov 2021 20:09:30 +0800 Subject: [PATCH 306/392] feat: coordinator sidebar search tab to trigger searching --- .../Root/ContentSplitViewController.swift | 19 ++++----- .../Scene/Root/RootSplitViewController.swift | 39 ++++++++++++++++++- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 577f8d6a4..850b1429f 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -10,6 +10,10 @@ import UIKit import Combine import CoreDataStack +protocol ContentSplitViewControllerDelegate: AnyObject { + func contentSplitViewController(_ contentSplitViewController: ContentSplitViewController, sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) +} + final class ContentSplitViewController: UIViewController, NeedsDependency { var disposeBag = Set() @@ -19,6 +23,8 @@ final class ContentSplitViewController: UIViewController, NeedsDependency { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + weak var delegate: ContentSplitViewControllerDelegate? + private(set) lazy var sidebarViewController: SidebarViewController = { let sidebarViewController = SidebarViewController() sidebarViewController.context = context @@ -87,18 +93,7 @@ extension ContentSplitViewController { extension ContentSplitViewController: SidebarViewControllerDelegate { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) { - guard let _ = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { - assertionFailure() - return - } - let previousTab = currentSupplementaryTab - currentSupplementaryTab = tab - - if previousTab == tab, - let navigationController = mainTabBarController.selectedViewController as? UINavigationController - { - navigationController.popToRootViewController(animated: true) - } + delegate?.contentSplitViewController(self, sidebarViewController: sidebarViewController, didSelectTab: tab) } func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView) { diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 22354751d..7c03287f1 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -23,6 +23,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { let contentSplitViewController = ContentSplitViewController() contentSplitViewController.context = context contentSplitViewController.coordinator = coordinator + contentSplitViewController.delegate = self return contentSplitViewController }() @@ -131,6 +132,36 @@ extension RootSplitViewController { } +// MARK: - ContentSplitViewControllerDelegate +extension RootSplitViewController: ContentSplitViewControllerDelegate { + func contentSplitViewController(_ contentSplitViewController: ContentSplitViewController, sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) { + guard let _ = MainTabBarController.Tab.allCases.firstIndex(of: tab) else { + assertionFailure() + return + } + switch tab { + case .search: + guard let navigationController = searchViewController.navigationController else { return } + if navigationController.viewControllers.count == 1 { + searchViewController.searchBarTapPublisher.send() + } else { + navigationController.popToRootViewController(animated: true) + } + + default: + let previousTab = contentSplitViewController.currentSupplementaryTab + contentSplitViewController.currentSupplementaryTab = tab + + if previousTab == tab, + let navigationController = contentSplitViewController.mainTabBarController.selectedViewController as? UINavigationController + { + navigationController.popToRootViewController(animated: true) + } + + } + } +} + // MARK: - UISplitViewControllerDelegate extension RootSplitViewController: UISplitViewControllerDelegate { @@ -180,7 +211,13 @@ extension RootSplitViewController: UISplitViewControllerDelegate { } RootSplitViewController.transform(from: compactMainTabBarViewController, to: contentSplitViewController.mainTabBarController) - contentSplitViewController.currentSupplementaryTab = compactMainTabBarViewController.currentTab.value + + let tab = compactMainTabBarViewController.currentTab.value + if tab == .search { + contentSplitViewController.currentSupplementaryTab = .home + } else { + contentSplitViewController.currentSupplementaryTab = compactMainTabBarViewController.currentTab.value + } return proposedDisplayMode } From 0eba513d5c57e44b29e0123bd42dcdcb2c292f7e Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 1 Nov 2021 20:11:18 +0800 Subject: [PATCH 307/392] chore: update version to 1.2.0 (82) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 9da0855b7..16c084cec 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 9da0855b7..16c084cec 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 9da0855b7..16c084cec 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 11914fe75..60f0f5d74 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4863,7 +4863,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4892,7 +4892,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5000,11 +5000,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5031,11 +5031,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5060,11 +5060,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5090,11 +5090,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5157,7 +5157,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5182,7 +5182,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5207,7 +5207,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5232,7 +5232,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5257,7 +5257,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5282,7 +5282,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5307,7 +5307,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5332,7 +5332,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5423,7 +5423,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5490,11 +5490,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5539,7 +5539,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5564,11 +5564,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5660,7 +5660,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5727,11 +5727,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5776,7 +5776,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5801,11 +5801,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 81; + DYLIB_CURRENT_VERSION = 82; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5831,7 +5831,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5855,7 +5855,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 81; + CURRENT_PROJECT_VERSION = 82; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 05869c6aa..cb88c3960 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 35 + 42 CoreDataStack.xcscheme_^#shared#^_ orderHint - 39 + 43 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 36 + 44 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 41 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index dc3e86199..a75982e39 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 81 + 82 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 6fabe37eb..ed243297d 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 9da0855b7..16c084cec 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 9da0855b7..16c084cec 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 43c0dff37..89e562534 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 73d43d819..79ba82cef 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 81 + 82 NSExtension NSExtensionAttributes From 86d475fe5658fd37592ddad045d2c3e4b29dc148 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 1 Nov 2021 20:14:26 +0800 Subject: [PATCH 308/392] feat: add i18n string for follower/following list footer --- Localization/app.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Localization/app.json b/Localization/app.json index 3d0e36d03..5c01ae7e0 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -414,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 4f531a72d12369e0ebfc66f41d574641916156b9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:12 +0100 Subject: [PATCH 309/392] New translations app.json (Kurmanji (Kurdish)) --- Localization/StringsConvertor/input/kmr_TR/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 5330ea480..4fdfd0e7d 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -67,6 +67,7 @@ "done": "Qediya", "confirm": "Bipejirîne", "continue": "Bidomîne", + "compose": "Compose", "cancel": "Dev jê berde", "discard": "Biavêje", "try_again": "Dîsa biceribîne", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Bigere", "search_bar": { From 9ffa6a2e6717f0887a4fe8ba0e8da8acb180cfce Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:13 +0100 Subject: [PATCH 310/392] New translations app.json (Russian) --- Localization/StringsConvertor/input/ru_RU/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/ru_RU/app.json b/Localization/StringsConvertor/input/ru_RU/app.json index a5c34023a..c1ad3ee49 100644 --- a/Localization/StringsConvertor/input/ru_RU/app.json +++ b/Localization/StringsConvertor/input/ru_RU/app.json @@ -67,6 +67,7 @@ "done": "Готово", "confirm": "Подтвердить", "continue": "Продолжить", + "compose": "Compose", "cancel": "Отмена", "discard": "Отмена", "try_again": "Попробовать снова", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Поиск", "search_bar": { From 9d265d9a18a091394ca43f2659df2fa78009d656 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:14 +0100 Subject: [PATCH 311/392] New translations app.json (Welsh) --- Localization/StringsConvertor/input/cy_GB/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/cy_GB/app.json b/Localization/StringsConvertor/input/cy_GB/app.json index 3ec77cf10..5c01ae7e0 100644 --- a/Localization/StringsConvertor/input/cy_GB/app.json +++ b/Localization/StringsConvertor/input/cy_GB/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 88909303360557a3f9908ddfe418a65e70568c66 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:15 +0100 Subject: [PATCH 312/392] New translations app.json (Hindi) --- Localization/StringsConvertor/input/hi_IN/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/hi_IN/app.json b/Localization/StringsConvertor/input/hi_IN/app.json index 3ec77cf10..5c01ae7e0 100644 --- a/Localization/StringsConvertor/input/hi_IN/app.json +++ b/Localization/StringsConvertor/input/hi_IN/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From ede66ab8575014376d52c93e6a97e978b1292e35 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:16 +0100 Subject: [PATCH 313/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index fb3024f2b..f9e56214c 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -67,6 +67,7 @@ "done": "เสร็จสิ้น", "confirm": "ยืนยัน", "continue": "ดำเนินการต่อ", + "compose": "Compose", "cancel": "ยกเลิก", "discard": "ละทิ้ง", "try_again": "ลองอีกครั้ง", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "ค้นหา", "search_bar": { From bf556d6e674c135ba291cfba35fb5894932d81c7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:17 +0100 Subject: [PATCH 314/392] New translations app.json (Spanish, Argentina) --- Localization/StringsConvertor/input/es_AR/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index 4ae708521..c0c884e24 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -67,6 +67,7 @@ "done": "Listo", "confirm": "Confirmar", "continue": "Continuar", + "compose": "Compose", "cancel": "Cancelar", "discard": "Descartar", "try_again": "Intentá de nuevo", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Buscar", "search_bar": { From 9644a2332925756799601122b0643632151d3903 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:18 +0100 Subject: [PATCH 315/392] New translations app.json (Indonesian) --- Localization/StringsConvertor/input/id_ID/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/id_ID/app.json b/Localization/StringsConvertor/input/id_ID/app.json index 6ba29ad8f..6f3171254 100644 --- a/Localization/StringsConvertor/input/id_ID/app.json +++ b/Localization/StringsConvertor/input/id_ID/app.json @@ -67,6 +67,7 @@ "done": "Selesai", "confirm": "Konfirmasi", "continue": "Lanjut", + "compose": "Compose", "cancel": "Batal", "discard": "Discard", "try_again": "Coba Lagi", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Cari", "search_bar": { From f983162838b7cc16cebe44529da3f521fb3f2d36 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:19 +0100 Subject: [PATCH 316/392] New translations app.json (Portuguese, Brazilian) --- Localization/StringsConvertor/input/pt_BR/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_BR/app.json b/Localization/StringsConvertor/input/pt_BR/app.json index 3ec77cf10..5c01ae7e0 100644 --- a/Localization/StringsConvertor/input/pt_BR/app.json +++ b/Localization/StringsConvertor/input/pt_BR/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 157721384630e73ecbcebd18ce1107da9c905f85 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:20 +0100 Subject: [PATCH 317/392] New translations app.json (English) --- Localization/StringsConvertor/input/en_US/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/en_US/app.json b/Localization/StringsConvertor/input/en_US/app.json index 3ec77cf10..5c01ae7e0 100644 --- a/Localization/StringsConvertor/input/en_US/app.json +++ b/Localization/StringsConvertor/input/en_US/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 78e0b170d0713d79ceb146caf85b2aad87af617e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:21 +0100 Subject: [PATCH 318/392] New translations app.json (Chinese Traditional) --- Localization/StringsConvertor/input/zh_TW/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_TW/app.json b/Localization/StringsConvertor/input/zh_TW/app.json index 3ec77cf10..5c01ae7e0 100644 --- a/Localization/StringsConvertor/input/zh_TW/app.json +++ b/Localization/StringsConvertor/input/zh_TW/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 5fca21c7d9e3f262b11a44946c282c519f3b90d9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:22 +0100 Subject: [PATCH 319/392] New translations app.json (Chinese Simplified) --- Localization/StringsConvertor/input/zh_CN/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index b7728b60c..b3a8866bb 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -67,6 +67,7 @@ "done": "完成", "confirm": "确认", "continue": "继续", + "compose": "Compose", "cancel": "取消", "discard": "放弃", "try_again": "再试一次", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "搜索", "search_bar": { From 627c2b4999f039aa9b07094ee47ff923ac44c5ed Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:23 +0100 Subject: [PATCH 320/392] New translations app.json (Swedish) --- Localization/StringsConvertor/input/sv_SE/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_SE/app.json b/Localization/StringsConvertor/input/sv_SE/app.json index d0a9ad795..7acf48755 100644 --- a/Localization/StringsConvertor/input/sv_SE/app.json +++ b/Localization/StringsConvertor/input/sv_SE/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Fortsätt", + "compose": "Compose", "cancel": "Avbryt", "discard": "Discard", "try_again": "Försök igen", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 05ec22990e0632fa3345582ab9b6463635391407 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:24 +0100 Subject: [PATCH 321/392] New translations app.json (Portuguese) --- Localization/StringsConvertor/input/pt_PT/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_PT/app.json b/Localization/StringsConvertor/input/pt_PT/app.json index 3ec77cf10..5c01ae7e0 100644 --- a/Localization/StringsConvertor/input/pt_PT/app.json +++ b/Localization/StringsConvertor/input/pt_PT/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From b85bfb65d3d418de32763737b63870daa840ad75 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:25 +0100 Subject: [PATCH 322/392] New translations app.json (Japanese) --- Localization/StringsConvertor/input/ja_JP/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/ja_JP/app.json b/Localization/StringsConvertor/input/ja_JP/app.json index 1c7d408f5..417ca3e3a 100644 --- a/Localization/StringsConvertor/input/ja_JP/app.json +++ b/Localization/StringsConvertor/input/ja_JP/app.json @@ -67,6 +67,7 @@ "done": "完了", "confirm": "確認", "continue": "続ける", + "compose": "Compose", "cancel": "キャンセル", "discard": "破棄", "try_again": "再実行", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "検索", "search_bar": { From e4eada46f4d48c658d0013ae0f3f1cbd3de5fa54 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:26 +0100 Subject: [PATCH 323/392] New translations app.json (Dutch) --- Localization/StringsConvertor/input/nl_NL/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/nl_NL/app.json b/Localization/StringsConvertor/input/nl_NL/app.json index d57a38ef2..d8ee1e574 100644 --- a/Localization/StringsConvertor/input/nl_NL/app.json +++ b/Localization/StringsConvertor/input/nl_NL/app.json @@ -67,6 +67,7 @@ "done": "Klaar", "confirm": "Bevestigen", "continue": "Doorgaan", + "compose": "Compose", "cancel": "Annuleren", "discard": "Weggooien", "try_again": "Probeer Opnieuw", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Zoeken", "search_bar": { From 12c8198cb943ade95ca3897905da903b26f637e4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:27 +0100 Subject: [PATCH 324/392] New translations app.json (Korean) --- Localization/StringsConvertor/input/ko_KR/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/ko_KR/app.json b/Localization/StringsConvertor/input/ko_KR/app.json index a9fb71ee8..571b14659 100644 --- a/Localization/StringsConvertor/input/ko_KR/app.json +++ b/Localization/StringsConvertor/input/ko_KR/app.json @@ -67,6 +67,7 @@ "done": "완료", "confirm": "확인", "continue": "계속", + "compose": "Compose", "cancel": "취소", "discard": "버리기", "try_again": "다시 시도", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "검색", "search_bar": { From 54cfcc10aaaa40717203bdbfe02f80fd1a94d03e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:28 +0100 Subject: [PATCH 325/392] New translations app.json (Danish) --- Localization/StringsConvertor/input/da_DK/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/da_DK/app.json b/Localization/StringsConvertor/input/da_DK/app.json index 3ec77cf10..5c01ae7e0 100644 --- a/Localization/StringsConvertor/input/da_DK/app.json +++ b/Localization/StringsConvertor/input/da_DK/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 5a5e9f60f77039e21aa7ee7b973a981e5d819a4c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:30 +0100 Subject: [PATCH 326/392] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index 9ffdc5bee..41349483e 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -67,6 +67,7 @@ "done": "Fet", "confirm": "Confirma", "continue": "Continua", + "compose": "Compose", "cancel": "Cancel·la", "discard": "Descarta", "try_again": "Torna a provar", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Cerca", "search_bar": { From 0ed72e48be1ad9868ea6255bb8b7f5b8deb17ef4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:31 +0100 Subject: [PATCH 327/392] New translations app.json (Spanish) --- Localization/StringsConvertor/input/es_ES/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/es_ES/app.json b/Localization/StringsConvertor/input/es_ES/app.json index 5e96daff0..1710318b9 100644 --- a/Localization/StringsConvertor/input/es_ES/app.json +++ b/Localization/StringsConvertor/input/es_ES/app.json @@ -67,6 +67,7 @@ "done": "Hecho", "confirm": "Confirmar", "continue": "Continuar", + "compose": "Compose", "cancel": "Cancelar", "discard": "Descartar", "try_again": "Inténtalo de nuevo", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Buscar", "search_bar": { From a310737ee3720321b0274828d154c37ad40e0fb4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:32 +0100 Subject: [PATCH 328/392] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index 5c101dbe9..e27f097e4 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -67,6 +67,7 @@ "done": "Terminé", "confirm": "Confirmer", "continue": "Continuer", + "compose": "Compose", "cancel": "Annuler", "discard": "Abandonner", "try_again": "Réessayer", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Rechercher", "search_bar": { From 894d62ba231a69251a91941d769edf2d66f86dde Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:33 +0100 Subject: [PATCH 329/392] New translations app.json (Romanian) --- Localization/StringsConvertor/input/ro_RO/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/ro_RO/app.json b/Localization/StringsConvertor/input/ro_RO/app.json index ef819f8e6..3927247ee 100644 --- a/Localization/StringsConvertor/input/ro_RO/app.json +++ b/Localization/StringsConvertor/input/ro_RO/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Continue", + "compose": "Compose", "cancel": "Cancel", "discard": "Discard", "try_again": "Try Again", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 2b70a770cf1aa63b784ef06fc7a939f1c62758d0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:34 +0100 Subject: [PATCH 330/392] New translations app.json (Scottish Gaelic) --- Localization/StringsConvertor/input/gd_GB/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index a73925bba..12d862a55 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -67,6 +67,7 @@ "done": "Deiseil", "confirm": "Dearbh", "continue": "Lean air adhart", + "compose": "Compose", "cancel": "Sguir dheth", "discard": "Tilg air falbh", "try_again": "Feuch ris a-rithist", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Lorg", "search_bar": { From 5c0a07110c827fcf7fb4109f86e6cd67c683fbcd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:35 +0100 Subject: [PATCH 331/392] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 4bf55d918..44aebc154 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -67,6 +67,7 @@ "done": "تمّ", "confirm": "تأكيد", "continue": "واصل", + "compose": "Compose", "cancel": "إلغاء", "discard": "تجاهل", "try_again": "المُحاولة مرة أُخرى", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "بحث", "search_bar": { From caadcf8eaa7ab3ec2335a5c04702c13ead2555bb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:36 +0100 Subject: [PATCH 332/392] New translations app.json (German) --- Localization/StringsConvertor/input/de_DE/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/de_DE/app.json b/Localization/StringsConvertor/input/de_DE/app.json index 43d8ed70a..dc8cdf8c0 100644 --- a/Localization/StringsConvertor/input/de_DE/app.json +++ b/Localization/StringsConvertor/input/de_DE/app.json @@ -67,6 +67,7 @@ "done": "Fertig", "confirm": "Bestätigen", "continue": "Fortfahren", + "compose": "Compose", "cancel": "Abbrechen", "discard": "Verwerfen", "try_again": "Nochmals versuchen", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Suche", "search_bar": { From 8ef001e02c999d3daedeeef88952a7987533e79c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 13:44:37 +0100 Subject: [PATCH 333/392] New translations app.json (Swedish, Finland) --- Localization/StringsConvertor/input/sv_FI/app.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_FI/app.json b/Localization/StringsConvertor/input/sv_FI/app.json index d0a9ad795..7acf48755 100644 --- a/Localization/StringsConvertor/input/sv_FI/app.json +++ b/Localization/StringsConvertor/input/sv_FI/app.json @@ -67,6 +67,7 @@ "done": "Done", "confirm": "Confirm", "continue": "Fortsätt", + "compose": "Compose", "cancel": "Avbryt", "discard": "Discard", "try_again": "Försök igen", @@ -413,6 +414,12 @@ } } }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, "search": { "title": "Search", "search_bar": { From 3f945a1cf8839f016d9173026a4e659c00a4c6bf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 14:40:30 +0100 Subject: [PATCH 334/392] New translations app.json (Kurmanji (Kurdish)) --- Localization/StringsConvertor/input/kmr_TR/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 4fdfd0e7d..7534aede0 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -67,7 +67,7 @@ "done": "Qediya", "confirm": "Bipejirîne", "continue": "Bidomîne", - "compose": "Compose", + "compose": "Binivîsîne", "cancel": "Dev jê berde", "discard": "Biavêje", "try_again": "Dîsa biceribîne", @@ -415,10 +415,10 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "Şopîner ji rajekerên din nayê dîtin." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "Şopandin ji rajekerên din nayê dîtin." }, "search": { "title": "Bigere", From a487c19cba3c9121e64579a4b87f8df738cd81d0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 14:40:32 +0100 Subject: [PATCH 335/392] New translations app.json (Scottish Gaelic) --- Localization/StringsConvertor/input/gd_GB/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index 12d862a55..b5c66f8f6 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -67,7 +67,7 @@ "done": "Deiseil", "confirm": "Dearbh", "continue": "Lean air adhart", - "compose": "Compose", + "compose": "Sgrìobh", "cancel": "Sguir dheth", "discard": "Tilg air falbh", "try_again": "Feuch ris a-rithist", @@ -415,10 +415,10 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "Cha dèid cò air a leanas tu air frithealaichean eile a shealltainn." }, "search": { "title": "Lorg", From 45ee6941ba3f95515589f484e790a57834d44d69 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 14:40:33 +0100 Subject: [PATCH 336/392] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index 41349483e..2ecd587c6 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -67,7 +67,7 @@ "done": "Fet", "confirm": "Confirma", "continue": "Continua", - "compose": "Compose", + "compose": "Composa", "cancel": "Cancel·la", "discard": "Descarta", "try_again": "Torna a provar", @@ -415,10 +415,10 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "Els seguidors d'altres servidors no son mostrats." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "Els seguits d'altres servidors no son mostrats." }, "search": { "title": "Cerca", From 524f7c0cf6d4834f8136e8ca7a95b3e1fab050fb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 1 Nov 2021 18:14:37 +0100 Subject: [PATCH 337/392] New translations Intents.stringsdict (Dutch) --- .../Intents/input/nl_NL/Intents.stringsdict | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/nl_NL/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/nl_NL/Intents.stringsdict index 18422c772..9043720db 100644 --- a/Localization/StringsConvertor/Intents/input/nl_NL/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/nl_NL/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Er zijn %#@count_option@ die overeenkomen met ‘${content}’. count_option NSStringFormatSpecTypeKey @@ -13,7 +13,7 @@ NSStringFormatValueTypeKey %ld one - 1 option + 1 optie other %ld options @@ -21,7 +21,7 @@ There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Er zijn %#@count_option@ die overeenkomen met ‘${visibility}’. count_option NSStringFormatSpecTypeKey @@ -29,7 +29,7 @@ NSStringFormatValueTypeKey %ld one - 1 option + 1 optie other %ld options From 0d39d061a1ee2be1a9f535d41372001c1324bfee Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 14:28:21 +0800 Subject: [PATCH 338/392] feat: update the notification tab "Mentions" segment table UI --- .../Diffiable/Item/NotificationItem.swift | 8 +- .../Section/Status/NotificationSection.swift | 296 ++++++++++-------- ...icationViewController+StatusProvider.swift | 17 +- .../NotificationViewController.swift | 134 +++++--- .../NotificationViewModel+Diffable.swift | 26 +- ...otificationViewModel+LoadOldestState.swift | 4 +- .../Notification/NotificationViewModel.swift | 8 +- .../Scene/Share/View/Content/StatusView.swift | 10 + 8 files changed, 319 insertions(+), 184 deletions(-) diff --git a/Mastodon/Diffiable/Item/NotificationItem.swift b/Mastodon/Diffiable/Item/NotificationItem.swift index 22949b3a5..fc7d0e0d9 100644 --- a/Mastodon/Diffiable/Item/NotificationItem.swift +++ b/Mastodon/Diffiable/Item/NotificationItem.swift @@ -10,7 +10,7 @@ import Foundation enum NotificationItem { case notification(objectID: NSManagedObjectID, attribute: Item.StatusAttribute) - + case notificationStatus(objectID: NSManagedObjectID, attribute: Item.StatusAttribute) // display notification status without card wrapper case bottomLoader } @@ -19,6 +19,8 @@ extension NotificationItem: Equatable { switch (lhs, rhs) { case (.notification(let idLeft, _), .notification(let idRight, _)): return idLeft == idRight + case (.notificationStatus(let idLeft, _), .notificationStatus(let idRight, _)): + return idLeft == idRight case (.bottomLoader, .bottomLoader): return true default: @@ -32,6 +34,8 @@ extension NotificationItem: Hashable { switch self { case .notification(let id, _): hasher.combine(id) + case .notificationStatus(let id, _): + hasher.combine(id) case .bottomLoader: hasher.combine(String(describing: NotificationItem.bottomLoader.self)) } @@ -43,6 +47,8 @@ extension NotificationItem { switch self { case .notification(let objectID, _): return .mastodonNotification(objectID: objectID) + case .notificationStatus(let objectID, _): + return .mastodonNotification(objectID: objectID) case .bottomLoader: return nil } diff --git a/Mastodon/Diffiable/Section/Status/NotificationSection.swift b/Mastodon/Diffiable/Section/Status/NotificationSection.swift index 215ba67cb..22283a479 100644 --- a/Mastodon/Diffiable/Section/Status/NotificationSection.swift +++ b/Mastodon/Diffiable/Section/Status/NotificationSection.swift @@ -21,9 +21,10 @@ enum NotificationSection: Equatable, Hashable { extension NotificationSection { static func tableViewDiffableDataSource( for tableView: UITableView, + dependency: NeedsDependency, managedObjectContext: NSManagedObjectContext, delegate: NotificationTableViewCellDelegate, - dependency: NeedsDependency + statusTableViewCellDelegate: StatusTableViewCellDelegate ) -> UITableViewDiffableDataSource { UITableViewDiffableDataSource(tableView: tableView) { [weak delegate, weak dependency] @@ -32,137 +33,45 @@ extension NotificationSection { switch notificationItem { case .notification(let objectID, let attribute): guard let notification = try? managedObjectContext.existingObject(with: objectID) as? MastodonNotification, - !notification.isDeleted else { - return UITableViewCell() - } + !notification.isDeleted + else { return UITableViewCell() } let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NotificationStatusTableViewCell.self), for: indexPath) as! NotificationStatusTableViewCell - cell.delegate = delegate - - // configure author - cell.configure( - with: AvatarConfigurableViewConfiguration( - avatarImageURL: notification.account.avatarImageURL() - ) + configure( + tableView: tableView, + cell: cell, + notification: notification, + dependency: dependency, + attribute: attribute ) + cell.delegate = delegate + return cell - func createActionImage() -> UIImage? { - return UIImage( - systemName: notification.notificationType.actionImageName, - withConfiguration: UIImage.SymbolConfiguration( - pointSize: 12, weight: .semibold - ) - )? - .withTintColor(.systemBackground) - .af.imageAspectScaled(toFit: CGSize(width: 14, height: 14)) - } + case .notificationStatus(objectID: let objectID, attribute: let attribute): + guard let notification = try? managedObjectContext.existingObject(with: objectID) as? MastodonNotification, + !notification.isDeleted, + let status = notification.status, + let requestUserID = dependency.context.authenticationService.activeMastodonAuthenticationBox.value?.userID + else { return UITableViewCell() } + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell - cell.avatarButton.badgeImageView.backgroundColor = notification.notificationType.color - cell.avatarButton.badgeImageView.image = createActionImage() - cell.traitCollectionDidChange - .receive(on: DispatchQueue.main) - .sink { [weak cell] in - guard let cell = cell else { return } - cell.avatarButton.badgeImageView.image = createActionImage() - } - .store(in: &cell.disposeBag) - - // configure author name, notification description, timestamp - let nameText = notification.account.displayNameWithFallback - let titleLabelText: String = { - switch notification.notificationType { - case .favourite: return L10n.Scene.Notification.userFavoritedYourPost(nameText) - case .follow: return L10n.Scene.Notification.userFollowedYou(nameText) - case .followRequest: return L10n.Scene.Notification.userRequestedToFollowYou(nameText) - case .mention: return L10n.Scene.Notification.userMentionedYou(nameText) - case .poll: return L10n.Scene.Notification.userYourPollHasEnded(nameText) - case .reblog: return L10n.Scene.Notification.userRebloggedYourPost(nameText) - default: return "" - } - }() - - do { - let nameContent = MastodonContent(content: nameText, emojis: notification.account.emojiMeta) - let nameMetaContent = try MastodonMetaContent.convert(document: nameContent) - - let mastodonContent = MastodonContent(content: titleLabelText, emojis: notification.account.emojiMeta) - let metaContent = try MastodonMetaContent.convert(document: mastodonContent) - - cell.titleLabel.configure(content: metaContent) - - if let nameRange = metaContent.string.range(of: nameMetaContent.string) { - let nsRange = NSRange(nameRange, in: metaContent.string) - cell.titleLabel.textStorage.addAttributes([ - .font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20), - .foregroundColor: Asset.Colors.brandBlue.color, - ], range: nsRange) - } - - } catch { - let metaContent = PlaintextMetaContent(string: titleLabelText) - cell.titleLabel.configure(content: metaContent) - } - - let createAt = notification.createAt - cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow - AppContext.shared.timestampUpdatePublisher - .receive(on: DispatchQueue.main) - .sink { [weak cell] _ in - guard let cell = cell else { return } - cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow - } - .store(in: &cell.disposeBag) - - // configure follow request (if exist) - if case .followRequest = notification.notificationType { - cell.acceptButton.publisher(for: .touchUpInside) - .sink { [weak cell] _ in - guard let cell = cell else { return } - cell.delegate?.notificationTableViewCell(cell, notification: notification, acceptButtonDidPressed: cell.acceptButton) - } - .store(in: &cell.disposeBag) - cell.rejectButton.publisher(for: .touchUpInside) - .sink { [weak cell] _ in - guard let cell = cell else { return } - cell.delegate?.notificationTableViewCell(cell, notification: notification, rejectButtonDidPressed: cell.rejectButton) - } - .store(in: &cell.disposeBag) - cell.buttonStackView.isHidden = false - } else { - cell.buttonStackView.isHidden = true - } - - // configure status (if exist) - if let status = notification.status { - let frame = CGRect( - x: 0, - y: 0, - width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right, - height: tableView.readableContentGuide.layoutFrame.height - ) - StatusSection.configure( - cell: cell, - tableView: tableView, - timelineContext: .notifications, - dependency: dependency, - readableLayoutFrame: frame, - status: status, - requestUserID: notification.userID, - statusItemAttribute: attribute - ) - cell.statusContainerView.isHidden = false - cell.containerStackView.alignment = .top - cell.containerStackViewBottomLayoutConstraint.constant = 0 - } else { - if case .followRequest = notification.notificationType { - cell.containerStackView.alignment = .top - } else { - cell.containerStackView.alignment = .center - } - cell.statusContainerView.isHidden = true - cell.containerStackViewBottomLayoutConstraint.constant = 5 // 5pt margin when no status view - } - + // configure cell + StatusSection.configureStatusTableViewCell( + cell: cell, + tableView: tableView, + timelineContext: .notifications, + dependency: dependency, + readableLayoutFrame: tableView.readableContentGuide.layoutFrame, + status: status, + requestUserID: requestUserID, + statusItemAttribute: attribute + ) + cell.statusView.headerContainerView.isHidden = true // set header hide + cell.statusView.actionToolbarContainer.isHidden = true // set toolbar hide + cell.statusView.actionToolbarPlaceholderPaddingView.isHidden = false + cell.delegate = statusTableViewCellDelegate + cell.isAccessibilityElement = true + StatusSection.configureStatusAccessibilityLabel(cell: cell) return cell case .bottomLoader: @@ -174,3 +83,136 @@ extension NotificationSection { } } +extension NotificationSection { + static func configure( + tableView: UITableView, + cell: NotificationStatusTableViewCell, + notification: MastodonNotification, + dependency: NeedsDependency, + attribute: Item.StatusAttribute + ) { + // configure author + cell.configure( + with: AvatarConfigurableViewConfiguration( + avatarImageURL: notification.account.avatarImageURL() + ) + ) + + func createActionImage() -> UIImage? { + return UIImage( + systemName: notification.notificationType.actionImageName, + withConfiguration: UIImage.SymbolConfiguration( + pointSize: 12, weight: .semibold + ) + )? + .withTintColor(.systemBackground) + .af.imageAspectScaled(toFit: CGSize(width: 14, height: 14)) + } + + cell.avatarButton.badgeImageView.backgroundColor = notification.notificationType.color + cell.avatarButton.badgeImageView.image = createActionImage() + cell.traitCollectionDidChange + .receive(on: DispatchQueue.main) + .sink { [weak cell] in + guard let cell = cell else { return } + cell.avatarButton.badgeImageView.image = createActionImage() + } + .store(in: &cell.disposeBag) + + // configure author name, notification description, timestamp + let nameText = notification.account.displayNameWithFallback + let titleLabelText: String = { + switch notification.notificationType { + case .favourite: return L10n.Scene.Notification.userFavoritedYourPost(nameText) + case .follow: return L10n.Scene.Notification.userFollowedYou(nameText) + case .followRequest: return L10n.Scene.Notification.userRequestedToFollowYou(nameText) + case .mention: return L10n.Scene.Notification.userMentionedYou(nameText) + case .poll: return L10n.Scene.Notification.userYourPollHasEnded(nameText) + case .reblog: return L10n.Scene.Notification.userRebloggedYourPost(nameText) + default: return "" + } + }() + + do { + let nameContent = MastodonContent(content: nameText, emojis: notification.account.emojiMeta) + let nameMetaContent = try MastodonMetaContent.convert(document: nameContent) + + let mastodonContent = MastodonContent(content: titleLabelText, emojis: notification.account.emojiMeta) + let metaContent = try MastodonMetaContent.convert(document: mastodonContent) + + cell.titleLabel.configure(content: metaContent) + + if let nameRange = metaContent.string.range(of: nameMetaContent.string) { + let nsRange = NSRange(nameRange, in: metaContent.string) + cell.titleLabel.textStorage.addAttributes([ + .font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20), + .foregroundColor: Asset.Colors.brandBlue.color, + ], range: nsRange) + } + + } catch { + let metaContent = PlaintextMetaContent(string: titleLabelText) + cell.titleLabel.configure(content: metaContent) + } + + let createAt = notification.createAt + cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow + AppContext.shared.timestampUpdatePublisher + .receive(on: DispatchQueue.main) + .sink { [weak cell] _ in + guard let cell = cell else { return } + cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow + } + .store(in: &cell.disposeBag) + + // configure follow request (if exist) + if case .followRequest = notification.notificationType { + cell.acceptButton.publisher(for: .touchUpInside) + .sink { [weak cell] _ in + guard let cell = cell else { return } + cell.delegate?.notificationTableViewCell(cell, notification: notification, acceptButtonDidPressed: cell.acceptButton) + } + .store(in: &cell.disposeBag) + cell.rejectButton.publisher(for: .touchUpInside) + .sink { [weak cell] _ in + guard let cell = cell else { return } + cell.delegate?.notificationTableViewCell(cell, notification: notification, rejectButtonDidPressed: cell.rejectButton) + } + .store(in: &cell.disposeBag) + cell.buttonStackView.isHidden = false + } else { + cell.buttonStackView.isHidden = true + } + + // configure status (if exist) + if let status = notification.status { + let frame = CGRect( + x: 0, + y: 0, + width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right, + height: tableView.readableContentGuide.layoutFrame.height + ) + StatusSection.configure( + cell: cell, + tableView: tableView, + timelineContext: .notifications, + dependency: dependency, + readableLayoutFrame: frame, + status: status, + requestUserID: notification.userID, + statusItemAttribute: attribute + ) + cell.statusContainerView.isHidden = false + cell.containerStackView.alignment = .top + cell.containerStackViewBottomLayoutConstraint.constant = 0 + } else { + if case .followRequest = notification.notificationType { + cell.containerStackView.alignment = .top + } else { + cell.containerStackView.alignment = .center + } + cell.statusContainerView.isHidden = true + cell.containerStackViewBottomLayoutConstraint.constant = 5 // 5pt margin when no status view + } + } +} diff --git a/Mastodon/Scene/Notification/NotificationViewController+StatusProvider.swift b/Mastodon/Scene/Notification/NotificationViewController+StatusProvider.swift index 127cca1b9..57272404e 100644 --- a/Mastodon/Scene/Notification/NotificationViewController+StatusProvider.swift +++ b/Mastodon/Scene/Notification/NotificationViewController+StatusProvider.swift @@ -19,21 +19,25 @@ extension NotificationViewController: StatusProvider { func status(for cell: UITableViewCell?, indexPath: IndexPath?) -> Future { return Future { promise in - guard let cell = cell, - let diffableDataSource = self.viewModel.diffableDataSource, - let indexPath = self.tableView.indexPath(for: cell), + guard let diffableDataSource = self.viewModel.diffableDataSource else { + assertionFailure() + promise(.success(nil)) + return + } + guard let indexPath = indexPath ?? cell.flatMap({ self.tableView.indexPath(for: $0) }), let item = diffableDataSource.itemIdentifier(for: indexPath) else { promise(.success(nil)) return } switch item { - case .notification(let objectID, _): + case .notification(let objectID, _), + .notificationStatus(let objectID, _): self.viewModel.fetchedResultsController.managedObjectContext.perform { let notification = self.viewModel.fetchedResultsController.managedObjectContext.object(with: objectID) as! MastodonNotification promise(.success(notification.status)) } - default: + case .bottomLoader: promise(.success(nil)) } } @@ -68,3 +72,6 @@ extension NotificationViewController: StatusProvider { } } + +// MARK: - UserProvider +extension NotificationViewController: UserProvider { } diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift index 55b4504dc..0567d04dd 100644 --- a/Mastodon/Scene/Notification/NotificationViewController.swift +++ b/Mastodon/Scene/Notification/NotificationViewController.swift @@ -14,8 +14,10 @@ import OSLog import UIKit import Meta import MetaTextKit +import AVKit -final class NotificationViewController: UIViewController, NeedsDependency { +final class NotificationViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -23,15 +25,18 @@ final class NotificationViewController: UIViewController, NeedsDependency { var observations = Set() private(set) lazy var viewModel = NotificationViewModel(context: context) + + let mediaPreviewTransitionController = MediaPreviewTransitionController() let segmentControl: UISegmentedControl = { let control = UISegmentedControl(items: [L10n.Scene.Notification.Title.everything, L10n.Scene.Notification.Title.mentions]) - control.selectedSegmentIndex = NotificationViewModel.NotificationSegment.EveryThing.rawValue + control.selectedSegmentIndex = NotificationViewModel.NotificationSegment.everyThing.rawValue return control }() let tableView: UITableView = { let tableView = ControlContainableTableView() + tableView.register(StatusTableViewCell.self, forCellReuseIdentifier: String(describing: StatusTableViewCell.self)) tableView.register(NotificationStatusTableViewCell.self, forCellReuseIdentifier: String(describing: NotificationStatusTableViewCell.self)) tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) tableView.estimatedRowHeight = UITableView.automaticDimension @@ -82,7 +87,12 @@ extension NotificationViewController { tableView.delegate = self viewModel.tableView = tableView viewModel.contentOffsetAdjustableTimelineViewControllerDelegate = self - viewModel.setupDiffableDataSource(for: tableView, delegate: self, dependency: self) + viewModel.setupDiffableDataSource( + for: tableView, + dependency: self, + delegate: self, + statusTableViewCellDelegate: self + ) viewModel.viewDidLoad.send() // bind refresh control @@ -128,9 +138,9 @@ extension NotificationViewController { self.viewModel.needsScrollToTopAfterDataSourceUpdate = true switch segment { - case .EveryThing: + case .everyThing: self.viewModel.notificationPredicate.value = MastodonNotification.predicate(domain: domain, userID: userID) - case .Mentions: + case .mentions: self.viewModel.notificationPredicate.value = MastodonNotification.predicate(domain: domain, userID: userID, typeRaw: Mastodon.Entity.Notification.NotificationType.mention.rawValue) } } @@ -148,8 +158,8 @@ extension NotificationViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - tableView.deselectRow(with: transitionCoordinator, animated: animated) + + aspectViewWillAppear(animated) // fetch latest notification when scroll position is within half screen height to prevent list reload if tableView.contentOffset.y < view.frame.height * 0.5 { @@ -181,6 +191,12 @@ extension NotificationViewController { // reset notification count context.notificationService.clearNotificationCountForActiveUser() } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + aspectViewDidDisappear(animated) + } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) @@ -208,33 +224,34 @@ extension NotificationViewController { } } -// MARK: - StatusTableViewControllerAspect -extension NotificationViewController: StatusTableViewControllerAspect { } - -extension NotificationViewController { - +// MARK: - TableViewCellHeightCacheableContainer +extension NotificationViewController: TableViewCellHeightCacheableContainer { + var cellFrameCache: NSCache { return viewModel.cellFrameCache } + func cacheTableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let diffableDataSource = viewModel.diffableDataSource else { return } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } switch item { - case .notification(let objectID, _): + case .notification(let objectID, _), + .notificationStatus(let objectID, _): guard let object = try? viewModel.fetchedResultsController.managedObjectContext.existingObject(with: objectID) as? MastodonNotification else { return } - let key = object.id as NSString + let key = object.objectID.hashValue let frame = cell.frame - viewModel.cellFrameCache.setObject(NSValue(cgRect: frame), forKey: key) + viewModel.cellFrameCache.setObject(NSValue(cgRect: frame), forKey: NSNumber(value: key)) case .bottomLoader: break } } - + func handleTableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { guard let diffableDataSource = viewModel.diffableDataSource else { return UITableView.automaticDimension } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return UITableView.automaticDimension } switch item { - case .notification(let objectID, _): + case .notification(let objectID, _), + .notificationStatus(let objectID, _): guard let object = try? viewModel.fetchedResultsController.managedObjectContext.existingObject(with: objectID) as? MastodonNotification else { return UITableView.automaticDimension } - let key = object.id as NSString - guard let frame = viewModel.cellFrameCache.object(forKey: key)?.cgRectValue else { return UITableView.automaticDimension } + let key = object.objectID.hashValue + guard let frame = viewModel.cellFrameCache.object(forKey: NSNumber(value: key))?.cgRectValue else { return UITableView.automaticDimension } return frame.height case .bottomLoader: return TimelineLoaderTableViewCell.cellHeight @@ -242,22 +259,55 @@ extension NotificationViewController { } } + +// MARK: - StatusTableViewControllerAspect +extension NotificationViewController: StatusTableViewControllerAspect { } + // MARK: - UITableViewDelegate extension NotificationViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + aspectTableView(tableView, estimatedHeightForRowAt: indexPath) + } + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let diffableDataSource = viewModel.diffableDataSource else { return } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } - open(item: item) + switch item { + case .notificationStatus: + aspectTableView(tableView, willDisplay: cell, forRowAt: indexPath) + case .bottomLoader: + if !tableView.isDragging, !tableView.isDecelerating { + viewModel.loadOldestStateMachine.enter(NotificationViewModel.LoadOldestState.Loading.self) + } + default: + break + } } func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { - cacheTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) + aspectTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + aspectTableView(tableView, didSelectRowAt: indexPath) } - func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - return handleTableView(tableView, estimatedHeightForRowAt: indexPath) + func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { + return aspectTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point) + } + + func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { + aspectTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator) } } @@ -278,19 +328,6 @@ extension NotificationViewController { break } } - - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - guard let diffableDataSource = viewModel.diffableDataSource else { return } - guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } - switch item { - case .bottomLoader: - if !tableView.isDragging, !tableView.isDecelerating { - viewModel.loadOldestStateMachine.enter(NotificationViewModel.LoadOldestState.Loading.self) - } - default: - break - } - } } // MARK: - ContentOffsetAdjustableTimelineViewControllerDelegate @@ -388,6 +425,7 @@ extension NotificationViewController: ScrollViewContainer { } } +// MARK: - LoadMoreConfigurableTableViewContainer extension NotificationViewController: LoadMoreConfigurableTableViewContainer { typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell typealias LoadingState = NotificationViewModel.LoadOldestState.Loading @@ -395,6 +433,24 @@ extension NotificationViewController: LoadMoreConfigurableTableViewContainer { var loadMoreConfigurableStateMachine: GKStateMachine { viewModel.loadOldestStateMachine } } +// MARK: - AVPlayerViewControllerDelegate +extension NotificationViewController: AVPlayerViewControllerDelegate { + func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { + handlePlayerViewController(playerViewController, willBeginFullScreenPresentationWithAnimationCoordinator: coordinator) + } + + func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { + handlePlayerViewController(playerViewController, willEndFullScreenPresentationWithAnimationCoordinator: coordinator) + } +} + +// MARK: - statusTableViewCellDelegate +extension NotificationViewController: StatusTableViewCellDelegate { + var playerViewControllerDelegate: AVPlayerViewControllerDelegate? { + return self + } +} + extension NotificationViewController { enum CategorySwitch: String, CaseIterable { @@ -452,9 +508,9 @@ extension NotificationViewController { switch category { case .showEverything: - viewModel.selectedIndex.value = .EveryThing + viewModel.selectedIndex.value = .everyThing case .showMentions: - viewModel.selectedIndex.value = .Mentions + viewModel.selectedIndex.value = .mentions } } diff --git a/Mastodon/Scene/Notification/NotificationViewModel+Diffable.swift b/Mastodon/Scene/Notification/NotificationViewModel+Diffable.swift index 6a542bf2c..6c7a70e43 100644 --- a/Mastodon/Scene/Notification/NotificationViewModel+Diffable.swift +++ b/Mastodon/Scene/Notification/NotificationViewModel+Diffable.swift @@ -14,14 +14,16 @@ import MastodonSDK extension NotificationViewModel { func setupDiffableDataSource( for tableView: UITableView, + dependency: NeedsDependency, delegate: NotificationTableViewCellDelegate, - dependency: NeedsDependency + statusTableViewCellDelegate: StatusTableViewCellDelegate ) { diffableDataSource = NotificationSection.tableViewDiffableDataSource( for: tableView, + dependency: dependency, managedObjectContext: fetchedResultsController.managedObjectContext, delegate: delegate, - dependency: dependency + statusTableViewCellDelegate: statusTableViewCellDelegate ) var snapshot = NSDiffableDataSourceSnapshot() @@ -81,11 +83,23 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate { } var newSnapshot = NSDiffableDataSourceSnapshot() newSnapshot.appendSections([.main]) - let items: [NotificationItem] = notifications.map { notification in - let attribute: Item.StatusAttribute = oldSnapshotAttributeDict[notification.objectID] ?? Item.StatusAttribute() - return NotificationItem.notification(objectID: notification.objectID, attribute: attribute) + + let segment = self.selectedIndex.value + switch segment { + case .everyThing: + let items: [NotificationItem] = notifications.map { notification in + let attribute: Item.StatusAttribute = oldSnapshotAttributeDict[notification.objectID] ?? Item.StatusAttribute() + return NotificationItem.notification(objectID: notification.objectID, attribute: attribute) + } + newSnapshot.appendItems(items, toSection: .main) + case .mentions: + let items: [NotificationItem] = notifications.map { notification in + let attribute: Item.StatusAttribute = oldSnapshotAttributeDict[notification.objectID] ?? Item.StatusAttribute() + return NotificationItem.notificationStatus(objectID: notification.objectID, attribute: attribute) + } + newSnapshot.appendItems(items, toSection: .main) } - newSnapshot.appendItems(items, toSection: .main) + if !notifications.isEmpty, self.noMoreNotification.value == false { newSnapshot.appendItems([.bottomLoader], toSection: .main) } diff --git a/Mastodon/Scene/Notification/NotificationViewModel+LoadOldestState.swift b/Mastodon/Scene/Notification/NotificationViewModel+LoadOldestState.swift index 9567d6cbb..bf2c03174 100644 --- a/Mastodon/Scene/Notification/NotificationViewModel+LoadOldestState.swift +++ b/Mastodon/Scene/Notification/NotificationViewModel+LoadOldestState.swift @@ -92,13 +92,13 @@ extension NotificationViewModel.LoadOldestState { } receiveValue: { [weak viewModel] response in guard let viewModel = viewModel else { return } switch viewModel.selectedIndex.value { - case .EveryThing: + case .everyThing: if response.value.isEmpty { stateMachine.enter(NoMore.self) } else { stateMachine.enter(Idle.self) } - case .Mentions: + case .mentions: viewModel.noMoreNotification.value = response.value.isEmpty let list = response.value.filter { $0.type == Mastodon.Entity.Notification.NotificationType.mention } if list.isEmpty { diff --git a/Mastodon/Scene/Notification/NotificationViewModel.swift b/Mastodon/Scene/Notification/NotificationViewModel.swift index 712380917..98b7deec3 100644 --- a/Mastodon/Scene/Notification/NotificationViewModel.swift +++ b/Mastodon/Scene/Notification/NotificationViewModel.swift @@ -23,13 +23,13 @@ final class NotificationViewModel: NSObject { weak var contentOffsetAdjustableTimelineViewControllerDelegate: ContentOffsetAdjustableTimelineViewControllerDelegate? let viewDidLoad = PassthroughSubject() - let selectedIndex = CurrentValueSubject(.EveryThing) + let selectedIndex = CurrentValueSubject(.everyThing) let noMoreNotification = CurrentValueSubject(false) let activeMastodonAuthenticationBox: CurrentValueSubject let fetchedResultsController: NSFetchedResultsController! let notificationPredicate = CurrentValueSubject(nil) - let cellFrameCache = NSCache() + let cellFrameCache = NSCache() var needsScrollToTopAfterDataSourceUpdate = false let dataSourceDidUpdated = PassthroughSubject() @@ -161,7 +161,7 @@ final class NotificationViewModel: NSObject { extension NotificationViewModel { enum NotificationSegment: Int { - case EveryThing - case Mentions + case everyThing + case mentions } } diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift index 957764fa7..62eb3d6b0 100644 --- a/Mastodon/Scene/Share/View/Content/StatusView.swift +++ b/Mastodon/Scene/Share/View/Content/StatusView.swift @@ -203,6 +203,9 @@ final class StatusView: UIView { return actionToolbarContainer }() + // set display when needs bottom padding + let actionToolbarPlaceholderPaddingView = UIView() + let contentMetaText: MetaText = { let metaText = MetaText() metaText.textView.backgroundColor = .clear @@ -451,6 +454,13 @@ extension StatusView { containerStackView.sendSubviewToBack(actionToolbarContainer) actionToolbarContainer.setContentCompressionResistancePriority(.defaultHigh, for: .vertical) actionToolbarContainer.setContentHuggingPriority(.required - 1, for: .vertical) + + actionToolbarPlaceholderPaddingView.translatesAutoresizingMaskIntoConstraints = false + containerStackView.addArrangedSubview(actionToolbarPlaceholderPaddingView) + NSLayoutConstraint.activate([ + actionToolbarPlaceholderPaddingView.heightAnchor.constraint(equalToConstant: 12).priority(.required - 1), + ]) + actionToolbarPlaceholderPaddingView.isHidden = true headerContainerView.isHidden = true statusMosaicImageViewContainer.isHidden = true From 8ebb2e5347460b6a112992411cdad4d76f0a4f3d Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 14:56:42 +0800 Subject: [PATCH 339/392] feat: add following list --- Mastodon.xcodeproj/project.pbxproj | 28 +++ .../xcschemes/xcschememanagement.plist | 8 +- Mastodon/Coordinator/SceneCoordinator.swift | 5 + Mastodon/Diffiable/Item/UserItem.swift | 1 + Mastodon/Diffiable/Section/UserSection.swift | 3 +- .../FollowerListViewController+Provider.swift | 3 +- .../Follower/FollowerListViewController.swift | 7 +- .../FollowerListViewModel+Diffable.swift | 16 +- .../FollowerListViewModel+State.swift | 12 -- ...FollowingListViewController+Provider.swift | 51 +++++ .../FollowingListViewController.swift | 108 ++++++++++ .../FollowingListViewModel+Diffable.swift | 61 ++++++ .../FollowingListViewModel+State.swift | 196 ++++++++++++++++++ .../Following/FollowingListViewModel.swift | 53 +++++ .../Scene/Profile/ProfileViewController.swift | 15 +- 15 files changed, 536 insertions(+), 31 deletions(-) create mode 100644 Mastodon/Scene/Profile/Following/FollowingListViewController+Provider.swift create mode 100644 Mastodon/Scene/Profile/Following/FollowingListViewController.swift create mode 100644 Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift create mode 100644 Mastodon/Scene/Profile/Following/FollowingListViewModel.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 60f0f5d74..8408f3ac3 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -296,6 +296,11 @@ DB59F10425EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F10325EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift */; }; DB59F10E25EF724F001F1DAB /* APIService+Poll.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F10D25EF724F001F1DAB /* APIService+Poll.swift */; }; DB59F11825EFA35B001F1DAB /* StripProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F11725EFA35B001F1DAB /* StripProgressView.swift */; }; + DB5B7295273112B100081888 /* FollowingListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B7294273112B100081888 /* FollowingListViewController.swift */; }; + DB5B7298273112C800081888 /* FollowingListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B7297273112C800081888 /* FollowingListViewModel.swift */; }; + DB5B729A2731137900081888 /* FollowingListViewController+Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B72992731137900081888 /* FollowingListViewController+Provider.swift */; }; + DB5B729C273113C200081888 /* FollowingListViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B729B273113C200081888 /* FollowingListViewModel+Diffable.swift */; }; + DB5B729E273113F300081888 /* FollowingListViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B729D273113F300081888 /* FollowingListViewModel+State.swift */; }; DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180DC263918E30018D199 /* MediaPreviewViewController.swift */; }; DB6180E02639194B0018D199 /* MediaPreviewPagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180DF2639194B0018D199 /* MediaPreviewPagingViewController.swift */; }; DB6180E326391A4C0018D199 /* ViewControllerAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180E226391A4C0018D199 /* ViewControllerAnimatedTransitioning.swift */; }; @@ -1110,6 +1115,11 @@ DB59F10325EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewCellHeightCacheableContainer.swift; sourceTree = ""; }; DB59F10D25EF724F001F1DAB /* APIService+Poll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Poll.swift"; sourceTree = ""; }; DB59F11725EFA35B001F1DAB /* StripProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StripProgressView.swift; sourceTree = ""; }; + DB5B7294273112B100081888 /* FollowingListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingListViewController.swift; sourceTree = ""; }; + DB5B7297273112C800081888 /* FollowingListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingListViewModel.swift; sourceTree = ""; }; + DB5B72992731137900081888 /* FollowingListViewController+Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowingListViewController+Provider.swift"; sourceTree = ""; }; + DB5B729B273113C200081888 /* FollowingListViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowingListViewModel+Diffable.swift"; sourceTree = ""; }; + DB5B729D273113F300081888 /* FollowingListViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowingListViewModel+State.swift"; sourceTree = ""; }; DB6180DC263918E30018D199 /* MediaPreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewViewController.swift; sourceTree = ""; }; DB6180DF2639194B0018D199 /* MediaPreviewPagingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewPagingViewController.swift; sourceTree = ""; }; DB6180E226391A4C0018D199 /* ViewControllerAnimatedTransitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerAnimatedTransitioning.swift; sourceTree = ""; }; @@ -2453,6 +2463,18 @@ path = View; sourceTree = ""; }; + DB5B7296273112B400081888 /* Following */ = { + isa = PBXGroup; + children = ( + DB5B7294273112B100081888 /* FollowingListViewController.swift */, + DB5B72992731137900081888 /* FollowingListViewController+Provider.swift */, + DB5B7297273112C800081888 /* FollowingListViewModel.swift */, + DB5B729B273113C200081888 /* FollowingListViewModel+Diffable.swift */, + DB5B729D273113F300081888 /* FollowingListViewModel+State.swift */, + ); + path = Following; + sourceTree = ""; + }; DB6180DE263919350018D199 /* MediaPreview */ = { isa = PBXGroup; children = ( @@ -2902,6 +2924,7 @@ DBB5253B2611ECF5002F1F29 /* Timeline */, DBE3CDF1261C6B3100430CC6 /* Favorite */, DB6B74F0272FB55400C70B6E /* Follower */, + DB5B7296273112B400081888 /* Following */, DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */, DBAE3F812615DDA3004B8251 /* ProfileViewController+UserProvider.swift */, DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */, @@ -3918,6 +3941,7 @@ DBAE3F8E2616E0B1004B8251 /* APIService+Block.swift in Sources */, 5DF1057F25F88A4100D6C0D4 /* TouchBlockingView.swift in Sources */, DB1D843426579931000346B3 /* TableViewControllerNavigateable.swift in Sources */, + DB5B729A2731137900081888 /* FollowingListViewController+Provider.swift in Sources */, 0FAA0FDF25E0B57E0017CCDE /* WelcomeViewController.swift in Sources */, 2D206B8C25F6015000143C56 /* AudioPlaybackService.swift in Sources */, 2D59819B25E4A581000FB903 /* MastodonConfirmEmailViewController.swift in Sources */, @@ -3929,6 +3953,7 @@ DB03A793272A7E5700EE37C5 /* SidebarListHeaderView.swift in Sources */, DB4FFC2B269EC39600D62E92 /* SearchToSearchDetailViewControllerAnimatedTransitioning.swift in Sources */, DBCC3B9526157E6E0045B23D /* APIService+Relationship.swift in Sources */, + DB5B7298273112C800081888 /* FollowingListViewModel.swift in Sources */, 2D7631B325C159F700929FB9 /* Item.swift in Sources */, 5DF1054125F886D400D6C0D4 /* VideoPlaybackService.swift in Sources */, DB6B35182601FA3400DC1E11 /* MastodonAttachmentService.swift in Sources */, @@ -4065,6 +4090,7 @@ DBE3CE01261D623D00430CC6 /* FavoriteViewModel+State.swift in Sources */, 2D82BA0525E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift in Sources */, 2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */, + DB5B7295273112B100081888 /* FollowingListViewController.swift in Sources */, 0F202201261326E6000C64BF /* HashtagTimelineViewModel.swift in Sources */, DB6D9F9726367249008423CD /* SettingsViewController.swift in Sources */, DB4F097F26A03DA600D62E92 /* SearchHistoryFetchedResultController.swift in Sources */, @@ -4075,8 +4101,10 @@ DB73BF47271199CA00781945 /* Instance.swift in Sources */, DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */, DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */, + DB5B729C273113C200081888 /* FollowingListViewModel+Diffable.swift in Sources */, DB9E0D6F25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift in Sources */, DBB9759C262462E1004620BD /* ThreadMetaView.swift in Sources */, + DB5B729E273113F300081888 /* FollowingListViewModel+State.swift in Sources */, 2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */, 5DDDF1A92617489F00311060 /* Mastodon+Entity+History.swift in Sources */, DB59F11825EFA35B001F1DAB /* StripProgressView.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index cb88c3960..2d2dd1932 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 42 + 36 CoreDataStack.xcscheme_^#shared#^_ orderHint - 43 + 35 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 44 + 38 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 41 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index cda20255b..e7611056f 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -179,6 +179,7 @@ extension SceneCoordinator { case profile(viewModel: ProfileViewModel) case favorite(viewModel: FavoriteViewModel) case follower(viewModel: FollowerListViewModel) + case following(viewModel: FollowingListViewModel) // setting case settings(viewModel: SettingsViewModel) @@ -429,6 +430,10 @@ private extension SceneCoordinator { let _viewController = FollowerListViewController() _viewController.viewModel = viewModel viewController = _viewController + case .following(let viewModel): + let _viewController = FollowingListViewController() + _viewController.viewModel = viewModel + viewController = _viewController case .suggestionAccount(let viewModel): let _viewController = SuggestionAccountViewController() _viewController.viewModel = viewModel diff --git a/Mastodon/Diffiable/Item/UserItem.swift b/Mastodon/Diffiable/Item/UserItem.swift index 6f3c591b1..bd15f35ea 100644 --- a/Mastodon/Diffiable/Item/UserItem.swift +++ b/Mastodon/Diffiable/Item/UserItem.swift @@ -10,6 +10,7 @@ import CoreData enum UserItem: Hashable { case follower(objectID: NSManagedObjectID) + case following(objectID: NSManagedObjectID) case bottomLoader case bottomHeader(text: String) } diff --git a/Mastodon/Diffiable/Section/UserSection.swift b/Mastodon/Diffiable/Section/UserSection.swift index 58e80c6e3..9c7e2f212 100644 --- a/Mastodon/Diffiable/Section/UserSection.swift +++ b/Mastodon/Diffiable/Section/UserSection.swift @@ -30,7 +30,8 @@ extension UserSection { ] tableView, indexPath, item -> UITableViewCell? in guard let dependency = dependency else { return UITableViewCell() } switch item { - case .follower(let objectID): + case .follower(let objectID), + .following(let objectID): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell managedObjectContext.performAndWait { let user = managedObjectContext.object(with: objectID) as! MastodonUser diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift index 627ed7772..25e102846 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewController+Provider.swift @@ -37,7 +37,8 @@ extension FollowerListViewController: UserProvider { let managedObjectContext = self.viewModel.userFetchedResultsController.fetchedResultsController.managedObjectContext switch item { - case .follower(let objectID): + case .follower(let objectID), + .following(let objectID): managedObjectContext.perform { let user = managedObjectContext.object(with: objectID) as? MastodonUser promise(.success(user)) diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift index 428448666..97e62ea8d 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift @@ -7,11 +7,10 @@ import os.log import UIKit -import AVKit import GameplayKit import Combine -final class FollowerListViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { +final class FollowerListViewController: UIViewController, NeedsDependency { var disposeBag = Set() @@ -19,9 +18,7 @@ final class FollowerListViewController: UIViewController, NeedsDependency, Media weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var viewModel: FollowerListViewModel! - - let mediaPreviewTransitionController = MediaPreviewTransitionController() - + lazy var tableView: UITableView = { let tableView = UITableView() tableView.register(UserTableViewCell.self, forCellReuseIdentifier: String(describing: UserTableViewCell.self)) diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift index 90b9cb311..c048e1723 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift @@ -18,16 +18,19 @@ extension FollowerListViewModel { managedObjectContext: userFetchedResultsController.fetchedResultsController.managedObjectContext ) + // workaround to append loader wrong animation issue // set empty section to make update animation top-to-bottom style var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) - diffableDataSource?.apply(snapshot) - - // workaround to append loader wrong animation issue snapshot.appendItems([.bottomLoader], toSection: .main) - diffableDataSource?.apply(snapshot) + if #available(iOS 15.0, *) { + diffableDataSource?.applySnapshotUsingReloadData(snapshot, completion: nil) + } else { + // Fallback on earlier versions + diffableDataSource?.apply(snapshot, animatingDifferences: false) + } - userFetchedResultsController.objectIDs.removeDuplicates() + userFetchedResultsController.objectIDs .receive(on: DispatchQueue.main) .sink { [weak self] objectIDs in guard let self = self else { return } @@ -45,7 +48,8 @@ extension FollowerListViewModel { case is State.Idle, is State.Loading, is State.Fail: snapshot.appendItems([.bottomLoader], toSection: .main) case is State.NoMore: - break + let text = "Followers from other servers are not displayed." + snapshot.appendItems([.bottomHeader(text: text)], toSection: .main) default: break } diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift index b012a59bb..876933181 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift @@ -179,18 +179,6 @@ extension FollowerListViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let _ = stateMachine else { return } - guard let diffableDataSource = viewModel.diffableDataSource else { - assertionFailure() - return - } - DispatchQueue.main.async { - var snapshot = diffableDataSource.snapshot() - snapshot.deleteItems([.bottomLoader]) - let header = UserItem.bottomHeader(text: "Followers from other servers are not displayed") - snapshot.appendItems([header], toSection: .main) - diffableDataSource.apply(snapshot, animatingDifferences: false) - } } } } diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewController+Provider.swift b/Mastodon/Scene/Profile/Following/FollowingListViewController+Provider.swift new file mode 100644 index 000000000..aaeb52328 --- /dev/null +++ b/Mastodon/Scene/Profile/Following/FollowingListViewController+Provider.swift @@ -0,0 +1,51 @@ +// +// FollowingListViewController+Provider.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import os.log +import UIKit +import Combine +import CoreData +import CoreDataStack + +extension FollowingListViewController: UserProvider { + + func mastodonUser() -> Future { + Future { promise in + promise(.success(nil)) + } + } + + func mastodonUser(for cell: UITableViewCell?) -> Future { + Future { [weak self] promise in + guard let self = self else { return } + guard let diffableDataSource = self.viewModel.diffableDataSource else { + assertionFailure() + promise(.success(nil)) + return + } + guard let cell = cell, + let indexPath = self.tableView.indexPath(for: cell), + let item = diffableDataSource.itemIdentifier(for: indexPath) else { + promise(.success(nil)) + return + } + + let managedObjectContext = self.viewModel.userFetchedResultsController.fetchedResultsController.managedObjectContext + + switch item { + case .follower(let objectID), + .following(let objectID): + managedObjectContext.perform { + let user = managedObjectContext.object(with: objectID) as? MastodonUser + promise(.success(user)) + } + case .bottomLoader, .bottomHeader: + promise(.success(nil)) + } + } + } +} diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewController.swift b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift new file mode 100644 index 000000000..35691b82d --- /dev/null +++ b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift @@ -0,0 +1,108 @@ +// +// FollowingListViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import os.log +import UIKit +import GameplayKit +import Combine + +final class FollowingListViewController: UIViewController, NeedsDependency { + + var disposeBag = Set() + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var viewModel: FollowingListViewModel! + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.register(UserTableViewCell.self, forCellReuseIdentifier: String(describing: UserTableViewCell.self)) + tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) + tableView.register(TimelineFooterTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineFooterTableViewCell.self)) + tableView.rowHeight = UITableView.automaticDimension + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension FollowingListViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: RunLoop.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + 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.delegate = self + viewModel.setupDiffableDataSource( + for: tableView, + dependency: self + ) + // TODO: add UserTableViewCellDelegate + + // trigger user timeline loading + Publishers.CombineLatest( + viewModel.domain.removeDuplicates().eraseToAnyPublisher(), + viewModel.userID.removeDuplicates().eraseToAnyPublisher() + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.viewModel.stateMachine.enter(FollowingListViewModel.State.Reloading.self) + } + .store(in: &disposeBag) + } + +} + +// MARK: - LoadMoreConfigurableTableViewContainer +extension FollowingListViewController: LoadMoreConfigurableTableViewContainer { + typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell + typealias LoadingState = FollowingListViewModel.State.Loading + var loadMoreConfigurableTableView: UITableView { tableView } + var loadMoreConfigurableStateMachine: GKStateMachine { viewModel.stateMachine } +} + +// MARK: - UIScrollViewDelegate +extension FollowingListViewController { + func scrollViewDidScroll(_ scrollView: UIScrollView) { + handleScrollViewDidScroll(scrollView) + } +} + + +// MARK: - UITableViewDelegate +extension FollowingListViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + handleTableView(tableView, didSelectRowAt: indexPath) + } +} + +// MARK: - UserTableViewCellDelegate +extension FollowingListViewController: UserTableViewCellDelegate { } diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift new file mode 100644 index 000000000..58af276d0 --- /dev/null +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift @@ -0,0 +1,61 @@ +// +// FollowingListViewModel+Diffable.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import UIKit + +extension FollowingListViewModel { + func setupDiffableDataSource( + for tableView: UITableView, + dependency: NeedsDependency + ) { + diffableDataSource = UserSection.tableViewDiffableDataSource( + for: tableView, + dependency: dependency, + managedObjectContext: userFetchedResultsController.fetchedResultsController.managedObjectContext + ) + + // workaround to append loader wrong animation issue + // set empty section to make update animation top-to-bottom style + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + snapshot.appendItems([.bottomLoader], toSection: .main) + if #available(iOS 15.0, *) { + diffableDataSource?.applySnapshotUsingReloadData(snapshot, completion: nil) + } else { + // Fallback on earlier versions + diffableDataSource?.apply(snapshot, animatingDifferences: false) + } + + userFetchedResultsController.objectIDs + .receive(on: DispatchQueue.main) + .sink { [weak self] objectIDs in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + let items: [UserItem] = objectIDs.map { + UserItem.following(objectID: $0) + } + snapshot.appendItems(items, toSection: .main) + + if let currentState = self.stateMachine.currentState { + switch currentState { + case is State.Idle, is State.Loading, is State.Fail: + snapshot.appendItems([.bottomLoader], toSection: .main) + case is State.NoMore: + break + default: + break + } + } + + diffableDataSource.apply(snapshot) + } + .store(in: &disposeBag) + } +} diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift new file mode 100644 index 000000000..d5c30b43a --- /dev/null +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift @@ -0,0 +1,196 @@ +// +// FollowingListViewModel+State.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import os.log +import Foundation +import GameplayKit +import MastodonSDK + +extension FollowingListViewModel { + class State: GKState { + weak var viewModel: FollowingListViewModel? + + init(viewModel: FollowingListViewModel) { + self.viewModel = viewModel + } + + override func didEnter(from previousState: GKState?) { + os_log("%{public}s[%{public}ld], %{public}s: enter %s, previous: %s", ((#file as NSString).lastPathComponent), #line, #function, self.debugDescription, previousState.debugDescription) + } + } +} + +extension FollowingListViewModel.State { + class Initial: FollowingListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + guard let viewModel = viewModel else { return false } + switch stateClass { + case is Reloading.Type: + return viewModel.userID.value != nil + default: + return false + } + } + } + + class Reloading: FollowingListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + // reset + viewModel.userFetchedResultsController.userIDs.value = [] + + stateMachine.enter(Loading.self) + } + } + + class Fail: FollowingListViewModel.State { + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading 3s later…", ((#file as NSString).lastPathComponent), #line, #function) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading", ((#file as NSString).lastPathComponent), #line, #function) + stateMachine.enter(Loading.self) + } + } + } + + class Idle: FollowingListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type, is Loading.Type: + return true + default: + return false + } + } + } + + class Loading: FollowingListViewModel.State { + + var maxID: String? + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + + if previousState is Reloading { + maxID = nil + } + + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + guard let userID = viewModel.userID.value, !userID.isEmpty else { + stateMachine.enter(Fail.self) + return + } + + guard let activeMastodonAuthenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { + stateMachine.enter(Fail.self) + return + } + + viewModel.context.apiService.followers( + userID: userID, + maxID: maxID, + authorizationBox: activeMastodonAuthenticationBox + ) + .receive(on: DispatchQueue.main) + .sink { completion in + switch completion { + case .failure(let error): + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch user timeline fail: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription) + stateMachine.enter(Fail.self) + case .finished: + break + } + } receiveValue: { response in + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + + var hasNewAppend = false + var userIDs = viewModel.userFetchedResultsController.userIDs.value + for user in response.value { + guard !userIDs.contains(user.id) else { continue } + userIDs.append(user.id) + hasNewAppend = true + } + + let maxID = response.link?.maxID + + if hasNewAppend, maxID != nil { + stateMachine.enter(Idle.self) + } else { + stateMachine.enter(NoMore.self) + } + self.maxID = maxID + viewModel.userFetchedResultsController.userIDs.value = userIDs + } + .store(in: &viewModel.disposeBag) + } // end func didEnter + } + + class NoMore: FollowingListViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let _ = stateMachine else { return } + guard let diffableDataSource = viewModel.diffableDataSource else { + assertionFailure() + return + } + DispatchQueue.main.async { + var snapshot = diffableDataSource.snapshot() + snapshot.deleteItems([.bottomLoader]) + let header = UserItem.bottomHeader(text: "Followers from other servers are not displayed") + snapshot.appendItems([header], toSection: .main) + diffableDataSource.apply(snapshot, animatingDifferences: false) + } + } + } +} diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift new file mode 100644 index 000000000..0677f6cb4 --- /dev/null +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift @@ -0,0 +1,53 @@ +// +// FollowingListViewModel.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import Foundation +import Combine +import Combine +import CoreData +import CoreDataStack +import GameplayKit +import MastodonSDK + +final class FollowingListViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let domain: CurrentValueSubject + let userID: CurrentValueSubject + let userFetchedResultsController: UserFetchedResultsController + + // output + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + init(context: AppContext, domain: String?, userID: String?) { + self.context = context + self.userFetchedResultsController = UserFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: domain, + additionalTweetPredicate: nil + ) + self.domain = CurrentValueSubject(domain) + self.userID = CurrentValueSubject(userID) + // super.init() + + } +} diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 04d582315..5ff71ba99 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -1001,8 +1001,19 @@ extension ProfileViewController: ProfileHeaderViewDelegate { transition: .show ) case .following: - // TODO: - break + guard let domain = viewModel.domain.value, + let userID = viewModel.userID.value + else { return } + let followingListViewModel = FollowingListViewModel( + context: context, + domain: domain, + userID: userID + ) + coordinator.present( + scene: .following(viewModel: followingListViewModel), + from: self, + transition: .show + ) } } From 613916e0406d9c8a4823d089382e3f8b34e7bebf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 2 Nov 2021 08:05:08 +0100 Subject: [PATCH 340/392] New translations app.json (Chinese Simplified) --- Localization/StringsConvertor/input/zh_CN/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index b3a8866bb..905afdd86 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -67,7 +67,7 @@ "done": "完成", "confirm": "确认", "continue": "继续", - "compose": "Compose", + "compose": "撰写", "cancel": "取消", "discard": "放弃", "try_again": "再试一次", @@ -415,10 +415,10 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "不会显示来自其它服务器的关注者" }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "不会显示来自其它服务器的关注" }, "search": { "title": "搜索", From dfb84fdb5bad9258b37246908cf618e2bc42ae48 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 15:07:45 +0800 Subject: [PATCH 341/392] chore: update i18n resources --- Mastodon/Generated/Strings.swift | 10 +++ .../Resources/ar.lproj/Localizable.strings | 3 + .../Resources/ca.lproj/Localizable.strings | 3 + .../Resources/de.lproj/Localizable.strings | 3 + .../Resources/en.lproj/Localizable.strings | 3 + .../es-419.lproj/Localizable.strings | 3 + .../Resources/es.lproj/Localizable.strings | 3 + .../Resources/fr.lproj/Localizable.strings | 3 + .../Resources/gd-GB.lproj/Localizable.strings | 3 + .../Resources/ja.lproj/Localizable.strings | 3 + .../Resources/ku-TR.lproj/Localizable.strings | 67 ++++++++++--------- .../ku-TR.lproj/Localizable.stringsdict | 4 +- .../Resources/nl.lproj/Localizable.strings | 3 + .../Resources/ru.lproj/Localizable.strings | 3 + .../Resources/th.lproj/Localizable.strings | 3 + .../zh-Hans.lproj/Localizable.strings | 3 + 16 files changed, 86 insertions(+), 34 deletions(-) diff --git a/Mastodon/Generated/Strings.swift b/Mastodon/Generated/Strings.swift index 93cc4ca38..ebf9869c4 100644 --- a/Mastodon/Generated/Strings.swift +++ b/Mastodon/Generated/Strings.swift @@ -106,6 +106,8 @@ internal enum L10n { } /// Cancel internal static let cancel = L10n.tr("Localizable", "Common.Controls.Actions.Cancel") + /// Compose + internal static let compose = L10n.tr("Localizable", "Common.Controls.Actions.Compose") /// Confirm internal static let confirm = L10n.tr("Localizable", "Common.Controls.Actions.Confirm") /// Continue @@ -523,6 +525,14 @@ internal enum L10n { /// Your Favorites internal static let title = L10n.tr("Localizable", "Scene.Favorite.Title") } + internal enum Follower { + /// Followers from other servers are not displayed. + internal static let footer = L10n.tr("Localizable", "Scene.Follower.Footer") + } + internal enum Following { + /// Follows from other servers are not displayed. + internal static let footer = L10n.tr("Localizable", "Scene.Following.Footer") + } internal enum HomeTimeline { /// Home internal static let title = L10n.tr("Localizable", "Scene.HomeTimeline.Title") diff --git a/Mastodon/Resources/ar.lproj/Localizable.strings b/Mastodon/Resources/ar.lproj/Localizable.strings index 5950546a9..8681e584d 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.strings +++ b/Mastodon/Resources/ar.lproj/Localizable.strings @@ -28,6 +28,7 @@ Please check your internet connection."; "Common.Controls.Actions.Back" = "العودة"; "Common.Controls.Actions.BlockDomain" = "حظر %@"; "Common.Controls.Actions.Cancel" = "إلغاء"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "تأكيد"; "Common.Controls.Actions.Continue" = "واصل"; "Common.Controls.Actions.CopyPhoto" = "نسخ الصورة"; @@ -190,6 +191,8 @@ uploaded to Mastodon."; اضغط على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيء واحد أخير."; "Scene.Favorite.Title" = "مفضلتك"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "إظهار منشورات جديدة"; "Scene.HomeTimeline.NavigationBarState.Offline" = "غير متصل"; "Scene.HomeTimeline.NavigationBarState.Published" = "تم نشره!"; diff --git a/Mastodon/Resources/ca.lproj/Localizable.strings b/Mastodon/Resources/ca.lproj/Localizable.strings index 71eb62b00..1642fc8a5 100644 --- a/Mastodon/Resources/ca.lproj/Localizable.strings +++ b/Mastodon/Resources/ca.lproj/Localizable.strings @@ -28,6 +28,7 @@ Comprova la teva connexió a Internet."; "Common.Controls.Actions.Back" = "Enrere"; "Common.Controls.Actions.BlockDomain" = "Bloqueja %@"; "Common.Controls.Actions.Cancel" = "Cancel·la"; +"Common.Controls.Actions.Compose" = "Composa"; "Common.Controls.Actions.Confirm" = "Confirma"; "Common.Controls.Actions.Continue" = "Continua"; "Common.Controls.Actions.CopyPhoto" = "Copia la foto"; @@ -190,6 +191,8 @@ carregat a Mastodon."; toca l'enllaç per a confirmar el teu compte."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Favorite.Title" = "Els teus Favorits"; +"Scene.Follower.Footer" = "Els seguidors d'altres servidors no son mostrats."; +"Scene.Following.Footer" = "Els seguits d'altres servidors no son mostrats."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Veure noves publicacions"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Fora de línia"; "Scene.HomeTimeline.NavigationBarState.Published" = "Publicat!"; diff --git a/Mastodon/Resources/de.lproj/Localizable.strings b/Mastodon/Resources/de.lproj/Localizable.strings index 2780723ed..12fba5387 100644 --- a/Mastodon/Resources/de.lproj/Localizable.strings +++ b/Mastodon/Resources/de.lproj/Localizable.strings @@ -28,6 +28,7 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Actions.Back" = "Zurück"; "Common.Controls.Actions.BlockDomain" = "%@ blockieren"; "Common.Controls.Actions.Cancel" = "Abbrechen"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Bestätigen"; "Common.Controls.Actions.Continue" = "Fortfahren"; "Common.Controls.Actions.CopyPhoto" = "Foto kopieren"; @@ -190,6 +191,8 @@ kann nicht auf Mastodon hochgeladen werden."; tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.ConfirmEmail.Title" = "Noch eine letzte Sache."; "Scene.Favorite.Title" = "Deine Favoriten"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Neue Beiträge anzeigen"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Veröffentlicht!"; diff --git a/Mastodon/Resources/en.lproj/Localizable.strings b/Mastodon/Resources/en.lproj/Localizable.strings index a8852675c..0f3ed66ae 100644 --- a/Mastodon/Resources/en.lproj/Localizable.strings +++ b/Mastodon/Resources/en.lproj/Localizable.strings @@ -28,6 +28,7 @@ Please check your internet connection."; "Common.Controls.Actions.Back" = "Back"; "Common.Controls.Actions.BlockDomain" = "Block %@"; "Common.Controls.Actions.Cancel" = "Cancel"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Confirm"; "Common.Controls.Actions.Continue" = "Continue"; "Common.Controls.Actions.CopyPhoto" = "Copy Photo"; @@ -190,6 +191,8 @@ uploaded to Mastodon."; tap the link to confirm your account."; "Scene.ConfirmEmail.Title" = "One last thing."; "Scene.Favorite.Title" = "Your Favorites"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Published!"; diff --git a/Mastodon/Resources/es-419.lproj/Localizable.strings b/Mastodon/Resources/es-419.lproj/Localizable.strings index 209502b26..3ffd12049 100644 --- a/Mastodon/Resources/es-419.lproj/Localizable.strings +++ b/Mastodon/Resources/es-419.lproj/Localizable.strings @@ -28,6 +28,7 @@ Por favor, revisá tu conexión a Internet."; "Common.Controls.Actions.Back" = "Volver"; "Common.Controls.Actions.BlockDomain" = "Bloquear a %@"; "Common.Controls.Actions.Cancel" = "Cancelar"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Confirmar"; "Common.Controls.Actions.Continue" = "Continuar"; "Common.Controls.Actions.CopyPhoto" = "Copiar foto"; @@ -190,6 +191,8 @@ y no se puede subir a Mastodon."; pulsá en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Favorite.Title" = "Tus favoritos"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ver nuevos mensajes"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Desconectado"; "Scene.HomeTimeline.NavigationBarState.Published" = "¡Enviado!"; diff --git a/Mastodon/Resources/es.lproj/Localizable.strings b/Mastodon/Resources/es.lproj/Localizable.strings index 1fffc928a..5e7f9afbe 100644 --- a/Mastodon/Resources/es.lproj/Localizable.strings +++ b/Mastodon/Resources/es.lproj/Localizable.strings @@ -28,6 +28,7 @@ Por favor, revise su conexión a internet."; "Common.Controls.Actions.Back" = "Atrás"; "Common.Controls.Actions.BlockDomain" = "Bloquear %@"; "Common.Controls.Actions.Cancel" = "Cancelar"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Confirmar"; "Common.Controls.Actions.Continue" = "Continuar"; "Common.Controls.Actions.CopyPhoto" = "Copiar foto"; @@ -190,6 +191,8 @@ subirse a Mastodon."; pulsa en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Favorite.Title" = "Tus Favoritos"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ver nuevas publicaciones"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Sin Conexión"; "Scene.HomeTimeline.NavigationBarState.Published" = "¡Publicado!"; diff --git a/Mastodon/Resources/fr.lproj/Localizable.strings b/Mastodon/Resources/fr.lproj/Localizable.strings index 76df6b600..9514a7a5e 100644 --- a/Mastodon/Resources/fr.lproj/Localizable.strings +++ b/Mastodon/Resources/fr.lproj/Localizable.strings @@ -28,6 +28,7 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Actions.Back" = "Retour"; "Common.Controls.Actions.BlockDomain" = "Bloquer %@"; "Common.Controls.Actions.Cancel" = "Annuler"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Confirmer"; "Common.Controls.Actions.Continue" = "Continuer"; "Common.Controls.Actions.CopyPhoto" = "Copier la photo"; @@ -190,6 +191,8 @@ téléversé sur Mastodon."; tapotez le lien pour confirmer votre compte."; "Scene.ConfirmEmail.Title" = "Une dernière chose."; "Scene.Favorite.Title" = "Vos favoris"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Voir les nouvelles publications"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Hors ligne"; "Scene.HomeTimeline.NavigationBarState.Published" = "Publié!"; diff --git a/Mastodon/Resources/gd-GB.lproj/Localizable.strings b/Mastodon/Resources/gd-GB.lproj/Localizable.strings index 6c01adb0a..3f80f6411 100644 --- a/Mastodon/Resources/gd-GB.lproj/Localizable.strings +++ b/Mastodon/Resources/gd-GB.lproj/Localizable.strings @@ -28,6 +28,7 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Actions.Back" = "Air ais"; "Common.Controls.Actions.BlockDomain" = "Bac %@"; "Common.Controls.Actions.Cancel" = "Sguir dheth"; +"Common.Controls.Actions.Compose" = "Sgrìobh"; "Common.Controls.Actions.Confirm" = "Dearbh"; "Common.Controls.Actions.Continue" = "Lean air adhart"; "Common.Controls.Actions.CopyPhoto" = "Dèan lethbhreac dhen dealbh"; @@ -190,6 +191,8 @@ a luchdadh suas gu Mastodon."; thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.ConfirmEmail.Title" = "Aon rud eile."; "Scene.Favorite.Title" = "Na h-annsachdan agad"; +"Scene.Follower.Footer" = "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn."; +"Scene.Following.Footer" = "Cha dèid cò air a leanas tu air frithealaichean eile a shealltainn."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Seall na postaichean ùra"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Far loidhne"; "Scene.HomeTimeline.NavigationBarState.Published" = "Chaidh fhoillseachadh!"; diff --git a/Mastodon/Resources/ja.lproj/Localizable.strings b/Mastodon/Resources/ja.lproj/Localizable.strings index beadccf22..98bf71639 100644 --- a/Mastodon/Resources/ja.lproj/Localizable.strings +++ b/Mastodon/Resources/ja.lproj/Localizable.strings @@ -28,6 +28,7 @@ "Common.Controls.Actions.Back" = "戻る"; "Common.Controls.Actions.BlockDomain" = "%@をブロック"; "Common.Controls.Actions.Cancel" = "キャンセル"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "確認"; "Common.Controls.Actions.Continue" = "続ける"; "Common.Controls.Actions.CopyPhoto" = "写真をコピー"; @@ -184,6 +185,8 @@ "Scene.ConfirmEmail.Subtitle" = "先程 %@ にメールを送信しました。リンクをタップしてアカウントを確認してください。"; "Scene.ConfirmEmail.Title" = "さいごにもうひとつ。"; "Scene.Favorite.Title" = "お気に入り"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "新しい投稿を見る"; "Scene.HomeTimeline.NavigationBarState.Offline" = "オフライン"; "Scene.HomeTimeline.NavigationBarState.Published" = "投稿しました!"; diff --git a/Mastodon/Resources/ku-TR.lproj/Localizable.strings b/Mastodon/Resources/ku-TR.lproj/Localizable.strings index 345f10cf9..7f84febe0 100644 --- a/Mastodon/Resources/ku-TR.lproj/Localizable.strings +++ b/Mastodon/Resources/ku-TR.lproj/Localizable.strings @@ -28,6 +28,7 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Actions.Back" = "Vegere"; "Common.Controls.Actions.BlockDomain" = "%@ asteng bike"; "Common.Controls.Actions.Cancel" = "Dev jê berde"; +"Common.Controls.Actions.Compose" = "Binivîsîne"; "Common.Controls.Actions.Confirm" = "Bipejirîne"; "Common.Controls.Actions.Continue" = "Bidomîne"; "Common.Controls.Actions.CopyPhoto" = "Wêne kopî bikin"; @@ -90,7 +91,7 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Keyboard.Timeline.ReplyStatus" = "Bersivê bide şandiyê"; "Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Hişyariya naverokê veke/bigire"; "Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Di postê da Bijartin veke/bigire"; -"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Toggle Reblog on Post"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Ji vû nivîsandin di şandiyê de biguherîne"; "Common.Controls.Status.Actions.Favorite" = "Bijartî"; "Common.Controls.Status.Actions.Menu" = "Menû"; "Common.Controls.Status.Actions.Reblog" = "Ji nû ve blog"; @@ -134,25 +135,25 @@ Profîla te ji wan ra wiha xuya dike."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Bêtir bersivan nîşan bide"; "Common.Controls.Timeline.Timestamp.Now" = "Niha"; "Scene.AccountList.AddAccount" = "Ajimêr tevlî bike"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.DismissAccountSwitcher" = "Guherkera ajimêrê paş guh bike"; "Scene.AccountList.TabBarHint" = "Profîla hilbijartî ya niha: %@. Du caran bitikîne û paşê dest bide ser da ku guhêrbara ajimêr were nîşandan"; "Scene.Compose.Accessibility.AppendAttachment" = "Pêvek tevlî bike"; "Scene.Compose.Accessibility.AppendPoll" = "Rapirsî tevlî bike"; -"Scene.Compose.Accessibility.CustomEmojiPicker" = "Custom Emoji Picker"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Hilbijêrê emojî yên kesanekirî"; "Scene.Compose.Accessibility.DisableContentWarning" = "Hişyariya naverokê neçalak bike"; -"Scene.Compose.Accessibility.EnableContentWarning" = "Enable Content Warning"; +"Scene.Compose.Accessibility.EnableContentWarning" = "Hişyariya naverokê neçalak bike"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Menuya Xuyabûna Şandiyê"; "Scene.Compose.Accessibility.RemovePoll" = "Rapirsî rake"; "Scene.Compose.Attachment.AttachmentBroken" = "Ev %@ naxebite û nayê barkirin li ser Mastodon."; -"Scene.Compose.Attachment.DescriptionPhoto" = "Describe the photo for the visually-impaired..."; -"Scene.Compose.Attachment.DescriptionVideo" = "Describe the video for the visually-impaired..."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Wêneyê ji bo kêmbînên dîtbar bide nasîn..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Vîdyoyê ji bo kêmbînên dîtbar bide nasîn..."; "Scene.Compose.Attachment.Photo" = "wêne"; "Scene.Compose.Attachment.Video" = "vîdyo"; -"Scene.Compose.AutoComplete.SpaceToAdd" = "Space to add"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Bicîhkirinê tevlî bike"; "Scene.Compose.ComposeAction" = "Biweşîne"; -"Scene.Compose.ContentInputPlaceholder" = "Type or paste what’s on your mind"; -"Scene.Compose.ContentWarning.Placeholder" = "Write an accurate warning here..."; +"Scene.Compose.ContentInputPlaceholder" = "Tiştê ku di hişê te de ye binivîsin an jî pêve bike"; +"Scene.Compose.ContentWarning.Placeholder" = "Li vir hişyariyek hûrgilî binivîsine..."; "Scene.Compose.Keyboard.AppendAttachmentEntry" = "Pêvek lê zêde bike - %@"; "Scene.Compose.Keyboard.DiscardPost" = "Şandî bihelîne"; "Scene.Compose.Keyboard.PublishPost" = "Şandiye bide weşan"; @@ -182,14 +183,16 @@ Profîla te ji wan ra wiha xuya dike."; "Scene.ConfirmEmail.DontReceiveEmail.Description" = "Kontrol bike ka navnîşana e-nameya te rast e û her wiha peldanka xwe ya spam."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "E-namyê yê dîsa bişîne"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "E-nameyê xwe kontrol bike"; -"Scene.ConfirmEmail.OpenEmailApp.Description" = "We just sent you an email. Check your junk folder if you haven’t."; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "Me tenê ji te re e-nameyek şand. Heke nehatiye peldanka xwe ya spamê kontrol bike."; "Scene.ConfirmEmail.OpenEmailApp.Mail" = "E-name"; "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Rajegirê e-nameyê veke"; -"Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; -"Scene.ConfirmEmail.Subtitle" = "We just sent an email to %@, -tap the link to confirm your account."; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Nameyên xwe yên wergirtî kontrol bike."; +"Scene.ConfirmEmail.Subtitle" = "Me tenê e-nameyek ji %@ re şand, +girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ConfirmEmail.Title" = "Tiştekî dawî."; "Scene.Favorite.Title" = "Bijareyên te"; +"Scene.Follower.Footer" = "Şopîner ji rajekerên din nayê dîtin."; +"Scene.Following.Footer" = "Şopandin ji rajekerên din nayê dîtin."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Şandiyên nû bibîne"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Derhêl"; "Scene.HomeTimeline.NavigationBarState.Published" = "Hate weşandin!"; @@ -250,13 +253,13 @@ tap the link to confirm your account."; "Scene.Register.Input.Username.DuplicatePrompt" = "Navê vê bikarhêner tê girtin."; "Scene.Register.Input.Username.Placeholder" = "navê bikarhêner"; "Scene.Register.Title" = "Ji me re hinekî qala xwe bike."; -"Scene.Report.Content1" = "Are there any other posts you’d like to add to the report?"; -"Scene.Report.Content2" = "Is there anything the moderators should know about this report?"; +"Scene.Report.Content1" = "Şandiyên din hene ku tu dixwazî tevlî ragihandinê bikî?"; +"Scene.Report.Content2" = "Derbarê vê ragihandinê de tiştek heye ku divê çavdêr bizanin?"; "Scene.Report.Send" = "Ragihandinê bişîne"; "Scene.Report.SkipToSend" = "Bêyî şirove bişîne"; "Scene.Report.Step1" = "Gav 1 ji 2"; "Scene.Report.Step2" = "Gav 2 ji 2"; -"Scene.Report.TextPlaceholder" = "Type or paste additional comments"; +"Scene.Report.TextPlaceholder" = "Şiroveyên daxwazkirê binivîsine an jî pê ve bike"; "Scene.Report.Title" = "%@ ragihîne"; "Scene.Search.Recommend.Accounts.Description" = "Dibe ku tu bixwazî van hesaban bişopînî"; "Scene.Search.Recommend.Accounts.Follow" = "Bişopîne"; @@ -306,17 +309,17 @@ Her kîjan rajekar be."; "Scene.ServerRules.Subtitle" = "Ev rêzik ji aliyê rêvebirên %@ ve tên sazkirin."; "Scene.ServerRules.TermsOfService" = "şert û mercên xizmetê"; "Scene.ServerRules.Title" = "Hin qaîdeyên bingehîn."; -"Scene.Settings.Footer.MastodonDescription" = "Mastodon is open source software. You can report issues on GitHub at %@ (%@)"; -"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window"; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon nermalava çavkaniya vekirî ye. Tu dikarî pirsgirêkan li ser GitHub-ê ragihînî di %@ (%@) de"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Sazkariyên çarçoveyê bigire"; "Scene.Settings.Section.Appearance.Automatic" = "Xweber"; "Scene.Settings.Section.Appearance.Dark" = "Her dem tarî"; "Scene.Settings.Section.Appearance.Light" = "Her dem ronî"; "Scene.Settings.Section.Appearance.Title" = "Xuyang"; -"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings"; -"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy"; -"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service"; -"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone"; -"Scene.Settings.Section.Notifications.Boosts" = "Reblogs my post"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Sazkariyên ajimêr"; +"Scene.Settings.Section.BoringZone.Privacy" = "Polîtikaya nihêniyê"; +"Scene.Settings.Section.BoringZone.Terms" = "Mercên bikaranînê"; +"Scene.Settings.Section.BoringZone.Title" = "Devera acizker"; +"Scene.Settings.Section.Notifications.Boosts" = "Şandiya min ji nû ve binivîsine"; "Scene.Settings.Section.Notifications.Favorites" = "Şandiyên min hez kir"; "Scene.Settings.Section.Notifications.Follows" = "Min şopand"; "Scene.Settings.Section.Notifications.Mentions" = "Qale min kir"; @@ -326,21 +329,21 @@ Her kîjan rajekar be."; "Scene.Settings.Section.Notifications.Trigger.Follower" = "şopînerek"; "Scene.Settings.Section.Notifications.Trigger.Noone" = "ne yek"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Min agahdar bike gava"; -"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars"; -"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Avatarên anîmasyonî neçalak bike"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Emojiyên anîmasyonî neçalak bike"; "Scene.Settings.Section.Preference.Title" = "Hilbijarte"; -"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode"; -"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links"; -"Scene.Settings.Section.SpicyZone.Clear" = "Clear Media Cache"; -"Scene.Settings.Section.SpicyZone.Signout" = "Sign Out"; -"Scene.Settings.Section.SpicyZone.Title" = "The Spicy Zone"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Moda tarî ya reş a rastîn"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Ji bo vekirina girêdanan geroka berdest bi kar bîne"; +"Scene.Settings.Section.SpicyZone.Clear" = "Pêşbîra medyayê pak bike"; +"Scene.Settings.Section.SpicyZone.Signout" = "Derkeve"; +"Scene.Settings.Section.SpicyZone.Title" = "Devera germ"; "Scene.Settings.Title" = "Sazkarî"; "Scene.SuggestionAccount.FollowExplain" = "Gava tu kesekî dişopînî, tu yê şandiyê wan di serrûpelê de bibîne."; "Scene.SuggestionAccount.Title" = "Kesên bo ku bişopînî bibîne"; "Scene.Thread.BackTitle" = "Şandî"; -"Scene.Thread.Title" = "Post from %@"; +"Scene.Thread.Title" = "Şandî ji %@"; "Scene.Welcome.Slogan" = "Torên civakî di destên te de."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.AccessibilityHint" = "Du caran bitikîne da ku çarçoveyahilpekok ji holê rakî"; "Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Dest bide ser bişkoja profîlê da ku di navbera gelek ajimêrann de biguherînî."; "Scene.Wizard.NewInMastodon" = "Nû di Mastodon de"; \ No newline at end of file diff --git a/Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict b/Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict index 064b8bf2b..8ae1b812a 100644 --- a/Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ku-TR.lproj/Localizable.stringsdict @@ -109,9 +109,9 @@ NSStringFormatValueTypeKey ld one - 1 reblog + 1 ji nû ve nivîsandin other - %ld reblogs + %ld ji nû ve nivîsandin plural.count.vote diff --git a/Mastodon/Resources/nl.lproj/Localizable.strings b/Mastodon/Resources/nl.lproj/Localizable.strings index 1ebda1172..9c84e138f 100644 --- a/Mastodon/Resources/nl.lproj/Localizable.strings +++ b/Mastodon/Resources/nl.lproj/Localizable.strings @@ -27,6 +27,7 @@ "Common.Controls.Actions.Back" = "Terug"; "Common.Controls.Actions.BlockDomain" = "Blokkeer %@"; "Common.Controls.Actions.Cancel" = "Annuleren"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Bevestigen"; "Common.Controls.Actions.Continue" = "Doorgaan"; "Common.Controls.Actions.CopyPhoto" = "Foto kopiëren"; @@ -184,6 +185,8 @@ Uw profiel ziet er zo uit voor hen."; klik op de link om uw account te bevestigen."; "Scene.ConfirmEmail.Title" = "Nog één ding."; "Scene.Favorite.Title" = "Uw favorieten"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Bekijk nieuwe berichten"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Gepubliceerd!"; diff --git a/Mastodon/Resources/ru.lproj/Localizable.strings b/Mastodon/Resources/ru.lproj/Localizable.strings index 3a8adbbab..1a4f92fc6 100644 --- a/Mastodon/Resources/ru.lproj/Localizable.strings +++ b/Mastodon/Resources/ru.lproj/Localizable.strings @@ -28,6 +28,7 @@ "Common.Controls.Actions.Back" = "Назад"; "Common.Controls.Actions.BlockDomain" = "Заблокировать %@"; "Common.Controls.Actions.Cancel" = "Отмена"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Подтвердить"; "Common.Controls.Actions.Continue" = "Продолжить"; "Common.Controls.Actions.CopyPhoto" = "Скопировать изображение"; @@ -200,6 +201,8 @@ подтвердить свою учётную запись."; "Scene.ConfirmEmail.Title" = "И ещё кое-что."; "Scene.Favorite.Title" = "Ваше избранное"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Показать новые"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Не в сети"; "Scene.HomeTimeline.NavigationBarState.Published" = "Опубликовано!"; diff --git a/Mastodon/Resources/th.lproj/Localizable.strings b/Mastodon/Resources/th.lproj/Localizable.strings index a61b1d15f..d05bb5834 100644 --- a/Mastodon/Resources/th.lproj/Localizable.strings +++ b/Mastodon/Resources/th.lproj/Localizable.strings @@ -28,6 +28,7 @@ "Common.Controls.Actions.Back" = "ย้อนกลับ"; "Common.Controls.Actions.BlockDomain" = "ปิดกั้น %@"; "Common.Controls.Actions.Cancel" = "ยกเลิก"; +"Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "ยืนยัน"; "Common.Controls.Actions.Continue" = "ดำเนินการต่อ"; "Common.Controls.Actions.CopyPhoto" = "คัดลอกรูปภาพ"; @@ -190,6 +191,8 @@ แตะที่ลิงก์เพื่อยืนยันบัญชีของคุณ"; "Scene.ConfirmEmail.Title" = "หนึ่งสิ่งสุดท้าย"; "Scene.Favorite.Title" = "รายการโปรดของคุณ"; +"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "ดูโพสต์ใหม่"; "Scene.HomeTimeline.NavigationBarState.Offline" = "ออฟไลน์"; "Scene.HomeTimeline.NavigationBarState.Published" = "เผยแพร่แล้ว!"; diff --git a/Mastodon/Resources/zh-Hans.lproj/Localizable.strings b/Mastodon/Resources/zh-Hans.lproj/Localizable.strings index 21c41a15d..7a6b02032 100644 --- a/Mastodon/Resources/zh-Hans.lproj/Localizable.strings +++ b/Mastodon/Resources/zh-Hans.lproj/Localizable.strings @@ -28,6 +28,7 @@ "Common.Controls.Actions.Back" = "返回"; "Common.Controls.Actions.BlockDomain" = "屏蔽 %@"; "Common.Controls.Actions.Cancel" = "取消"; +"Common.Controls.Actions.Compose" = "撰写"; "Common.Controls.Actions.Confirm" = "确认"; "Common.Controls.Actions.Continue" = "继续"; "Common.Controls.Actions.CopyPhoto" = "拷贝照片"; @@ -190,6 +191,8 @@ 点击链接确认你的帐户。"; "Scene.ConfirmEmail.Title" = "最后一件事。"; "Scene.Favorite.Title" = "你的喜欢"; +"Scene.Follower.Footer" = "不会显示来自其它服务器的关注者"; +"Scene.Following.Footer" = "不会显示来自其它服务器的关注"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "查看新帖子"; "Scene.HomeTimeline.NavigationBarState.Offline" = "离线"; "Scene.HomeTimeline.NavigationBarState.Published" = "已发送"; From 206beb6d19d46fc71f4b62ee8b79eedb37dd655d Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 16:00:42 +0800 Subject: [PATCH 342/392] chore: update following/follower list footer display logic --- .../Follower/FollowerListViewModel+Diffable.swift | 6 +++++- .../Follower/FollowerListViewModel+State.swift | 2 +- .../Following/FollowingListViewModel+Diffable.swift | 7 ++++++- .../Following/FollowingListViewModel+State.swift | 12 ------------ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift index c048e1723..fc9f31779 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift @@ -48,7 +48,11 @@ extension FollowerListViewModel { case is State.Idle, is State.Loading, is State.Fail: snapshot.appendItems([.bottomLoader], toSection: .main) case is State.NoMore: - let text = "Followers from other servers are not displayed." + guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value, + let userID = self.userID.value, + userID != activeMastodonAuthenticationBox.userID + else { break } + let text = L10n.Scene.Follower.footer snapshot.appendItems([.bottomHeader(text: text)], toSection: .main) default: break diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift index 876933181..30621f6a3 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift @@ -155,7 +155,7 @@ extension FollowerListViewModel.State { let maxID = response.link?.maxID - if hasNewAppend, maxID != nil { + if maxID != nil { stateMachine.enter(Idle.self) } else { stateMachine.enter(NoMore.self) diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift index 58af276d0..dc6f1f6fd 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift @@ -48,7 +48,12 @@ extension FollowingListViewModel { case is State.Idle, is State.Loading, is State.Fail: snapshot.appendItems([.bottomLoader], toSection: .main) case is State.NoMore: - break + guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value, + let userID = self.userID.value, + userID != activeMastodonAuthenticationBox.userID + else { break } + let text = L10n.Scene.Following.footer + snapshot.appendItems([.bottomHeader(text: text)], toSection: .main) default: break } diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift index d5c30b43a..e6fadf7f8 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift @@ -179,18 +179,6 @@ extension FollowingListViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let _ = stateMachine else { return } - guard let diffableDataSource = viewModel.diffableDataSource else { - assertionFailure() - return - } - DispatchQueue.main.async { - var snapshot = diffableDataSource.snapshot() - snapshot.deleteItems([.bottomLoader]) - let header = UserItem.bottomHeader(text: "Followers from other servers are not displayed") - snapshot.appendItems([header], toSection: .main) - diffableDataSource.apply(snapshot, animatingDifferences: false) - } } } } From c9c0aaf148034d46c1218a85067461d90579f50b Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 16:01:22 +0800 Subject: [PATCH 343/392] fix: follower list pagination not works issue --- Mastodon/Service/APIService/APIService+Follower.swift | 5 +++++ .../MastodonSDK/API/Mastodon+API+Account+Followers.swift | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Mastodon/Service/APIService/APIService+Follower.swift b/Mastodon/Service/APIService/APIService+Follower.swift index db29a0a29..f75d2420d 100644 --- a/Mastodon/Service/APIService/APIService+Follower.swift +++ b/Mastodon/Service/APIService/APIService+Follower.swift @@ -23,10 +23,15 @@ extension APIService { let authorization = authorizationBox.userAuthorization let requestMastodonUserID = authorizationBox.userID + let query = Mastodon.API.Account.FollowerQuery( + maxID: maxID, + limit: nil + ) return Mastodon.API.Account.followers( session: session, domain: domain, userID: userID, + query: query, authorization: authorization ) .flatMap { response -> AnyPublisher, Error> in diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift index b09a5f07b..a900a1c12 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Followers.swift @@ -35,11 +35,12 @@ extension Mastodon.API.Account { session: URLSession, domain: String, userID: Mastodon.Entity.Account.ID, + query: FollowerQuery, authorization: Mastodon.API.OAuth.Authorization ) -> AnyPublisher, Error> { let request = Mastodon.API.get( url: followersEndpointURL(domain: domain, userID: userID), - query: nil, + query: query, authorization: authorization ) return session.dataTaskPublisher(for: request) From 6d7de85f6272faab92a7725a5527d5bd780a7341 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 16:02:46 +0800 Subject: [PATCH 344/392] fix: account switcher popover too small issue --- Mastodon/Scene/Root/ContentSplitViewController.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 850b1429f..8ca597872 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -101,7 +101,8 @@ extension ContentSplitViewController: SidebarViewControllerDelegate { let accountListViewController = coordinator.present(scene: .accountList, from: nil, transition: .popover(sourceView: sourceView)) as! AccountListViewController accountListViewController.dragIndicatorView.barView.isHidden = true - accountListViewController.preferredContentSize = CGSize(width: 300, height: 320) + // content width needs > 300 to make checkmark display + accountListViewController.preferredContentSize = CGSize(width: 375, height: 400) } } From 07eab320f40b7e643d0465ad45b4633a2c4fb594 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 16:03:34 +0800 Subject: [PATCH 345/392] fix: iPad layout update not take care of search tab selection logic issue --- .../Root/MainTab/MainTabBarController.swift | 4 ++ .../Scene/Root/RootSplitViewController.swift | 50 +++++++++++++------ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index d34c85531..e76db6b3a 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -351,6 +351,10 @@ extension MainTabBarController { return viewController(of: NotificationViewController.self) } + var searchViewController: SearchViewController? { + return viewController(of: SearchViewController.self) + } + } // MARK: - UITabBarControllerDelegate diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 7c03287f1..13df6f889 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -19,6 +19,8 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + private var isPrimaryDisplay = false + private(set) lazy var contentSplitViewController: ContentSplitViewController = { let contentSplitViewController = ContentSplitViewController() contentSplitViewController.context = context @@ -79,13 +81,6 @@ extension RootSplitViewController { super.viewDidLoad() updateBehavior(size: view.frame.size) - contentSplitViewController.$currentSupplementaryTab - .receive(on: DispatchQueue.main) - .sink { [weak self] _ in - guard let self = self else { return } - self.updateBehavior(size: self.view.frame.size) - } - .store(in: &disposeBag) setupBackground(theme: ThemeService.shared.currentTheme.value) ThemeService.shared.currentTheme @@ -97,6 +92,12 @@ extension RootSplitViewController { .store(in: &disposeBag) } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateBehavior(size: view.frame.size) + } + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) @@ -109,15 +110,23 @@ extension RootSplitViewController { } private func updateBehavior(size: CGSize) { - switch contentSplitViewController.currentSupplementaryTab { - case .search: + if size.width > 960 { + show(.primary) + isPrimaryDisplay = true + + } else { hide(.primary) + isPrimaryDisplay = false + } + + switch (contentSplitViewController.currentSupplementaryTab, isPrimaryDisplay) { + case (.search, true): + // needs switch to other tab when primary display + // use FIFO queue save tab history + contentSplitViewController.currentSupplementaryTab = .home default: - if size.width > 960 { - show(.primary) - } else { - hide(.primary) - } + // do nothing + break } } @@ -140,7 +149,11 @@ extension RootSplitViewController: ContentSplitViewControllerDelegate { return } switch tab { - case .search: + case .search: + guard isPrimaryDisplay else { + // only control search tab behavior when primary display + fallthrough + } guard let navigationController = searchViewController.navigationController else { return } if navigationController.viewControllers.count == 1 { searchViewController.searchBarTapPublisher.send() @@ -165,7 +178,7 @@ extension RootSplitViewController: ContentSplitViewControllerDelegate { // MARK: - UISplitViewControllerDelegate extension RootSplitViewController: UISplitViewControllerDelegate { - private static func transform(from: UITabBarController, to: UITabBarController) { + private static func transform(from: UITabBarController, to: UITabBarController) { let sourceNavigationControllers = from.viewControllers ?? [] let targetNavigationControllers = to.viewControllers ?? [] @@ -181,6 +194,11 @@ extension RootSplitViewController: UISplitViewControllerDelegate { to.selectedIndex = from.selectedIndex } + private static func transform(from: UINavigationController, to: UINavigationController) { + let viewControllers = from.popToRootViewController(animated: false) ?? [] + to.viewControllers.append(contentsOf: viewControllers) + } + // .regular to .compact func splitViewController( _ svc: UISplitViewController, From 30b2a35b84d685f2def2b1c8cfbb2181bd6918bf Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 16:12:20 +0800 Subject: [PATCH 346/392] feat: implement following list --- Mastodon.xcodeproj/project.pbxproj | 4 + .../xcschemes/xcschememanagement.plist | 8 +- .../FollowerListViewModel+State.swift | 2 +- .../FollowingListViewModel+State.swift | 2 +- .../APIService/APIService+Following.swift | 70 ++++++++++++++++ .../API/Mastodon+API+Account+Following.swift | 82 +++++++++++++++++++ 6 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 Mastodon/Service/APIService/APIService+Following.swift create mode 100644 MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Following.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 8408f3ac3..98cff7ec9 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -320,6 +320,7 @@ DB66728C25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66728B25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift */; }; DB66729625F9F91600D60309 /* ComposeStatusSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729525F9F91600D60309 /* ComposeStatusSection.swift */; }; DB66729C25F9F91F00D60309 /* ComposeStatusItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */; }; + DB67D08427312970006A36CF /* APIService+Following.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB67D08327312970006A36CF /* APIService+Following.swift */; }; DB68045B2636DC6A00430867 /* MastodonNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68045A2636DC6A00430867 /* MastodonNotification.swift */; }; DB6804662636DC9000430867 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D939AB425EDD8A90076FA61 /* String.swift */; }; DB68046C2636DC9E00430867 /* MastodonNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68045A2636DC6A00430867 /* MastodonNotification.swift */; }; @@ -1139,6 +1140,7 @@ DB66728B25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ComposeViewModel+DataSource.swift"; sourceTree = ""; }; DB66729525F9F91600D60309 /* ComposeStatusSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusSection.swift; sourceTree = ""; }; DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusItem.swift; sourceTree = ""; }; + DB67D08327312970006A36CF /* APIService+Following.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Following.swift"; sourceTree = ""; }; DB68045A2636DC6A00430867 /* MastodonNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonNotification.swift; sourceTree = ""; }; DB68047F2637CD4C00430867 /* AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DB6804812637CD4C00430867 /* AppShared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppShared.h; sourceTree = ""; }; @@ -2326,6 +2328,7 @@ 2D34D9DA261494120081BFC0 /* APIService+Search.swift */, 0F202212261351F5000C64BF /* APIService+HashtagTimeline.swift */, DB6B74F9272FC2B500C70B6E /* APIService+Follower.swift */, + DB67D08327312970006A36CF /* APIService+Following.swift */, DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */, 5B24BBE1262DB19100A9381B /* APIService+Report.swift */, DBAE3F932616E28B004B8251 /* APIService+Follow.swift */, @@ -4125,6 +4128,7 @@ 2D82B9FF25E7863200E36F0F /* OnboardingViewControllerAppearance.swift in Sources */, 5DF1054725F8870E00D6C0D4 /* VideoPlayerViewModel.swift in Sources */, DB73BF43271192BB00781945 /* InstanceService.swift in Sources */, + DB67D08427312970006A36CF /* APIService+Following.swift in Sources */, DBA9443A265CC0FC00C537E1 /* Fields.swift in Sources */, 2DE0FAC12615F04D00CDF649 /* RecommendHashTagSection.swift in Sources */, DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 2d2dd1932..5a5418919 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 36 + 37 CoreDataStack.xcscheme_^#shared#^_ orderHint - 35 + 36 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 38 + 35 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 38 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift index 30621f6a3..43e532673 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+State.swift @@ -155,7 +155,7 @@ extension FollowerListViewModel.State { let maxID = response.link?.maxID - if maxID != nil { + if hasNewAppend && maxID != nil { stateMachine.enter(Idle.self) } else { stateMachine.enter(NoMore.self) diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift index e6fadf7f8..0ec3d6262 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift @@ -128,7 +128,7 @@ extension FollowingListViewModel.State { return } - viewModel.context.apiService.followers( + viewModel.context.apiService.following( userID: userID, maxID: maxID, authorizationBox: activeMastodonAuthenticationBox diff --git a/Mastodon/Service/APIService/APIService+Following.swift b/Mastodon/Service/APIService/APIService+Following.swift new file mode 100644 index 000000000..8f477d6ec --- /dev/null +++ b/Mastodon/Service/APIService/APIService+Following.swift @@ -0,0 +1,70 @@ +// +// APIService+Following.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import UIKit +import Combine +import CoreData +import CoreDataStack +import CommonOSLog +import MastodonSDK + +extension APIService { + + func following( + userID: Mastodon.Entity.Account.ID, + maxID: String?, + authorizationBox: MastodonAuthenticationBox + ) -> AnyPublisher, Error> { + let domain = authorizationBox.domain + let authorization = authorizationBox.userAuthorization + let requestMastodonUserID = authorizationBox.userID + + let query = Mastodon.API.Account.FollowingQuery( + maxID: maxID, + limit: nil + ) + return Mastodon.API.Account.following( + session: session, + domain: domain, + userID: userID, + query: query, + authorization: authorization + ) + .flatMap { response -> AnyPublisher, Error> in + let managedObjectContext = self.backgroundManagedObjectContext + return managedObjectContext.performChanges { + let requestMastodonUserRequest = MastodonUser.sortedFetchRequest + requestMastodonUserRequest.predicate = MastodonUser.predicate(domain: domain, id: requestMastodonUserID) + requestMastodonUserRequest.fetchLimit = 1 + guard let requestMastodonUser = managedObjectContext.safeFetch(requestMastodonUserRequest).first else { return } + + for entity in response.value { + _ = APIService.CoreData.createOrMergeMastodonUser( + into: managedObjectContext, + for: requestMastodonUser, + in: domain, + entity: entity, + userCache: nil, + networkDate: response.networkDate, + log: .api + ) + } + } + .tryMap { result -> Mastodon.Response.Content<[Mastodon.Entity.Account]> in + switch result { + case .success: + return response + case .failure(let error): + throw error + } + } + .eraseToAnyPublisher() + } + .eraseToAnyPublisher() + } + +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Following.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Following.swift new file mode 100644 index 000000000..c992c7584 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Following.swift @@ -0,0 +1,82 @@ +// +// Mastodon+API+Account+Following.swift +// +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import Foundation +import Combine + +extension Mastodon.API.Account { + + static func followingEndpointURL(domain: String, userID: Mastodon.Entity.Account.ID) -> URL { + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("accounts") + .appendingPathComponent(userID) + .appendingPathComponent("following") + } + + /// Following + /// + /// Accounts which the given account is following, if network is not hidden by the account owner. + /// + /// - Since: 0.0.0 + /// - Version: 3.4.1 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/accounts/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - userID: ID of the account in the database + /// - authorization: User token + /// - Returns: `AnyPublisher` contains `[Account]` nested in the response + public static func following( + session: URLSession, + domain: String, + userID: Mastodon.Entity.Account.ID, + query: FollowingQuery, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: followingEndpointURL(domain: domain, userID: userID), + query: query, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Account].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + public struct FollowingQuery: Codable, GetQuery { + + public let maxID: String? + public let limit: Int? // default 40 + + enum CodingKeys: String, CodingKey { + case maxID = "max_id" + case limit + } + + public init( + maxID: String?, + limit: Int? + ) { + self.maxID = maxID + self.limit = limit + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + maxID.flatMap { items.append(URLQueryItem(name: "max_id", value: $0)) } + limit.flatMap { items.append(URLQueryItem(name: "limit", value: String($0))) } + guard !items.isEmpty else { return nil } + return items + } + + } + +} From a7f6b1d222633bd6e8d3f1703aa31001330d4b9a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 2 Nov 2021 11:38:48 +0100 Subject: [PATCH 347/392] New translations app.json (Spanish) --- Localization/StringsConvertor/input/es_ES/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/es_ES/app.json b/Localization/StringsConvertor/input/es_ES/app.json index 1710318b9..72967c40f 100644 --- a/Localization/StringsConvertor/input/es_ES/app.json +++ b/Localization/StringsConvertor/input/es_ES/app.json @@ -67,7 +67,7 @@ "done": "Hecho", "confirm": "Confirmar", "continue": "Continuar", - "compose": "Compose", + "compose": "Redactar", "cancel": "Cancelar", "discard": "Descartar", "try_again": "Inténtalo de nuevo", @@ -415,10 +415,10 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "No se muestran los seguidores de otros servidores." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "No se muestran los seguidos de otros servidores." }, "search": { "title": "Buscar", From 865718351d3230a447618a85ea855690c8fd5a17 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 19:15:46 +0800 Subject: [PATCH 348/392] feat: update wizard for new iPad design --- Mastodon.xcodeproj/project.pbxproj | 16 +- Mastodon/Coordinator/SceneCoordinator.swift | 24 +- .../Welcome/View/WizardCardView.swift | 7 + .../MainTab/MainTabBarController+Wizard.swift | 137 ------------ .../Root/MainTab/MainTabBarController.swift | 47 ++-- .../Scene/Root/RootSplitViewController.swift | 87 ++++++++ .../Root/Sidebar/SidebarViewController.swift | 1 + .../Scene/Root/Sidebar/SidebarViewModel.swift | 9 +- .../Scene/Wizard/WizardViewController.swift | 211 ++++++++++++++++++ 9 files changed, 371 insertions(+), 168 deletions(-) delete mode 100644 Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift create mode 100644 Mastodon/Scene/Wizard/WizardViewController.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 98cff7ec9..619baa12b 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -315,12 +315,12 @@ DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180F726391D660018D199 /* MediaPreviewingViewController.swift */; }; DB6180FA26391F2E0018D199 /* MediaPreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180F926391F2E0018D199 /* MediaPreviewViewModel.swift */; }; DB63BE7F268DD1070011D3F9 /* NotificationViewController+StatusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63BE7E268DD1070011D3F9 /* NotificationViewController+StatusProvider.swift */; }; - DB647C5726F1E97300F7F82C /* MainTabBarController+Wizard.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB647C5626F1E97300F7F82C /* MainTabBarController+Wizard.swift */; }; DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB647C5826F1EA2700F7F82C /* WizardPreference.swift */; }; DB66728C25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66728B25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift */; }; DB66729625F9F91600D60309 /* ComposeStatusSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729525F9F91600D60309 /* ComposeStatusSection.swift */; }; DB66729C25F9F91F00D60309 /* ComposeStatusItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */; }; DB67D08427312970006A36CF /* APIService+Following.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB67D08327312970006A36CF /* APIService+Following.swift */; }; + DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB67D08527312E67006A36CF /* WizardViewController.swift */; }; DB68045B2636DC6A00430867 /* MastodonNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68045A2636DC6A00430867 /* MastodonNotification.swift */; }; DB6804662636DC9000430867 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D939AB425EDD8A90076FA61 /* String.swift */; }; DB68046C2636DC9E00430867 /* MastodonNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68045A2636DC6A00430867 /* MastodonNotification.swift */; }; @@ -1135,12 +1135,12 @@ DB6180F726391D660018D199 /* MediaPreviewingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewingViewController.swift; sourceTree = ""; }; DB6180F926391F2E0018D199 /* MediaPreviewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewViewModel.swift; sourceTree = ""; }; DB63BE7E268DD1070011D3F9 /* NotificationViewController+StatusProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationViewController+StatusProvider.swift"; sourceTree = ""; }; - DB647C5626F1E97300F7F82C /* MainTabBarController+Wizard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainTabBarController+Wizard.swift"; sourceTree = ""; }; DB647C5826F1EA2700F7F82C /* WizardPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardPreference.swift; sourceTree = ""; }; DB66728B25F9F8DC00D60309 /* ComposeViewModel+DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ComposeViewModel+DataSource.swift"; sourceTree = ""; }; DB66729525F9F91600D60309 /* ComposeStatusSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusSection.swift; sourceTree = ""; }; DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusItem.swift; sourceTree = ""; }; DB67D08327312970006A36CF /* APIService+Following.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Following.swift"; sourceTree = ""; }; + DB67D08527312E67006A36CF /* WizardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardViewController.swift; sourceTree = ""; }; DB68045A2636DC6A00430867 /* MastodonNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonNotification.swift; sourceTree = ""; }; DB68047F2637CD4C00430867 /* AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DB6804812637CD4C00430867 /* AppShared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppShared.h; sourceTree = ""; }; @@ -2529,6 +2529,14 @@ path = Image; sourceTree = ""; }; + DB67D08727312E6A006A36CF /* Wizard */ = { + isa = PBXGroup; + children = ( + DB67D08527312E67006A36CF /* WizardViewController.swift */, + ); + path = Wizard; + sourceTree = ""; + }; DB6804802637CD4C00430867 /* AppShared */ = { isa = PBXGroup; children = ( @@ -2770,7 +2778,6 @@ isa = PBXGroup; children = ( DB8AF54F25C13703002E6C99 /* MainTabBarController.swift */, - DB647C5626F1E97300F7F82C /* MainTabBarController+Wizard.swift */, ); path = MainTab; sourceTree = ""; @@ -2782,6 +2789,7 @@ DB6180E426391A500018D199 /* Transition */, DB852D1D26FB021900FC9D81 /* Root */, DB01409B25C40BB600F9F3CF /* Onboarding */, + DB67D08727312E6A006A36CF /* Wizard */, DB9F58ED26EF435800E7BBE9 /* Account */, 2D38F1D325CD463600561493 /* HomeTimeline */, 2D76316325C14BAC00929FB9 /* PublicTimeline */, @@ -4358,6 +4366,7 @@ DB71FD2C25F86A5100512AE1 /* AvatarStackContainerButton.swift in Sources */, DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */, DBBC24C026A5443100398BB9 /* MastodonTheme.swift in Sources */, + DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */, DBBC24B526A540AE00398BB9 /* AvatarConfigurableView.swift in Sources */, DB9A489026035963008B817C /* APIService+Media.swift in Sources */, DBFEF07726A691FB006D7ED1 /* MastodonAuthenticationBox.swift in Sources */, @@ -4371,7 +4380,6 @@ DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */, DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */, DB6D9F6F2635807F008423CD /* Setting.swift in Sources */, - DB647C5726F1E97300F7F82C /* MainTabBarController+Wizard.swift in Sources */, DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */, DBB525412611ED54002F1F29 /* ProfileHeaderViewController.swift in Sources */, DB6B74F8272FBFB100C70B6E /* FollowerListViewController+Provider.swift in Sources */, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index e7611056f..9fbb2b774 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -23,6 +23,7 @@ final public class SceneCoordinator { private(set) weak var tabBarController: MainTabBarController! private(set) weak var splitViewController: RootSplitViewController? + private(set) var wizardViewController: WizardViewController? private(set) var secondaryStackHashValues = Set() @@ -221,17 +222,34 @@ extension SceneCoordinator { extension SceneCoordinator { func setup() { + let rootViewController: UIViewController switch UIDevice.current.userInterfaceIdiom { case .phone: let viewController = MainTabBarController(context: appContext, coordinator: self) - sceneDelegate.window?.rootViewController = viewController - tabBarController = viewController + self.splitViewController = nil + self.tabBarController = viewController + rootViewController = viewController default: let splitViewController = RootSplitViewController(context: appContext, coordinator: self) self.splitViewController = splitViewController self.tabBarController = splitViewController.contentSplitViewController.mainTabBarController - sceneDelegate.window?.rootViewController = splitViewController + rootViewController = splitViewController } + + let wizardViewController = WizardViewController() + if !wizardViewController.items.isEmpty, + let delegate = rootViewController as? WizardViewControllerDelegate + { + // do not add as child view controller. + // otherwise, the tab bar controller will add as a new tab + wizardViewController.delegate = delegate + wizardViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] + wizardViewController.view.frame = rootViewController.view.bounds + rootViewController.view.addSubview(wizardViewController.view) + self.wizardViewController = wizardViewController + } + + sceneDelegate.window?.rootViewController = rootViewController } func setupOnboardingIfNeeds(animated: Bool) { diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift index 024fb205d..6f18afc94 100644 --- a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift +++ b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift @@ -96,6 +96,13 @@ extension WizardCardView { path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: -.pi / 2, endAngle: -.pi, clockwise: false) path.addLine(to: CGPoint(x: rect.minX - radius, y: rect.maxY + radius + WizardCardView.bubbleArrowHeight)) path.close() + case .allCorners: // no arrow + path.move(to: CGPoint(x: rect.maxX, y: rect.maxY + radius)) + path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.maxY), radius: radius, startAngle: .pi / 2, endAngle: .pi, clockwise: true) + path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: .pi, endAngle: .pi / 2 * 3, clockwise: true) + path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.minY), radius: radius, startAngle: .pi / 2 * 3, endAngle: .pi * 2, clockwise: true) + path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.maxY), radius: radius, startAngle: .pi * 2, endAngle: .pi / 2 * 5, clockwise: true) + path.close() default: assertionFailure("FIXME") } diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift deleted file mode 100644 index b69a6b786..000000000 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController+Wizard.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// MainTabBarController+Wizard.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021-9-15. -// - -import os.log -import UIKit - -protocol WizardDelegate: AnyObject { - func spotlight(item: MainTabBarController.Wizard.Item) -> UIBezierPath - func layoutWizardCard(_ wizard: MainTabBarController.Wizard, item: MainTabBarController.Wizard.Item) -} - -extension MainTabBarController { - class Wizard { - - let logger = Logger(subsystem: "Wizard", category: "UI") - - weak var delegate: WizardDelegate? - - private(set) var items: [Item] - - let backgroundView: UIView = { - let view = UIView() - view.backgroundColor = UIColor.black.withAlphaComponent(0.7) - return view - }() - - init() { - var items: [Item] = [] - if !UserDefaults.shared.didShowMultipleAccountSwitchWizard { - items.append(.multipleAccountSwitch) - } - self.items = items - - let backgroundTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer - backgroundTapGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.Wizard.backgroundTapGestureRecognizerHandler(_:))) - backgroundView.addGestureRecognizer(backgroundTapGestureRecognizer) - } - } -} - -extension MainTabBarController.Wizard { - enum Item { - case multipleAccountSwitch - - var title: String { - return L10n.Scene.Wizard.newInMastodon - } - - var description: String { - switch self { - case .multipleAccountSwitch: - return L10n.Scene.Wizard.multipleAccountSwitchIntroDescription - } - } - - func markAsRead() { - switch self { - case .multipleAccountSwitch: - UserDefaults.shared.didShowMultipleAccountSwitchWizard = true - } - } - } -} - -extension MainTabBarController.Wizard { - - func setup(in view: UIView) { - assert(delegate != nil, "need set delegate before use") - - guard !items.isEmpty else { return } - - backgroundView.frame = view.bounds - backgroundView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(backgroundView) - NSLayoutConstraint.activate([ - backgroundView.topAnchor.constraint(equalTo: view.topAnchor), - backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - } - - func consume() { - guard !items.isEmpty else { - backgroundView.removeFromSuperview() - return - } - let item = items.removeFirst() - perform(item: item) - } - - private func perform(item: Item) { - guard let delegate = delegate else { - assertionFailure() - return - } - - // prepare for reuse - prepareForReuse() - - // set wizard item read - item.markAsRead() - - // add spotlight - let spotlight = delegate.spotlight(item: item) - let maskLayer = CAShapeLayer() - let path = UIBezierPath(rect: backgroundView.bounds) - path.append(spotlight) - maskLayer.fillRule = .evenOdd - maskLayer.path = path.cgPath - backgroundView.layer.mask = maskLayer - - // layout wizard card - delegate.layoutWizardCard(self, item: item) - } - - private func prepareForReuse() { - backgroundView.subviews.forEach { subview in - subview.removeFromSuperview() - } - backgroundView.mask = nil - backgroundView.layer.mask = nil - } - -} - -extension MainTabBarController.Wizard { - @objc private func backgroundTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") - - consume() - } -} diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index e76db6b3a..2cb964277 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -21,8 +21,6 @@ class MainTabBarController: UITabBarController { static let avatarButtonSize = CGSize(width: 25, height: 25) let avatarButton = CircleAvatarButton() - - let wizard = Wizard() var currentTab = CurrentValueSubject(.home) @@ -108,6 +106,8 @@ class MainTabBarController: UITabBarController { var _viewControllers: [UIViewController] = [] + private(set) var isReadyForWizardAvatarButton = false + init(context: AppContext, coordinator: SceneCoordinator) { self.context = context self.coordinator = coordinator @@ -247,9 +247,6 @@ extension MainTabBarController { profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName) } .store(in: &disposeBag) - - wizard.delegate = self - wizard.setup(in: view) let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer() tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:))) @@ -265,7 +262,7 @@ extension MainTabBarController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - wizard.consume() + isReadyForWizardAvatarButton = true } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { @@ -377,51 +374,57 @@ extension MainTabBarController: UITabBarControllerDelegate { } } -// MARK: - WizardDataSource -extension MainTabBarController: WizardDelegate { - func spotlight(item: Wizard.Item) -> UIBezierPath { +// MARK: - WizardViewControllerDelegate +extension MainTabBarController: WizardViewControllerDelegate { + func readyToLayoutItem(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> Bool { switch item { case .multipleAccountSwitch: - guard let avatarButtonFrameInView = avatarButtonFrameInView() else { - return UIBezierPath() - } - return UIBezierPath(ovalIn: avatarButtonFrameInView) - + return isReadyForWizardAvatarButton } } - func layoutWizardCard(_ wizard: MainTabBarController.Wizard, item: Wizard.Item) { + func layoutSpotlight(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> UIBezierPath { switch item { case .multipleAccountSwitch: - guard let avatarButtonFrameInView = avatarButtonFrameInView() else { + guard let avatarButtonFrameInView = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) else { + return UIBezierPath() + } + return UIBezierPath(ovalIn: avatarButtonFrameInView) + } + } + + func layoutWizardCard(_ wizardViewController: WizardViewController, item: WizardViewController.Item) { + switch item { + case .multipleAccountSwitch: + guard let avatarButtonFrameInView = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) else { return } let anchorView = UIView() anchorView.frame = avatarButtonFrameInView - wizard.backgroundView.addSubview(anchorView) + wizardViewController.backgroundView.addSubview(anchorView) let wizardCardView = WizardCardView() wizardCardView.arrowRectCorner = view.traitCollection.layoutDirection == .leftToRight ? .bottomRight : .bottomLeft wizardCardView.titleLabel.text = item.title wizardCardView.descriptionLabel.text = item.description - + wizardCardView.translatesAutoresizingMaskIntoConstraints = false - wizard.backgroundView.addSubview(wizardCardView) + wizardViewController.backgroundView.addSubview(wizardCardView) NSLayoutConstraint.activate([ anchorView.topAnchor.constraint(equalTo: wizardCardView.bottomAnchor, constant: 13), // 13pt spacing wizardCardView.trailingAnchor.constraint(equalTo: anchorView.centerXAnchor), - wizardCardView.widthAnchor.constraint(equalTo: wizard.backgroundView.widthAnchor, multiplier: 2.0/3.0).priority(.required - 1), + wizardCardView.widthAnchor.constraint(equalTo: wizardViewController.view.widthAnchor, multiplier: 2.0/3.0).priority(.required - 1), ]) wizardCardView.setContentHuggingPriority(.defaultLow, for: .vertical) } } - private func avatarButtonFrameInView() -> CGRect? { + private func avatarButtonFrameInWizardView(wizardView: UIView) -> CGRect? { guard let superview = avatarButton.superview else { assertionFailure() return nil } - return superview.convert(avatarButton.frame, to: view) + return superview.convert(avatarButton.frame, to: wizardView) } } diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 13df6f889..2b3c858e0 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -241,3 +241,90 @@ extension RootSplitViewController: UISplitViewControllerDelegate { } } + +// MARK: - WizardViewControllerDelegate +extension RootSplitViewController: WizardViewControllerDelegate { + + func readyToLayoutItem(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> Bool { + guard traitCollection.horizontalSizeClass != .compact else { + return compactMainTabBarViewController.readyToLayoutItem(wizardViewController, item: item) + } + + switch item { + case .multipleAccountSwitch: + return contentSplitViewController.sidebarViewController.viewModel.isReadyForWizardAvatarButton + } + } + + + func layoutSpotlight(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> UIBezierPath { + guard traitCollection.horizontalSizeClass != .compact else { + return compactMainTabBarViewController.layoutSpotlight(wizardViewController, item: item) + } + + switch item { + case .multipleAccountSwitch: + guard let frame = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) + else { + assertionFailure() + return UIBezierPath() + } + return UIBezierPath(ovalIn: frame) + } + } + + func layoutWizardCard(_ wizardViewController: WizardViewController, item: WizardViewController.Item) { + guard traitCollection.horizontalSizeClass != .compact else { + return compactMainTabBarViewController.layoutWizardCard(wizardViewController, item: item) + } + + guard let frame = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) else { + return + } + + let anchorView = UIView() + anchorView.frame = frame + wizardViewController.backgroundView.addSubview(anchorView) + + let wizardCardView = WizardCardView() + wizardCardView.arrowRectCorner = .allCorners // no arrow + wizardCardView.titleLabel.text = item.title + wizardCardView.descriptionLabel.text = item.description + + wizardCardView.translatesAutoresizingMaskIntoConstraints = false + wizardViewController.backgroundView.addSubview(wizardCardView) + NSLayoutConstraint.activate([ + wizardCardView.centerYAnchor.constraint(equalTo: anchorView.centerYAnchor), + wizardCardView.leadingAnchor.constraint(equalTo: anchorView.trailingAnchor, constant: 20), // 20pt spacing + wizardCardView.widthAnchor.constraint(equalToConstant: 320), + ]) + wizardCardView.setContentHuggingPriority(.defaultLow, for: .vertical) + } + + private func avatarButtonFrameInWizardView(wizardView: UIView) -> CGRect? { + guard let diffableDataSource = contentSplitViewController.sidebarViewController.viewModel.diffableDataSource, + let indexPath = diffableDataSource.indexPath(for: .tab(.me)), + let cell = contentSplitViewController.sidebarViewController.collectionView.cellForItem(at: indexPath) as? SidebarListCollectionViewCell, + let contentView = cell._contentView, + let frame = sourceViewFrameInTargetView( + sourceView: contentView.avatarButton, + targetView: wizardView + ) + else { + assertionFailure() + return nil + } + return frame + } + + private func sourceViewFrameInTargetView( + sourceView: UIView, + targetView: UIView + ) -> CGRect? { + guard let superview = sourceView.superview else { + assertionFailure() + return nil + } + return superview.convert(sourceView.frame, to: targetView) + } +} diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 7958c5080..d2dae2478 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -125,6 +125,7 @@ extension SidebarViewController { secondaryCollectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] secondaryCollectionView, _ in guard let self = self else { return } + self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): secondaryCollectionView contentSize: \(secondaryCollectionView.contentSize.debugDescription)") let height = secondaryCollectionView.contentSize.height self.secondaryCollectionViewHeightLayoutConstraint.constant = height self.collectionView.contentInset.bottom = height diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 83abf4e6b..1f982429e 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -23,6 +23,7 @@ final class SidebarViewModel { // output var diffableDataSource: UICollectionViewDiffableDataSource? var secondaryDiffableDataSource: UICollectionViewDiffableDataSource? + private(set) var isReadyForWizardAvatarButton = false let activeMastodonAuthenticationObjectID = CurrentValueSubject(nil) @@ -170,8 +171,12 @@ extension SidebarViewModel { .setting, ] sectionSnapshot.append(items, to: nil) - _diffableDataSource.apply(sectionSnapshot, to: .main) - + // animatingDifferences must to be `true` + // otherwise the UI layout will infinity loop + _diffableDataSource.apply(sectionSnapshot, to: .main, animatingDifferences: true) { [weak self] in + guard let self = self else { return } + self.isReadyForWizardAvatarButton = true + } // secondary let _secondaryDiffableDataSource = UICollectionViewDiffableDataSource(collectionView: secondaryCollectionView) { collectionView, indexPath, item in diff --git a/Mastodon/Scene/Wizard/WizardViewController.swift b/Mastodon/Scene/Wizard/WizardViewController.swift new file mode 100644 index 000000000..2678c712d --- /dev/null +++ b/Mastodon/Scene/Wizard/WizardViewController.swift @@ -0,0 +1,211 @@ +// +// WizardViewController.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-2. +// + +import os.log +import UIKit +import Combine + +protocol WizardViewControllerDelegate: AnyObject { + func readyToLayoutItem(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> Bool + func layoutSpotlight(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> UIBezierPath + func layoutWizardCard(_ wizardViewController: WizardViewController, item: WizardViewController.Item) +} + +class WizardViewController: UIViewController { + + let logger = Logger(subsystem: "Wizard", category: "UI") + + var disposeBag = Set() + weak var delegate: WizardViewControllerDelegate? + + private(set) var items: [Item] = { + var items: [Item] = [] + if !UserDefaults.shared.didShowMultipleAccountSwitchWizard { + items.append(.multipleAccountSwitch) + } + return items + }() + + let pendingItem = CurrentValueSubject(nil) + let currentItem = CurrentValueSubject(nil) + + let backgroundView: UIView = { + let view = UIView() + view.backgroundColor = UIColor.black.withAlphaComponent(0.7) + return view + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension WizardViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + setup() + + let backgroundTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer + backgroundTapGestureRecognizer.addTarget(self, action: #selector(WizardViewController.backgroundTapGestureRecognizerHandler(_:))) + backgroundView.addGestureRecognizer(backgroundTapGestureRecognizer) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + // Create a timer to consume pending item + Timer.publish(every: 0.5, on: .main, in: .default) + .autoconnect() + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard self.pendingItem.value != nil else { return } + self.consume() + } + .store(in: &disposeBag) + + consume() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + invalidLayoutForCurrentItem() + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + coordinator.animate { context in + + } completion: { [weak self] context in + guard let self = self else { return } + self.invalidLayoutForCurrentItem() + } + + } + +} + +extension WizardViewController { + enum Item { + case multipleAccountSwitch + + var title: String { + return L10n.Scene.Wizard.newInMastodon + } + + var description: String { + switch self { + case .multipleAccountSwitch: + return L10n.Scene.Wizard.multipleAccountSwitchIntroDescription + } + } + + func markAsRead() { + switch self { + case .multipleAccountSwitch: + UserDefaults.shared.didShowMultipleAccountSwitchWizard = true + } + } + } +} + +extension WizardViewController { + + func setup() { + assert(delegate != nil, "need set delegate before use") + + guard !items.isEmpty else { return } + + backgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + backgroundView.frame = view.bounds + view.addSubview(backgroundView) + } + + func destroy() { + view.removeFromSuperview() + } + + func consume() { + guard !items.isEmpty else { + destroy() + return + } + + guard let first = items.first else { return } + guard delegate?.readyToLayoutItem(self, item: first) == true else { + pendingItem.value = first + return + } + pendingItem.value = nil + currentItem.value = nil + + let item = items.removeFirst() + perform(item: item) + } + + private func perform(item: Item) { + guard let delegate = delegate else { + assertionFailure() + return + } + + // prepare for reuse + prepareForReuse() + + // set wizard item read + item.markAsRead() + + // add spotlight + let spotlight = delegate.layoutSpotlight(self, item: item) + let maskLayer = CAShapeLayer() + // expand rect to make sure view always fill the screen when device rotate + let expandRect: CGRect = { + var rect = backgroundView.bounds + rect.size.width *= 2 + rect.size.height *= 2 + return rect + }() + let path = UIBezierPath(rect: expandRect) + path.append(spotlight) + maskLayer.fillRule = .evenOdd + maskLayer.path = path.cgPath + backgroundView.layer.mask = maskLayer + + // layout wizard card + delegate.layoutWizardCard(self, item: item) + + currentItem.value = item + } + + private func prepareForReuse() { + backgroundView.subviews.forEach { subview in + subview.removeFromSuperview() + } + backgroundView.mask = nil + backgroundView.layer.mask = nil + } + + private func invalidLayoutForCurrentItem() { + if let item = currentItem.value { + perform(item: item) + } + } + +} + +extension WizardViewController { + @objc private func backgroundTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + consume() + } +} From 1aea75fb830f01a3a76d90f0f435dbb03e1b6cd3 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Nov 2021 19:16:34 +0800 Subject: [PATCH 349/392] chore: update version to 1.2.0 (83) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 16c084cec..be737c933 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 16c084cec..be737c933 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 16c084cec..be737c933 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 619baa12b..a2a357c8c 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4903,7 +4903,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4932,7 +4932,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5040,11 +5040,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5071,11 +5071,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5100,11 +5100,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5130,11 +5130,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5197,7 +5197,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5222,7 +5222,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5247,7 +5247,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5272,7 +5272,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5297,7 +5297,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5322,7 +5322,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5347,7 +5347,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5372,7 +5372,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5463,7 +5463,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5530,11 +5530,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5579,7 +5579,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5604,11 +5604,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5700,7 +5700,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5767,11 +5767,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5816,7 +5816,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5841,11 +5841,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 82; + DYLIB_CURRENT_VERSION = 83; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5871,7 +5871,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5895,7 +5895,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 82; + CURRENT_PROJECT_VERSION = 83; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 5a5418919..fce311786 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 37 + 44 CoreDataStack.xcscheme_^#shared#^_ orderHint - 36 + 43 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 35 + 41 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 38 + 42 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index a75982e39..f5b56d6da 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 82 + 83 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index ed243297d..a79ce28b2 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 16c084cec..be737c933 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 16c084cec..be737c933 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 89e562534..7f407c80d 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 79ba82cef..fd2a138c0 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 82 + 83 NSExtension NSExtensionAttributes From f6351f3c35a1adbdfdb3393ae7893590ddad9cac Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 2 Nov 2021 19:03:38 +0100 Subject: [PATCH 350/392] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index f9e56214c..7852b5d01 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -67,7 +67,7 @@ "done": "เสร็จสิ้น", "confirm": "ยืนยัน", "continue": "ดำเนินการต่อ", - "compose": "Compose", + "compose": "เขียน", "cancel": "ยกเลิก", "discard": "ละทิ้ง", "try_again": "ลองอีกครั้ง", @@ -415,10 +415,10 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "ไม่ได้แสดงผู้ติดตามจากเซิร์ฟเวอร์อื่น ๆ" }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "ไม่ได้แสดงการติดตามจากเซิร์ฟเวอร์อื่น ๆ" }, "search": { "title": "ค้นหา", From 716326351e5f0206b8f12c5fcfef01eaf75aabc9 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 14:24:52 +0800 Subject: [PATCH 351/392] feat: add store rating supports --- Mastodon.xcodeproj/project.pbxproj | 4 +++ .../xcschemes/xcschememanagement.plist | 8 +++--- .../Preference/StoreReviewPreference.swift | 26 +++++++++++++++++++ ...meTimelineViewController+DebugAction.swift | 6 +++++ .../HomeTimelineViewController.swift | 16 ++++++++++++ Mastodon/Service/StatusPublishService.swift | 2 +- Mastodon/Supporting Files/AppDelegate.swift | 5 ++++ 7 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 Mastodon/Preference/StoreReviewPreference.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a2a357c8c..5e23b5786 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -321,6 +321,7 @@ DB66729C25F9F91F00D60309 /* ComposeStatusItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */; }; DB67D08427312970006A36CF /* APIService+Following.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB67D08327312970006A36CF /* APIService+Following.swift */; }; DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB67D08527312E67006A36CF /* WizardViewController.swift */; }; + DB67D089273256D7006A36CF /* StoreReviewPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB67D088273256D7006A36CF /* StoreReviewPreference.swift */; }; DB68045B2636DC6A00430867 /* MastodonNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68045A2636DC6A00430867 /* MastodonNotification.swift */; }; DB6804662636DC9000430867 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D939AB425EDD8A90076FA61 /* String.swift */; }; DB68046C2636DC9E00430867 /* MastodonNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68045A2636DC6A00430867 /* MastodonNotification.swift */; }; @@ -1141,6 +1142,7 @@ DB66729B25F9F91F00D60309 /* ComposeStatusItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusItem.swift; sourceTree = ""; }; DB67D08327312970006A36CF /* APIService+Following.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Following.swift"; sourceTree = ""; }; DB67D08527312E67006A36CF /* WizardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardViewController.swift; sourceTree = ""; }; + DB67D088273256D7006A36CF /* StoreReviewPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreReviewPreference.swift; sourceTree = ""; }; DB68045A2636DC6A00430867 /* MastodonNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonNotification.swift; sourceTree = ""; }; DB68047F2637CD4C00430867 /* AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DB6804812637CD4C00430867 /* AppShared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppShared.h; sourceTree = ""; }; @@ -2447,6 +2449,7 @@ DB1D842F26566512000346B3 /* KeyboardPreference.swift */, DBCBCC0C2680B908000F5B51 /* HomeTimelinePreference.swift */, DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */, + DB67D088273256D7006A36CF /* StoreReviewPreference.swift */, ); path = Preference; sourceTree = ""; @@ -4101,6 +4104,7 @@ DBE3CE01261D623D00430CC6 /* FavoriteViewModel+State.swift in Sources */, 2D82BA0525E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift in Sources */, 2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */, + DB67D089273256D7006A36CF /* StoreReviewPreference.swift in Sources */, DB5B7295273112B100081888 /* FollowingListViewController.swift in Sources */, 0F202201261326E6000C64BF /* HashtagTimelineViewModel.swift in Sources */, DB6D9F9726367249008423CD /* SettingsViewController.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index fce311786..e6093a218 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 44 + 35 CoreDataStack.xcscheme_^#shared#^_ orderHint - 43 + 38 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 41 + 36 MastodonIntents.xcscheme_^#shared#^_ @@ -117,7 +117,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 42 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Preference/StoreReviewPreference.swift b/Mastodon/Preference/StoreReviewPreference.swift new file mode 100644 index 000000000..e3a403f6d --- /dev/null +++ b/Mastodon/Preference/StoreReviewPreference.swift @@ -0,0 +1,26 @@ +// +// StoreReviewPreference.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-3. +// + +import Foundation + +extension UserDefaults { + + @objc dynamic var processCompletedCount: Int { + get { + return integer(forKey: #function) + } + set { self[#function] = newValue } + } + + @objc dynamic var lastVersionPromptedForReview: String? { + get { + return string(forKey: #function) + } + set { self[#function] = newValue } + } + +} diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index 6d79d0603..6e75a17e7 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -15,6 +15,7 @@ import FLEX import SwiftUI import MastodonUI import MastodonSDK +import StoreKit extension HomeTimelineViewController { var debugMenu: UIMenu { @@ -77,6 +78,11 @@ extension HomeTimelineViewController { guard let self = self else { return } self.showThreadAction(action) }, + UIAction(title: "Store Rating", image: UIImage(systemName: "star.fill"), attributes: []) { [weak self] action in + guard let self = self else { return } + guard let windowScene = self.view.window?.windowScene else { return } + SKStoreReviewController.requestReview(in: windowScene) + }, ] ) } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 6b5476885..62695f211 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -14,6 +14,7 @@ import CoreDataStack import GameplayKit import MastodonSDK import AlamofireImage +import StoreKit final class HomeTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { @@ -144,6 +145,21 @@ extension HomeTimelineViewController { } .store(in: &disposeBag) + viewModel.homeTimelineNavigationBarTitleViewModel.state + .removeDuplicates() + .filter { $0 == .publishedButton } + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard UserDefaults.shared.lastVersionPromptedForReview == nil else { return } + guard UserDefaults.shared.processCompletedCount > 3 else { return } + guard let windowScene = self.view.window?.windowScene else { return } + let version = UIApplication.appVersion() + UserDefaults.shared.lastVersionPromptedForReview = version + SKStoreReviewController.requestReview(in: windowScene) + } + .store(in: &disposeBag) + tableView.refreshControl = refreshControl refreshControl.addTarget(self, action: #selector(HomeTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged) diff --git a/Mastodon/Service/StatusPublishService.swift b/Mastodon/Service/StatusPublishService.swift index ed894f933..f5c4cb2dd 100644 --- a/Mastodon/Service/StatusPublishService.swift +++ b/Mastodon/Service/StatusPublishService.swift @@ -12,6 +12,7 @@ import Combine import CoreData import CoreDataStack import MastodonSDK +import UIKit final class StatusPublishService { @@ -72,7 +73,6 @@ extension StatusPublishService { self.viewModels.value = viewModels os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: composeViewModel removed", ((#file as NSString).lastPathComponent), #line, #function) - } } diff --git a/Mastodon/Supporting Files/AppDelegate.swift b/Mastodon/Supporting Files/AppDelegate.swift index 87d16241a..e2cb7c41b 100644 --- a/Mastodon/Supporting Files/AppDelegate.swift +++ b/Mastodon/Supporting Files/AppDelegate.swift @@ -36,6 +36,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { UNUserNotificationCenter.current().delegate = self application.registerForRemoteNotifications() + // increase app process count + var count = UserDefaults.shared.processCompletedCount + count += 1 // Int64. could ignore overflow here + UserDefaults.shared.processCompletedCount = count + #if ASDK && DEBUG // PerformanceMonitor.shared().start() // ASDisplayNode.shouldShowRangeDebugOverlay = true From bab09c36fde9a6cbaf587e842277c8bb13b6a8bb Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 15:15:55 +0800 Subject: [PATCH 352/392] fix: AutoLayout may enter infinity layout loop issue --- .../Scene/Root/Sidebar/SidebarViewController.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index d2dae2478..b5f67e769 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -125,10 +125,16 @@ extension SidebarViewController { secondaryCollectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] secondaryCollectionView, _ in guard let self = self else { return } + + let contentHeight = secondaryCollectionView.contentSize.height + guard contentHeight > 0 else { return } self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): secondaryCollectionView contentSize: \(secondaryCollectionView.contentSize.debugDescription)") - let height = secondaryCollectionView.contentSize.height - self.secondaryCollectionViewHeightLayoutConstraint.constant = height - self.collectionView.contentInset.bottom = height + + let currentFrameHeight = secondaryCollectionView.frame.height + guard currentFrameHeight < contentHeight else { return } + + self.secondaryCollectionViewHeightLayoutConstraint.constant = contentHeight + self.collectionView.contentInset.bottom = contentHeight } .store(in: &observations) @@ -147,7 +153,6 @@ extension SidebarViewController { coordinator.animate { context in self.collectionView.collectionViewLayout.invalidateLayout() -// // do nothing } completion: { [weak self] context in // guard let self = self else { return } } From 757578e97e7d3c0f9439b70e9d759f5a8ff5416a Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 15:16:17 +0800 Subject: [PATCH 353/392] fix: image transitioning clip invisible tab bar issue --- ...viewViewControllerAnimatedTransitioning.swift | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift index 9fbbbd888..ec4ac35ad 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift @@ -184,9 +184,13 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { let maskLayerToPath = maskLayerToRect.flatMap { UIBezierPath(rect: $0) }?.cgPath let maskLayerToFinalRect: CGRect? = { guard case .mosaic = transitionItem.source else { return nil } - guard let tabBarController = toVC.tabBarController, let tabBarSuperView = tabBarController.tabBar.superview else { return nil } - let tabBarFrameInWindow = tabBarSuperView.convert(tabBarController.tabBar.frame, to: nil) var rect = maskLayerToRect ?? transitionMaskView.frame + // clip tabBar when bar visible + guard let tabBarController = toVC.tabBarController, + !tabBarController.tabBar.isHidden, + let tabBarSuperView = tabBarController.tabBar.superview + else { return rect } + let tabBarFrameInWindow = tabBarSuperView.convert(tabBarController.tabBar.frame, to: nil) let offset = rect.maxY - tabBarFrameInWindow.minY guard offset > 0 else { return rect } rect.size.height -= offset @@ -473,9 +477,13 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { let maskLayerToFinalRect: CGRect? = { guard case .mosaic = transitionItem.source else { return nil } - guard let tabBarController = toVC.tabBarController, let tabBarSuperView = tabBarController.tabBar.superview else { return nil } - let tabBarFrameInWindow = tabBarSuperView.convert(tabBarController.tabBar.frame, to: nil) var rect = maskLayerToRect ?? transitionMaskView.frame + // clip rect bottom when tabBar visible + guard let tabBarController = toVC.tabBarController, + !tabBarController.tabBar.isHidden, + let tabBarSuperView = tabBarController.tabBar.superview + else { return rect } + let tabBarFrameInWindow = tabBarSuperView.convert(tabBarController.tabBar.frame, to: nil) let offset = rect.maxY - tabBarFrameInWindow.minY guard offset > 0 else { return rect } rect.size.height -= offset From e15e373f3db4e74c1625124c3bfdd5e35590bc0f Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 15:29:25 +0800 Subject: [PATCH 354/392] fix: search controller cannot trigger become first responder issue --- Mastodon/Scene/Root/RootSplitViewController.swift | 4 ++-- .../Search/SearchDetail/SearchDetailViewController.swift | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 2b3c858e0..f13383de6 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -307,8 +307,8 @@ extension RootSplitViewController: WizardViewControllerDelegate { let cell = contentSplitViewController.sidebarViewController.collectionView.cellForItem(at: indexPath) as? SidebarListCollectionViewCell, let contentView = cell._contentView, let frame = sourceViewFrameInTargetView( - sourceView: contentView.avatarButton, - targetView: wizardView + sourceView: contentView.avatarButton, + targetView: wizardView ) else { assertionFailure() diff --git a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift index b401e7955..486a3b48a 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift @@ -245,7 +245,9 @@ extension SearchDetailViewController { searchBar.becomeFirstResponder() } else { searchController.isActive = true - searchController.searchBar.becomeFirstResponder() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.33) { + self.searchController.searchBar.becomeFirstResponder() + } } } From b95dc6ad279d72b3a5ad074f987628a15bd0bfd8 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 15:31:59 +0800 Subject: [PATCH 355/392] chore: update i18n resources --- Mastodon/Resources/es.lproj/Localizable.strings | 6 +++--- Mastodon/Resources/th.lproj/Localizable.strings | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mastodon/Resources/es.lproj/Localizable.strings b/Mastodon/Resources/es.lproj/Localizable.strings index 5e7f9afbe..dcf12dfe2 100644 --- a/Mastodon/Resources/es.lproj/Localizable.strings +++ b/Mastodon/Resources/es.lproj/Localizable.strings @@ -28,7 +28,7 @@ Por favor, revise su conexión a internet."; "Common.Controls.Actions.Back" = "Atrás"; "Common.Controls.Actions.BlockDomain" = "Bloquear %@"; "Common.Controls.Actions.Cancel" = "Cancelar"; -"Common.Controls.Actions.Compose" = "Compose"; +"Common.Controls.Actions.Compose" = "Redactar"; "Common.Controls.Actions.Confirm" = "Confirmar"; "Common.Controls.Actions.Continue" = "Continuar"; "Common.Controls.Actions.CopyPhoto" = "Copiar foto"; @@ -191,8 +191,8 @@ subirse a Mastodon."; pulsa en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Favorite.Title" = "Tus Favoritos"; -"Scene.Follower.Footer" = "Followers from other servers are not displayed."; -"Scene.Following.Footer" = "Follows from other servers are not displayed."; +"Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; +"Scene.Following.Footer" = "No se muestran los seguidos de otros servidores."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ver nuevas publicaciones"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Sin Conexión"; "Scene.HomeTimeline.NavigationBarState.Published" = "¡Publicado!"; diff --git a/Mastodon/Resources/th.lproj/Localizable.strings b/Mastodon/Resources/th.lproj/Localizable.strings index d05bb5834..1bd954fe5 100644 --- a/Mastodon/Resources/th.lproj/Localizable.strings +++ b/Mastodon/Resources/th.lproj/Localizable.strings @@ -28,7 +28,7 @@ "Common.Controls.Actions.Back" = "ย้อนกลับ"; "Common.Controls.Actions.BlockDomain" = "ปิดกั้น %@"; "Common.Controls.Actions.Cancel" = "ยกเลิก"; -"Common.Controls.Actions.Compose" = "Compose"; +"Common.Controls.Actions.Compose" = "เขียน"; "Common.Controls.Actions.Confirm" = "ยืนยัน"; "Common.Controls.Actions.Continue" = "ดำเนินการต่อ"; "Common.Controls.Actions.CopyPhoto" = "คัดลอกรูปภาพ"; @@ -191,8 +191,8 @@ แตะที่ลิงก์เพื่อยืนยันบัญชีของคุณ"; "Scene.ConfirmEmail.Title" = "หนึ่งสิ่งสุดท้าย"; "Scene.Favorite.Title" = "รายการโปรดของคุณ"; -"Scene.Follower.Footer" = "Followers from other servers are not displayed."; -"Scene.Following.Footer" = "Follows from other servers are not displayed."; +"Scene.Follower.Footer" = "ไม่ได้แสดงผู้ติดตามจากเซิร์ฟเวอร์อื่น ๆ"; +"Scene.Following.Footer" = "ไม่ได้แสดงการติดตามจากเซิร์ฟเวอร์อื่น ๆ"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "ดูโพสต์ใหม่"; "Scene.HomeTimeline.NavigationBarState.Offline" = "ออฟไลน์"; "Scene.HomeTimeline.NavigationBarState.Published" = "เผยแพร่แล้ว!"; From a590917afdb294d37c4d61546a75715bebc43e7e Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 15:49:42 +0800 Subject: [PATCH 356/392] chore: update MetaTextKit package version to v2.1.2 to workaround SDWebImage crash issue --- Mastodon.xcodeproj/project.pbxproj | 66 +++++++++---------- .../xcschemes/xcschememanagement.plist | 34 +++++----- .../xcshareddata/swiftpm/Package.resolved | 4 +- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 5e23b5786..1c0c420dd 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4907,7 +4907,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4936,7 +4936,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5044,11 +5044,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5075,11 +5075,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5104,11 +5104,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5201,7 +5201,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5226,7 +5226,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5251,7 +5251,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5276,7 +5276,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5301,7 +5301,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5326,7 +5326,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5351,7 +5351,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5376,7 +5376,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5467,7 +5467,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5534,11 +5534,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5583,7 +5583,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5608,11 +5608,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5704,7 +5704,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5771,11 +5771,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5820,7 +5820,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5845,11 +5845,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 83; + DYLIB_CURRENT_VERSION = 84; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5875,7 +5875,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5899,7 +5899,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 83; + CURRENT_PROJECT_VERSION = 84; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -6070,7 +6070,7 @@ repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git"; requirement = { kind = exactVersion; - version = 2.1.1; + version = 2.1.2; }; }; DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index e6093a218..1bf25c439 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 35 + 38 CoreDataStack.xcscheme_^#shared#^_ orderHint - 38 + 37 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -22,7 +22,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 13 + 14 Mastodon - Release.xcscheme_^#shared#^_ @@ -32,17 +32,17 @@ Mastodon - ar.xcscheme_^#shared#^_ orderHint - 10 + 11 Mastodon - ca.xcscheme_^#shared#^_ orderHint - 16 + 17 Mastodon - de.xcscheme_^#shared#^_ orderHint - 11 + 12 Mastodon - en.xcscheme_^#shared#^_ @@ -52,42 +52,42 @@ Mastodon - es-419.xcscheme_^#shared#^_ orderHint - 8 + 9 Mastodon - es.xcscheme_^#shared#^_ orderHint - 7 + 8 Mastodon - fr.xcscheme_^#shared#^_ orderHint - 9 + 10 Mastodon - jp.xcscheme_^#shared#^_ orderHint - 14 + 15 Mastodon - nl.xcscheme_^#shared#^_ orderHint - 12 + 13 Mastodon - ru.xcscheme_^#shared#^_ orderHint - 4 + 5 Mastodon - th.xcscheme_^#shared#^_ orderHint - 5 + 6 Mastodon - zh_Hans.xcscheme_^#shared#^_ orderHint - 15 + 16 Mastodon.xcscheme_^#shared#^_ @@ -97,7 +97,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 36 + 39 MastodonIntents.xcscheme_^#shared#^_ @@ -112,12 +112,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 6 + 7 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 41 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index b305c8156..11dde7269 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -96,8 +96,8 @@ "repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git", "state": { "branch": null, - "revision": "a5f412b72fc08cd1348e2388fc7ec326365e1823", - "version": "2.1.1" + "revision": "7af4182f64329440a4656f2cba307cb5848e496a", + "version": "2.1.2" } }, { From 66f69ccd65b31b22a4e6f9df1b9f0fe61c0eabea Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 15:50:48 +0800 Subject: [PATCH 357/392] chore: update version to 1.2.0 (84) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index be737c933..af3c11d9a 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index be737c933..af3c11d9a 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index be737c933..af3c11d9a 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index f5b56d6da..c5ed838f9 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 83 + 84 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index a79ce28b2..43bd255d9 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index be737c933..af3c11d9a 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index be737c933..af3c11d9a 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 7f407c80d..7250b3468 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index fd2a138c0..262484f7b 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 83 + 84 NSExtension NSExtensionAttributes From 1338757670871abef2c4fc45eb59b3eaf1b158b5 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 16:13:11 +0800 Subject: [PATCH 358/392] chore: update gitignore rules --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2c475f675..a605c524d 100644 --- a/.gitignore +++ b/.gitignore @@ -122,5 +122,4 @@ xcuserdata Localization/StringsConvertor/input Localization/StringsConvertor/output -.DS_Store -/Mastodon.xcworkspace/xcshareddata/swiftpm +.DS_Store \ No newline at end of file From 9dac014c7f87673cb7a0abb4b5abe0256cb400e7 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 3 Nov 2021 16:21:09 +0800 Subject: [PATCH 359/392] chore: update CI configure for Xcode 13.1 --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea365bca9..b2979d002 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,8 +19,8 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 - - name: force Xcode 13.0 - run: sudo xcode-select -switch /Applications/Xcode_13.0.app + - name: force Xcode 13.1 + run: sudo xcode-select -switch /Applications/Xcode_13.1.app - name: setup run: exec ./.github/scripts/setup.sh - name: build From 42ea3f95ca4758e29511801292b904acf08bb396 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 12:17:02 +0800 Subject: [PATCH 360/392] fix: some language issue may clip trend card label issue --- .../SearchRecommendTagsCollectionViewCell.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift index 3734bc8a4..3a20788b5 100644 --- a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift +++ b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift @@ -27,6 +27,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell { let label = UILabel() label.textColor = .white label.font = .preferredFont(forTextStyle: .body) + label.numberOfLines = 2 return label }() From 00cf2db8a1573ae80bd7f495b18ca14df360226a Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 14:12:22 +0800 Subject: [PATCH 361/392] chore: set sidebar logo color to app tint color --- Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift index 2056c5dcd..6a1bb3ddf 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListHeaderView.swift @@ -11,7 +11,8 @@ final class SidebarListHeaderView: UICollectionReusableView { let imageView: UIImageView = { let imageView = UIImageView() - imageView.image = Asset.Scene.Sidebar.logo.image + imageView.image = Asset.Scene.Sidebar.logo.image.withRenderingMode(.alwaysTemplate) + imageView.tintColor = .label return imageView }() From 469acd12f544c006ca299e766c30f60bb817a9a1 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 15:13:17 +0800 Subject: [PATCH 362/392] fix: account switch scene not adopt elevated color issue --- .../Scene/Account/AccountViewController.swift | 12 ++++++++-- .../Cell/AccountListTableViewCell.swift | 10 ++++++++ .../Cell/AddAccountTableViewCell.swift | 12 ++++++++++ .../MastodonRegisterViewController.swift | 4 ++-- .../Scene/Report/ReportViewController.swift | 24 +++++++++---------- .../Report/ReportedStatusTableviewCell.swift | 3 ++- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index 4f2ece253..fce9c7320 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -75,7 +75,7 @@ extension AccountListViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor.withAlphaComponent(0.9) + setupBackgroundColor(theme: ThemeService.shared.currentTheme.value) ThemeService.shared.currentTheme .receive(on: DispatchQueue.main) .sink { [weak self] theme in @@ -131,7 +131,15 @@ extension AccountListViewController { } private func setupBackgroundColor(theme: Theme) { - view.backgroundColor = theme.systemBackgroundColor.withAlphaComponent(0.9) + let backgroundColor = UIColor { traitCollection in + switch traitCollection.userInterfaceLevel { + case .elevated where traitCollection.userInterfaceStyle == .dark: + return theme.systemElevatedBackgroundColor + default: + return theme.systemBackgroundColor.withAlphaComponent(0.9) + } + } + view.backgroundColor = backgroundColor } } diff --git a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift index b8f7d5381..f6ab75877 100644 --- a/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AccountListTableViewCell.swift @@ -12,6 +12,7 @@ import MetaTextKit final class AccountListTableViewCell: UITableViewCell { + private var _disposeBag = Set() var disposeBag = Set() let avatarButton = CircleAvatarButton(frame: .zero) @@ -47,6 +48,15 @@ final class AccountListTableViewCell: UITableViewCell { extension AccountListTableViewCell { private func _init() { + backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemGroupedBackgroundColor + ThemeService.shared.currentTheme + .receive(on: RunLoop.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemGroupedBackgroundColor + } + .store(in: &_disposeBag) + avatarButton.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(avatarButton) NSLayoutConstraint.activate([ diff --git a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift index 722896641..0873c1390 100644 --- a/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift +++ b/Mastodon/Scene/Account/Cell/AddAccountTableViewCell.swift @@ -6,10 +6,13 @@ // import UIKit +import Combine import MetaTextKit final class AddAccountTableViewCell: UITableViewCell { + private var _disposeBag = Set() + let iconImageView: UIImageView = { let image = UIImage(systemName: "plus.circle.fill")! let imageView = UIImageView(image: image) @@ -41,6 +44,15 @@ final class AddAccountTableViewCell: UITableViewCell { extension AddAccountTableViewCell { private func _init() { + backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemGroupedBackgroundColor + ThemeService.shared.currentTheme + .receive(on: RunLoop.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemGroupedBackgroundColor + } + .store(in: &_disposeBag) + iconImageView.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(iconImageView) NSLayoutConstraint.activate([ diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift index b86c46745..4cf4da14d 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift @@ -312,7 +312,7 @@ extension MastodonRegisterViewController { view.addGestureRecognizer(tapGestureRecognizer) tapGestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerHandler)) - // stackview + // stackView stackView.axis = .vertical stackView.distribution = .fill stackView.spacing = 40 @@ -370,7 +370,7 @@ extension MastodonRegisterViewController { scrollView.frameLayoutGuide.widthAnchor.constraint(equalTo: scrollView.contentLayoutGuide.widthAnchor), ]) - // stackview + // stackView scrollView.addSubview(stackView) stackView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ diff --git a/Mastodon/Scene/Report/ReportViewController.swift b/Mastodon/Scene/Report/ReportViewController.swift index 6a7161c91..b97424cb5 100644 --- a/Mastodon/Scene/Report/ReportViewController.swift +++ b/Mastodon/Scene/Report/ReportViewController.swift @@ -51,7 +51,7 @@ class ReportViewController: UIViewController, NeedsDependency { return view }() - lazy var stackview: UIStackView = { + lazy var stackView: UIStackView = { let view = UIStackView() view.axis = .vertical view.alignment = .fill @@ -122,19 +122,19 @@ class ReportViewController: UIViewController, NeedsDependency { setupNavigation() - stackview.addArrangedSubview(header) - stackview.addArrangedSubview(contentView) - stackview.addArrangedSubview(footer) - stackview.addArrangedSubview(bottomSpacing) + stackView.addArrangedSubview(header) + stackView.addArrangedSubview(contentView) + stackView.addArrangedSubview(footer) + stackView.addArrangedSubview(bottomSpacing) contentView.addSubview(tableView) - view.addSubview(stackview) + view.addSubview(stackView) NSLayoutConstraint.activate([ - stackview.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), - stackview.leadingAnchor.constraint(equalTo: view.leadingAnchor), - stackview.bottomAnchor.constraint(equalTo: view.bottomAnchor), - stackview.trailingAnchor.constraint(equalTo: view.trailingAnchor), + stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.topAnchor.constraint(equalTo: contentView.topAnchor), tableView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), @@ -273,8 +273,8 @@ class ReportViewController: UIViewController, NeedsDependency { navigationItem.titleView = titleView if let user = beReportedUser { do { - let mastodonConent = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojiMeta) - let metaContent = try MastodonMetaContent.convert(document: mastodonConent) + let mastodonContent = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojiMeta) + let metaContent = try MastodonMetaContent.convert(document: mastodonContent) titleView.update(titleMetaContent: metaContent, subtitle: nil) } catch { let metaContent = PlaintextMetaContent(string: user.displayNameWithFallback) diff --git a/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift b/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift index ff566a248..0880c479a 100644 --- a/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift +++ b/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift @@ -19,6 +19,7 @@ final class ReportedStatusTableViewCell: UITableViewCell, StatusCell { static let bottomPaddingHeight: CGFloat = 10 weak var dependency: ReportViewController? + private var _disposeBag = Set() var disposeBag = Set() var observations = Set() @@ -98,7 +99,7 @@ extension ReportedStatusTableViewCell { guard let self = self else { return } self.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemGroupedBackgroundColor } - .store(in: &disposeBag) + .store(in: &_disposeBag) checkbox.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(checkbox) From 0462ade3ae46e239c7c488853d65ff8ce2325082 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 15:20:37 +0800 Subject: [PATCH 363/392] fix: iPad columns separator line color not update when toggle device appearance issue --- Mastodon/Scene/Root/RootSplitViewController.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index f13383de6..505e9089d 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -109,6 +109,12 @@ extension RootSplitViewController { } } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + setupBackground(theme: ThemeService.shared.currentTheme.value) + } + private func updateBehavior(size: CGSize) { if size.width > 960 { show(.primary) @@ -136,7 +142,7 @@ extension RootSplitViewController { private func setupBackground(theme: Theme) { // this set column separator line color - view.backgroundColor = theme.separator + view.backgroundColor = .opaqueSeparator } } From 1cbc38525395fd9fc51d9ba4e80281d102dd5a1e Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 15:21:12 +0800 Subject: [PATCH 364/392] fix: sidebar avatar button color not update when toggle device appearance issue --- .../Root/Sidebar/View/SidebarListContentView.swift | 2 +- Mastodon/Scene/Share/View/Button/AvatarButton.swift | 12 ++++++++++++ .../Scene/Share/View/Button/CircleAvatarButton.swift | 11 +++++++---- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift index d85d3a8be..d6ae40e17 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -18,7 +18,7 @@ final class SidebarListContentView: UIView, UIContentView { let avatarButton: CircleAvatarButton = { let button = CircleAvatarButton() button.borderWidth = 2 - button.borderColor = UIColor.label.cgColor + button.borderColor = UIColor.label return button }() diff --git a/Mastodon/Scene/Share/View/Button/AvatarButton.swift b/Mastodon/Scene/Share/View/Button/AvatarButton.swift index 9bc87a053..6249ea373 100644 --- a/Mastodon/Scene/Share/View/Button/AvatarButton.swift +++ b/Mastodon/Scene/Share/View/Button/AvatarButton.swift @@ -38,6 +38,18 @@ class AvatarButton: UIControl { avatarImageView.bottomAnchor.constraint(equalTo: bottomAnchor), ]) } + + override func layoutSubviews() { + super.layoutSubviews() + + updateAppearance() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + updateAppearance() + } func updateAppearance() { avatarImageView.alpha = primaryActionState.contains(.highlighted) ? 0.6 : 1.0 diff --git a/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift b/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift index 0bc2aeefd..74591dda9 100644 --- a/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift +++ b/Mastodon/Scene/Share/View/Button/CircleAvatarButton.swift @@ -9,15 +9,18 @@ import UIKit final class CircleAvatarButton: AvatarButton { - var borderColor: CGColor = UIColor.systemFill.cgColor + @Published var needsHighlighted = false + + var borderColor: UIColor = UIColor.systemFill var borderWidth: CGFloat = 1.0 - override func layoutSubviews() { - super.layoutSubviews() + override func updateAppearance() { + super.updateAppearance() layer.masksToBounds = true layer.cornerRadius = frame.width * 0.5 - layer.borderColor = borderColor + layer.borderColor = borderColor.cgColor layer.borderWidth = borderWidth } + } From 868e86e0776a0fa40e39186a18cc6c4ab452e8af Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 16:24:42 +0800 Subject: [PATCH 365/392] feat: make tabBar avatar button border highlighted when selected --- .../Scene/Root/MainTab/MainTabBarController.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 2cb964277..8688a8fab 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -252,6 +252,14 @@ extension MainTabBarController { tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:))) tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer) + currentTab + .receive(on: DispatchQueue.main) + .sink { [weak self] tab in + guard let self = self else { return } + self.updateAvatarButtonAppearance() + } + .store(in: &disposeBag) + updateTabBarDisplay() #if DEBUG @@ -269,6 +277,7 @@ extension MainTabBarController { super.traitCollectionDidChange(previousTraitCollection) updateTabBarDisplay() + updateAvatarButtonAppearance() } } @@ -340,6 +349,11 @@ extension MainTabBarController { self.avatarButton.setContentHuggingPriority(.required - 1, for: .vertical) self.avatarButton.isUserInteractionEnabled = false } + + private func updateAvatarButtonAppearance() { + avatarButton.borderColor = currentTab.value == .me ? .label : .systemFill + avatarButton.setNeedsLayout() + } } extension MainTabBarController { From 29e3d10e9737f4b34691ba9eeb4b15c79af84dc2 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 19:22:51 +0800 Subject: [PATCH 366/392] fix: wizard display before sign-in at the first time install issue --- .../Root/MainTab/MainTabBarController.swift | 14 ++++++----- .../Scene/Root/Sidebar/SidebarViewModel.swift | 24 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 8688a8fab..4b803bc49 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -252,6 +252,14 @@ extension MainTabBarController { tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:))) tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer) + context.authenticationService.activeMastodonAuthenticationBox + .receive(on: DispatchQueue.main) + .sink { [weak self] authenticationBox in + guard let self = self else { return } + self.isReadyForWizardAvatarButton = authenticationBox != nil + } + .store(in: &disposeBag) + currentTab .receive(on: DispatchQueue.main) .sink { [weak self] tab in @@ -267,12 +275,6 @@ extension MainTabBarController { #endif } - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - isReadyForWizardAvatarButton = true - } - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 1f982429e..5ababf161 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -18,32 +18,36 @@ final class SidebarViewModel { // input let context: AppContext - let searchHistoryFetchedResultController: SearchHistoryFetchedResultController - + @Published private var isSidebarDataSourceReady = false + @Published private var isAvatarButtonDataReady = false + // output var diffableDataSource: UICollectionViewDiffableDataSource? var secondaryDiffableDataSource: UICollectionViewDiffableDataSource? - private(set) var isReadyForWizardAvatarButton = false + @Published private(set) var isReadyForWizardAvatarButton = false let activeMastodonAuthenticationObjectID = CurrentValueSubject(nil) init(context: AppContext) { self.context = context - self.searchHistoryFetchedResultController = SearchHistoryFetchedResultController(managedObjectContext: context.managedObjectContext) + + Publishers.CombineLatest( + $isSidebarDataSourceReady, + $isAvatarButtonDataReady + ) + .map { $0 && $1 } + .assign(to: &$isReadyForWizardAvatarButton) context.authenticationService.activeMastodonAuthentication .sink { [weak self] authentication in guard let self = self else { return } - // bind search history - self.searchHistoryFetchedResultController.domain.value = authentication?.domain - self.searchHistoryFetchedResultController.userID.value = authentication?.userID // bind objectID self.activeMastodonAuthenticationObjectID.value = authentication?.objectID + + self.isAvatarButtonDataReady = authentication != nil } .store(in: &disposeBag) - - try? searchHistoryFetchedResultController.fetchedResultsController.performFetch() } } @@ -175,7 +179,7 @@ extension SidebarViewModel { // otherwise the UI layout will infinity loop _diffableDataSource.apply(sectionSnapshot, to: .main, animatingDifferences: true) { [weak self] in guard let self = self else { return } - self.isReadyForWizardAvatarButton = true + self.isSidebarDataSourceReady = true } // secondary From cd9d7982bccf61f0f2430b916bce5298204d7456 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 19:24:06 +0800 Subject: [PATCH 367/392] chore: display illustration in welcome scene --- .../xcschemes/xcschememanagement.plist | 19 +++-- .../MastodonRegisterViewController.swift | 71 ++++++++++++++++--- .../OnboardingViewControllerAppearance.swift | 6 +- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 1bf25c439..921a52196 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,17 +7,17 @@ AppShared.xcscheme_^#shared#^_ orderHint - 38 + 36 CoreDataStack.xcscheme_^#shared#^_ orderHint - 37 + 38 Mastodon - ASDK.xcscheme_^#shared#^_ orderHint - 3 + 4 Mastodon - RTL.xcscheme_^#shared#^_ @@ -27,7 +27,7 @@ Mastodon - Release.xcscheme_^#shared#^_ orderHint - 2 + 3 Mastodon - ar.xcscheme_^#shared#^_ @@ -37,18 +37,23 @@ Mastodon - ca.xcscheme_^#shared#^_ orderHint - 17 + 18 Mastodon - de.xcscheme_^#shared#^_ orderHint 12 - Mastodon - en.xcscheme_^#shared#^_ + Mastodon - double length.xcscheme_^#shared#^_ orderHint 1 + Mastodon - en.xcscheme_^#shared#^_ + + orderHint + 2 + Mastodon - es-419.xcscheme_^#shared#^_ orderHint @@ -117,7 +122,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 41 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift index 4cf4da14d..8428aaa79 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift @@ -802,23 +802,48 @@ extension MastodonRegisterViewController { let password = viewModel.password.value let locale: String = { - let fallbackLanguageCode = Locale.current.languageCode ?? "en" + guard let url = Bundle.main.url(forResource: "local-codes", withExtension: "json"), + let data = try? Data(contentsOf: url), + let localCode = try? JSONDecoder().decode(MastodonLocalCode.self, from: data) + else { + assertionFailure() + return "en" + } + let fallbackLanguageCode: String = { + let code = Locale.current.languageCode ?? "en" + guard localCode[code] != nil else { return "en" } + return code + }() + + // pick device preferred language guard let identifier = Locale.preferredLanguages.first else { return fallbackLanguageCode } + // prepare languageCode and validate then return fallback if needs let local = Locale(identifier: identifier) - guard let languageCode = local.languageCode else { + guard let languageCode = local.languageCode, + localCode[languageCode] != nil + else { return fallbackLanguageCode } - switch languageCode { - case "zh": - // Check Simplified Chinese / Traditional Chinese - // https://github.com/gunchleoc/mastodon/blob/ed6153b8f24d3a8f5a124cc95683bd1f20aec882/app/helpers/settings_helper.rb - guard let regionCode = local.regionCode else { return languageCode } - return "zh" + "-" + regionCode - default: + // prepare extendCode and validate then return fallback if needs + let extendCodes: [String] = { + let locales = Locale.preferredLanguages.map { Locale(identifier: $0) } + return locales.compactMap { locale in + guard let languageCode = locale.languageCode, + let regionCode = locale.regionCode + else { return nil } + return languageCode + "-" + regionCode + } + }() + let _firstMatchExtendCode = extendCodes.first { code in + localCode[code] != nil + } + guard let firstMatchExtendCode = _firstMatchExtendCode else { return languageCode } + return firstMatchExtendCode + }() let query = Mastodon.API.Account.RegisterQuery( reason: viewModel.reason.value, @@ -828,6 +853,8 @@ extension MastodonRegisterViewController { agreement: true, // user confirmed in the server rules scene locale: locale ) + + var retryCount = 0 // register without show server rules context.apiService.accountRegister( @@ -835,6 +862,32 @@ extension MastodonRegisterViewController { query: query, authorization: viewModel.applicationAuthorization ) + .tryCatch { [weak self] error -> AnyPublisher, Error> in + guard let self = self else { throw error } + guard let error = self.viewModel.error.value as? Mastodon.API.Error, + case let .generic(errorEntity) = error.mastodonError, + errorEntity.error == "Validation failed: Locale is not included in the list" + else { + throw error + } + guard retryCount == 0 else { + throw error + } + let retryQuery = Mastodon.API.Account.RegisterQuery( + reason: query.reason, + username: query.username, + email: query.email, + password: query.password, + agreement: query.agreement, + locale: self.viewModel.instance.languages?.first ?? "en" + ) + retryCount += 1 + return self.context.apiService.accountRegister( + domain: self.viewModel.domain, + query: retryQuery, + authorization: self.viewModel.applicationAuthorization + ) + } .receive(on: DispatchQueue.main) .sink { [weak self] completion in guard let self = self else { return } diff --git a/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift b/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift index 4a4d04bf6..17c4699ec 100644 --- a/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift +++ b/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift @@ -80,8 +80,8 @@ extension OnboardingViewControllerAppearance { extension OnboardingViewControllerAppearance { static var viewEdgeMargin: CGFloat { guard UIDevice.current.userInterfaceIdiom == .pad else { return .zero } - - let shortEdgeWidth = min(UIScreen.main.bounds.height, UIScreen.main.bounds.width) - return shortEdgeWidth * 0.17 // magic + return 20 +// let shortEdgeWidth = min(UIScreen.main.bounds.height, UIScreen.main.bounds.width) +// return shortEdgeWidth * 0.17 // magic } } From 6117c903f14508c7c7ef79e88a7ba42d3eb0b0f3 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 19:24:46 +0800 Subject: [PATCH 368/392] fix: register may fail due to locale parameter issue --- Mastodon.xcodeproj/project.pbxproj | 8 + Mastodon/Helper/MastodonLocalCode.swift | 12 ++ Mastodon/Resources/local-codes.json | 80 ++++++++ .../Welcome/WelcomeViewController.swift | 191 ++++++++++-------- 4 files changed, 202 insertions(+), 89 deletions(-) create mode 100644 Mastodon/Helper/MastodonLocalCode.swift create mode 100644 Mastodon/Resources/local-codes.json diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 1c0c420dd..a1fec6337 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -607,6 +607,8 @@ DBF1D24E269DAF5D00C1C08A /* SearchDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */; }; DBF1D251269DB01200C1C08A /* SearchHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */; }; DBF1D257269DBAC600C1C08A /* SearchDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */; }; + DBF3B73F2733EAED00E21627 /* local-codes.json in Resources */ = {isa = PBXBuildFile; fileRef = DBF3B73E2733EAED00E21627 /* local-codes.json */; }; + DBF3B7412733EB9400E21627 /* MastodonLocalCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */; }; DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */ = {isa = PBXBuildFile; productRef = DBF7A0FB26830C33004176A2 /* FPSIndicator */; }; DBF8AE16263293E400C9C23C /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF8AE15263293E400C9C23C /* NotificationService.swift */; }; DBF8AE1A263293E400C9C23C /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = DBF8AE13263293E400C9C23C /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -1426,6 +1428,8 @@ DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewController.swift; sourceTree = ""; }; DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryViewController.swift; sourceTree = ""; }; DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewModel.swift; sourceTree = ""; }; + DBF3B73E2733EAED00E21627 /* local-codes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "local-codes.json"; sourceTree = ""; }; + DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLocalCode.swift; sourceTree = ""; }; DBF53F5F25C14E88008AAC7B /* Mastodon.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = Mastodon.xctestplan; path = Mastodon/Mastodon.xctestplan; sourceTree = ""; }; DBF53F6025C14E9D008AAC7B /* MastodonSDK.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MastodonSDK.xctestplan; sourceTree = ""; }; DBF8AE13263293E400C9C23C /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2212,6 +2216,7 @@ isa = PBXGroup; children = ( 164F0EBB267D4FE400249499 /* BoopSound.caf */, + DBF3B73E2733EAED00E21627 /* local-codes.json */, DB427DDE25BAA00100D1B89D /* Assets.xcassets */, DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */, DB564BCE269F2F83001E39A7 /* Localizable.stringsdict */, @@ -3146,6 +3151,7 @@ DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */, DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */, DBFEF07626A691FB006D7ED1 /* MastodonAuthenticationBox.swift */, + DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */, ); path = Helper; sourceTree = ""; @@ -3663,6 +3669,7 @@ DB427DDF25BAA00100D1B89D /* Assets.xcassets in Resources */, DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */, DBA4B0F626C269880077136E /* Intents.stringsdict in Resources */, + DBF3B73F2733EAED00E21627 /* local-codes.json in Resources */, DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */, DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */, DB68A05D25E9055900CFDF14 /* Settings.bundle in Resources */, @@ -4400,6 +4407,7 @@ 2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */, DB1EE7B2267F9525000CC337 /* StatusProvider+StatusNodeDelegate.swift in Sources */, 5B24BBE2262DB19100A9381B /* APIService+Report.swift in Sources */, + DBF3B7412733EB9400E21627 /* MastodonLocalCode.swift in Sources */, DB4F096A269EDAD200D62E92 /* SearchResultViewModel+State.swift in Sources */, 5BB04FF5262F0E6D0043BFF6 /* ReportSection.swift in Sources */, DBA94436265CBB7400C537E1 /* ProfileFieldItem.swift in Sources */, diff --git a/Mastodon/Helper/MastodonLocalCode.swift b/Mastodon/Helper/MastodonLocalCode.swift new file mode 100644 index 000000000..65d71895e --- /dev/null +++ b/Mastodon/Helper/MastodonLocalCode.swift @@ -0,0 +1,12 @@ +// +// MastodonLocalCode.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-4. +// + +import Foundation + +// https://github.com/gunchleoc/mastodon/blob/ed6153b8f24d3a8f5a124cc95683bd1f20aec882/app/helpers/settings_helper.rb +// last update 2021/11/4 +typealias MastodonLocalCode = [String: String] diff --git a/Mastodon/Resources/local-codes.json b/Mastodon/Resources/local-codes.json new file mode 100644 index 000000000..949649791 --- /dev/null +++ b/Mastodon/Resources/local-codes.json @@ -0,0 +1,80 @@ +{ + "af": "Afrikaans", + "ar": "العربية", + "ast": "Asturianu", + "bg": "Български", + "bn": "বাংলা", + "br": "Breton", + "ca": "Català", + "co": "Corsu", + "cs": "Čeština", + "cy": "Cymraeg", + "da": "Dansk", + "de": "Deutsch", + "el": "Ελληνικά", + "en": "English", + "eo": "Esperanto", + "es-AR": "Español (Argentina)", + "es": "Español", + "et": "Eesti", + "eu": "Euskara", + "fa": "فارسی", + "fi": "Suomi", + "fr": "Français", + "ga": "Gaeilge", + "gd": "Gàidhlig", + "gl": "Galego", + "he": "עברית", + "hi": "हिन्दी", + "hr": "Hrvatski", + "hu": "Magyar", + "hy": "Հայերեն", + "id": "Bahasa Indonesia", + "io": "Ido", + "is": "Íslenska", + "it": "Italiano", + "ja": "日本語", + "ka": "ქართული", + "kab": "Taqbaylit", + "kk": "Қазақша", + "kn": "ಕನ್ನಡ", + "ko": "한국어", + "ku": "سۆرانی", + "lt": "Lietuvių", + "lv": "Latviešu", + "mk": "Македонски", + "ml": "മലയാളം", + "mr": "मराठी", + "ms": "Bahasa Melayu", + "nl": "Nederlands", + "nn": "Nynorsk", + "no": "Norsk", + "oc": "Occitan", + "pl": "Polski", + "pt-BR": "Português (Brasil)", + "pt-PT": "Português (Portugal)", + "pt": "Português", + "ro": "Română", + "ru": "Русский", + "sa": "संस्कृतम्", + "sc": "Sardu", + "si": "සිංහල", + "sk": "Slovenčina", + "sl": "Slovenščina", + "sq": "Shqip", + "sr-Latn": "Srpski (latinica)", + "sr": "Српски", + "sv": "Svenska", + "ta": "தமிழ்", + "te": "తెలుగు", + "th": "ไทย", + "tr": "Türkçe", + "uk": "Українська", + "ur": "اُردُو", + "vi": "Tiếng Việt", + "zgh": "ⵜⴰⵎⴰⵣⵉⵖⵜ", + "zh-CN": "简体中文", + "zh-HK": "繁體中文(香港)", + "zh-TW": "繁體中文(臺灣)", + "zh": "中文" +} \ No newline at end of file diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index a2a266f9d..bf33ea13d 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -15,6 +15,7 @@ final class WelcomeViewController: UIViewController, NeedsDependency { weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var disposeBag = Set() + var observations = Set() private(set) lazy var viewModel = WelcomeViewModel(context: context) let welcomeIllustrationView = WelcomeIllustrationView() @@ -23,7 +24,7 @@ final class WelcomeViewController: UIViewController, NeedsDependency { private(set) lazy var dismissBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(WelcomeViewController.dismissBarButtonItemDidPressed(_:))) private(set) lazy var logoImageView: UIImageView = { - let image = view.traitCollection.userInterfaceIdiom == .phone ? Asset.Scene.Welcome.mastodonLogo.image : Asset.Scene.Welcome.mastodonLogoBlackLarge.image + let image = Asset.Scene.Welcome.mastodonLogo.image let imageView = UIImageView(image: image) imageView.translatesAutoresizingMaskIntoConstraints = false return imageView @@ -40,15 +41,15 @@ final class WelcomeViewController: UIViewController, NeedsDependency { return label }() - private(set) lazy var signUpButton: PrimaryActionButton = { + private(set) lazy var signUpButton: PrimaryActionButton = { let button = PrimaryActionButton() button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal) - let backgroundImageColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? .white : Asset.Colors.brandBlue.color - let backgroundImageHighlightedColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? UIColor(white: 0.8, alpha: 1.0) : Asset.Colors.brandBlueDarken20.color + let backgroundImageColor: UIColor = .white + let backgroundImageHighlightedColor: UIColor = UIColor(white: 0.8, alpha: 1.0) button.setBackgroundImage(.placeholder(color: backgroundImageColor), for: .normal) button.setBackgroundImage(.placeholder(color: backgroundImageHighlightedColor), for: .highlighted) - let titleColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? Asset.Colors.brandBlue.color : UIColor.white + let titleColor: UIColor = Asset.Colors.brandBlue.color button.setTitleColor(titleColor, for: .normal) button.translatesAutoresizingMaskIntoConstraints = false return button @@ -58,7 +59,7 @@ final class WelcomeViewController: UIViewController, NeedsDependency { let button = UIButton(type: .system) button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) button.setTitle(L10n.Common.Controls.Actions.signIn, for: .normal) - let titleColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? UIColor.white.withAlphaComponent(0.8) : Asset.Colors.brandBlue.color + let titleColor: UIColor = UIColor.white.withAlphaComponent(0.8) button.setTitleColor(titleColor, for: .normal) button.translatesAutoresizingMaskIntoConstraints = false return button @@ -75,6 +76,8 @@ extension WelcomeViewController { override func viewDidLoad() { super.viewDidLoad() + // preferredContentSize = CGSize(width: 547, height: 678) + navigationController?.navigationBar.prefersLargeTitles = true navigationItem.largeTitleDisplayMode = .never view.overrideUserInterfaceStyle = .light @@ -106,16 +109,31 @@ extension WelcomeViewController { self.navigationItem.leftBarButtonItem = needsShowDismissEntry ? self.dismissBarButtonItem : nil } .store(in: &disposeBag) + + view.observe(\.frame, options: [.initial, .new]) { [weak self] view, _ in + guard let self = self else { return } + switch view.traitCollection.userInterfaceIdiom { + case .phone: + break + default: + self.welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.isHidden = view.frame.height < 800 + } + } + .store(in: &observations) } override func viewSafeAreaInsetsDidChange() { super.viewSafeAreaInsetsDidChange() - // shift illustration down for non-notch phone var overlap: CGFloat = 5 + // shift illustration down for non-notch phone if view.safeAreaInsets.bottom == 0 { overlap += 56 } + // shift illustration down for iPad modal + if UIDevice.current.userInterfaceIdiom != .phone { + overlap += 20 + } welcomeIllustrationViewBottomAnchorLayoutConstraint?.constant = overlap } @@ -137,85 +155,80 @@ extension WelcomeViewController { } // set illustration for phone - if traitCollection.userInterfaceIdiom == .phone { - guard welcomeIllustrationView.superview == nil else { - return - } - - welcomeIllustrationView.translatesAutoresizingMaskIntoConstraints = false - welcomeIllustrationViewBottomAnchorLayoutConstraint = welcomeIllustrationView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 5) - - view.addSubview(welcomeIllustrationView) - NSLayoutConstraint.activate([ - view.leftAnchor.constraint(equalTo: welcomeIllustrationView.leftAnchor, constant: 15), - welcomeIllustrationView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 15), - welcomeIllustrationViewBottomAnchorLayoutConstraint! - ]) - - welcomeIllustrationView.cloudBaseImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -5, maxX: 5, minY: -5, maxY: 5) - ) - welcomeIllustrationView.rightHillImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -15, maxX: 25, minY: -10, maxY: 10) - ) - welcomeIllustrationView.leftHillImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -25, maxX: 15, minY: -15, maxY: 15) - ) - welcomeIllustrationView.centerHillImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -14, maxX: 14, minY: -5, maxY: 25) - ) - - let topPaddingView = UIView() - topPaddingView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(topPaddingView) - NSLayoutConstraint.activate([ - topPaddingView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor), - topPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), - topPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), - ]) - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(welcomeIllustrationView.elephantOnAirplaneWithContrailImageView) - NSLayoutConstraint.activate([ - view.leftAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.leftAnchor, constant: 12), // add 12pt bleeding - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.topAnchor.constraint(equalTo: topPaddingView.bottomAnchor), - // make a little bit large - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.84), - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.heightAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor, multiplier: 105.0/318.0), - ]) - let bottomPaddingView = UIView() - bottomPaddingView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(bottomPaddingView) - NSLayoutConstraint.activate([ - bottomPaddingView.topAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.bottomAnchor), - bottomPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), - bottomPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), - bottomPaddingView.bottomAnchor.constraint(equalTo: view.centerYAnchor), - bottomPaddingView.heightAnchor.constraint(equalTo: topPaddingView.heightAnchor, multiplier: 4), - ]) - - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -20, maxX: 12, minY: -20, maxY: 12) // maxX should not larger then the bleeding (12pt) - ) - - view.bringSubviewToFront(logoImageView) - view.bringSubviewToFront(sloganLabel) - } - - // set slogan for non-phone - if traitCollection.userInterfaceIdiom != .phone { - guard sloganLabel.superview == nil else { - return - } - view.addSubview(sloganLabel) - NSLayoutConstraint.activate([ - sloganLabel.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 16), - view.readableContentGuide.trailingAnchor.constraint(equalTo: sloganLabel.trailingAnchor, constant: 16), - sloganLabel.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 168), - ]) + guard welcomeIllustrationView.superview == nil else { + return } - view.bringSubviewToFront(sloganLabel) + welcomeIllustrationView.translatesAutoresizingMaskIntoConstraints = false + welcomeIllustrationViewBottomAnchorLayoutConstraint = welcomeIllustrationView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 5) + + view.addSubview(welcomeIllustrationView) + NSLayoutConstraint.activate([ + view.leftAnchor.constraint(equalTo: welcomeIllustrationView.leftAnchor, constant: 15), + welcomeIllustrationView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 15), + welcomeIllustrationViewBottomAnchorLayoutConstraint! + ]) + + welcomeIllustrationView.cloudBaseImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -5, maxX: 5, minY: -5, maxY: 5) + ) + welcomeIllustrationView.rightHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -15, maxX: 25, minY: -10, maxY: 10) + ) + welcomeIllustrationView.leftHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -25, maxX: 15, minY: -15, maxY: 15) + ) + welcomeIllustrationView.centerHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -14, maxX: 14, minY: -5, maxY: 25) + ) + + let topPaddingView = UIView() + topPaddingView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(topPaddingView) + NSLayoutConstraint.activate([ + topPaddingView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor), + topPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), + topPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), + ]) + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(welcomeIllustrationView.elephantOnAirplaneWithContrailImageView) + NSLayoutConstraint.activate([ + view.leftAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.leftAnchor, constant: 12), // add 12pt bleeding + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.topAnchor.constraint(equalTo: topPaddingView.bottomAnchor), + // make a little bit large + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.84), + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.heightAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor, multiplier: 105.0/318.0), + ]) + let bottomPaddingView = UIView() + bottomPaddingView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(bottomPaddingView) + NSLayoutConstraint.activate([ + bottomPaddingView.topAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.bottomAnchor), + bottomPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), + bottomPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), + bottomPaddingView.bottomAnchor.constraint(equalTo: view.centerYAnchor), + bottomPaddingView.heightAnchor.constraint(equalTo: topPaddingView.heightAnchor, multiplier: 4), + ]) + + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -20, maxX: 12, minY: -20, maxY: 12) // maxX should not larger then the bleeding (12pt) + ) + view.bringSubviewToFront(logoImageView) + view.bringSubviewToFront(sloganLabel) + + // set slogan for non-phone +// if traitCollection.userInterfaceIdiom != .phone { +// guard sloganLabel.superview == nil else { +// return +// } +// view.addSubview(sloganLabel) +// NSLayoutConstraint.activate([ +// sloganLabel.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 16), +// view.readableContentGuide.trailingAnchor.constraint(equalTo: sloganLabel.trailingAnchor, constant: 16), +// sloganLabel.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 168), +// ]) +// } } } @@ -261,12 +274,12 @@ extension WelcomeViewController: UIAdaptivePresentationControllerDelegate { // make underneath view controller alive to fix layout issue due to view life cycle return .fullScreen default: - switch traitCollection.horizontalSizeClass { - case .regular: - return .pageSheet - default: - return .fullScreen - } + return .formSheet +// switch traitCollection.horizontalSizeClass { +// case .regular: +// default: +// return .fullScreen +// } } } From dd118023b96eb172554f24685e84ebc0c75cdbc6 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 4 Nov 2021 19:26:01 +0800 Subject: [PATCH 369/392] chore: update version to 1.2.0 (85) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index af3c11d9a..5e09203d5 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index af3c11d9a..5e09203d5 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index af3c11d9a..5e09203d5 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a1fec6337..bad59c2b5 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4915,7 +4915,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4944,7 +4944,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5052,11 +5052,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5083,11 +5083,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5112,11 +5112,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5142,11 +5142,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5234,7 +5234,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5259,7 +5259,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5284,7 +5284,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5309,7 +5309,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5334,7 +5334,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5359,7 +5359,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5384,7 +5384,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5475,7 +5475,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5542,11 +5542,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5591,7 +5591,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5616,11 +5616,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5712,7 +5712,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5779,11 +5779,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5828,7 +5828,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5853,11 +5853,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 84; + DYLIB_CURRENT_VERSION = 85; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5883,7 +5883,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5907,7 +5907,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 84; + CURRENT_PROJECT_VERSION = 85; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 921a52196..7aa368605 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 36 + 42 CoreDataStack.xcscheme_^#shared#^_ orderHint - 38 + 43 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -102,7 +102,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 39 + 45 MastodonIntents.xcscheme_^#shared#^_ @@ -122,7 +122,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 44 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index c5ed838f9..d788a77cb 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 84 + 85 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 43bd255d9..ac52ba389 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index af3c11d9a..5e09203d5 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index af3c11d9a..5e09203d5 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 7250b3468..ae1666ce1 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 262484f7b..1b8fa72ce 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 84 + 85 NSExtension NSExtensionAttributes From 2c52c01fb76bcd05476b9c6fe0a3085d9ec108c1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 6 Nov 2021 13:05:51 +0100 Subject: [PATCH 370/392] New translations app.json (Spanish, Argentina) --- Localization/StringsConvertor/input/es_AR/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index c0c884e24..ed909ecf1 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -67,7 +67,7 @@ "done": "Listo", "confirm": "Confirmar", "continue": "Continuar", - "compose": "Compose", + "compose": "Redactar", "cancel": "Cancelar", "discard": "Descartar", "try_again": "Intentá de nuevo", @@ -415,10 +415,10 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "No se muestran los seguidores de otros servidores." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "No se muestran las cuentas de otros servidores que seguís." }, "search": { "title": "Buscar", From 2b9f03013736ddbb5459c903f627653cb404be19 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 8 Nov 2021 11:34:36 +0100 Subject: [PATCH 371/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 7534aede0..c3666dc60 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -16,8 +16,8 @@ "poll_ended": "Rapirsîya qediya" }, "discard_post_content": { - "title": "Reşnivîs jêbibe", - "message": "Piştrast bikin ku naveroka posteyê ya hatîye nivîsandin jê bibin." + "title": "Reşnivîsê paşguh bike", + "message": "Bipejrîne ku naveroka şandiyê ya hatiye nivîsandin paşguh bikî." }, "publish_post_failure": { "title": "Weşandin têkçû", @@ -28,7 +28,7 @@ } }, "edit_profile_failure": { - "title": "Çewtiya profîlê biguherîne", + "title": "Di serrastkirina profîlê çewtî", "message": "Nikare profîlê serrast bike. Jkx dîsa biceribîne." }, "sign_out": { @@ -42,15 +42,15 @@ }, "save_photo_failure": { "title": "Tomarkirina wêneyê têkçû", - "message": "Ji kerema xwe destûra gihîştina pirtûkxaneya wêneyê çalak bikin da ku wêneyê hilînin." + "message": "Ji kerema xwe mafê bide gihîştina wênegehê çalak bike da ku wêne werin tomarkirin." }, "delete_post": { "title": "Ma tu dixwazî vê şandiyê jê bibî?", "delete": "Jê bibe" }, "clean_cache": { - "title": "Pêşbîrê paqij bike", - "message": "Pêşbîra %s biserketî hate paqijkirin." + "title": "Pêşbîrê pak bike", + "message": "Pêşbîra %s biserketî hate pakkirin." } }, "controls": { @@ -72,8 +72,8 @@ "discard": "Biavêje", "try_again": "Dîsa biceribîne", "take_photo": "Wêne bikişîne", - "save_photo": "Wêneyê hilîne", - "copy_photo": "Wêne kopî bikin", + "save_photo": "Wêneyê tomar bike", + "copy_photo": "Wêneyê jê bigire", "sign_in": "Têkeve", "sign_up": "Tomar bibe", "see_more": "Bêtir bibîne", @@ -82,8 +82,8 @@ "share_user": "%s parve bike", "share_post": "Şandiyê parve bike", "open_in_safari": "Di Safariyê de veke", - "find_people": "Kesên ku bişopînin bibînin", - "manually_search": "Ji devlê i destan lêgerînê bike", + "find_people": "Mirovan bo şopandinê bibîne", + "manually_search": "Ji devlê bi destan lêgerînê bike", "skip": "Derbas bike", "reply": "Bersivê bide", "report_user": "%s ragihîne", @@ -113,47 +113,47 @@ "open_reblogger_profile": "Profîla nivîskaran veke", "reply_status": "Bersivê bide şandiyê", "toggle_reblog": "Ji vû nivîsandin di şandiyê de biguherîne", - "toggle_favorite": "Di postê da Bijartin veke/bigire", - "toggle_content_warning": "Hişyariya naverokê veke/bigire", - "preview_image": "Wêneya pêşdîtinê" + "toggle_favorite": "Li ser şandiyê bijarte biguherîne", + "toggle_content_warning": "Hişyariya naverokê biguherîne", + "preview_image": "Pêşdîtina wêneyê" }, "segmented_control": { - "previous_section": "Beşa berê", - "next_section": "Beşa paşê" + "previous_section": "Beşa paş", + "next_section": "Beşa pêş" } }, "status": { - "user_reblogged": "%s ji nû ve hat blogkirin", + "user_reblogged": "%s ji nû ve hate nivîsandin", "user_replied_to": "Bersiv da %s", "show_post": "Şandiyê nîşan bide", "show_user_profile": "Profîla bikarhêner nîşan bide", "content_warning": "Hişyariya naverokê", - "media_content_warning": "Ji bo aşkerakirinê derekî bitikîne", + "media_content_warning": "Ji bo eşkerekirinê li derekî bitikîne", "poll": { - "vote": "Deng", + "vote": "Deng bide", "closed": "Girtî" }, "actions": { "reply": "Bersivê bide", - "reblog": "Ji nû ve blog", - "unreblog": "Ji nû ve blogkirin betal bikin", - "favorite": "Bijartî", - "unfavorite": "Nebijare", - "menu": "Menû" + "reblog": "Ji nû ve nivîsandin", + "unreblog": "Ji nû ve nivîsandinê vegere", + "favorite": "Bijarte", + "unfavorite": "Nebijarte", + "menu": "Kulîn" }, "tag": { "url": "URL", - "mention": "Behs", + "mention": "Qalkirin", "link": "Girêdan", - "hashtag": "Etîket", + "hashtag": "Hashtag", "email": "E-name", - "emoji": "E-name" + "emoji": "Emojî" } }, "friendship": { "follow": "Bişopîne", "following": "Dişopîne", - "request": "Daxwazên şopandinê", + "request": "Daxwaz bike", "pending": "Tê nirxandin", "block": "Asteng bike", "block_user": "%s asteng bike", @@ -174,18 +174,18 @@ "now": "Niha" }, "loader": { - "load_missing_posts": "Barkirina posteyên kêm", - "loading_missing_posts": "Barkirina posteyên kêm...", + "load_missing_posts": "Şandiyên wendayî bar bike", + "loading_missing_posts": "Şandiyên wendayî tên barkirin...", "show_more_replies": "Bêtir bersivan nîşan bide" }, "header": { - "no_status_found": "Şandî nehate dîtin", - "blocking_warning": "Tu nikarî profîla vî bikarhênerî bibînî\nHeta ku tu wan asteng bikî.\nProfîla te ji wan ra wiha xuya dike.", - "user_blocking_warning": "Tu nikarî profîla %s bibînî\nHeta ku tu wan asteng bikî.\nProfîla te ji wan ra wiha xuya dike.", - "blocked_warning": "Tu nikarî profîla vî bikarhênerî bibînî\nheta ku astengîya te rakin.", + "no_status_found": "Tu şandî nehate dîtin", + "blocking_warning": "Tu nikarî profîla vî/ê bikarhênerî bibînî\nHeya ku tu astengiyê li ser wî/ê ranekî.\nProfîla te ji wan ra wiha xuya dike.", + "user_blocking_warning": "Tu nikarî profîla %s bibînî\nHeya ku tu astengiyê li ser wî/ê ranekî.\nProfîla te ji wan ra wiha xuya dike.", + "blocked_warning": "Tu nikarî profîla vî/ê bikarhênerî bibînî\nheya ku ew astengiyê li ser te rakin.", "user_blocked_warning": "Tu nikarî profîla %s bibînî\nHeta ku astengîya te rakin.", - "suspended_warning": "Ev bikarhêner hat sekinandin.", - "user_suspended_warning": "Hesaba %s hat sekinandin." + "suspended_warning": "Ev bikarhêner hatiye rawestandin.", + "user_suspended_warning": "Ajimêra %s hatiye rawestandin." } } } @@ -219,15 +219,15 @@ "label": { "language": "ZIMAN", "users": "BIKARHÊNER", - "category": "KATEGORÎ" + "category": "BEŞ" }, "input": { - "placeholder": "Serverek bibînin an jî beşdarî ya xwe bibin..." + "placeholder": "Rajekarekî bibîne an jî beşdarî ya xwe bibe..." }, "empty_state": { - "finding_servers": "Dîtina serverên berdest...", + "finding_servers": "Peydakirina rajekarên berdest...", "bad_network": "Di dema barkirina daneyan da tiştek xelet derket. Girêdana xwe ya înternetê kontrol bike.", - "no_results": "Encam nade" + "no_results": "Encam tune" } }, "register": { @@ -247,8 +247,8 @@ "placeholder": "e-name" }, "password": { - "placeholder": "şîfre", - "hint": "Şîfreya we herî kêm heşt tîpan hewce dike" + "placeholder": "pêborîn", + "hint": "Pêborîna te herî kêm divê ji 8 tîpan pêk bê" }, "invite": { "registration_user_invite_request": "Tu çima dixwazî beşdar bibî?" @@ -258,7 +258,7 @@ "item": { "username": "Navê bikarhêner", "email": "E-name", - "password": "Şîfre", + "password": "Pêborîn", "agreement": "Lihevhatin", "locale": "Herêm", "reason": "Sedem" @@ -279,7 +279,7 @@ "username_invalid": "Navê bikarhêner divê tenê tîpên alfanumerîk û binxet hebe", "username_too_long": "Navê bikarhêner pir dirêj e (ji 30 tîpan dirêjtir nabe)", "email_invalid": "Ev ne navnîşana e-nameyek derbasdar e", - "password_too_short": "Şîfre pir kurt e (divê herî kêm 8 tîpan be)" + "password_too_short": "Pêborîn pir kurt e (divê herî kêm 8 tîp be)" } } }, @@ -372,7 +372,7 @@ "append_poll": "Rapirsî tevlî bike", "remove_poll": "Rapirsî rake", "custom_emoji_picker": "Hilbijêrê emojî yên kesanekirî", - "enable_content_warning": "Hişyariya naverokê neçalak bike", + "enable_content_warning": "Hişyariya naverokê çalak bike", "disable_content_warning": "Hişyariya naverokê neçalak bike", "post_visibility_menu": "Menuya Xuyabûna Şandiyê" }, @@ -387,12 +387,12 @@ }, "profile": { "dashboard": { - "posts": "şandîyan", + "posts": "şandî", "following": "dişopîne", - "followers": "şopîneran" + "followers": "şopîner" }, "fields": { - "add_row": "Rêzê lê zêde bike", + "add_row": "Rêzê tevlî bike", "placeholder": { "label": "Nîşan", "content": "Naverok" From 39bb50f539bc1bfb1cc518aef5301d59901fd13c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 8 Nov 2021 12:38:11 +0100 Subject: [PATCH 372/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index c3666dc60..108cf234c 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -399,7 +399,7 @@ } }, "segmented_control": { - "posts": "Şandîyan", + "posts": "Şandî", "replies": "Bersivan", "media": "Medya" }, @@ -423,11 +423,11 @@ "search": { "title": "Bigere", "search_bar": { - "placeholder": "Li etîketan û bikarhêneran bigerin", - "cancel": "Betal kirin" + "placeholder": "Li hashtag û bikarhêneran bigere", + "cancel": "Dev jê berde" }, "recommend": { - "button_text": "Hemûyé bibîne", + "button_text": "Hemûyan bibîne", "hash_tag": { "title": "Trend li ser Mastodon", "description": "Etîketên ku pir balê dikişînin", @@ -435,7 +435,7 @@ }, "accounts": { "title": "Hesabên ku hûn dikarin hez bikin", - "description": "Dibe ku tu bixwazî van hesaban bişopînî", + "description": "Dibe ku tu bixwazî van ajimêran bişopînî", "follow": "Bişopîne" } }, @@ -443,28 +443,28 @@ "segment": { "all": "Hemû", "people": "Mirov", - "hashtags": "Etîketan", - "posts": "Şandîyan" + "hashtags": "Hashtag", + "posts": "Şandî" }, "empty_state": { "no_results": "Encam tune" }, "recent_search": "Lêgerînên dawî", - "clear": "Paqij bike" + "clear": "Pak bike" } }, "favorite": { - "title": "Bijareyên te" + "title": "Bijarteyên te" }, "notification": { "title": { "Everything": "Her tişt", - "Mentions": "Behs" + "Mentions": "Qalkirin" }, "user_followed_you": "%s te şopand", - "user_favorited your post": "%s posta we bijarte", + "user_favorited your post": "%s şandiya te hez kir", "user_reblogged_your_post": "%s posta we ji nû ve tomar kir", - "user_mentioned_you": "%s behsa te kir", + "user_mentioned_you": "%s qale te kir", "user_requested_to_follow_you": "%s daxwaza şopandina te kir", "user_your_poll_has_ended": "%s Anketa te qediya", "keyobard": { From 8d9c8371617a891b04b10816f060d24ef8ffb8ec Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 8 Nov 2021 12:38:14 +0100 Subject: [PATCH 373/392] New translations Intents.strings (Kurmanji (Kurdish)) --- .../Intents/input/kmr_TR/Intents.strings | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings index 3e1c69fc3..13a86e0c0 100644 --- a/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/kmr_TR/Intents.strings @@ -24,15 +24,15 @@ "Zo4jgJ" = "Xuyaniya şandiyê"; -"apSxMG-dYQ5NN" = "Vebijarkên ${count} hene ku li gorî 'Giştî' ne."; +"apSxMG-dYQ5NN" = "Vebijarkên ${count} hene ku li gorî 'Gelemperî' ne."; -"apSxMG-ehFLjY" = "Vebijarkên ${count} hene ku li gorî 'Tenê Şopandin' hene."; +"apSxMG-ehFLjY" = "Vebijarkên ${count} hene ku li gorî 'Tenê Şopaneran' hene."; -"ayoYEb-dYQ5NN" = "${content}, Giştî"; +"ayoYEb-dYQ5NN" = "${content}, Gelemperî"; "ayoYEb-ehFLjY" = "${content}, Tenê şopînêr"; -"dUyuGg" = "Li ser Mastodon bişînin"; +"dUyuGg" = "Di Mastodon de biweşîne"; "dYQ5NN" = "Gelemperî"; @@ -42,10 +42,10 @@ "k7dbKQ" = "Şandî bi serkeftî hate şandin."; -"oGiqmY-dYQ5NN" = "Tenê ji bo pejirandinê, we 'Giştî' dixwest?"; +"oGiqmY-dYQ5NN" = "Tenê ji bo pejirandinê, te 'Gelemperî' dixwest?"; -"oGiqmY-ehFLjY" = "Tenê ji bo piştrastkirinê, we 'Tenê Şopdarên' dixwest?"; +"oGiqmY-ehFLjY" = "Tenê ji bo pejirandinê, te 'Tenê Şopîner' dixwest?"; "rM6dvp" = "Girêdan"; -"ryJLwG" = "Bi serkeftî hat şandin. "; +"ryJLwG" = "Şandî bi serkeftî hate şandin. "; From 287a6dc6150d53d767ac6e515618b9cf49738626 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 8 Nov 2021 14:09:54 +0100 Subject: [PATCH 374/392] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 108cf234c..c360eb430 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -226,7 +226,7 @@ }, "empty_state": { "finding_servers": "Peydakirina rajekarên berdest...", - "bad_network": "Di dema barkirina daneyan da tiştek xelet derket. Girêdana xwe ya înternetê kontrol bike.", + "bad_network": "Di dema barkirina daneyan da çewtî derket. Girêdana xwe ya înternetê kontrol bike.", "no_results": "Encam tune" } }, @@ -259,38 +259,38 @@ "username": "Navê bikarhêner", "email": "E-name", "password": "Pêborîn", - "agreement": "Lihevhatin", - "locale": "Herêm", + "agreement": "Peyman", + "locale": "Zimanê navrûyê", "reason": "Sedem" }, "reason": { - "blocked": "%s peydekerê e-nameya bêdestûr dihewîne", - "unreachable": "%s xuya nake", + "blocked": "%s peydekerê e-peyamê yê qedexekirî dihewîne", + "unreachable": "%s xuya ye ku tune ye", "taken": "%s jixwe tê bikaranîn", - "reserved": "%s peyveke mifteya veqetandî ye", - "accepted": "%s divê were qebûlkirin", + "reserved": "%s peyveke parastî ye", + "accepted": "%s divê were pejirandin", "blank": "%s pêwist e", "invalid": "%s ne derbasdar e", - "too_long": "%s gelekî dirêj e", + "too_long": "%s pir dirêj e", "too_short": "%s pir kurt e", - "inclusion": "%s nirxeke ku tê destekirin nîn e" + "inclusion": "%s ne nirxek piştgirî ye" }, "special": { - "username_invalid": "Navê bikarhêner divê tenê tîpên alfanumerîk û binxet hebe", + "username_invalid": "Navê bikarhêner divê tenê ji tîpên alfajimarî û binxêz pêk be", "username_too_long": "Navê bikarhêner pir dirêj e (ji 30 tîpan dirêjtir nabe)", - "email_invalid": "Ev ne navnîşana e-nameyek derbasdar e", + "email_invalid": "Ev navnîşaneke e-nameyê ne derbasdar e", "password_too_short": "Pêborîn pir kurt e (divê herî kêm 8 tîp be)" } } }, "server_rules": { - "title": "Hin qaîdeyên bingehîn.", + "title": "Hinek rêzikên bingehîn.", "subtitle": "Ev rêzik ji aliyê rêvebirên %s ve tên sazkirin.", - "prompt": "Bi berdewamî, hûn ji bo %s di bin şertên polîtîkaya xizmet û nepenîtiyê da ne.", - "terms_of_service": "şert û mercên xizmetê", - "privacy_policy": "polîtîkaya nepenîtiyê", + "prompt": "Bi domandinê, tu ji bo %s di bin mercên bikaranînê û polîtîkaya nepenîtiyê dipejirînî.", + "terms_of_service": "mercên bikaranînê", + "privacy_policy": "polîtikaya nihêniyê", "button": { - "confirm": "Ez tev dibim" + "confirm": "Ez dipejirînim" } }, "confirm_email": { @@ -374,15 +374,15 @@ "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": "Menuya Xuyabûna Şandiyê" + "post_visibility_menu": "Kulîna xuyabûna şandiyê" }, "keyboard": { - "discard_post": "Şandî bihelîne", - "publish_post": "Şandiye bide weşan", - "toggle_poll": "Anketê veke/bigire", - "toggle_content_warning": "Hişyariya naverokê veke/bigire", - "append_attachment_entry": "Pêvek lê zêde bike - %s", - "select_visibility_entry": "Xuyanîbûn hilbijêre - %s" + "discard_post": "Şandî paşguh bike", + "publish_post": "Şandiyê biweşîne", + "toggle_poll": "Rapirsiyê biguherîne", + "toggle_content_warning": "Hişyariya naverokê biguherîne", + "append_attachment_entry": "Pêvek tevlî bike - %s", + "select_visibility_entry": "Xuyabûnê hilbijêre - %s" } }, "profile": { @@ -400,17 +400,17 @@ }, "segmented_control": { "posts": "Şandî", - "replies": "Bersivan", + "replies": "Bersiv", "media": "Medya" }, "relationship_action_alert": { "confirm_unmute_user": { - "title": "Hesabê ji bê deng rake", - "message": "Ji bo vekirina bê dengkirinê bipejirin %s" + "title": "Ajimêrê bêdeng neke", + "message": "Ji bo vekirina bêdengkirinê bipejirîne %s" }, "confirm_unblock_usre": { - "title": "Hesabê ji bloke rake", - "message": "Ji bo rakirina blokê bipejirin %s" + "title": "Astengiyê li ser ajimêr rake", + "message": "Ji bo rakirina astengkirinê bipejirîne %s" } } }, @@ -429,12 +429,12 @@ "recommend": { "button_text": "Hemûyan bibîne", "hash_tag": { - "title": "Trend li ser Mastodon", - "description": "Etîketên ku pir balê dikişînin", + "title": "Rojev li ser Mastodon", + "description": "Hashtag ên ku pir balê dikişînin", "people_talking": "%s kes diaxivin" }, "accounts": { - "title": "Hesabên ku hûn dikarin hez bikin", + "title": "Ajimêrên ku belkî tu jê hez bikî", "description": "Dibe ku tu bixwazî van ajimêran bişopînî", "follow": "Bişopîne" } @@ -465,11 +465,11 @@ "user_favorited your post": "%s şandiya te hez kir", "user_reblogged_your_post": "%s posta we ji nû ve tomar kir", "user_mentioned_you": "%s qale te kir", - "user_requested_to_follow_you": "%s daxwaza şopandina te kir", - "user_your_poll_has_ended": "%s Anketa te qediya", + "user_requested_to_follow_you": "%s dixwazê te bişopîne", + "user_your_poll_has_ended": "Rapirsîya te qediya", "keyobard": { "show_everything": "Her tiştî nîşan bide", - "show_mentions": "Behskirîya nîşan bike" + "show_mentions": "Qalkirinan nîşan bike" } }, "thread": { @@ -488,8 +488,8 @@ "notifications": { "title": "Agahdarî", "favorites": "Şandiyên min hez kir", - "follows": "Min şopand", - "boosts": "Şandiya min ji nû ve binivîsine", + "follows": "Min dişopîne", + "boosts": "Şandiya min ji nû ve nivîsand", "mentions": "Qale min kir", "trigger": { "anyone": "her kes", From 832b146c826e987c9094555f183ef25ee6082575 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 10 Nov 2021 17:55:12 +0800 Subject: [PATCH 375/392] feat: update list fetch trigger logic for UserTimeline scene --- Mastodon.xcodeproj/project.pbxproj | 4 ++ .../xcschemes/xcschememanagement.plist | 8 +-- .../Timeline/UserTimelineViewController.swift | 34 ++++++---- .../Timeline/UserTimelineViewModel.swift | 1 + .../ViewModel/ListBatchFetchViewModel.swift | 68 +++++++++++++++++++ 5 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 Mastodon/Scene/Share/ViewModel/ListBatchFetchViewModel.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index bad59c2b5..d7bab5217 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -377,6 +377,7 @@ DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */; }; DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; }; DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; }; + DB7274F4273BB9B200577D95 /* ListBatchFetchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */; }; DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73B48F261F030A002E9E9F /* SafariActivity.swift */; }; DB73BF3B2711885500781945 /* UserDefaults+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */; }; DB73BF4127118B6D00781945 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF4027118B6D00781945 /* Instance.swift */; }; @@ -1195,6 +1196,7 @@ DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Status.swift"; sourceTree = ""; }; DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = ""; }; DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = ""; }; + DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListBatchFetchViewModel.swift; sourceTree = ""; }; DB73B48F261F030A002E9E9F /* SafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariActivity.swift; sourceTree = ""; }; DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Notification.swift"; sourceTree = ""; }; DB73BF4027118B6D00781945 /* Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Instance.swift; sourceTree = ""; }; @@ -2972,6 +2974,7 @@ DB9D6C2225E502C60051B173 /* MosaicImageViewModel.swift */, 2DA6055025F74407006356F9 /* AudioContainerViewModel.swift */, 5DF1054625F8870E00D6C0D4 /* VideoPlayerViewModel.swift */, + DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -4233,6 +4236,7 @@ 2D24E11D2626D8B100A59D4F /* NotificationStatusTableViewCell.swift in Sources */, DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */, DB1E346825F518E20079D7DF /* CategoryPickerSection.swift in Sources */, + DB7274F4273BB9B200577D95 /* ListBatchFetchViewModel.swift in Sources */, 2D61254D262547C200299647 /* APIService+Notification.swift in Sources */, DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */, DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 7aa368605..921a52196 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 42 + 36 CoreDataStack.xcscheme_^#shared#^_ orderHint - 43 + 38 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -102,7 +102,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 45 + 39 MastodonIntents.xcscheme_^#shared#^_ @@ -122,7 +122,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 44 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift index 42e9376cf..4bee3b8af 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift @@ -72,6 +72,16 @@ extension UserTimelineViewController { statusTableViewCellDelegate: self ) + // setup batch fetch + viewModel.listBatchFetchViewModel.setup(scrollView: tableView) + viewModel.listBatchFetchViewModel.shouldFetch + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.viewModel.stateMachine.enter(UserTimelineViewModel.State.Loading.self) + } + .store(in: &disposeBag) + // trigger user timeline loading Publishers.CombineLatest( viewModel.domain.removeDuplicates().eraseToAnyPublisher(), @@ -104,11 +114,11 @@ extension UserTimelineViewController { extension UserTimelineViewController: StatusTableViewControllerAspect { } // MARK: - UIScrollViewDelegate -extension UserTimelineViewController { - func scrollViewDidScroll(_ scrollView: UIScrollView) { - aspectScrollViewDidScroll(scrollView) - } -} +//extension UserTimelineViewController { +// func scrollViewDidScroll(_ scrollView: UIScrollView) { +// aspectScrollViewDidScroll(scrollView) +// } +//} // MARK: - TableViewCellHeightCacheableContainer extension UserTimelineViewController: TableViewCellHeightCacheableContainer { @@ -186,13 +196,13 @@ extension UserTimelineViewController: ScrollViewContainer { } // MARK: - LoadMoreConfigurableTableViewContainer -extension UserTimelineViewController: LoadMoreConfigurableTableViewContainer { - typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell - typealias LoadingState = UserTimelineViewModel.State.Loading - - var loadMoreConfigurableTableView: UITableView { return tableView } - var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.stateMachine } -} +//extension UserTimelineViewController: LoadMoreConfigurableTableViewContainer { +// typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell +// typealias LoadingState = UserTimelineViewModel.State.Loading +// +// var loadMoreConfigurableTableView: UITable``````View { return tableView } +// var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.stateMachine } +//} extension UserTimelineViewController { override var keyCommands: [UIKeyCommand]? { diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift index 42edafb0f..5bf520d6d 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift @@ -23,6 +23,7 @@ final class UserTimelineViewModel { let userID: CurrentValueSubject let queryFilter: CurrentValueSubject let statusFetchedResultsController: StatusFetchedResultsController + let listBatchFetchViewModel = ListBatchFetchViewModel() var cellFrameCache = NSCache() let isBlocking = CurrentValueSubject(false) diff --git a/Mastodon/Scene/Share/ViewModel/ListBatchFetchViewModel.swift b/Mastodon/Scene/Share/ViewModel/ListBatchFetchViewModel.swift new file mode 100644 index 000000000..78eaf6ae3 --- /dev/null +++ b/Mastodon/Scene/Share/ViewModel/ListBatchFetchViewModel.swift @@ -0,0 +1,68 @@ +// +// ListBatchFetchViewModel.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-10. +// + +import UIKit +import Combine + +// ref: Texture.ASBatchFetchingDelegate +final class ListBatchFetchViewModel { + + var disposeBag = Set() + + // timer running on `common` mode + let timerPublisher = Timer.publish(every: 1.0, on: .main, in: .common) + .autoconnect() + .share() + .eraseToAnyPublisher() + + // input + private(set) weak var scrollView: UIScrollView? + let hasMore = CurrentValueSubject(true) + + // output + let shouldFetch = PassthroughSubject() + + init() { + Publishers.CombineLatest( + hasMore, + timerPublisher + ) + .sink { [weak self] hasMore, _ in + guard let self = self else { return } + guard hasMore else { return } + guard let scrollView = self.scrollView else { return } + + // skip trigger if user interacting + if scrollView.isDragging || scrollView.isTracking { return } + + // send fetch request + if scrollView.contentSize.height < scrollView.frame.height { + self.shouldFetch.send() + } else { + let frame = scrollView.frame + let contentOffset = scrollView.contentOffset + let contentSize = scrollView.contentSize + + let visibleBottomY = contentOffset.y + frame.height + let offset = 2 * frame.height + let fetchThrottleOffsetY = contentSize.height - offset + + if visibleBottomY > fetchThrottleOffsetY { + self.shouldFetch.send() + } + } + } + .store(in: &disposeBag) + } + +} + +extension ListBatchFetchViewModel { + func setup(scrollView: UIScrollView) { + self.scrollView = scrollView + } +} From b609e010aeb394927cff1ef7d5c9e72b5b57be3c Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 10 Nov 2021 17:55:37 +0800 Subject: [PATCH 376/392] fix: split view column separator line color not set to theme style issue --- Mastodon/Scene/Root/RootSplitViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index 505e9089d..e9d7549bd 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -142,7 +142,7 @@ extension RootSplitViewController { private func setupBackground(theme: Theme) { // this set column separator line color - view.backgroundColor = .opaqueSeparator + view.backgroundColor = theme.separator } } From 9d1c1322d9b5c9009d88d6e277535bd85503a488 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 10 Nov 2021 17:56:16 +0800 Subject: [PATCH 377/392] chore: update version to 1.2.0 (86) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 5e09203d5..8dc24c39e 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 5e09203d5..8dc24c39e 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 5e09203d5..8dc24c39e 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index d7bab5217..55fc0af75 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4919,7 +4919,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4948,7 +4948,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5056,11 +5056,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5087,11 +5087,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5116,11 +5116,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5146,11 +5146,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5213,7 +5213,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5238,7 +5238,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5263,7 +5263,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5288,7 +5288,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5313,7 +5313,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5338,7 +5338,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5363,7 +5363,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5388,7 +5388,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5479,7 +5479,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5546,11 +5546,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5595,7 +5595,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5620,11 +5620,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5716,7 +5716,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5783,11 +5783,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5832,7 +5832,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5857,11 +5857,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 85; + DYLIB_CURRENT_VERSION = 86; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5887,7 +5887,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5911,7 +5911,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 85; + CURRENT_PROJECT_VERSION = 86; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 921a52196..2b0badaea 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 36 + 43 CoreDataStack.xcscheme_^#shared#^_ orderHint - 38 + 44 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -102,7 +102,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 39 + 42 MastodonIntents.xcscheme_^#shared#^_ @@ -122,7 +122,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 45 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index d788a77cb..98e4a1eb0 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 85 + 86 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index ac52ba389..57166c457 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 5e09203d5..8dc24c39e 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 5e09203d5..8dc24c39e 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index ae1666ce1..803a158bb 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 1b8fa72ce..7ffaa7806 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 85 + 86 NSExtension NSExtensionAttributes From 06ea9a22b918bf0dcfe05364ac2a92d39deeb455 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 10 Nov 2021 17:58:37 +0800 Subject: [PATCH 378/392] chore: update i18n resources --- .../es-419.lproj/Localizable.strings | 6 +- .../Resources/ku-TR.lproj/Localizable.strings | 194 +++++++++--------- .../Scene/Root/Sidebar/SidebarViewModel.swift | 4 +- MastodonIntent/ku-TR.lproj/Intents.strings | 14 +- 4 files changed, 109 insertions(+), 109 deletions(-) diff --git a/Mastodon/Resources/es-419.lproj/Localizable.strings b/Mastodon/Resources/es-419.lproj/Localizable.strings index 3ffd12049..cf97fe803 100644 --- a/Mastodon/Resources/es-419.lproj/Localizable.strings +++ b/Mastodon/Resources/es-419.lproj/Localizable.strings @@ -28,7 +28,7 @@ Por favor, revisá tu conexión a Internet."; "Common.Controls.Actions.Back" = "Volver"; "Common.Controls.Actions.BlockDomain" = "Bloquear a %@"; "Common.Controls.Actions.Cancel" = "Cancelar"; -"Common.Controls.Actions.Compose" = "Compose"; +"Common.Controls.Actions.Compose" = "Redactar"; "Common.Controls.Actions.Confirm" = "Confirmar"; "Common.Controls.Actions.Continue" = "Continuar"; "Common.Controls.Actions.CopyPhoto" = "Copiar foto"; @@ -191,8 +191,8 @@ y no se puede subir a Mastodon."; pulsá en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Favorite.Title" = "Tus favoritos"; -"Scene.Follower.Footer" = "Followers from other servers are not displayed."; -"Scene.Following.Footer" = "Follows from other servers are not displayed."; +"Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; +"Scene.Following.Footer" = "No se muestran las cuentas de otros servidores que seguís."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ver nuevos mensajes"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Desconectado"; "Scene.HomeTimeline.NavigationBarState.Published" = "¡Enviado!"; diff --git a/Mastodon/Resources/ku-TR.lproj/Localizable.strings b/Mastodon/Resources/ku-TR.lproj/Localizable.strings index 7f84febe0..d0d0f294e 100644 --- a/Mastodon/Resources/ku-TR.lproj/Localizable.strings +++ b/Mastodon/Resources/ku-TR.lproj/Localizable.strings @@ -1,21 +1,21 @@ "Common.Alerts.BlockDomain.BlockEntireDomain" = "Navperê asteng bike"; "Common.Alerts.BlockDomain.Title" = "Tu ji xwe bawerî, bi rastî tu dixwazî hemû %@ asteng bikî? Di gelek rewşan de asteng kirin an jî bêdeng kirin têrê dike û tê tercîh kirin. Tu nikarî naveroka vê navperê di demnameyê an jî agahdariyên xwe de bibînî. Şopînerên te yê di vê navperê were jêbirin."; -"Common.Alerts.CleanCache.Message" = "Pêşbîra %@ biserketî hate paqijkirin."; -"Common.Alerts.CleanCache.Title" = "Pêşbîrê paqij bike"; +"Common.Alerts.CleanCache.Message" = "Pêşbîra %@ biserketî hate pakkirin."; +"Common.Alerts.CleanCache.Title" = "Pêşbîrê pak bike"; "Common.Alerts.Common.PleaseTryAgain" = "Ji kerema xwe dîsa biceribîne."; "Common.Alerts.Common.PleaseTryAgainLater" = "Ji kerema xwe paşê dîsa biceribîne."; "Common.Alerts.DeletePost.Delete" = "Jê bibe"; "Common.Alerts.DeletePost.Title" = "Ma tu dixwazî vê şandiyê jê bibî?"; -"Common.Alerts.DiscardPostContent.Message" = "Piştrast bikin ku naveroka posteyê ya hatîye nivîsandin jê bibin."; -"Common.Alerts.DiscardPostContent.Title" = "Reşnivîs jêbibe"; +"Common.Alerts.DiscardPostContent.Message" = "Bipejrîne ku naveroka şandiyê ya hatiye nivîsandin paşguh bikî."; +"Common.Alerts.DiscardPostContent.Title" = "Reşnivîsê paşguh bike"; "Common.Alerts.EditProfileFailure.Message" = "Nikare profîlê serrast bike. Jkx dîsa biceribîne."; -"Common.Alerts.EditProfileFailure.Title" = "Çewtiya profîlê biguherîne"; +"Common.Alerts.EditProfileFailure.Title" = "Di serrastkirina profîlê çewtî"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Nikare ji bêtirî yek vîdyoyekê tevlî şandiyê bike."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Nikare vîdyoyekê tevlî şandiyê ku berê wêne tê de heye bike."; "Common.Alerts.PublishPostFailure.Message" = "Weşandina şandiyê têkçû. Jkx girêdana înternetê xwe kontrol bike."; "Common.Alerts.PublishPostFailure.Title" = "Weşandin têkçû"; -"Common.Alerts.SavePhotoFailure.Message" = "Ji kerema xwe destûra gihîştina pirtûkxaneya wêneyê çalak bikin da ku wêneyê hilînin."; +"Common.Alerts.SavePhotoFailure.Message" = "Ji kerema xwe mafê bide gihîştina wênegehê çalak bike da ku wêne werin tomarkirin."; "Common.Alerts.SavePhotoFailure.Title" = "Tomarkirina wêneyê têkçû"; "Common.Alerts.ServerError.Title" = "Çewtiya rajekar"; "Common.Alerts.SignOut.Confirm" = "Derkeve"; @@ -31,13 +31,13 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Actions.Compose" = "Binivîsîne"; "Common.Controls.Actions.Confirm" = "Bipejirîne"; "Common.Controls.Actions.Continue" = "Bidomîne"; -"Common.Controls.Actions.CopyPhoto" = "Wêne kopî bikin"; +"Common.Controls.Actions.CopyPhoto" = "Wêneyê jê bigire"; "Common.Controls.Actions.Delete" = "Jê bibe"; "Common.Controls.Actions.Discard" = "Biavêje"; "Common.Controls.Actions.Done" = "Qediya"; "Common.Controls.Actions.Edit" = "Serrast bike"; -"Common.Controls.Actions.FindPeople" = "Kesên ku bişopînin bibînin"; -"Common.Controls.Actions.ManuallySearch" = "Ji devlê i destan lêgerînê bike"; +"Common.Controls.Actions.FindPeople" = "Mirovan bo şopandinê bibîne"; +"Common.Controls.Actions.ManuallySearch" = "Ji devlê bi destan lêgerînê bike"; "Common.Controls.Actions.Next" = "Pêş"; "Common.Controls.Actions.Ok" = "BAŞ E"; "Common.Controls.Actions.Open" = "Veke"; @@ -48,7 +48,7 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Actions.Reply" = "Bersivê bide"; "Common.Controls.Actions.ReportUser" = "%@ ragihîne"; "Common.Controls.Actions.Save" = "Tomar bike"; -"Common.Controls.Actions.SavePhoto" = "Wêneyê hilîne"; +"Common.Controls.Actions.SavePhoto" = "Wêneyê tomar bike"; "Common.Controls.Actions.SeeMore" = "Bêtir bibîne"; "Common.Controls.Actions.Settings" = "Sazkarî"; "Common.Controls.Actions.Share" = "Parve bike"; @@ -71,7 +71,7 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Friendship.MuteUser" = "%@ bêdeng bike"; "Common.Controls.Friendship.Muted" = "Bêdengkirî"; "Common.Controls.Friendship.Pending" = "Tê nirxandin"; -"Common.Controls.Friendship.Request" = "Daxwazên şopandinê"; +"Common.Controls.Friendship.Request" = "Daxwaz bike"; "Common.Controls.Friendship.Unblock" = "Astengiyê rake"; "Common.Controls.Friendship.UnblockUser" = "%@ asteng neke"; "Common.Controls.Friendship.Unmute" = "Bêdeng neke"; @@ -80,58 +80,58 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Keyboard.Common.OpenSettings" = "Sazkariyan Veke"; "Common.Controls.Keyboard.Common.ShowFavorites" = "Bijarteyan nîşan bide"; "Common.Controls.Keyboard.Common.SwitchToTab" = "Biguherîne bo %@"; -"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Beşa paşê"; -"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Beşa berê"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Beşa pêş"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Beşa paş"; "Common.Controls.Keyboard.Timeline.NextStatus" = "Şandiya pêş"; "Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Profîla nivîskaran veke"; "Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Profîla nivîskaran veke"; "Common.Controls.Keyboard.Timeline.OpenStatus" = "Şandiyê veke"; -"Common.Controls.Keyboard.Timeline.PreviewImage" = "Wêneya pêşdîtinê"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Pêşdîtina wêneyê"; "Common.Controls.Keyboard.Timeline.PreviousStatus" = "Şandeya paş"; "Common.Controls.Keyboard.Timeline.ReplyStatus" = "Bersivê bide şandiyê"; -"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Hişyariya naverokê veke/bigire"; -"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Di postê da Bijartin veke/bigire"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Hişyariya naverokê biguherîne"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Li ser şandiyê bijarte biguherîne"; "Common.Controls.Keyboard.Timeline.ToggleReblog" = "Ji vû nivîsandin di şandiyê de biguherîne"; -"Common.Controls.Status.Actions.Favorite" = "Bijartî"; -"Common.Controls.Status.Actions.Menu" = "Menû"; -"Common.Controls.Status.Actions.Reblog" = "Ji nû ve blog"; +"Common.Controls.Status.Actions.Favorite" = "Bijarte"; +"Common.Controls.Status.Actions.Menu" = "Kulîn"; +"Common.Controls.Status.Actions.Reblog" = "Ji nû ve nivîsandin"; "Common.Controls.Status.Actions.Reply" = "Bersivê bide"; -"Common.Controls.Status.Actions.Unfavorite" = "Nebijare"; -"Common.Controls.Status.Actions.Unreblog" = "Ji nû ve blogkirin betal bikin"; +"Common.Controls.Status.Actions.Unfavorite" = "Nebijarte"; +"Common.Controls.Status.Actions.Unreblog" = "Ji nû ve nivîsandinê vegere"; "Common.Controls.Status.ContentWarning" = "Hişyariya naverokê"; -"Common.Controls.Status.MediaContentWarning" = "Ji bo aşkerakirinê derekî bitikîne"; +"Common.Controls.Status.MediaContentWarning" = "Ji bo eşkerekirinê li derekî bitikîne"; "Common.Controls.Status.Poll.Closed" = "Girtî"; -"Common.Controls.Status.Poll.Vote" = "Deng"; +"Common.Controls.Status.Poll.Vote" = "Deng bide"; "Common.Controls.Status.ShowPost" = "Şandiyê nîşan bide"; "Common.Controls.Status.ShowUserProfile" = "Profîla bikarhêner nîşan bide"; "Common.Controls.Status.Tag.Email" = "E-name"; -"Common.Controls.Status.Tag.Emoji" = "E-name"; -"Common.Controls.Status.Tag.Hashtag" = "Etîket"; +"Common.Controls.Status.Tag.Emoji" = "Emojî"; +"Common.Controls.Status.Tag.Hashtag" = "Hashtag"; "Common.Controls.Status.Tag.Link" = "Girêdan"; -"Common.Controls.Status.Tag.Mention" = "Behs"; +"Common.Controls.Status.Tag.Mention" = "Qalkirin"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.UserReblogged" = "%@ ji nû ve hat blogkirin"; +"Common.Controls.Status.UserReblogged" = "%@ ji nû ve hate nivîsandin"; "Common.Controls.Status.UserRepliedTo" = "Bersiv da %@"; "Common.Controls.Tabs.Home" = "Serrûpel"; "Common.Controls.Tabs.Notification" = "Agahdarî"; "Common.Controls.Tabs.Profile" = "Profîl"; "Common.Controls.Tabs.Search" = "Bigere"; "Common.Controls.Timeline.Filtered" = "Parzûnkirî"; -"Common.Controls.Timeline.Header.BlockedWarning" = "Tu nikarî profîla vî bikarhênerî bibînî -heta ku astengîya te rakin."; -"Common.Controls.Timeline.Header.BlockingWarning" = "Tu nikarî profîla vî bikarhênerî bibînî -Heta ku tu wan asteng bikî. +"Common.Controls.Timeline.Header.BlockedWarning" = "Tu nikarî profîla vî/ê bikarhênerî bibînî +heya ku ew astengiyê li ser te rakin."; +"Common.Controls.Timeline.Header.BlockingWarning" = "Tu nikarî profîla vî/ê bikarhênerî bibînî +Heya ku tu astengiyê li ser wî/ê ranekî. Profîla te ji wan ra wiha xuya dike."; -"Common.Controls.Timeline.Header.NoStatusFound" = "Şandî nehate dîtin"; -"Common.Controls.Timeline.Header.SuspendedWarning" = "Ev bikarhêner hat sekinandin."; +"Common.Controls.Timeline.Header.NoStatusFound" = "Tu şandî nehate dîtin"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "Ev bikarhêner hatiye rawestandin."; "Common.Controls.Timeline.Header.UserBlockedWarning" = "Tu nikarî profîla %@ bibînî Heta ku astengîya te rakin."; "Common.Controls.Timeline.Header.UserBlockingWarning" = "Tu nikarî profîla %@ bibînî -Heta ku tu wan asteng bikî. +Heya ku tu astengiyê li ser wî/ê ranekî. Profîla te ji wan ra wiha xuya dike."; -"Common.Controls.Timeline.Header.UserSuspendedWarning" = "Hesaba %@ hat sekinandin."; -"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Barkirina posteyên kêm"; -"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Barkirina posteyên kêm..."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "Ajimêra %@ hatiye rawestandin."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Şandiyên wendayî bar bike"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Şandiyên wendayî tên barkirin..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Bêtir bersivan nîşan bide"; "Common.Controls.Timeline.Timestamp.Now" = "Niha"; "Scene.AccountList.AddAccount" = "Ajimêr tevlî bike"; @@ -141,8 +141,8 @@ Profîla te ji wan ra wiha xuya dike."; "Scene.Compose.Accessibility.AppendPoll" = "Rapirsî tevlî bike"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Hilbijêrê emojî yên kesanekirî"; "Scene.Compose.Accessibility.DisableContentWarning" = "Hişyariya naverokê neçalak bike"; -"Scene.Compose.Accessibility.EnableContentWarning" = "Hişyariya naverokê neçalak bike"; -"Scene.Compose.Accessibility.PostVisibilityMenu" = "Menuya Xuyabûna Şandiyê"; +"Scene.Compose.Accessibility.EnableContentWarning" = "Hişyariya naverokê çalak bike"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Kulîna xuyabûna şandiyê"; "Scene.Compose.Accessibility.RemovePoll" = "Rapirsî rake"; "Scene.Compose.Attachment.AttachmentBroken" = "Ev %@ naxebite û nayê barkirin li ser Mastodon."; @@ -154,12 +154,12 @@ Profîla te ji wan ra wiha xuya dike."; "Scene.Compose.ComposeAction" = "Biweşîne"; "Scene.Compose.ContentInputPlaceholder" = "Tiştê ku di hişê te de ye binivîsin an jî pêve bike"; "Scene.Compose.ContentWarning.Placeholder" = "Li vir hişyariyek hûrgilî binivîsine..."; -"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Pêvek lê zêde bike - %@"; -"Scene.Compose.Keyboard.DiscardPost" = "Şandî bihelîne"; -"Scene.Compose.Keyboard.PublishPost" = "Şandiye bide weşan"; -"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Xuyanîbûn hilbijêre - %@"; -"Scene.Compose.Keyboard.ToggleContentWarning" = "Hişyariya naverokê veke/bigire"; -"Scene.Compose.Keyboard.TogglePoll" = "Anketê veke/bigire"; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Pêvek tevlî bike - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "Şandî paşguh bike"; +"Scene.Compose.Keyboard.PublishPost" = "Şandiyê biweşîne"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Xuyabûnê hilbijêre - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "Hişyariya naverokê biguherîne"; +"Scene.Compose.Keyboard.TogglePoll" = "Rapirsiyê biguherîne"; "Scene.Compose.MediaSelection.Browse" = "Bigere"; "Scene.Compose.MediaSelection.Camera" = "Wêne bikişîne"; "Scene.Compose.MediaSelection.PhotoLibrary" = "Wênegeh"; @@ -190,7 +190,7 @@ Profîla te ji wan ra wiha xuya dike."; "Scene.ConfirmEmail.Subtitle" = "Me tenê e-nameyek ji %@ re şand, girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ConfirmEmail.Title" = "Tiştekî dawî."; -"Scene.Favorite.Title" = "Bijareyên te"; +"Scene.Favorite.Title" = "Bijarteyên te"; "Scene.Follower.Footer" = "Şopîner ji rajekerên din nayê dîtin."; "Scene.Following.Footer" = "Şopandin ji rajekerên din nayê dîtin."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Şandiyên nû bibîne"; @@ -199,57 +199,57 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.HomeTimeline.NavigationBarState.Publishing" = "Şandî tê weşandin..."; "Scene.HomeTimeline.Title" = "Serrûpel"; "Scene.Notification.Keyobard.ShowEverything" = "Her tiştî nîşan bide"; -"Scene.Notification.Keyobard.ShowMentions" = "Behskirîya nîşan bike"; +"Scene.Notification.Keyobard.ShowMentions" = "Qalkirinan nîşan bike"; "Scene.Notification.Title.Everything" = "Her tişt"; -"Scene.Notification.Title.Mentions" = "Behs"; -"Scene.Notification.UserFavorited Your Post" = "%@ posta we bijarte"; +"Scene.Notification.Title.Mentions" = "Qalkirin"; +"Scene.Notification.UserFavorited Your Post" = "%@ şandiya te hez kir"; "Scene.Notification.UserFollowedYou" = "%@ te şopand"; -"Scene.Notification.UserMentionedYou" = "%@ behsa te kir"; +"Scene.Notification.UserMentionedYou" = "%@ qale te kir"; "Scene.Notification.UserRebloggedYourPost" = "%@ posta we ji nû ve tomar kir"; -"Scene.Notification.UserRequestedToFollowYou" = "%@ daxwaza şopandina te kir"; -"Scene.Notification.UserYourPollHasEnded" = "%@ Anketa te qediya"; +"Scene.Notification.UserRequestedToFollowYou" = "%@ dixwazê te bişopîne"; +"Scene.Notification.UserYourPollHasEnded" = "Rapirsîya te qediya"; "Scene.Preview.Keyboard.ClosePreview" = "Pêşdîtin bigire"; "Scene.Preview.Keyboard.ShowNext" = "A pêş nîşan bide"; "Scene.Preview.Keyboard.ShowPrevious" = "A paş nîşan bide"; -"Scene.Profile.Dashboard.Followers" = "şopîneran"; +"Scene.Profile.Dashboard.Followers" = "şopîner"; "Scene.Profile.Dashboard.Following" = "dişopîne"; -"Scene.Profile.Dashboard.Posts" = "şandîyan"; -"Scene.Profile.Fields.AddRow" = "Rêzê lê zêde bike"; +"Scene.Profile.Dashboard.Posts" = "şandî"; +"Scene.Profile.Fields.AddRow" = "Rêzê tevlî bike"; "Scene.Profile.Fields.Placeholder.Content" = "Naverok"; "Scene.Profile.Fields.Placeholder.Label" = "Nîşan"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Message" = "Ji bo rakirina blokê bipejirin %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Title" = "Hesabê ji bloke rake"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Ji bo vekirina bê dengkirinê bipejirin %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Hesabê ji bê deng rake"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Message" = "Ji bo rakirina astengkirinê bipejirîne %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Title" = "Astengiyê li ser ajimêr rake"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Ji bo vekirina bêdengkirinê bipejirîne %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Ajimêrê bêdeng neke"; "Scene.Profile.SegmentedControl.Media" = "Medya"; -"Scene.Profile.SegmentedControl.Posts" = "Şandîyan"; -"Scene.Profile.SegmentedControl.Replies" = "Bersivan"; -"Scene.Register.Error.Item.Agreement" = "Lihevhatin"; +"Scene.Profile.SegmentedControl.Posts" = "Şandî"; +"Scene.Profile.SegmentedControl.Replies" = "Bersiv"; +"Scene.Register.Error.Item.Agreement" = "Peyman"; "Scene.Register.Error.Item.Email" = "E-name"; -"Scene.Register.Error.Item.Locale" = "Herêm"; -"Scene.Register.Error.Item.Password" = "Şîfre"; +"Scene.Register.Error.Item.Locale" = "Zimanê navrûyê"; +"Scene.Register.Error.Item.Password" = "Pêborîn"; "Scene.Register.Error.Item.Reason" = "Sedem"; "Scene.Register.Error.Item.Username" = "Navê bikarhêner"; -"Scene.Register.Error.Reason.Accepted" = "%@ divê were qebûlkirin"; +"Scene.Register.Error.Reason.Accepted" = "%@ divê were pejirandin"; "Scene.Register.Error.Reason.Blank" = "%@ pêwist e"; -"Scene.Register.Error.Reason.Blocked" = "%@ peydekerê e-nameya bêdestûr dihewîne"; -"Scene.Register.Error.Reason.Inclusion" = "%@ nirxeke ku tê destekirin nîn e"; +"Scene.Register.Error.Reason.Blocked" = "%@ peydekerê e-peyamê yê qedexekirî dihewîne"; +"Scene.Register.Error.Reason.Inclusion" = "%@ ne nirxek piştgirî ye"; "Scene.Register.Error.Reason.Invalid" = "%@ ne derbasdar e"; -"Scene.Register.Error.Reason.Reserved" = "%@ peyveke mifteya veqetandî ye"; +"Scene.Register.Error.Reason.Reserved" = "%@ peyveke parastî ye"; "Scene.Register.Error.Reason.Taken" = "%@ jixwe tê bikaranîn"; -"Scene.Register.Error.Reason.TooLong" = "%@ gelekî dirêj e"; +"Scene.Register.Error.Reason.TooLong" = "%@ pir dirêj e"; "Scene.Register.Error.Reason.TooShort" = "%@ pir kurt e"; -"Scene.Register.Error.Reason.Unreachable" = "%@ xuya nake"; -"Scene.Register.Error.Special.EmailInvalid" = "Ev ne navnîşana e-nameyek derbasdar e"; -"Scene.Register.Error.Special.PasswordTooShort" = "Şîfre pir kurt e (divê herî kêm 8 tîpan be)"; -"Scene.Register.Error.Special.UsernameInvalid" = "Navê bikarhêner divê tenê tîpên alfanumerîk û binxet hebe"; +"Scene.Register.Error.Reason.Unreachable" = "%@ xuya ye ku tune ye"; +"Scene.Register.Error.Special.EmailInvalid" = "Ev navnîşaneke e-nameyê ne derbasdar e"; +"Scene.Register.Error.Special.PasswordTooShort" = "Pêborîn pir kurt e (divê herî kêm 8 tîp be)"; +"Scene.Register.Error.Special.UsernameInvalid" = "Navê bikarhêner divê tenê ji tîpên alfajimarî û binxêz pêk be"; "Scene.Register.Error.Special.UsernameTooLong" = "Navê bikarhêner pir dirêj e (ji 30 tîpan dirêjtir nabe)"; "Scene.Register.Input.Avatar.Delete" = "Jê bibe"; "Scene.Register.Input.DisplayName.Placeholder" = "navê nîşanê"; "Scene.Register.Input.Email.Placeholder" = "e-name"; "Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Tu çima dixwazî beşdar bibî?"; -"Scene.Register.Input.Password.Hint" = "Şîfreya we herî kêm heşt tîpan hewce dike"; -"Scene.Register.Input.Password.Placeholder" = "şîfre"; +"Scene.Register.Input.Password.Hint" = "Pêborîna te herî kêm divê ji 8 tîpan pêk bê"; +"Scene.Register.Input.Password.Placeholder" = "pêborîn"; "Scene.Register.Input.Username.DuplicatePrompt" = "Navê vê bikarhêner tê girtin."; "Scene.Register.Input.Username.Placeholder" = "navê bikarhêner"; "Scene.Register.Title" = "Ji me re hinekî qala xwe bike."; @@ -261,22 +261,22 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.Report.Step2" = "Gav 2 ji 2"; "Scene.Report.TextPlaceholder" = "Şiroveyên daxwazkirê binivîsine an jî pê ve bike"; "Scene.Report.Title" = "%@ ragihîne"; -"Scene.Search.Recommend.Accounts.Description" = "Dibe ku tu bixwazî van hesaban bişopînî"; +"Scene.Search.Recommend.Accounts.Description" = "Dibe ku tu bixwazî van ajimêran bişopînî"; "Scene.Search.Recommend.Accounts.Follow" = "Bişopîne"; -"Scene.Search.Recommend.Accounts.Title" = "Hesabên ku hûn dikarin hez bikin"; -"Scene.Search.Recommend.ButtonText" = "Hemûyé bibîne"; -"Scene.Search.Recommend.HashTag.Description" = "Etîketên ku pir balê dikişînin"; +"Scene.Search.Recommend.Accounts.Title" = "Ajimêrên ku belkî tu jê hez bikî"; +"Scene.Search.Recommend.ButtonText" = "Hemûyan bibîne"; +"Scene.Search.Recommend.HashTag.Description" = "Hashtag ên ku pir balê dikişînin"; "Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ kes diaxivin"; -"Scene.Search.Recommend.HashTag.Title" = "Trend li ser Mastodon"; -"Scene.Search.SearchBar.Cancel" = "Betal kirin"; -"Scene.Search.SearchBar.Placeholder" = "Li etîketan û bikarhêneran bigerin"; -"Scene.Search.Searching.Clear" = "Paqij bike"; +"Scene.Search.Recommend.HashTag.Title" = "Rojev li ser Mastodon"; +"Scene.Search.SearchBar.Cancel" = "Dev jê berde"; +"Scene.Search.SearchBar.Placeholder" = "Li hashtag û bikarhêneran bigere"; +"Scene.Search.Searching.Clear" = "Pak bike"; "Scene.Search.Searching.EmptyState.NoResults" = "Encam tune"; "Scene.Search.Searching.RecentSearch" = "Lêgerînên dawî"; "Scene.Search.Searching.Segment.All" = "Hemû"; -"Scene.Search.Searching.Segment.Hashtags" = "Etîketan"; +"Scene.Search.Searching.Segment.Hashtags" = "Hashtag"; "Scene.Search.Searching.Segment.People" = "Mirov"; -"Scene.Search.Searching.Segment.Posts" = "Şandîyan"; +"Scene.Search.Searching.Segment.Posts" = "Şandî"; "Scene.Search.Title" = "Bigere"; "Scene.ServerPicker.Button.Category.Academia" = "akademî"; "Scene.ServerPicker.Button.Category.Activism" = "çalakî"; @@ -294,21 +294,21 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ServerPicker.Button.Category.Tech" = "teknolojî"; "Scene.ServerPicker.Button.SeeLess" = "Kêmtir bibîne"; "Scene.ServerPicker.Button.SeeMore" = "Bêtir bibîne"; -"Scene.ServerPicker.EmptyState.BadNetwork" = "Di dema barkirina daneyan da tiştek xelet derket. Girêdana xwe ya înternetê kontrol bike."; -"Scene.ServerPicker.EmptyState.FindingServers" = "Dîtina serverên berdest..."; -"Scene.ServerPicker.EmptyState.NoResults" = "Encam nade"; -"Scene.ServerPicker.Input.Placeholder" = "Serverek bibînin an jî beşdarî ya xwe bibin..."; -"Scene.ServerPicker.Label.Category" = "KATEGORÎ"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Di dema barkirina daneyan da çewtî derket. Girêdana xwe ya înternetê kontrol bike."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Peydakirina rajekarên berdest..."; +"Scene.ServerPicker.EmptyState.NoResults" = "Encam tune"; +"Scene.ServerPicker.Input.Placeholder" = "Rajekarekî bibîne an jî beşdarî ya xwe bibe..."; +"Scene.ServerPicker.Label.Category" = "BEŞ"; "Scene.ServerPicker.Label.Language" = "ZIMAN"; "Scene.ServerPicker.Label.Users" = "BIKARHÊNER"; "Scene.ServerPicker.Title" = "Rajekarekê hilbijêre, Her kîjan rajekar be."; -"Scene.ServerRules.Button.Confirm" = "Ez tev dibim"; -"Scene.ServerRules.PrivacyPolicy" = "polîtîkaya nepenîtiyê"; -"Scene.ServerRules.Prompt" = "Bi berdewamî, hûn ji bo %@ di bin şertên polîtîkaya xizmet û nepenîtiyê da ne."; +"Scene.ServerRules.Button.Confirm" = "Ez dipejirînim"; +"Scene.ServerRules.PrivacyPolicy" = "polîtikaya nihêniyê"; +"Scene.ServerRules.Prompt" = "Bi domandinê, tu ji bo %@ di bin mercên bikaranînê û polîtîkaya nepenîtiyê dipejirînî."; "Scene.ServerRules.Subtitle" = "Ev rêzik ji aliyê rêvebirên %@ ve tên sazkirin."; -"Scene.ServerRules.TermsOfService" = "şert û mercên xizmetê"; -"Scene.ServerRules.Title" = "Hin qaîdeyên bingehîn."; +"Scene.ServerRules.TermsOfService" = "mercên bikaranînê"; +"Scene.ServerRules.Title" = "Hinek rêzikên bingehîn."; "Scene.Settings.Footer.MastodonDescription" = "Mastodon nermalava çavkaniya vekirî ye. Tu dikarî pirsgirêkan li ser GitHub-ê ragihînî di %@ (%@) de"; "Scene.Settings.Keyboard.CloseSettingsWindow" = "Sazkariyên çarçoveyê bigire"; "Scene.Settings.Section.Appearance.Automatic" = "Xweber"; @@ -319,9 +319,9 @@ Her kîjan rajekar be."; "Scene.Settings.Section.BoringZone.Privacy" = "Polîtikaya nihêniyê"; "Scene.Settings.Section.BoringZone.Terms" = "Mercên bikaranînê"; "Scene.Settings.Section.BoringZone.Title" = "Devera acizker"; -"Scene.Settings.Section.Notifications.Boosts" = "Şandiya min ji nû ve binivîsine"; +"Scene.Settings.Section.Notifications.Boosts" = "Şandiya min ji nû ve nivîsand"; "Scene.Settings.Section.Notifications.Favorites" = "Şandiyên min hez kir"; -"Scene.Settings.Section.Notifications.Follows" = "Min şopand"; +"Scene.Settings.Section.Notifications.Follows" = "Min dişopîne"; "Scene.Settings.Section.Notifications.Mentions" = "Qale min kir"; "Scene.Settings.Section.Notifications.Title" = "Agahdarî"; "Scene.Settings.Section.Notifications.Trigger.Anyone" = "her kes"; diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 5ababf161..baa468d2a 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -145,7 +145,7 @@ extension SidebarViewModel { return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) case .compose: let item = SidebarListContentView.Item( - title: "Compose", // TODO: update i18n + title: L10n.Common.Controls.Actions.compose image: UIImage(systemName: "square.and.pencil")!, imageURL: nil ) @@ -190,7 +190,7 @@ extension SidebarViewModel { } let item = SidebarListContentView.Item( - title: "Compose", // FIXME: + title: L10n.Common.Controls.Actions.compose, image: UIImage(systemName: "square.and.pencil")!, imageURL: nil ) diff --git a/MastodonIntent/ku-TR.lproj/Intents.strings b/MastodonIntent/ku-TR.lproj/Intents.strings index 3e1c69fc3..13a86e0c0 100644 --- a/MastodonIntent/ku-TR.lproj/Intents.strings +++ b/MastodonIntent/ku-TR.lproj/Intents.strings @@ -24,15 +24,15 @@ "Zo4jgJ" = "Xuyaniya şandiyê"; -"apSxMG-dYQ5NN" = "Vebijarkên ${count} hene ku li gorî 'Giştî' ne."; +"apSxMG-dYQ5NN" = "Vebijarkên ${count} hene ku li gorî 'Gelemperî' ne."; -"apSxMG-ehFLjY" = "Vebijarkên ${count} hene ku li gorî 'Tenê Şopandin' hene."; +"apSxMG-ehFLjY" = "Vebijarkên ${count} hene ku li gorî 'Tenê Şopaneran' hene."; -"ayoYEb-dYQ5NN" = "${content}, Giştî"; +"ayoYEb-dYQ5NN" = "${content}, Gelemperî"; "ayoYEb-ehFLjY" = "${content}, Tenê şopînêr"; -"dUyuGg" = "Li ser Mastodon bişînin"; +"dUyuGg" = "Di Mastodon de biweşîne"; "dYQ5NN" = "Gelemperî"; @@ -42,10 +42,10 @@ "k7dbKQ" = "Şandî bi serkeftî hate şandin."; -"oGiqmY-dYQ5NN" = "Tenê ji bo pejirandinê, we 'Giştî' dixwest?"; +"oGiqmY-dYQ5NN" = "Tenê ji bo pejirandinê, te 'Gelemperî' dixwest?"; -"oGiqmY-ehFLjY" = "Tenê ji bo piştrastkirinê, we 'Tenê Şopdarên' dixwest?"; +"oGiqmY-ehFLjY" = "Tenê ji bo pejirandinê, te 'Tenê Şopîner' dixwest?"; "rM6dvp" = "Girêdan"; -"ryJLwG" = "Bi serkeftî hat şandin. "; +"ryJLwG" = "Şandî bi serkeftî hate şandin. "; From 6ac184a42797b84c6de99d284531d9c0b41859fe Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 10 Nov 2021 18:00:16 +0800 Subject: [PATCH 379/392] chore: update to version 1.2.0 (87) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- .../Scene/Root/Sidebar/SidebarViewModel.swift | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 12 files changed, 46 insertions(+), 46 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 8dc24c39e..9e3842757 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 8dc24c39e..9e3842757 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 8dc24c39e..9e3842757 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 55fc0af75..e5118bf8d 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4919,7 +4919,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4948,7 +4948,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5056,11 +5056,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5087,11 +5087,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5116,11 +5116,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5146,11 +5146,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5213,7 +5213,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5238,7 +5238,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5263,7 +5263,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5288,7 +5288,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5313,7 +5313,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5338,7 +5338,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5363,7 +5363,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5388,7 +5388,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5479,7 +5479,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5546,11 +5546,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5595,7 +5595,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5620,11 +5620,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5716,7 +5716,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5783,11 +5783,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5832,7 +5832,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5857,11 +5857,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 86; + DYLIB_CURRENT_VERSION = 87; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5887,7 +5887,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5911,7 +5911,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 86; + CURRENT_PROJECT_VERSION = 87; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b4fed1ca6..aa6a21a4c 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 51 + 47 CoreDataStack.xcscheme_^#shared#^_ orderHint - 50 + 46 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -102,7 +102,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 53 + 45 MastodonIntents.xcscheme_^#shared#^_ @@ -122,7 +122,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 52 + 48 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 98e4a1eb0..00bab8799 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 86 + 87 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index baa468d2a..37b46932b 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -145,7 +145,7 @@ extension SidebarViewModel { return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) case .compose: let item = SidebarListContentView.Item( - title: L10n.Common.Controls.Actions.compose + title: L10n.Common.Controls.Actions.compose, image: UIImage(systemName: "square.and.pencil")!, imageURL: nil ) diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 57166c457..986b62577 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 8dc24c39e..9e3842757 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 8dc24c39e..9e3842757 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 803a158bb..a6cdb01a1 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 7ffaa7806..b5052eb9e 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 86 + 87 NSExtension NSExtensionAttributes From e02decdb5616629bad3361a1ee82ed2884c3b0a0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 15 Nov 2021 05:20:58 +0100 Subject: [PATCH 380/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 44aebc154..d37dc8ca6 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -67,7 +67,7 @@ "done": "تمّ", "confirm": "تأكيد", "continue": "واصل", - "compose": "Compose", + "compose": "كِتابة", "cancel": "إلغاء", "discard": "تجاهل", "try_again": "المُحاولة مرة أُخرى", @@ -112,9 +112,9 @@ "open_author_profile": "افتح الملف التعريفي للمؤلف", "open_reblogger_profile": "افتح الملف التعريفي لمشارِك المنشور", "reply_status": "رد على المنشور", - "toggle_reblog": "Toggle Reblog on Post", - "toggle_favorite": "Toggle Favorite on Post", - "toggle_content_warning": "Toggle Content Warning", + "toggle_reblog": "تبديل إعادة تدوين منشور", + "toggle_favorite": "تبديل المفضلة لِمنشور", + "toggle_content_warning": "تبديل تحذير المُحتَوى", "preview_image": "معاينة الصورة" }, "segmented_control": { @@ -128,7 +128,7 @@ "show_post": "اظهر المنشور", "show_user_profile": "اظهر الملف التعريفي للمستخدم", "content_warning": "تحذير عن المحتوى", - "media_content_warning": "Tap anywhere to reveal", + "media_content_warning": "انقر على أي مكان للكشف", "poll": { "vote": "صَوّت", "closed": "انتهى" @@ -180,12 +180,12 @@ }, "header": { "no_status_found": "لا توجد هناك منشورات", - "blocking_warning": "You can’t view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.", + "blocking_warning": "لا يُمكنك الاطلاع على الملف الشخصي لهذا المُستخدِم\nحتَّى تَرفعَ الحَظر عنه.\nملفًّكَ الشخصي يَظهَرُ بِمثل هذِهِ الحالة بالنسبةِ لَهُ أيضًا.", "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." + "suspended_warning": "تمَّ إيقاف هذا المُستخدِم.", + "user_suspended_warning": "لقد أوقِفَ حِساب %s." } } } From 784ae0a747f29e5499c37e6db41020759a23b554 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 15 Nov 2021 06:21:46 +0100 Subject: [PATCH 381/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index d37dc8ca6..3e788d6ce 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -17,14 +17,14 @@ }, "discard_post_content": { "title": "تجاهل المسودة", - "message": "Confirm to discard composed post content." + "message": "أكِّد للتخلص مِن مُحتوى مَنشور مؤلَّف." }, "publish_post_failure": { "title": "أخفقت عملية النشر", - "message": "Failed to publish the post.\nPlease check your internet connection.", + "message": "فَشَلَ نَشر المَنشور.\nيُرجى التحقق من اتصالك بالإنترنت.", "attachments_message": { - "video_attach_with_photo": "Cannot attach a video to a post that already contains images.", - "more_than_one_video": "Cannot attach more than one video." + "video_attach_with_photo": "لا يُمكن إرفاق مقطع مرئي إلى مَنشور يحتوي بالفعل على صُوَر.", + "more_than_one_video": "لا يُمكِنُ إرفاق أكثر مِن مَقطع مرئي واحِد." } }, "edit_profile_failure": { @@ -67,7 +67,7 @@ "done": "تمّ", "confirm": "تأكيد", "continue": "واصل", - "compose": "كِتابة", + "compose": "تأليف", "cancel": "إلغاء", "discard": "تجاهل", "try_again": "المُحاولة مرة أُخرى", @@ -101,7 +101,7 @@ "keyboard": { "common": { "switch_to_tab": "التبديل إلى %s", - "compose_new_post": "إنشاء منشور جديد", + "compose_new_post": "تأليف منشور جديد", "show_favorites": "إظهار المفضلة", "open_settings": "أفتح الإعدادات" }, @@ -192,7 +192,7 @@ }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands." + "slogan": "شبكات التواصل الاجتماعي\nمرة أُخرى بين يديك." }, "server_picker": { "title": "اِختر خادِم،\nأي خادِم.", @@ -226,7 +226,7 @@ }, "empty_state": { "finding_servers": "البحث عن خوادم متوفرة...", - "bad_network": "Something went wrong while loading the data. Check your internet connection.", + "bad_network": "حدث خطأٌ ما أثناء تحميل البيانات. تحقَّق من اتصالك بالإنترنت.", "no_results": "لا توجد نتائج" } }, @@ -264,20 +264,20 @@ "reason": "السبب" }, "reason": { - "blocked": "%s contains a disallowed email provider", - "unreachable": "%s does not seem to exist", - "taken": "%s is already in use", - "reserved": "%s is a reserved keyword", - "accepted": "%s must be accepted", + "blocked": "يحتوي %s على موفِّر خدمة بريد إلكتروني غير مسموح به", + "unreachable": "يبدوا أنَّ %s غير موجود", + "taken": "إنَّ %s مُستخدَمٌ بالفعل", + "reserved": "إنَّ %s عبارة عن كلمة مفتاحيَّة محجوزة", + "accepted": "يجب أن يُقبل %s", "blank": "%s مطلوب", "invalid": "%s غير صالح", "too_long": "%s طويل جداً", "too_short": "%s قصير جدا", - "inclusion": "%s is not a supported value" + "inclusion": "إنَّ %s قيمة غير مدعومة" }, "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)", + "username_invalid": "يُمكِن أن يحتوي اسم المستخدم على أحرف أبجدية، أرقام وشرطات سفلية فقط", + "username_too_long": "اسم المستخدم طويل جداً (يجب ألّا يكون أطول من 30 رمز)", "email_invalid": "هذا عنوان بريد إلكتروني غير صالح", "password_too_short": "كلمة المرور قصيرة جداً (يجب أن تكون 8 أحرف على الأقل)" } @@ -302,12 +302,12 @@ }, "dont_receive_email": { "title": "تحقق من بريدك الإلكتروني", - "description": "Check if your email address is correct as well as your junk folder if you haven’t.", + "description": "تحقق ممَّ إذا كان عنوان بريدك الإلكتروني صحيحًا وكذلك تأكد مِن مجلد البريد غير الهام إذا لم تكن قد فعلت ذلك.", "resend_email": "إعادة إرسال البريد الإلكتروني" }, "open_email_app": { "title": "تحقَّق من بريدك الوارِد.", - "description": "We just sent you an email. Check your junk folder if you haven’t.", + "description": "لقد أرسلنا لك بريدًا إلكترونيًا للتو. تحقق من مجلد البريد غير الهام الخاص بك إذا لم تكن قد فعلت ذلك.", "mail": "البريد", "open_email_client": "فتح عميل البريد الإلكتروني" } @@ -323,7 +323,7 @@ }, "suggestion_account": { "title": "ابحث عن أشخاص لمتابعتهم", - "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + "follow_explain": "عِندَ مُتابَعَتِكَ لأحدِهِم، سَوف تَرى مَنشوراته في تغذيَتِكَ الرئيسة." }, "compose": { "title": { @@ -341,9 +341,9 @@ "attachment": { "photo": "صورة", "video": "فيديو", - "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..." + "attachment_broken": "هذا ال%s مُعطَّل ويتعذَّر رفعه إلى ماستودون.", + "description_photo": "صِف الصورة للمكفوفين...", + "description_video": "صِف المقطع المرئي للمكفوفين..." }, "poll": { "duration_time": "المدة: %s", @@ -356,7 +356,7 @@ "option_number": "الخيار %ld" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "اكتب تَحذيرًا دَقيقًا هُنا..." }, "visibility": { "public": "للعامة", @@ -365,7 +365,7 @@ "direct": "ففط للأشخاص المشار إليهم" }, "auto_complete": { - "space_to_add": "Space to add" + "space_to_add": "انقر مساحة لإضافتِها" }, "accessibility": { "append_attachment": "إضافة مُرفَق", @@ -374,7 +374,7 @@ "custom_emoji_picker": "منتقي مخصص للإيموجي", "enable_content_warning": "تنشيط تحذير المحتوى", "disable_content_warning": "تعطيل تحذير الحتوى", - "post_visibility_menu": "Post Visibility Menu" + "post_visibility_menu": "قائمة ظهور المنشور" }, "keyboard": { "discard_post": "تجاهُل المنشور", @@ -406,19 +406,19 @@ "relationship_action_alert": { "confirm_unmute_user": { "title": "إلغاء كتم الحساب", - "message": "Confirm to unmute %s" + "message": "أكِّد لرفع كتمْ %s" }, "confirm_unblock_usre": { "title": "إلغاء حظر الحساب", - "message": "Confirm to unblock %s" + "message": "أكِّد لرفع حظر %s" } } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى." }, "search": { "title": "بحث", @@ -430,7 +430,7 @@ "button_text": "طالع الكل", "hash_tag": { "title": "ذات شعبية على ماستدون", - "description": "Hashtags that are getting quite a bit of attention", + "description": "الوسوم التي تحظى بقدر كبير من الاهتمام", "people_talking": "%s أشخاص يتحدَّثوا" }, "accounts": { @@ -529,11 +529,11 @@ "title": "ابلغ عن %s", "step1": "الخطوة 1 من 2", "step2": "الخطوة 2 من 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?", + "content1": "هل ترغب في إضافة أي مشاركات أُخرى إلى التقرير؟", + "content2": "هل هناك أي شيء يجب أن يعرفه المُراقبين حول هذا التقرير؟", "send": "ارسل الشكوى", "skip_to_send": "إرسال بدون تعليق", - "text_placeholder": "Type or paste additional comments" + "text_placeholder": "اكتب أو الصق تعليقات إضافيَّة" }, "preview": { "keyboard": { @@ -543,13 +543,13 @@ } }, "account_list": { - "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", + "tab_bar_hint": "المِلف المُحدَّد حاليًا: %s. انقر نقرًا مزدوجًا ثم اضغط مع الاستمرار لإظهار مُبدِّل الحِساب", "dismiss_account_switcher": "تجاهُل مبدِّل الحساب", "add_account": "إضافة حساب" }, "wizard": { "new_in_mastodon": "جديد في ماستودون", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "multiple_account_switch_intro_description": "بدِّل بين حسابات متعددة عبر الاستمرار بالضغط على زر الملف الشخصي.", "accessibility_hint": "انقر نقرًا مزدوجًا لتجاهل النافذة المنبثقة" } } From d22ccddbbccb3e702fb792c39982ff0ee11c11cb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 15 Nov 2021 07:36:18 +0100 Subject: [PATCH 382/392] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 3e788d6ce..71e0f538f 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -6,21 +6,21 @@ "please_try_again_later": "يُرجى المحاولة مرة أُخرى لاحقاً." }, "sign_up_failure": { - "title": "فشل التسجيل" + "title": "إخفاق في التسجيل" }, "server_error": { "title": "خطأ في الخادم" }, "vote_failure": { - "title": "فشل التصويت", + "title": "إخفاق في التصويت", "poll_ended": "انتهى استطلاع الرأي" }, "discard_post_content": { - "title": "تجاهل المسودة", + "title": "التخلص من المسودة", "message": "أكِّد للتخلص مِن مُحتوى مَنشور مؤلَّف." }, "publish_post_failure": { - "title": "أخفقت عملية النشر", + "title": "إخفاق في عمليَّة النشر", "message": "فَشَلَ نَشر المَنشور.\nيُرجى التحقق من اتصالك بالإنترنت.", "attachments_message": { "video_attach_with_photo": "لا يُمكن إرفاق مقطع مرئي إلى مَنشور يحتوي بالفعل على صُوَر.", @@ -33,19 +33,19 @@ }, "sign_out": { "title": "تسجيل الخروج", - "message": "هل أنت متأكد من أنك تريد تسجيل الخروج؟", + "message": "هل أنت متأكد من رغبتك في تسجيل الخروج؟", "confirm": "تسجيل الخروج" }, "block_domain": { - "title": "Are you really, really sure you want to block the entire %s? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed.", - "block_entire_domain": "حظر النطاق" + "title": "هل أنتَ مُتأكِّدٌ حقًا مِن رغبتك في حظر %s بالكامل؟ في معظم الحالات، يكون مِنَ الكافي والمُفَضَّل استهداف عدد محدود للحظر أو الكتم. لن ترى محتوى من هذا النطاق وسوف يتم إزالة جميع متابعيك المتواجدين فيه.", + "block_entire_domain": "حظر النِطاق" }, "save_photo_failure": { - "title": "فشل حفظ الصورة", - "message": "Please enable the photo library access permission to save the photo." + "title": "إخفاق في حفظ الصورة", + "message": "يُرجى إتاحة إذن الوصول إلى مكتبة الصور لحفظ الصورة." }, "delete_post": { - "title": "هل أنت متأكد من أنك تريد حذف هذا المنشور؟", + "title": "هل أنت متأكد من رغبتك في حذف هذا المنشور؟", "delete": "احذف" }, "clean_cache": { @@ -61,7 +61,7 @@ "open": "افتح", "add": "إضافة", "remove": "احذف", - "edit": "تعديل", + "edit": "تحرير", "save": "حفظ", "ok": "حسنًا", "done": "تمّ", @@ -71,21 +71,21 @@ "cancel": "إلغاء", "discard": "تجاهل", "try_again": "المُحاولة مرة أُخرى", - "take_photo": "التقط صورة", + "take_photo": "التقاط صورة", "save_photo": "حفظ الصورة", "copy_photo": "نسخ الصورة", "sign_in": "تسجيل الدخول", "sign_up": "إنشاء حِساب", "see_more": "عرض المزيد", - "preview": "معاينة", - "share": "شارك", - "share_user": "شارك %s", - "share_post": "شارك المنشور", - "open_in_safari": "افتحه في سفاري", + "preview": "مُعاينة", + "share": "المُشارك", + "share_user": "مُشاركة %s", + "share_post": "مشارك المنشور", + "open_in_safari": "الفتح في Safari", "find_people": "ابحث عن أشخاص لمتابعتهم", "manually_search": "البحث يدوياً بدلاً من ذلك", "skip": "تخطي", - "reply": "رد", + "reply": "الرَد", "report_user": "ابلغ عن %s", "block_domain": "حظر %s", "unblock_domain": "إلغاء حظر %s", @@ -130,7 +130,7 @@ "content_warning": "تحذير عن المحتوى", "media_content_warning": "انقر على أي مكان للكشف", "poll": { - "vote": "صَوّت", + "vote": "صَوِّت", "closed": "انتهى" }, "actions": { @@ -181,9 +181,9 @@ "header": { "no_status_found": "لا توجد هناك منشورات", "blocking_warning": "لا يُمكنك الاطلاع على الملف الشخصي لهذا المُستخدِم\nحتَّى تَرفعَ الحَظر عنه.\nملفًّكَ الشخصي يَظهَرُ بِمثل هذِهِ الحالة بالنسبةِ لَهُ أيضًا.", - "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.", + "user_blocking_warning": "لا يُمكنك الاطلاع على ملف %s الشخصي\nحتَّى تَرفعَ الحَظر عنه.\nملفًّكَ الشخصي يَظهَرُ بِمثل هذِهِ الحالة بالنسبةِ لَهُ أيضًا.", + "blocked_warning": "لا يُمكِنُكَ عَرض الملف الشخصي لهذا المُستخدِم\nحتَّى يَرفَعَ الحَظر عَنك.", + "user_blocked_warning": "لا يُمكِنُكَ عَرض ملف %s الشخصي\nحتَّى يَرفَعَ الحَظر عَنك.", "suspended_warning": "تمَّ إيقاف هذا المُستخدِم.", "user_suspended_warning": "لقد أوقِفَ حِساب %s." } @@ -450,7 +450,7 @@ "no_results": "ليس هناك أية نتيجة" }, "recent_search": "عمليات البحث الأخيرة", - "clear": "امسح" + "clear": "مَحو" } }, "favorite": { @@ -519,7 +519,7 @@ } }, "footer": { - "mastodon_description": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على غيت هب %s (%s)" + "mastodon_description": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء على GitHub في %s (%s)" }, "keyboard": { "close_settings_window": "إغلاق نافذة الإعدادات" @@ -529,15 +529,15 @@ "title": "ابلغ عن %s", "step1": "الخطوة 1 من 2", "step2": "الخطوة 2 من 2", - "content1": "هل ترغب في إضافة أي مشاركات أُخرى إلى التقرير؟", - "content2": "هل هناك أي شيء يجب أن يعرفه المُراقبين حول هذا التقرير؟", - "send": "ارسل الشكوى", + "content1": "هل ترغب في إضافة أي مشاركات أُخرى إلى الشكوى؟", + "content2": "هل هناك أي شيء يجب أن يعرفه المُراقبين حول هذه الشكوى؟", + "send": "إرسال الشكوى", "skip_to_send": "إرسال بدون تعليق", "text_placeholder": "اكتب أو الصق تعليقات إضافيَّة" }, "preview": { "keyboard": { - "close_preview": "إغلاق المعاينة", + "close_preview": "إغلاق المُعايَنَة", "show_next": "إظهار التالي", "show_previous": "إظهار السابق" } From 5916ed4716347f7f665070318ceb5f84e7446b4c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 15 Nov 2021 07:36:19 +0100 Subject: [PATCH 383/392] New translations Localizable.stringsdict (Arabic) --- .../StringsConvertor/input/ar_SA/Localizable.stringsdict | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index e3dee0d80..0b28c577a 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey ld zero - %ld unread notification + لا إشعار غير مقروء one إشعار واحِد غير مقروء two إشعاران غير مقروءان few - %ld unread notification + %ld إشعارات غير مقروءة many %ld إشعارًا غيرَ مقروء other @@ -277,7 +277,7 @@ NSStringFormatValueTypeKey ld zero - %ld followers + لا مُتابِع one مُتابِعٌ واحد two From efbda5a3847622d7588fbb23e114597e815afc2f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 19 Nov 2021 10:22:23 +0100 Subject: [PATCH 384/392] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index e27f097e4..74ac01eb2 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -545,7 +545,7 @@ "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" + "add_account": "Ajouter un compte" }, "wizard": { "new_in_mastodon": "New in Mastodon", From fe119641af4dc3590ee645273a058813f0ace7b6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 19 Nov 2021 11:50:16 +0100 Subject: [PATCH 385/392] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index 74ac01eb2..dd834928a 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -415,7 +415,7 @@ } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "Les abonné·e·s issus des autres serveurs ne sont pas affiché·e·s." }, "following": { "footer": "Follows from other servers are not displayed." @@ -548,9 +548,9 @@ "add_account": "Ajouter un compte" }, "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": "Nouveau dans Mastodon", + "multiple_account_switch_intro_description": "Basculez entre plusieurs comptes en appuyant de maniere prolongée sur le bouton profil.", + "accessibility_hint": "Tapotez deux fois pour fermer cet assistant" } } } \ No newline at end of file From 3983b94b96e234e58df4de30a8160b35a1c17800 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 19 Nov 2021 11:50:17 +0100 Subject: [PATCH 386/392] New translations Localizable.stringsdict (French) --- .../StringsConvertor/input/fr_FR/Localizable.stringsdict | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index d512b204c..4a912e4b3 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -13,15 +13,15 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notification non lue other - %ld unread notification + %ld notifications non lues a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + La limite d’entrée dépasse %#@character_count@ character_count NSStringFormatSpecTypeKey From 97f6769a0761ede69f136bf34afa729f9637a749 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 19 Nov 2021 11:50:18 +0100 Subject: [PATCH 387/392] New translations Intents.strings (French) --- .../StringsConvertor/Intents/input/fr_FR/Intents.strings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings index 628f794c9..f4fec3000 100644 --- a/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/fr_FR/Intents.strings @@ -6,7 +6,7 @@ "HZSGTr" = "Quel contenu à publier ?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Échec lors de la publication"; "KDNTJ4" = "Raison de l’échec"; @@ -40,11 +40,11 @@ "gfePDu" = "Échec lors de la publication. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Message publié avec succès."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Juste pour confirmer, vous vouliez « Public » ?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Juste pour confirmer, vous vouliez bien diffuser vers « abonné·e·s uniquement » ?"; "rM6dvp" = "URL"; From 4f6890ff01a0490fe166973fe38bb3acb1e0a898 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 3 Dec 2021 19:23:21 +0800 Subject: [PATCH 388/392] chore: deselect iPad target --- Mastodon.xcodeproj/project.pbxproj | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index e5118bf8d..acb82d7a0 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4934,7 +4934,7 @@ SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -4962,7 +4962,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -5227,7 +5227,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -5252,7 +5252,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5277,7 +5277,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5302,7 +5302,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -5327,7 +5327,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -5352,7 +5352,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5377,7 +5377,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5402,7 +5402,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -5494,7 +5494,7 @@ SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5608,7 +5608,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Release"; @@ -5731,7 +5731,7 @@ SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5845,7 +5845,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = "ASDK - Debug"; @@ -5900,7 +5900,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -5924,7 +5924,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; From cb554d6371ca1f734f91e7e66ebf42d371863f54 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 3 Dec 2021 19:26:28 +0800 Subject: [PATCH 389/392] chore: update i18n resources --- .../Resources/ar.lproj/Localizable.strings | 153 +++++++++--------- .../ar.lproj/Localizable.stringsdict | 6 +- .../Resources/fr.lproj/Localizable.strings | 10 +- .../fr.lproj/Localizable.stringsdict | 6 +- MastodonIntent/fr.lproj/Intents.strings | 8 +- 5 files changed, 91 insertions(+), 92 deletions(-) diff --git a/Mastodon/Resources/ar.lproj/Localizable.strings b/Mastodon/Resources/ar.lproj/Localizable.strings index 8681e584d..b878e0342 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.strings +++ b/Mastodon/Resources/ar.lproj/Localizable.strings @@ -1,63 +1,63 @@ -"Common.Alerts.BlockDomain.BlockEntireDomain" = "حظر النطاق"; -"Common.Alerts.BlockDomain.Title" = "Are you really, really sure you want to block the entire %@? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed."; +"Common.Alerts.BlockDomain.BlockEntireDomain" = "حظر النِطاق"; +"Common.Alerts.BlockDomain.Title" = "هل أنتَ مُتأكِّدٌ حقًا مِن رغبتك في حظر %@ بالكامل؟ في معظم الحالات، يكون مِنَ الكافي والمُفَضَّل استهداف عدد محدود للحظر أو الكتم. لن ترى محتوى من هذا النطاق وسوف يتم إزالة جميع متابعيك المتواجدين فيه."; "Common.Alerts.CleanCache.Message" = "تمَّ مَحو ذاكرة التخزين المؤقت %@ بنجاح."; "Common.Alerts.CleanCache.Title" = "مَحو ذاكرة التخزين المؤقت"; "Common.Alerts.Common.PleaseTryAgain" = "يُرجى المحاولة مرة أُخرى."; "Common.Alerts.Common.PleaseTryAgainLater" = "يُرجى المحاولة مرة أُخرى لاحقاً."; "Common.Alerts.DeletePost.Delete" = "احذف"; -"Common.Alerts.DeletePost.Title" = "هل أنت متأكد من أنك تريد حذف هذا المنشور؟"; -"Common.Alerts.DiscardPostContent.Message" = "Confirm to discard composed post content."; -"Common.Alerts.DiscardPostContent.Title" = "تجاهل المسودة"; +"Common.Alerts.DeletePost.Title" = "هل أنت متأكد من رغبتك في حذف هذا المنشور؟"; +"Common.Alerts.DiscardPostContent.Message" = "أكِّد للتخلص مِن مُحتوى مَنشور مؤلَّف."; +"Common.Alerts.DiscardPostContent.Title" = "التخلص من المسودة"; "Common.Alerts.EditProfileFailure.Message" = "لا يمكن تعديل الملف الشخصي. يُرجى المحاولة مرة أُخرى."; "Common.Alerts.EditProfileFailure.Title" = "خطأ في تَحرير الملف الشخصي"; -"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video."; -"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images."; -"Common.Alerts.PublishPostFailure.Message" = "Failed to publish the post. -Please check your internet connection."; -"Common.Alerts.PublishPostFailure.Title" = "أخفقت عملية النشر"; -"Common.Alerts.SavePhotoFailure.Message" = "Please enable the photo library access permission to save the photo."; -"Common.Alerts.SavePhotoFailure.Title" = "فشل حفظ الصورة"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "لا يُمكِنُ إرفاق أكثر مِن مَقطع مرئي واحِد."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "لا يُمكن إرفاق مقطع مرئي إلى مَنشور يحتوي بالفعل على صُوَر."; +"Common.Alerts.PublishPostFailure.Message" = "فَشَلَ نَشر المَنشور. +يُرجى التحقق من اتصالك بالإنترنت."; +"Common.Alerts.PublishPostFailure.Title" = "إخفاق في عمليَّة النشر"; +"Common.Alerts.SavePhotoFailure.Message" = "يُرجى إتاحة إذن الوصول إلى مكتبة الصور لحفظ الصورة."; +"Common.Alerts.SavePhotoFailure.Title" = "إخفاق في حفظ الصورة"; "Common.Alerts.ServerError.Title" = "خطأ في الخادم"; "Common.Alerts.SignOut.Confirm" = "تسجيل الخروج"; -"Common.Alerts.SignOut.Message" = "هل أنت متأكد من أنك تريد تسجيل الخروج؟"; +"Common.Alerts.SignOut.Message" = "هل أنت متأكد من رغبتك في تسجيل الخروج؟"; "Common.Alerts.SignOut.Title" = "تسجيل الخروج"; -"Common.Alerts.SignUpFailure.Title" = "فشل التسجيل"; +"Common.Alerts.SignUpFailure.Title" = "إخفاق في التسجيل"; "Common.Alerts.VoteFailure.PollEnded" = "انتهى استطلاع الرأي"; -"Common.Alerts.VoteFailure.Title" = "فشل التصويت"; +"Common.Alerts.VoteFailure.Title" = "إخفاق في التصويت"; "Common.Controls.Actions.Add" = "إضافة"; "Common.Controls.Actions.Back" = "العودة"; "Common.Controls.Actions.BlockDomain" = "حظر %@"; "Common.Controls.Actions.Cancel" = "إلغاء"; -"Common.Controls.Actions.Compose" = "Compose"; +"Common.Controls.Actions.Compose" = "تأليف"; "Common.Controls.Actions.Confirm" = "تأكيد"; "Common.Controls.Actions.Continue" = "واصل"; "Common.Controls.Actions.CopyPhoto" = "نسخ الصورة"; "Common.Controls.Actions.Delete" = "احذف"; "Common.Controls.Actions.Discard" = "تجاهل"; "Common.Controls.Actions.Done" = "تمّ"; -"Common.Controls.Actions.Edit" = "تعديل"; +"Common.Controls.Actions.Edit" = "تحرير"; "Common.Controls.Actions.FindPeople" = "ابحث عن أشخاص لمتابعتهم"; "Common.Controls.Actions.ManuallySearch" = "البحث يدوياً بدلاً من ذلك"; "Common.Controls.Actions.Next" = "التالي"; "Common.Controls.Actions.Ok" = "حسنًا"; "Common.Controls.Actions.Open" = "افتح"; -"Common.Controls.Actions.OpenInSafari" = "افتحه في سفاري"; -"Common.Controls.Actions.Preview" = "معاينة"; +"Common.Controls.Actions.OpenInSafari" = "الفتح في Safari"; +"Common.Controls.Actions.Preview" = "مُعاينة"; "Common.Controls.Actions.Previous" = "السابق"; "Common.Controls.Actions.Remove" = "احذف"; -"Common.Controls.Actions.Reply" = "رد"; +"Common.Controls.Actions.Reply" = "الرَد"; "Common.Controls.Actions.ReportUser" = "ابلغ عن %@"; "Common.Controls.Actions.Save" = "حفظ"; "Common.Controls.Actions.SavePhoto" = "حفظ الصورة"; "Common.Controls.Actions.SeeMore" = "عرض المزيد"; "Common.Controls.Actions.Settings" = "الإعدادات"; -"Common.Controls.Actions.Share" = "شارك"; -"Common.Controls.Actions.SharePost" = "شارك المنشور"; -"Common.Controls.Actions.ShareUser" = "شارك %@"; +"Common.Controls.Actions.Share" = "المُشارك"; +"Common.Controls.Actions.SharePost" = "مشارك المنشور"; +"Common.Controls.Actions.ShareUser" = "مُشاركة %@"; "Common.Controls.Actions.SignIn" = "تسجيل الدخول"; "Common.Controls.Actions.SignUp" = "إنشاء حِساب"; "Common.Controls.Actions.Skip" = "تخطي"; -"Common.Controls.Actions.TakePhoto" = "التقط صورة"; +"Common.Controls.Actions.TakePhoto" = "التقاط صورة"; "Common.Controls.Actions.TryAgain" = "المُحاولة مرة أُخرى"; "Common.Controls.Actions.UnblockDomain" = "إلغاء حظر %@"; "Common.Controls.Friendship.Block" = "حظر"; @@ -76,7 +76,7 @@ Please check your internet connection."; "Common.Controls.Friendship.UnblockUser" = "إلغاء حظر %@"; "Common.Controls.Friendship.Unmute" = "إلغاء الكتم"; "Common.Controls.Friendship.UnmuteUser" = "إلغاء كتم %@"; -"Common.Controls.Keyboard.Common.ComposeNewPost" = "إنشاء منشور جديد"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "تأليف منشور جديد"; "Common.Controls.Keyboard.Common.OpenSettings" = "أفتح الإعدادات"; "Common.Controls.Keyboard.Common.ShowFavorites" = "إظهار المفضلة"; "Common.Controls.Keyboard.Common.SwitchToTab" = "التبديل إلى %@"; @@ -89,9 +89,9 @@ Please check your internet connection."; "Common.Controls.Keyboard.Timeline.PreviewImage" = "معاينة الصورة"; "Common.Controls.Keyboard.Timeline.PreviousStatus" = "المنشور السابق"; "Common.Controls.Keyboard.Timeline.ReplyStatus" = "رد على المنشور"; -"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Toggle Content Warning"; -"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Toggle Favorite on Post"; -"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Toggle Reblog on Post"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "تبديل تحذير المُحتَوى"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "تبديل المفضلة لِمنشور"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "تبديل إعادة تدوين منشور"; "Common.Controls.Status.Actions.Favorite" = "إضافة إلى المفضلة"; "Common.Controls.Status.Actions.Menu" = "القائمة"; "Common.Controls.Status.Actions.Reblog" = "إعادة النشر"; @@ -99,9 +99,9 @@ Please check your internet connection."; "Common.Controls.Status.Actions.Unfavorite" = "إزالة من المفضلة"; "Common.Controls.Status.Actions.Unreblog" = "تراجع عن إعادة النشر"; "Common.Controls.Status.ContentWarning" = "تحذير عن المحتوى"; -"Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal"; +"Common.Controls.Status.MediaContentWarning" = "انقر على أي مكان للكشف"; "Common.Controls.Status.Poll.Closed" = "انتهى"; -"Common.Controls.Status.Poll.Vote" = "صَوّت"; +"Common.Controls.Status.Poll.Vote" = "صَوِّت"; "Common.Controls.Status.ShowPost" = "اظهر المنشور"; "Common.Controls.Status.ShowUserProfile" = "اظهر الملف التعريفي للمستخدم"; "Common.Controls.Status.Tag.Email" = "البريد الإلكتروني"; @@ -117,43 +117,42 @@ Please check your internet connection."; "Common.Controls.Tabs.Profile" = "الملف التعريفي"; "Common.Controls.Tabs.Search" = "بحث"; "Common.Controls.Timeline.Filtered" = "مُصفَّى"; -"Common.Controls.Timeline.Header.BlockedWarning" = "You can’t view this user’s profile -until they unblock you."; -"Common.Controls.Timeline.Header.BlockingWarning" = "You can’t view this user's profile -until you unblock them. -Your profile looks like this to them."; +"Common.Controls.Timeline.Header.BlockedWarning" = "لا يُمكِنُكَ عَرض الملف الشخصي لهذا المُستخدِم +حتَّى يَرفَعَ الحَظر عَنك."; +"Common.Controls.Timeline.Header.BlockingWarning" = "لا يُمكنك الاطلاع على الملف الشخصي لهذا المُستخدِم +حتَّى تَرفعَ الحَظر عنه. +ملفًّكَ الشخصي يَظهَرُ بِمثل هذِهِ الحالة بالنسبةِ لَهُ أيضًا."; "Common.Controls.Timeline.Header.NoStatusFound" = "لا توجد هناك منشورات"; -"Common.Controls.Timeline.Header.SuspendedWarning" = "This user has been suspended."; -"Common.Controls.Timeline.Header.UserBlockedWarning" = "You can’t view %@’s profile -until they unblock you."; -"Common.Controls.Timeline.Header.UserBlockingWarning" = "You can’t view %@’s profile -until you unblock them. -Your profile looks like this to them."; -"Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@’s account has been suspended."; +"Common.Controls.Timeline.Header.SuspendedWarning" = "تمَّ إيقاف هذا المُستخدِم."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "لا يُمكِنُكَ عَرض ملف %@ الشخصي +حتَّى يَرفَعَ الحَظر عَنك."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "لا يُمكنك الاطلاع على ملف %@ الشخصي +حتَّى تَرفعَ الحَظر عنه. +ملفًّكَ الشخصي يَظهَرُ بِمثل هذِهِ الحالة بالنسبةِ لَهُ أيضًا."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "لقد أوقِفَ حِساب %@."; "Common.Controls.Timeline.Loader.LoadMissingPosts" = "تحميل المنشورات المَفقودة"; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "تحميل المزيد من المنشورات..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "إظهار المزيد من الردود"; "Common.Controls.Timeline.Timestamp.Now" = "الأن"; "Scene.AccountList.AddAccount" = "إضافة حساب"; "Scene.AccountList.DismissAccountSwitcher" = "تجاهُل مبدِّل الحساب"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.TabBarHint" = "المِلف المُحدَّد حاليًا: %@. انقر نقرًا مزدوجًا ثم اضغط مع الاستمرار لإظهار مُبدِّل الحِساب"; "Scene.Compose.Accessibility.AppendAttachment" = "إضافة مُرفَق"; "Scene.Compose.Accessibility.AppendPoll" = "اضافة استطلاع رأي"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "منتقي مخصص للإيموجي"; "Scene.Compose.Accessibility.DisableContentWarning" = "تعطيل تحذير الحتوى"; "Scene.Compose.Accessibility.EnableContentWarning" = "تنشيط تحذير المحتوى"; -"Scene.Compose.Accessibility.PostVisibilityMenu" = "Post Visibility Menu"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "قائمة ظهور المنشور"; "Scene.Compose.Accessibility.RemovePoll" = "إزالة الاستطلاع"; -"Scene.Compose.Attachment.AttachmentBroken" = "This %@ is broken and can’t be -uploaded to Mastodon."; -"Scene.Compose.Attachment.DescriptionPhoto" = "Describe the photo for the visually-impaired..."; -"Scene.Compose.Attachment.DescriptionVideo" = "Describe the video for the visually-impaired..."; +"Scene.Compose.Attachment.AttachmentBroken" = "هذا ال%@ مُعطَّل ويتعذَّر رفعه إلى ماستودون."; +"Scene.Compose.Attachment.DescriptionPhoto" = "صِف الصورة للمكفوفين..."; +"Scene.Compose.Attachment.DescriptionVideo" = "صِف المقطع المرئي للمكفوفين..."; "Scene.Compose.Attachment.Photo" = "صورة"; "Scene.Compose.Attachment.Video" = "فيديو"; -"Scene.Compose.AutoComplete.SpaceToAdd" = "Space to add"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "انقر مساحة لإضافتِها"; "Scene.Compose.ComposeAction" = "انشر"; "Scene.Compose.ContentInputPlaceholder" = "أخبِرنا بِما يَجُولُ فِي ذِهنَك"; -"Scene.Compose.ContentWarning.Placeholder" = "Write an accurate warning here..."; +"Scene.Compose.ContentWarning.Placeholder" = "اكتب تَحذيرًا دَقيقًا هُنا..."; "Scene.Compose.Keyboard.AppendAttachmentEntry" = "إضافة مُرفَق - %@"; "Scene.Compose.Keyboard.DiscardPost" = "تجاهُل المنشور"; "Scene.Compose.Keyboard.PublishPost" = "نَشر المَنشُور"; @@ -180,10 +179,10 @@ uploaded to Mastodon."; "Scene.Compose.Visibility.Unlisted" = "غير مُدرَج"; "Scene.ConfirmEmail.Button.DontReceiveEmail" = "لم أستلم أبدًا بريدا إلكترونيا"; "Scene.ConfirmEmail.Button.OpenEmailApp" = "افتح تطبيق البريد الإلكتروني"; -"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Check if your email address is correct as well as your junk folder if you haven’t."; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "تحقق ممَّ إذا كان عنوان بريدك الإلكتروني صحيحًا وكذلك تأكد مِن مجلد البريد غير الهام إذا لم تكن قد فعلت ذلك."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "إعادة إرسال البريد الإلكتروني"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "تحقق من بريدك الإلكتروني"; -"Scene.ConfirmEmail.OpenEmailApp.Description" = "We just sent you an email. Check your junk folder if you haven’t."; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "لقد أرسلنا لك بريدًا إلكترونيًا للتو. تحقق من مجلد البريد غير الهام الخاص بك إذا لم تكن قد فعلت ذلك."; "Scene.ConfirmEmail.OpenEmailApp.Mail" = "البريد"; "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "فتح عميل البريد الإلكتروني"; "Scene.ConfirmEmail.OpenEmailApp.Title" = "تحقَّق من بريدك الوارِد."; @@ -191,8 +190,8 @@ uploaded to Mastodon."; اضغط على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيء واحد أخير."; "Scene.Favorite.Title" = "مفضلتك"; -"Scene.Follower.Footer" = "Followers from other servers are not displayed."; -"Scene.Following.Footer" = "Follows from other servers are not displayed."; +"Scene.Follower.Footer" = "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى."; +"Scene.Following.Footer" = "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "إظهار منشورات جديدة"; "Scene.HomeTimeline.NavigationBarState.Offline" = "غير متصل"; "Scene.HomeTimeline.NavigationBarState.Published" = "تم نشره!"; @@ -208,7 +207,7 @@ uploaded to Mastodon."; "Scene.Notification.UserRebloggedYourPost" = "أعاد %@ تدوين مشاركتك"; "Scene.Notification.UserRequestedToFollowYou" = "طلب %@ متابعتك"; "Scene.Notification.UserYourPollHasEnded" = "%@ اِنتهى استطلاعُكَ للرأي"; -"Scene.Preview.Keyboard.ClosePreview" = "إغلاق المعاينة"; +"Scene.Preview.Keyboard.ClosePreview" = "إغلاق المُعايَنَة"; "Scene.Preview.Keyboard.ShowNext" = "إظهار التالي"; "Scene.Preview.Keyboard.ShowPrevious" = "إظهار السابق"; "Scene.Profile.Dashboard.Followers" = "متابِع"; @@ -217,9 +216,9 @@ uploaded to Mastodon."; "Scene.Profile.Fields.AddRow" = "إضافة صف"; "Scene.Profile.Fields.Placeholder.Content" = "المحتوى"; "Scene.Profile.Fields.Placeholder.Label" = "التسمية"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Message" = "Confirm to unblock %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Message" = "أكِّد لرفع حظر %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.Title" = "إلغاء حظر الحساب"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Confirm to unmute %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "أكِّد لرفع كتمْ %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "إلغاء كتم الحساب"; "Scene.Profile.SegmentedControl.Media" = "وسائط"; "Scene.Profile.SegmentedControl.Posts" = "منشورات"; @@ -230,20 +229,20 @@ uploaded to Mastodon."; "Scene.Register.Error.Item.Password" = "الكلمة السرية"; "Scene.Register.Error.Item.Reason" = "السبب"; "Scene.Register.Error.Item.Username" = "اسم المستخدم"; -"Scene.Register.Error.Reason.Accepted" = "%@ must be accepted"; +"Scene.Register.Error.Reason.Accepted" = "يجب أن يُقبل %@"; "Scene.Register.Error.Reason.Blank" = "%@ مطلوب"; -"Scene.Register.Error.Reason.Blocked" = "%@ contains a disallowed email provider"; -"Scene.Register.Error.Reason.Inclusion" = "%@ is not a supported value"; +"Scene.Register.Error.Reason.Blocked" = "يحتوي %@ على موفِّر خدمة بريد إلكتروني غير مسموح به"; +"Scene.Register.Error.Reason.Inclusion" = "إنَّ %@ قيمة غير مدعومة"; "Scene.Register.Error.Reason.Invalid" = "%@ غير صالح"; -"Scene.Register.Error.Reason.Reserved" = "%@ is a reserved keyword"; -"Scene.Register.Error.Reason.Taken" = "%@ is already in use"; +"Scene.Register.Error.Reason.Reserved" = "إنَّ %@ عبارة عن كلمة مفتاحيَّة محجوزة"; +"Scene.Register.Error.Reason.Taken" = "إنَّ %@ مُستخدَمٌ بالفعل"; "Scene.Register.Error.Reason.TooLong" = "%@ طويل جداً"; "Scene.Register.Error.Reason.TooShort" = "%@ قصير جدا"; -"Scene.Register.Error.Reason.Unreachable" = "%@ does not seem to exist"; +"Scene.Register.Error.Reason.Unreachable" = "يبدوا أنَّ %@ غير موجود"; "Scene.Register.Error.Special.EmailInvalid" = "هذا عنوان بريد إلكتروني غير صالح"; "Scene.Register.Error.Special.PasswordTooShort" = "كلمة المرور قصيرة جداً (يجب أن تكون 8 أحرف على الأقل)"; -"Scene.Register.Error.Special.UsernameInvalid" = "Username must only contain alphanumeric characters and underscores"; -"Scene.Register.Error.Special.UsernameTooLong" = "Username is too long (can’t be longer than 30 characters)"; +"Scene.Register.Error.Special.UsernameInvalid" = "يُمكِن أن يحتوي اسم المستخدم على أحرف أبجدية، أرقام وشرطات سفلية فقط"; +"Scene.Register.Error.Special.UsernameTooLong" = "اسم المستخدم طويل جداً (يجب ألّا يكون أطول من 30 رمز)"; "Scene.Register.Input.Avatar.Delete" = "احذف"; "Scene.Register.Input.DisplayName.Placeholder" = "الاسم المعروض"; "Scene.Register.Input.Email.Placeholder" = "البريد الإلكتروني"; @@ -253,24 +252,24 @@ uploaded to Mastodon."; "Scene.Register.Input.Username.DuplicatePrompt" = "اسم المستخدم هذا غير متوفر."; "Scene.Register.Input.Username.Placeholder" = "اسم المستخدم"; "Scene.Register.Title" = "أخبرنا عنك."; -"Scene.Report.Content1" = "Are there any other posts you’d like to add to the report?"; -"Scene.Report.Content2" = "Is there anything the moderators should know about this report?"; -"Scene.Report.Send" = "ارسل الشكوى"; +"Scene.Report.Content1" = "هل ترغب في إضافة أي مشاركات أُخرى إلى الشكوى؟"; +"Scene.Report.Content2" = "هل هناك أي شيء يجب أن يعرفه المُراقبين حول هذه الشكوى؟"; +"Scene.Report.Send" = "إرسال الشكوى"; "Scene.Report.SkipToSend" = "إرسال بدون تعليق"; "Scene.Report.Step1" = "الخطوة 1 من 2"; "Scene.Report.Step2" = "الخطوة 2 من 2"; -"Scene.Report.TextPlaceholder" = "Type or paste additional comments"; +"Scene.Report.TextPlaceholder" = "اكتب أو الصق تعليقات إضافيَّة"; "Scene.Report.Title" = "ابلغ عن %@"; "Scene.Search.Recommend.Accounts.Description" = "قد ترغب في متابعة هذه الحسابات"; "Scene.Search.Recommend.Accounts.Follow" = "تابع"; "Scene.Search.Recommend.Accounts.Title" = "حسابات قد تعجبك"; "Scene.Search.Recommend.ButtonText" = "طالع الكل"; -"Scene.Search.Recommend.HashTag.Description" = "Hashtags that are getting quite a bit of attention"; +"Scene.Search.Recommend.HashTag.Description" = "الوسوم التي تحظى بقدر كبير من الاهتمام"; "Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ أشخاص يتحدَّثوا"; "Scene.Search.Recommend.HashTag.Title" = "ذات شعبية على ماستدون"; "Scene.Search.SearchBar.Cancel" = "إلغاء"; "Scene.Search.SearchBar.Placeholder" = "البحث عن وسوم أو مستخدمين·ات"; -"Scene.Search.Searching.Clear" = "امسح"; +"Scene.Search.Searching.Clear" = "مَحو"; "Scene.Search.Searching.EmptyState.NoResults" = "ليس هناك أية نتيجة"; "Scene.Search.Searching.RecentSearch" = "عمليات البحث الأخيرة"; "Scene.Search.Searching.Segment.All" = "الكل"; @@ -294,7 +293,7 @@ uploaded to Mastodon."; "Scene.ServerPicker.Button.Category.Tech" = "تكنولوجيا"; "Scene.ServerPicker.Button.SeeLess" = "اعرض أقل"; "Scene.ServerPicker.Button.SeeMore" = "اعرض المزيد"; -"Scene.ServerPicker.EmptyState.BadNetwork" = "Something went wrong while loading the data. Check your internet connection."; +"Scene.ServerPicker.EmptyState.BadNetwork" = "حدث خطأٌ ما أثناء تحميل البيانات. تحقَّق من اتصالك بالإنترنت."; "Scene.ServerPicker.EmptyState.FindingServers" = "البحث عن خوادم متوفرة..."; "Scene.ServerPicker.EmptyState.NoResults" = "لا توجد نتائج"; "Scene.ServerPicker.Input.Placeholder" = "ابحث عن خادم أو انضم إلى سيرفر خاص بك..."; @@ -309,7 +308,7 @@ uploaded to Mastodon."; "Scene.ServerRules.Subtitle" = "تم سنّ هذه القواعد من قبل مشرفي %@."; "Scene.ServerRules.TermsOfService" = "شروط الخدمة"; "Scene.ServerRules.Title" = "بعض القواعد الأساسية."; -"Scene.Settings.Footer.MastodonDescription" = "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على غيت هب %@ (%@)"; +"Scene.Settings.Footer.MastodonDescription" = "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء على GitHub في %@ (%@)"; "Scene.Settings.Keyboard.CloseSettingsWindow" = "إغلاق نافذة الإعدادات"; "Scene.Settings.Section.Appearance.Automatic" = "تلقائي"; "Scene.Settings.Section.Appearance.Dark" = "مظلمٌ دائِمًا"; @@ -338,12 +337,12 @@ uploaded to Mastodon."; "Scene.Settings.Section.SpicyZone.Signout" = "تسجيل الخروج"; "Scene.Settings.Section.SpicyZone.Title" = "المنطقة الحارة"; "Scene.Settings.Title" = "الإعدادات"; -"Scene.SuggestionAccount.FollowExplain" = "When you follow someone, you’ll see their posts in your home feed."; +"Scene.SuggestionAccount.FollowExplain" = "عِندَ مُتابَعَتِكَ لأحدِهِم، سَوف تَرى مَنشوراته في تغذيَتِكَ الرئيسة."; "Scene.SuggestionAccount.Title" = "ابحث عن أشخاص لمتابعتهم"; "Scene.Thread.BackTitle" = "منشور"; "Scene.Thread.Title" = "مَنشور مِن %@"; -"Scene.Welcome.Slogan" = "Social networking -back in your hands."; +"Scene.Welcome.Slogan" = "شبكات التواصل الاجتماعي +مرة أُخرى بين يديك."; "Scene.Wizard.AccessibilityHint" = "انقر نقرًا مزدوجًا لتجاهل النافذة المنبثقة"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "بدِّل بين حسابات متعددة عبر الاستمرار بالضغط على زر الملف الشخصي."; "Scene.Wizard.NewInMastodon" = "جديد في ماستودون"; \ No newline at end of file diff --git a/Mastodon/Resources/ar.lproj/Localizable.stringsdict b/Mastodon/Resources/ar.lproj/Localizable.stringsdict index e3dee0d80..0b28c577a 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/ar.lproj/Localizable.stringsdict @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey ld zero - %ld unread notification + لا إشعار غير مقروء one إشعار واحِد غير مقروء two إشعاران غير مقروءان few - %ld unread notification + %ld إشعارات غير مقروءة many %ld إشعارًا غيرَ مقروء other @@ -277,7 +277,7 @@ NSStringFormatValueTypeKey ld zero - %ld followers + لا مُتابِع one مُتابِعٌ واحد two diff --git a/Mastodon/Resources/fr.lproj/Localizable.strings b/Mastodon/Resources/fr.lproj/Localizable.strings index 9514a7a5e..a4dbfdb6f 100644 --- a/Mastodon/Resources/fr.lproj/Localizable.strings +++ b/Mastodon/Resources/fr.lproj/Localizable.strings @@ -134,7 +134,7 @@ Votre profil ressemble à ça pour lui."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Chargement des publications manquantes..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Charger plus de réponses"; "Common.Controls.Timeline.Timestamp.Now" = "À l’instant"; -"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.AddAccount" = "Ajouter un compte"; "Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; "Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; "Scene.Compose.Accessibility.AppendAttachment" = "Joindre un document"; @@ -191,7 +191,7 @@ téléversé sur Mastodon."; tapotez le lien pour confirmer votre compte."; "Scene.ConfirmEmail.Title" = "Une dernière chose."; "Scene.Favorite.Title" = "Vos favoris"; -"Scene.Follower.Footer" = "Followers from other servers are not displayed."; +"Scene.Follower.Footer" = "Les abonné·e·s issus des autres serveurs ne sont pas affiché·e·s."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Voir les nouvelles publications"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Hors ligne"; @@ -343,6 +343,6 @@ n'importe quel serveur."; "Scene.Thread.BackTitle" = "Publication"; "Scene.Thread.Title" = "Publication de %@"; "Scene.Welcome.Slogan" = "Le réseau social qui vous rend le contrôle."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.AccessibilityHint" = "Tapotez deux fois pour fermer cet assistant"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Basculez entre plusieurs comptes en appuyant de maniere prolongée sur le bouton profil."; +"Scene.Wizard.NewInMastodon" = "Nouveau dans Mastodon"; \ No newline at end of file diff --git a/Mastodon/Resources/fr.lproj/Localizable.stringsdict b/Mastodon/Resources/fr.lproj/Localizable.stringsdict index d512b204c..4a912e4b3 100644 --- a/Mastodon/Resources/fr.lproj/Localizable.stringsdict +++ b/Mastodon/Resources/fr.lproj/Localizable.stringsdict @@ -13,15 +13,15 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notification non lue other - %ld unread notification + %ld notifications non lues a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + La limite d’entrée dépasse %#@character_count@ character_count NSStringFormatSpecTypeKey diff --git a/MastodonIntent/fr.lproj/Intents.strings b/MastodonIntent/fr.lproj/Intents.strings index 628f794c9..f4fec3000 100644 --- a/MastodonIntent/fr.lproj/Intents.strings +++ b/MastodonIntent/fr.lproj/Intents.strings @@ -6,7 +6,7 @@ "HZSGTr" = "Quel contenu à publier ?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Échec lors de la publication"; "KDNTJ4" = "Raison de l’échec"; @@ -40,11 +40,11 @@ "gfePDu" = "Échec lors de la publication. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Message publié avec succès."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Juste pour confirmer, vous vouliez « Public » ?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Juste pour confirmer, vous vouliez bien diffuser vers « abonné·e·s uniquement » ?"; "rM6dvp" = "URL"; From 7859ebd4ffb674d4157fb81fe0c627c27fbeb818 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 3 Dec 2021 19:28:50 +0800 Subject: [PATCH 390/392] chore: add "Open in Browser" i18n word. #307 --- Localization/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/app.json b/Localization/app.json index 5c01ae7e0..6d3b2fcc2 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -82,6 +82,7 @@ "share_user": "Share %s", "share_post": "Share Post", "open_in_safari": "Open in Safari", + "open_in_browser": "Open in Browser", "find_people": "Find people to follow", "manually_search": "Manually search instead", "skip": "Skip", From 079792784cbcbac2db87a14c1e662e8db41fe540 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 3 Dec 2021 20:23:40 +0800 Subject: [PATCH 391/392] feat: patch some VoiceOver issues. #309 --- .../xcschemes/xcschememanagement.plist | 8 +++--- .../Section/Status/NotificationSection.swift | 28 +++++++++++++++++++ .../Section/Status/PollSection.swift | 9 ++++++ .../Section/Status/StatusSection.swift | 8 +++++- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index aa6a21a4c..913a8fdb7 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 47 + 37 CoreDataStack.xcscheme_^#shared#^_ orderHint - 46 + 36 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -102,7 +102,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 45 + 38 MastodonIntents.xcscheme_^#shared#^_ @@ -122,7 +122,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 48 + 39 SuppressBuildableAutocreation diff --git a/Mastodon/Diffiable/Section/Status/NotificationSection.swift b/Mastodon/Diffiable/Section/Status/NotificationSection.swift index 22283a479..864785007 100644 --- a/Mastodon/Diffiable/Section/Status/NotificationSection.swift +++ b/Mastodon/Diffiable/Section/Status/NotificationSection.swift @@ -45,6 +45,8 @@ extension NotificationSection { attribute: attribute ) cell.delegate = delegate + cell.isAccessibilityElement = true + NotificationSection.configureStatusAccessibilityLabel(cell: cell) return cell case .notificationStatus(objectID: let objectID, attribute: let attribute): @@ -215,4 +217,30 @@ extension NotificationSection { cell.containerStackViewBottomLayoutConstraint.constant = 5 // 5pt margin when no status view } } + + static func configureStatusAccessibilityLabel(cell: NotificationStatusTableViewCell) { + // FIXME: + cell.accessibilityLabel = { + var accessibilityViews: [UIView?] = [] + accessibilityViews.append(contentsOf: [ + cell.titleLabel, + cell.timestampLabel, + cell.statusView + ]) + if !cell.statusContainerView.isHidden { + if !cell.statusView.headerContainerView.isHidden { + accessibilityViews.append(cell.statusView.headerInfoLabel) + } + accessibilityViews.append(contentsOf: [ + cell.statusView.nameMetaLabel, + cell.statusView.dateLabel, + cell.statusView.contentMetaText.textView, + ]) + } + return accessibilityViews + .compactMap { $0?.accessibilityLabel } + .joined(separator: " ") + }() + } } + diff --git a/Mastodon/Diffiable/Section/Status/PollSection.swift b/Mastodon/Diffiable/Section/Status/PollSection.swift index add2a79b2..682a2abc0 100644 --- a/Mastodon/Diffiable/Section/Status/PollSection.swift +++ b/Mastodon/Diffiable/Section/Status/PollSection.swift @@ -37,6 +37,15 @@ extension PollSection { managedObjectContext.performAndWait { let option = managedObjectContext.object(with: objectID) as! PollOption PollSection.configure(cell: cell, pollOption: option, pollItemAttribute: attribute) + + cell.isAccessibilityElement = true + cell.accessibilityLabel = { + var labels: [String] = [option.title] + if let percentage = cell.pollOptionView.optionPercentageLabel.text { + labels.append(percentage) + } + return labels.joined(separator: ",") + }() } return cell } diff --git a/Mastodon/Diffiable/Section/Status/StatusSection.swift b/Mastodon/Diffiable/Section/Status/StatusSection.swift index ceb0c9458..61217c790 100644 --- a/Mastodon/Diffiable/Section/Status/StatusSection.swift +++ b/Mastodon/Diffiable/Section/Status/StatusSection.swift @@ -158,6 +158,11 @@ extension StatusSection { accessibilityElements.append(cell.statusView.avatarView) accessibilityElements.append(cell.statusView.nameMetaLabel) accessibilityElements.append(cell.statusView.dateLabel) + // poll + accessibilityElements.append(cell.statusView.pollTableView) + accessibilityElements.append(cell.statusView.pollVoteCountLabel) + accessibilityElements.append(cell.statusView.pollCountdownLabel) + accessibilityElements.append(cell.statusView.pollVoteButton) // TODO: a11y accessibilityElements.append(cell.statusView.contentMetaText.textView) accessibilityElements.append(contentsOf: cell.statusView.statusMosaicImageViewContainer.imageViews) @@ -389,7 +394,7 @@ extension StatusSection { // set timestamp let createdAt = (status.reblog ?? status).createdAt cell.statusView.dateLabel.text = createdAt.localizedSlowedTimeAgoSinceNow - cell.statusView.dateLabel.accessibilityValue = createdAt.timeAgoSinceNow + cell.statusView.dateLabel.accessibilityLabel = createdAt.timeAgoSinceNow AppContext.shared.timestampUpdatePublisher .receive(on: RunLoop.main) // will be paused when scrolling (on purpose) .sink { [weak cell] _ in @@ -978,6 +983,7 @@ extension StatusSection { cell.statusView.pollCountdownLabel.text = "-" } + cell.statusView.isUserInteractionEnabled = !poll.expired // make voice over touch passthroughable cell.statusView.pollTableView.allowsSelection = !poll.expired let votedOptions = poll.options.filter { option in From 15506171108617d8c161e5ae388b47640e0f2462 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 3 Dec 2021 20:29:25 +0800 Subject: [PATCH 392/392] chore: update version to 1.2.0 (88) --- AppShared/Info.plist | 2 +- CoreDataStack/Info.plist | 2 +- CoreDataStackTests/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 64 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 +-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 9e3842757..9fe845c60 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist index 9e3842757..9fe845c60 100644 --- a/CoreDataStack/Info.plist +++ b/CoreDataStack/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist index 9e3842757..9fe845c60 100644 --- a/CoreDataStackTests/Info.plist +++ b/CoreDataStackTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index acb82d7a0..6b7644e3e 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4919,7 +4919,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4948,7 +4948,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5056,11 +5056,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5087,11 +5087,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5116,11 +5116,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5146,11 +5146,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5213,7 +5213,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5238,7 +5238,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5263,7 +5263,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5288,7 +5288,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5313,7 +5313,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5338,7 +5338,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5363,7 +5363,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5388,7 +5388,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5479,7 +5479,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5546,11 +5546,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5595,7 +5595,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5620,11 +5620,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5716,7 +5716,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5783,11 +5783,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = CoreDataStack/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5832,7 +5832,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5857,11 +5857,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 87; + DYLIB_CURRENT_VERSION = 88; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5887,7 +5887,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5911,7 +5911,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 87; + CURRENT_PROJECT_VERSION = 88; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 913a8fdb7..5c99e944b 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AppShared.xcscheme_^#shared#^_ orderHint - 37 + 44 CoreDataStack.xcscheme_^#shared#^_ orderHint - 36 + 45 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -102,7 +102,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 38 + 43 MastodonIntents.xcscheme_^#shared#^_ @@ -122,7 +122,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 39 + 42 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 00bab8799..affa5b059 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 87 + 88 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 986b62577..8ac3d165b 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 9e3842757..9fe845c60 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 9e3842757..9fe845c60 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index a6cdb01a1..8e14f3a2a 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index b5052eb9e..1b3025474 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.2.0 CFBundleVersion - 87 + 88 NSExtension NSExtensionAttributes