mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-15 14:36:38 +00:00
Merge branch 'master' into group-knocking
This commit is contained in:
@@ -873,7 +873,7 @@ enum ChatResponse2: Decodable, ChatAPIResult {
|
||||
case ntfTokenStatus(status: NtfTknStatus)
|
||||
case ntfToken(token: DeviceToken, status: NtfTknStatus, ntfMode: NotificationsMode, ntfServer: String)
|
||||
case ntfConns(ntfConns: [NtfConn])
|
||||
case connNtfMessages(receivedMsgs: [NtfMsgInfo?])
|
||||
case connNtfMessages(receivedMsgs: [RcvNtfMsgInfo])
|
||||
// remote desktop responses
|
||||
case remoteCtrlList(remoteCtrls: [RemoteCtrlInfo])
|
||||
case remoteCtrlConnecting(remoteCtrl_: RemoteCtrlInfo?, ctrlAppInfo: CtrlAppInfo, appVersion: String)
|
||||
|
||||
@@ -814,8 +814,9 @@
|
||||
<target state="translated">جهة الاتصال مخفية:</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Contact is connected" xml:space="preserve">
|
||||
<trans-unit id="Contact is connected" xml:space="preserve" approved="no">
|
||||
<source>Contact is connected</source>
|
||||
<target state="translated">تم الاتصال</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Contact is not connected yet!" xml:space="preserve">
|
||||
@@ -850,8 +851,9 @@
|
||||
<source>Core built at: %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Core version: v%@" xml:space="preserve">
|
||||
<trans-unit id="Core version: v%@" xml:space="preserve" approved="no">
|
||||
<source>Core version: v%@</source>
|
||||
<target state="translated">الإصدار الأساسي: v%@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Create" xml:space="preserve" approved="no">
|
||||
@@ -901,8 +903,9 @@
|
||||
<target state="translated">عبارة المرور الحالية…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
|
||||
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve" approved="no">
|
||||
<source>Currently maximum supported file size is %@.</source>
|
||||
<target state="translated">الحد الأقصى لحجم الملف المدعوم حاليًا هو %@.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Dark" xml:space="preserve" approved="no">
|
||||
@@ -920,9 +923,11 @@
|
||||
<target state="translated">قاعدة البيانات مُعمّاة!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Database encryption passphrase will be updated and stored in the keychain. " xml:space="preserve">
|
||||
<trans-unit id="Database encryption passphrase will be updated and stored in the keychain. " xml:space="preserve" approved="no">
|
||||
<source>Database encryption passphrase will be updated and stored in the keychain.
|
||||
</source>
|
||||
<target state="translated">سيتم تحديث عبارة المرور الخاصة بتشفير قاعدة البيانات وتخزينها في سلسلة المفاتيح.
|
||||
</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Database encryption passphrase will be updated. " xml:space="preserve" approved="no">
|
||||
@@ -957,8 +962,9 @@
|
||||
<target state="translated">عبارة مرور قاعدة البيانات وتصديرها</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Database passphrase is different from saved in the keychain." xml:space="preserve">
|
||||
<trans-unit id="Database passphrase is different from saved in the keychain." xml:space="preserve" approved="no">
|
||||
<source>Database passphrase is different from saved in the keychain.</source>
|
||||
<target state="translated">عبارة المرور الخاصة بقاعدة البيانات مختلفة عن تلك المحفوظة في سلسلة المفاتيح.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Database passphrase is required to open chat." xml:space="preserve" approved="no">
|
||||
@@ -966,9 +972,11 @@
|
||||
<target state="translated">عبارة مرور قاعدة البيانات مطلوبة لفتح الدردشة.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Database will be encrypted and the passphrase stored in the keychain. " xml:space="preserve">
|
||||
<trans-unit id="Database will be encrypted and the passphrase stored in the keychain. " xml:space="preserve" approved="no">
|
||||
<source>Database will be encrypted and the passphrase stored in the keychain.
|
||||
</source>
|
||||
<target state="translated">سيتم تشفير قاعدة البيانات وتخزين عبارة المرور في سلسلة المفاتيح.
|
||||
</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Database will be encrypted. " xml:space="preserve" approved="no">
|
||||
@@ -978,8 +986,9 @@
|
||||
</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Database will be migrated when the app restarts" xml:space="preserve">
|
||||
<trans-unit id="Database will be migrated when the app restarts" xml:space="preserve" approved="no">
|
||||
<source>Database will be migrated when the app restarts</source>
|
||||
<target state="translated">سيتم نقل قاعدة البيانات عند إعادة تشغيل التطبيق</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Decentralized" xml:space="preserve" approved="no">
|
||||
@@ -1079,36 +1088,44 @@
|
||||
<target state="translated">حذف المجموعة؟</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete invitation" xml:space="preserve">
|
||||
<trans-unit id="Delete invitation" xml:space="preserve" approved="no">
|
||||
<source>Delete invitation</source>
|
||||
<target state="translated">حذف الدعوة</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete link" xml:space="preserve">
|
||||
<trans-unit id="Delete link" xml:space="preserve" approved="no">
|
||||
<source>Delete link</source>
|
||||
<target state="translated">حذف الرابط</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete link?" xml:space="preserve">
|
||||
<trans-unit id="Delete link?" xml:space="preserve" approved="no">
|
||||
<source>Delete link?</source>
|
||||
<target state="translated">حذف الرابط؟</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete message?" xml:space="preserve">
|
||||
<trans-unit id="Delete message?" xml:space="preserve" approved="no">
|
||||
<source>Delete message?</source>
|
||||
<target state="translated">حذف الرسالة؟</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete messages" xml:space="preserve">
|
||||
<trans-unit id="Delete messages" xml:space="preserve" approved="no">
|
||||
<source>Delete messages</source>
|
||||
<target state="translated">حذف الرسائل</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete messages after" xml:space="preserve">
|
||||
<trans-unit id="Delete messages after" xml:space="preserve" approved="no">
|
||||
<source>Delete messages after</source>
|
||||
<target state="translated">حذف الرسائل بعد</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete old database" xml:space="preserve">
|
||||
<trans-unit id="Delete old database" xml:space="preserve" approved="no">
|
||||
<source>Delete old database</source>
|
||||
<target state="translated">حذف قاعدة البيانات القديمة</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete old database?" xml:space="preserve">
|
||||
<trans-unit id="Delete old database?" xml:space="preserve" approved="no">
|
||||
<source>Delete old database?</source>
|
||||
<target state="translated">حذف قاعدة البيانات القديمة؟</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete pending connection" xml:space="preserve">
|
||||
@@ -1125,8 +1142,9 @@
|
||||
<target state="translated">حذف قائمة الانتظار</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete user profile?" xml:space="preserve">
|
||||
<trans-unit id="Delete user profile?" xml:space="preserve" approved="no">
|
||||
<source>Delete user profile?</source>
|
||||
<target state="translated">حذف ملف تعريف المستخدم؟</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Description" xml:space="preserve" approved="no">
|
||||
@@ -1134,8 +1152,9 @@
|
||||
<target state="translated">الوصف</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Develop" xml:space="preserve">
|
||||
<trans-unit id="Develop" xml:space="preserve" approved="no">
|
||||
<source>Develop</source>
|
||||
<target state="translated">يطور</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Developer tools" xml:space="preserve" approved="no">
|
||||
@@ -1168,28 +1187,34 @@
|
||||
<target state="translated">رسائل مباشرة</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Direct messages between members are prohibited." xml:space="preserve">
|
||||
<trans-unit id="Direct messages between members are prohibited." xml:space="preserve" approved="no">
|
||||
<source>Direct messages between members are prohibited.</source>
|
||||
<target state="translated">الرسائل المباشرة بين الأعضاء ممنوعة.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disable SimpleX Lock" xml:space="preserve">
|
||||
<trans-unit id="Disable SimpleX Lock" xml:space="preserve" approved="no">
|
||||
<source>Disable SimpleX Lock</source>
|
||||
<target state="translated">تعطيل قفل SimpleX</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disappearing messages" xml:space="preserve">
|
||||
<trans-unit id="Disappearing messages" xml:space="preserve" approved="no">
|
||||
<source>Disappearing messages</source>
|
||||
<target state="translated">الرسائل المختفية</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disappearing messages are prohibited in this chat." xml:space="preserve">
|
||||
<trans-unit id="Disappearing messages are prohibited in this chat." xml:space="preserve" approved="no">
|
||||
<source>Disappearing messages are prohibited in this chat.</source>
|
||||
<target state="translated">يُحظر اختفاء الرسائل في هذه الدردشة.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disappearing messages are prohibited." xml:space="preserve">
|
||||
<trans-unit id="Disappearing messages are prohibited." xml:space="preserve" approved="no">
|
||||
<source>Disappearing messages are prohibited.</source>
|
||||
<target state="translated">الرسائل المختفية ممنوعة.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disconnect" xml:space="preserve">
|
||||
<trans-unit id="Disconnect" xml:space="preserve" approved="no">
|
||||
<source>Disconnect</source>
|
||||
<target state="translated">قطع الاتصال</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Display name" xml:space="preserve">
|
||||
@@ -1200,12 +1225,14 @@
|
||||
<source>Display name:</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
|
||||
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve" approved="no">
|
||||
<source>Do NOT use SimpleX for emergency calls.</source>
|
||||
<target state="translated">لا تستخدم SimpleX لإجراء مكالمات الطوارئ.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Do it later" xml:space="preserve">
|
||||
<trans-unit id="Do it later" xml:space="preserve" approved="no">
|
||||
<source>Do it later</source>
|
||||
<target state="translated">افعل ذلك لاحقا</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve" approved="no">
|
||||
@@ -1258,76 +1285,93 @@
|
||||
<target state="translated">تفعيل الإشعارات دورية؟</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<trans-unit id="Encrypt" xml:space="preserve" approved="no">
|
||||
<source>Encrypt</source>
|
||||
<target state="translated">التشفير</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt database?" xml:space="preserve">
|
||||
<trans-unit id="Encrypt database?" xml:space="preserve" approved="no">
|
||||
<source>Encrypt database?</source>
|
||||
<target state="translated">تشفير قاعدة البيانات؟</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted database" xml:space="preserve">
|
||||
<trans-unit id="Encrypted database" xml:space="preserve" approved="no">
|
||||
<source>Encrypted database</source>
|
||||
<target state="translated">قاعدة بيانات مشفرة</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted message or another event" xml:space="preserve">
|
||||
<trans-unit id="Encrypted message or another event" xml:space="preserve" approved="no">
|
||||
<source>Encrypted message or another event</source>
|
||||
<target state="translated">رسالة مشفرة أو حدث آخر</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted message: database error" xml:space="preserve">
|
||||
<trans-unit id="Encrypted message: database error" xml:space="preserve" approved="no">
|
||||
<source>Encrypted message: database error</source>
|
||||
<target state="translated">رسالة مشفرة: خطأ في قاعدة البيانات</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted message: keychain error" xml:space="preserve">
|
||||
<trans-unit id="Encrypted message: keychain error" xml:space="preserve" approved="no">
|
||||
<source>Encrypted message: keychain error</source>
|
||||
<target state="translated">رسالة مشفرة: خطأ في سلسلة المفاتيح</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted message: no passphrase" xml:space="preserve">
|
||||
<trans-unit id="Encrypted message: no passphrase" xml:space="preserve" approved="no">
|
||||
<source>Encrypted message: no passphrase</source>
|
||||
<target state="translated">الرسالة المشفرة: لا توجد عبارة مرور</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted message: unexpected error" xml:space="preserve">
|
||||
<trans-unit id="Encrypted message: unexpected error" xml:space="preserve" approved="no">
|
||||
<source>Encrypted message: unexpected error</source>
|
||||
<target state="translated">رسالة مشفرة: خطأ غير متوقع</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter correct passphrase." xml:space="preserve">
|
||||
<trans-unit id="Enter correct passphrase." xml:space="preserve" approved="no">
|
||||
<source>Enter correct passphrase.</source>
|
||||
<target state="translated">أدخل عبارة المرور الصحيحة.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve" approved="no">
|
||||
<source>Enter passphrase…</source>
|
||||
<target state="translated">أدخل عبارة المرور…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter server manually" xml:space="preserve">
|
||||
<trans-unit id="Enter server manually" xml:space="preserve" approved="no">
|
||||
<source>Enter server manually</source>
|
||||
<target state="translated">أدخل الخادم يدوياً</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error" xml:space="preserve">
|
||||
<trans-unit id="Error" xml:space="preserve" approved="no">
|
||||
<source>Error</source>
|
||||
<target state="translated">خطأ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error accepting contact request" xml:space="preserve">
|
||||
<trans-unit id="Error accepting contact request" xml:space="preserve" approved="no">
|
||||
<source>Error accepting contact request</source>
|
||||
<target state="translated">خطأ في قبول طلب الاتصال</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error accessing database file" xml:space="preserve">
|
||||
<source>Error accessing database file</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error adding member(s)" xml:space="preserve">
|
||||
<trans-unit id="Error adding member(s)" xml:space="preserve" approved="no">
|
||||
<source>Error adding member(s)</source>
|
||||
<target state="translated">خطأ في إضافة عضو (أعضاء)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<trans-unit id="Error changing address" xml:space="preserve" approved="no">
|
||||
<source>Error changing address</source>
|
||||
<target state="translated">خطأ في تغيير العنوان</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing role" xml:space="preserve">
|
||||
<trans-unit id="Error changing role" xml:space="preserve" approved="no">
|
||||
<source>Error changing role</source>
|
||||
<target state="translated">خطأ في تغيير الدور المتغير</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing setting" xml:space="preserve">
|
||||
<trans-unit id="Error changing setting" xml:space="preserve" approved="no">
|
||||
<source>Error changing setting</source>
|
||||
<target state="translated">خطأ في تغيير الإعدادات</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error creating address" xml:space="preserve">
|
||||
@@ -5477,6 +5521,242 @@ This is your own one-time link!</source>
|
||||
<source>Conditions will be automatically accepted for enabled operators on: %@.</source>
|
||||
<target state="translated">سيتم قبول الشروط تلقائيًا للمشغلين الممكّنين على: %@.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Create new profile in [desktop app](https://simplex.chat/downloads/). 💻" xml:space="preserve" approved="no">
|
||||
<source>Create new profile in [desktop app](https://simplex.chat/downloads/). 💻</source>
|
||||
<target state="translated">أنشئ ملفًا شخصيًا جديدًا في [تطبيق سطح المكتب](https://simplex.chat/downloads/). 💻</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error adding server" xml:space="preserve" approved="no">
|
||||
<source>Error adding server</source>
|
||||
<target state="translated">خطأ في إضافة الخادم</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Created at: %@" xml:space="preserve" approved="no">
|
||||
<source>Created at: %@</source>
|
||||
<target state="translated">تم الإنشاء في: %@</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete %lld messages of members?" xml:space="preserve" approved="no">
|
||||
<source>Delete %lld messages of members?</source>
|
||||
<target state="translated">حذف %lld الرسائل القديمة للأعضاء؟</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disappearing message" xml:space="preserve" approved="no">
|
||||
<source>Disappearing message</source>
|
||||
<target state="translated">رسالة اختفاء</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled" xml:space="preserve" approved="no">
|
||||
<source>Enabled</source>
|
||||
<target state="translated">ممكّنة</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted message: database migration error" xml:space="preserve" approved="no">
|
||||
<source>Encrypted message: database migration error</source>
|
||||
<target state="translated">رسالة مشفرة: خطأ في ترحيل قاعدة البيانات</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete list?" xml:space="preserve" approved="no">
|
||||
<source>Delete list?</source>
|
||||
<target state="translated">Delete list?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delivered even when Apple drops them." xml:space="preserve" approved="no">
|
||||
<source>Delivered even when Apple drops them.</source>
|
||||
<target state="translated">يتم تسليمها حتى عندما تسقطها شركة Apple.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Destination server address of %@ is incompatible with forwarding server %@ settings." xml:space="preserve" approved="no">
|
||||
<source>Destination server address of %@ is incompatible with forwarding server %@ settings.</source>
|
||||
<target state="translated">عنوان خادم الوجهة %@ غير متوافق مع إعدادات خادم التوجيه %@.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Destination server version of %@ is incompatible with forwarding server %@." xml:space="preserve" approved="no">
|
||||
<source>Destination server version of %@ is incompatible with forwarding server %@.</source>
|
||||
<target state="translated">إصدار خادم الوجهة لـ %@ غير متوافق مع خادم التوجيه %@.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Don't create address" xml:space="preserve" approved="no">
|
||||
<source>Don't create address</source>
|
||||
<target state="translated">لا تنشئ عنوان</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Done" xml:space="preserve" approved="no">
|
||||
<source>Done</source>
|
||||
<target state="translated">تم</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duration" xml:space="preserve" approved="no">
|
||||
<source>Duration</source>
|
||||
<target state="translated">المدة</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt local files" xml:space="preserve" approved="no">
|
||||
<source>Encrypt local files</source>
|
||||
<target state="translated">تشفير الملفات المحلية</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encryption renegotiation in progress." xml:space="preserve" approved="no">
|
||||
<source>Encryption renegotiation in progress.</source>
|
||||
<target state="translated">إعادة التفاوض على التشفير قيد التنفيذ.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter Passcode" xml:space="preserve" approved="no">
|
||||
<source>Enter Passcode</source>
|
||||
<target state="translated">أدخل رمز المرور</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve" approved="no">
|
||||
<source>Enter passphrase</source>
|
||||
<target state="translated">قم بأدخل عبارة المرور</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter welcome message…" xml:space="preserve" approved="no">
|
||||
<source>Enter welcome message…</source>
|
||||
<target state="translated">أدخل رسالة ترحيب…</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter your name…" xml:space="preserve" approved="no">
|
||||
<source>Enter your name…</source>
|
||||
<target state="translated">أدخل اسمك…</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing to incognito!" xml:space="preserve" approved="no">
|
||||
<source>Error changing to incognito!</source>
|
||||
<target state="translated">خطأ في التغيير إلى التصفح المتخفي!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete %lld messages?" xml:space="preserve" approved="no">
|
||||
<source>Delete %lld messages?</source>
|
||||
<target state="translated">حذف %lld رسائل؟</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error aborting address change" xml:space="preserve" approved="no">
|
||||
<source>Error aborting address change</source>
|
||||
<target state="translated">خطأ في إجهاض تغيير العنوان</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disappears at" xml:space="preserve" approved="no">
|
||||
<source>Disappears at</source>
|
||||
<target state="translated">يختفي عند</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Do not use credentials with proxy." xml:space="preserve" approved="no">
|
||||
<source>Do not use credentials with proxy.</source>
|
||||
<target state="translated">لا تستخدم بيانات الاعتماد مع البروكسي.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error accepting conditions" xml:space="preserve" approved="no">
|
||||
<source>Error accepting conditions</source>
|
||||
<target state="translated">خطأ في قبول الشروط</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter password above to show!" xml:space="preserve" approved="no">
|
||||
<source>Enter password above to show!</source>
|
||||
<target state="translated">أدخل كلمة المرور أعلاه للعرض!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing connection profile" xml:space="preserve" approved="no">
|
||||
<source>Error changing connection profile</source>
|
||||
<target state="translated">خطأ في تغيير ملف تعريف الاتصال</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve" approved="no">
|
||||
<source>Desktop app version %@ is not compatible with this app.</source>
|
||||
<target state="translated">إصدار تطبيق سطح المكتب %@ غير متوافق مع هذا التطبيق.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt stored files & media" xml:space="preserve" approved="no">
|
||||
<source>Encrypt stored files & media</source>
|
||||
<target state="translated">تشفير الملفات والوسائط المخزنة</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter this device name…" xml:space="preserve" approved="no">
|
||||
<source>Enter this device name…</source>
|
||||
<target state="translated">أدخل اسم الجهاز…</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter welcome message… (optional)" xml:space="preserve" approved="no">
|
||||
<source>Enter welcome message… (optional)</source>
|
||||
<target state="translated">أدخل رسالة ترحيب... (اختياري)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Correct name to %@?" xml:space="preserve" approved="no">
|
||||
<source>Correct name to %@?</source>
|
||||
<target state="translated">الاسم الصحيح ل %@؟</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete member message?" xml:space="preserve" approved="no">
|
||||
<source>Delete member message?</source>
|
||||
<target state="translated">حذف رسالة العضو؟</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disable automatic message deletion?" xml:space="preserve" approved="no">
|
||||
<source>Disable automatic message deletion?</source>
|
||||
<target state="translated">تعطيل حذف الرسائل التلقائي؟</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disable delete messages" xml:space="preserve" approved="no">
|
||||
<source>Disable delete messages</source>
|
||||
<target state="translated">تعطيل حذف الرسائل</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disable for all" xml:space="preserve" approved="no">
|
||||
<source>Disable for all</source>
|
||||
<target state="translated">تعطيل للجميع</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disabled" xml:space="preserve" approved="no">
|
||||
<source>Disabled</source>
|
||||
<target state="translated">عاجز</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Documents:" xml:space="preserve" approved="no">
|
||||
<source>Documents:</source>
|
||||
<target state="translated">المستندات:</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="By using SimpleX Chat you agree to: - send only legal content in public groups. - respect other users – no spam." xml:space="preserve" approved="no">
|
||||
<source>By using SimpleX Chat you agree to:
|
||||
- send only legal content in public groups.
|
||||
- respect other users – no spam.</source>
|
||||
<target state="translated">باستخدامك SimpleX Chat، فإنك توافق على:
|
||||
- إرسال محتوى قانوني فقط في المجموعات العامة.
|
||||
- احترام المستخدمين الآخرين - ممنوع إرسال رسائل مزعجة.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Configure server operators" xml:space="preserve" approved="no">
|
||||
<source>Configure server operators</source>
|
||||
<target state="translated">تكوين مشغلي الخادم</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable Flux in Network & servers settings for better metadata privacy." xml:space="preserve" approved="no">
|
||||
<source>Enable Flux in Network & servers settings for better metadata privacy.</source>
|
||||
<target state="translated">تمكين التدفق في إعدادات الشبكة والخوادم لتحسين خصوصية البيانات الوصفية.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Discover and join groups" xml:space="preserve" approved="no">
|
||||
<source>Discover and join groups</source>
|
||||
<target state="translated">اكتشف المجموعات وانضم إليها</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Discover via local network" xml:space="preserve" approved="no">
|
||||
<source>Discover via local network</source>
|
||||
<target state="translated">اكتشف عبر الشبكة المحلية</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve" approved="no">
|
||||
<source>Enabled for</source>
|
||||
<target state="translated">ممكّن ل</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypted message: app is stopped" xml:space="preserve" approved="no">
|
||||
<source>Encrypted message: app is stopped</source>
|
||||
<target state="translated">رسالة مشفرة: تم إيقاف التطبيق</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter group name…" xml:space="preserve" approved="no">
|
||||
<source>Enter group name…</source>
|
||||
<target state="translated">أدخل اسم المجموعة…</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Do NOT use private routing." xml:space="preserve" approved="no">
|
||||
<source>Do NOT use private routing.</source>
|
||||
<target state="translated">لا تستخدم التوجيه الخاص.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encryption re-negotiation error" xml:space="preserve" approved="no">
|
||||
<source>Encryption re-negotiation error</source>
|
||||
<target state="translated">خطأ في إعادة تفاوض التشفير</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connection with desktop stopped" xml:space="preserve" approved="no">
|
||||
<source>Connection with desktop stopped</source>
|
||||
<target state="translated">تم إيقاف الاتصال بسطح المكتب</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Destination server error: %@" xml:space="preserve" approved="no">
|
||||
<source>Destination server error: %@</source>
|
||||
<target state="translated">خطأ خادم الوجهة: %@</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve" approved="no">
|
||||
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
|
||||
<target state="translated">لا ترسل الرسائل بشكل مباشر، حتى لو كان خادمك أو خادم الوجهة لا يدعم التوجيه الخاص.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Direct messages between members are prohibited in this chat." xml:space="preserve" approved="no">
|
||||
<source>Direct messages between members are prohibited in this chat.</source>
|
||||
<target state="translated">يُحظر إرسال الرسائل المباشرة بين الأعضاء في هذه الدردشة.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disconnect desktop?" xml:space="preserve" approved="no">
|
||||
<source>Disconnect desktop?</source>
|
||||
<target state="translated">فصل سطح المكتب؟</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disable (keep overrides)" xml:space="preserve" approved="no">
|
||||
<source>Disable (keep overrides)</source>
|
||||
<target state="translated">تعطيل (الاحتفاظ بالتجاوزات)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Disappears at: %@" xml:space="preserve" approved="no">
|
||||
<source>Disappears at: %@</source>
|
||||
<target state="translated">يختفي عند: %@</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Do not send history to new members." xml:space="preserve" approved="no">
|
||||
<source>Do not send history to new members.</source>
|
||||
<target state="translated">لا ترسل التاريخ إلى الأعضاء الجدد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve" approved="no">
|
||||
<source>Encryption re-negotiation failed.</source>
|
||||
<target state="translated">فشل إعادة التفاوض على التشفير.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="ar" datatype="plaintext">
|
||||
|
||||
@@ -778,6 +778,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Всички ваши контакти ще останат свързани.</target>
|
||||
@@ -7832,6 +7836,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Използвай чата</target>
|
||||
@@ -9661,6 +9669,10 @@ last received msg: %2$@</source>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -9673,10 +9685,6 @@ last received msg: %2$@</source>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="bg" datatype="plaintext">
|
||||
|
||||
@@ -145,18 +145,22 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve">
|
||||
<source>%d file(s) are still being downloaded.</source>
|
||||
<target>%d soubor(y) stále stahován(y).</target>
|
||||
<note>forward confirmation reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d file(s) failed to download." xml:space="preserve">
|
||||
<source>%d file(s) failed to download.</source>
|
||||
<target>%d soubor(y) se nepodařilo stáhnout.</target>
|
||||
<note>forward confirmation reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d file(s) were deleted." xml:space="preserve">
|
||||
<source>%d file(s) were deleted.</source>
|
||||
<target>%d soubor(y) smazán(y).</target>
|
||||
<note>forward confirmation reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve">
|
||||
<source>%d file(s) were not downloaded.</source>
|
||||
<target>%d soubor(y) nestažen(y).</target>
|
||||
<note>forward confirmation reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d hours" xml:space="preserve">
|
||||
@@ -743,6 +747,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Všechny vaše kontakty zůstanou připojeny.</target>
|
||||
@@ -7560,6 +7568,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Použijte chat</target>
|
||||
@@ -9323,6 +9335,10 @@ last received msg: %2$@</source>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -9335,10 +9351,6 @@ last received msg: %2$@</source>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="cs" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Alle Meldungen werden für Sie archiviert.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Alle Ihre Kontakte bleiben verbunden.</target>
|
||||
@@ -7201,6 +7205,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Short link" xml:space="preserve">
|
||||
<source>Short link</source>
|
||||
<target>Verkürzter Link</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
@@ -7305,6 +7310,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX channel link" xml:space="preserve">
|
||||
<source>SimpleX channel link</source>
|
||||
<target>SimpleX-Kanal-Link</target>
|
||||
<note>simplex link type</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX contact address" xml:space="preserve">
|
||||
@@ -7899,6 +7905,7 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
|
||||
</trans-unit>
|
||||
<trans-unit id="This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." xml:space="preserve">
|
||||
<source>This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link.</source>
|
||||
<target>Für diesen Link wird eine neuere App-Version benötigt. Bitte aktualisieren Sie die App oder bitten Sie Ihren Kontakt einen kompatiblen Link zu senden.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This link was used with another mobile device, please create a new link on the desktop." xml:space="preserve">
|
||||
@@ -8202,6 +8209,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
|
||||
</trans-unit>
|
||||
<trans-unit id="Unsupported connection link" xml:space="preserve">
|
||||
<source>Unsupported connection link</source>
|
||||
<target>Verbindungs-Link wird nicht unterstützt</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Up to 100 last messages are sent to new members." xml:space="preserve">
|
||||
@@ -8299,6 +8307,10 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
|
||||
<target>Solange kein Port konfiguriert ist, wird TCP-Port %@ genutzt.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Verwenden Sie Chat</target>
|
||||
@@ -8366,6 +8378,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
|
||||
</trans-unit>
|
||||
<trans-unit id="Use short links (BETA)" xml:space="preserve">
|
||||
<source>Use short links (BETA)</source>
|
||||
<target>Kurze Links verwenden (BETA)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
@@ -10191,6 +10204,10 @@ Zuletzt empfangene Nachricht: %2$@</target>
|
||||
<target>%d neue Ereignisse</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>Von: %@</target>
|
||||
@@ -10206,11 +10223,6 @@ Zuletzt empfangene Nachricht: %2$@</target>
|
||||
<target>Neue Nachrichten</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Neue Nachrichten in %d Chats</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="de" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,11 @@ swipe action</note>
|
||||
<target>All reports will be archived for you.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<target>All servers</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>All your contacts will remain connected.</target>
|
||||
@@ -8303,6 +8308,11 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Use TCP port %@ when no port is specified.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<target>Use TCP port 443 for preset servers only.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Use chat</target>
|
||||
@@ -10196,6 +10206,11 @@ last received msg: %2$@</target>
|
||||
<target>%d new events</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<target>From %d chat(s)</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>From: %@</target>
|
||||
@@ -10211,11 +10226,6 @@ last received msg: %2$@</target>
|
||||
<target>New messages</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>New messages in %d chats</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="en" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Todos los informes serán archivados para ti.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Todos tus contactos permanecerán conectados.</target>
|
||||
@@ -7201,6 +7205,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Short link" xml:space="preserve">
|
||||
<source>Short link</source>
|
||||
<target>Enlace corto</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
@@ -7305,6 +7310,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX channel link" xml:space="preserve">
|
||||
<source>SimpleX channel link</source>
|
||||
<target>Enlace de canal SimpleX</target>
|
||||
<note>simplex link type</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX contact address" xml:space="preserve">
|
||||
@@ -7899,6 +7905,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." xml:space="preserve">
|
||||
<source>This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link.</source>
|
||||
<target>Este enlace requiere una versión más reciente de la aplicación. Por favor, actualiza la aplicación o pide a tu contacto un enlace compatible.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This link was used with another mobile device, please create a new link on the desktop." xml:space="preserve">
|
||||
@@ -8202,6 +8209,7 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión
|
||||
</trans-unit>
|
||||
<trans-unit id="Unsupported connection link" xml:space="preserve">
|
||||
<source>Unsupported connection link</source>
|
||||
<target>Enlace de conexión no compatible</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Up to 100 last messages are sent to new members." xml:space="preserve">
|
||||
@@ -8299,6 +8307,10 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión
|
||||
<target>Se usa el puerto TCP %@ cuando no se ha especificado otro.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Usar Chat</target>
|
||||
@@ -8366,6 +8378,7 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión
|
||||
</trans-unit>
|
||||
<trans-unit id="Use short links (BETA)" xml:space="preserve">
|
||||
<source>Use short links (BETA)</source>
|
||||
<target>Usar enlaces cortos (BETA)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
@@ -10191,6 +10204,10 @@ last received msg: %2$@</source>
|
||||
<target>%d evento(s) nuevo(s)</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>De: %@</target>
|
||||
@@ -10206,11 +10223,6 @@ last received msg: %2$@</source>
|
||||
<target>Mensajes nuevos</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Mensajes nuevos en %d chat(s)</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="es" datatype="plaintext">
|
||||
|
||||
@@ -730,6 +730,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Kaikki kontaktisi pysyvät yhteydessä.</target>
|
||||
@@ -7537,6 +7541,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Käytä chattia</target>
|
||||
@@ -9298,6 +9306,10 @@ last received msg: %2$@</source>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -9310,10 +9322,6 @@ last received msg: %2$@</source>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="fi" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Tous les rapports seront archivés pour vous.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Tous vos contacts resteront connectés.</target>
|
||||
@@ -8227,6 +8231,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Utiliser le chat</target>
|
||||
@@ -10111,6 +10119,10 @@ dernier message reçu : %2$@</target>
|
||||
<target>%d nouveaux événements</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>De : %@</target>
|
||||
@@ -10126,11 +10138,6 @@ dernier message reçu : %2$@</target>
|
||||
<target>Nouveaux messages</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Nouveaux messages dans %d chats</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="fr" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Az összes jelentés archiválva lesz az Ön számára.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Az összes partnerével kapcsolatban marad.</target>
|
||||
@@ -1093,7 +1097,7 @@ swipe action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>Csatolás</target>
|
||||
<target>Mellékelés</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Audio & video calls" xml:space="preserve">
|
||||
@@ -4055,7 +4059,7 @@ Hiba: %2$@</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hide:" xml:space="preserve">
|
||||
<source>Hide:</source>
|
||||
<target>Elrejtés:</target>
|
||||
<target>Elrejtve:</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="History" xml:space="preserve">
|
||||
@@ -5906,7 +5910,7 @@ Hiba: %@</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Privacy redefined" xml:space="preserve">
|
||||
<source>Privacy redefined</source>
|
||||
<target>Adatvédelem újraértelmezve</target>
|
||||
<target>Újraértelmezett adatvédelem</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Private chats, groups and your contacts are not accessible to server operators." xml:space="preserve">
|
||||
@@ -7201,6 +7205,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Short link" xml:space="preserve">
|
||||
<source>Short link</source>
|
||||
<target>Rövid hivatkozás</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
@@ -7245,7 +7250,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show:" xml:space="preserve">
|
||||
<source>Show:</source>
|
||||
<target>Megjelenítés:</target>
|
||||
<target>Megjelenítve:</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX" xml:space="preserve">
|
||||
@@ -7305,6 +7310,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX channel link" xml:space="preserve">
|
||||
<source>SimpleX channel link</source>
|
||||
<target>SimpleX-csatornahivatkozás</target>
|
||||
<note>simplex link type</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX contact address" xml:space="preserve">
|
||||
@@ -7899,6 +7905,7 @@ Ez valamilyen hiba vagy sérült kapcsolat esetén fordulhat elő.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." xml:space="preserve">
|
||||
<source>This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link.</source>
|
||||
<target>Ez a hivatkozás újabb alkalmazásverziót igényel. Frissítse az alkalmazást vagy kérjen egy kompatibilis hivatkozást a partnerétől.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This link was used with another mobile device, please create a new link on the desktop." xml:space="preserve">
|
||||
@@ -8202,6 +8209,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso
|
||||
</trans-unit>
|
||||
<trans-unit id="Unsupported connection link" xml:space="preserve">
|
||||
<source>Unsupported connection link</source>
|
||||
<target>Nem támogatott kapcsolattartási hivatkozás</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Up to 100 last messages are sent to new members." xml:space="preserve">
|
||||
@@ -8299,6 +8307,10 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso
|
||||
<target>A következő TCP-port használata, amikor nincs port megadva: %@.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>SimpleX Chat használata</target>
|
||||
@@ -8366,6 +8378,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso
|
||||
</trans-unit>
|
||||
<trans-unit id="Use short links (BETA)" xml:space="preserve">
|
||||
<source>Use short links (BETA)</source>
|
||||
<target>Rövid hivatkozások használata (béta)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
@@ -10191,6 +10204,10 @@ utoljára fogadott üzenet: %2$@</target>
|
||||
<target>%d új esemény</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>Tőle: %@</target>
|
||||
@@ -10206,11 +10223,6 @@ utoljára fogadott üzenet: %2$@</target>
|
||||
<target>Új üzenetek</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Új üzenetek %d csevegésben</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="hu" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Tutte le segnalazioni verranno archiviate per te.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Tutti i tuoi contatti resteranno connessi.</target>
|
||||
@@ -7201,6 +7205,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Short link" xml:space="preserve">
|
||||
<source>Short link</source>
|
||||
<target>Link breve</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
@@ -7305,6 +7310,7 @@ chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX channel link" xml:space="preserve">
|
||||
<source>SimpleX channel link</source>
|
||||
<target>Link del canale SimpleX</target>
|
||||
<note>simplex link type</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX contact address" xml:space="preserve">
|
||||
@@ -7899,6 +7905,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
|
||||
</trans-unit>
|
||||
<trans-unit id="This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." xml:space="preserve">
|
||||
<source>This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link.</source>
|
||||
<target>Questo link richiede una versione più recente dell'app. Aggiornala o chiedi al tuo contatto di inviare un link compatibile.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This link was used with another mobile device, please create a new link on the desktop." xml:space="preserve">
|
||||
@@ -8202,6 +8209,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
</trans-unit>
|
||||
<trans-unit id="Unsupported connection link" xml:space="preserve">
|
||||
<source>Unsupported connection link</source>
|
||||
<target>Link di connessione non supportato</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Up to 100 last messages are sent to new members." xml:space="preserve">
|
||||
@@ -8299,6 +8307,10 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>Usa la porta TCP %@ quando non è specificata alcuna porta.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Usa la chat</target>
|
||||
@@ -8366,6 +8378,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
</trans-unit>
|
||||
<trans-unit id="Use short links (BETA)" xml:space="preserve">
|
||||
<source>Use short links (BETA)</source>
|
||||
<target>Usa link brevi (BETA)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
@@ -10191,6 +10204,10 @@ ultimo msg ricevuto: %2$@</target>
|
||||
<target>%d nuovi eventi</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>Da: %@</target>
|
||||
@@ -10206,11 +10223,6 @@ ultimo msg ricevuto: %2$@</target>
|
||||
<target>Nuovi messaggi</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Nuovi messaggi in %d chat</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="it" datatype="plaintext">
|
||||
|
||||
@@ -768,6 +768,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>あなたの連絡先が繋がったまま継続します。</target>
|
||||
@@ -7607,6 +7611,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>チャット</target>
|
||||
@@ -9369,6 +9377,10 @@ last received msg: %2$@</source>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -9381,10 +9393,6 @@ last received msg: %2$@</source>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="ja" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Alle rapporten worden voor u gearchiveerd.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Al uw contacten blijven verbonden.</target>
|
||||
@@ -8299,6 +8303,10 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
|
||||
<target>Gebruik TCP-poort %@ als er geen poort is opgegeven.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Gebruik chat</target>
|
||||
@@ -10191,6 +10199,10 @@ laatst ontvangen bericht: %2$@</target>
|
||||
<target>‐%d nieuwe gebeurtenissen</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>Van: %@</target>
|
||||
@@ -10206,11 +10218,6 @@ laatst ontvangen bericht: %2$@</target>
|
||||
<target>Nieuwe berichten</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Nieuwe berichten in %d chats</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="nl" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Wszystkie raporty zostaną dla Ciebie zarchiwizowane.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Wszystkie Twoje kontakty pozostaną połączone.</target>
|
||||
@@ -8104,6 +8108,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Użyj czatu</target>
|
||||
@@ -9975,6 +9983,10 @@ ostatnia otrzymana wiadomość: %2$@</target>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -9987,11 +9999,6 @@ ostatnia otrzymana wiadomość: %2$@</target>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Nowe wiadomości w %d czatach</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="pl" datatype="plaintext">
|
||||
|
||||
@@ -796,6 +796,10 @@ swipe action</note>
|
||||
<target>Все сообщения о нарушениях будут заархивированы для вас.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Все контакты, которые соединились через этот адрес, сохранятся.</target>
|
||||
@@ -8249,6 +8253,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Использовать TCP-порт %@, когда порт не указан.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Использовать чат</target>
|
||||
@@ -10135,6 +10143,10 @@ last received msg: %2$@</source>
|
||||
<target>%d новых сообщений</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>От: %@</target>
|
||||
@@ -10150,11 +10162,6 @@ last received msg: %2$@</source>
|
||||
<target>Новые сообщения</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Новые сообщения в %d разговоре(ах)</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="ru" datatype="plaintext">
|
||||
|
||||
@@ -722,6 +722,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่.</target>
|
||||
@@ -7509,6 +7513,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>ใช้แชท</target>
|
||||
@@ -9265,6 +9273,10 @@ last received msg: %2$@</source>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -9277,10 +9289,6 @@ last received msg: %2$@</source>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="th" datatype="plaintext">
|
||||
|
||||
@@ -788,6 +788,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Konuştuğun kişilerin tümü bağlı kalacaktır.</target>
|
||||
@@ -8119,6 +8123,10 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Sohbeti kullan</target>
|
||||
@@ -9989,6 +9997,10 @@ son alınan msj: %2$@</target>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -10001,10 +10013,6 @@ son alınan msj: %2$@</target>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="tr" datatype="plaintext">
|
||||
|
||||
@@ -788,6 +788,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>Всі ваші контакти залишаться на зв'язку.</target>
|
||||
@@ -8168,6 +8172,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>Використовуйте чат</target>
|
||||
@@ -10052,6 +10060,10 @@ last received msg: %2$@</source>
|
||||
<target>%d нових подій</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<target>Від: %@</target>
|
||||
@@ -10067,11 +10079,6 @@ last received msg: %2$@</source>
|
||||
<target>Нові повідомлення</target>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<target>Нові повідомлення в чатах %d</target>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="uk" datatype="plaintext">
|
||||
|
||||
@@ -768,6 +768,10 @@ swipe action</note>
|
||||
<source>All reports will be archived for you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All servers" xml:space="preserve">
|
||||
<source>All servers</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target>所有联系人会保持连接。</target>
|
||||
@@ -8010,6 +8014,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<source>Use TCP port %@ when no port is specified.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use TCP port 443 for preset servers only." xml:space="preserve">
|
||||
<source>Use TCP port 443 for preset servers only.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use chat" xml:space="preserve">
|
||||
<source>Use chat</source>
|
||||
<target>使用聊天</target>
|
||||
@@ -9875,6 +9883,10 @@ last received msg: %2$@</source>
|
||||
<source>%d new events</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From %d chat(s)" xml:space="preserve">
|
||||
<source>From %d chat(s)</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="From: %@" xml:space="preserve">
|
||||
<source>From: %@</source>
|
||||
<note>notification body</note>
|
||||
@@ -9887,10 +9899,6 @@ last received msg: %2$@</source>
|
||||
<source>New messages</source>
|
||||
<note>notification</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="New messages in %d chats" xml:space="preserve">
|
||||
<source>New messages in %d chats</source>
|
||||
<note>notification body</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="SimpleX SE/en.lproj/InfoPlist.strings" source-language="en" target-language="zh-Hans" datatype="plaintext">
|
||||
|
||||
@@ -53,7 +53,7 @@ enum NSEChatResponse: Decodable, ChatAPIResult {
|
||||
case chatRunning
|
||||
case rcvFileAccepted(user: UserRef, chatItem: AChatItem)
|
||||
case ntfConns(ntfConns: [NtfConn])
|
||||
case connNtfMessages(receivedMsgs: [NtfMsgInfo?])
|
||||
case connNtfMessages(receivedMsgs: [RcvNtfMsgInfo])
|
||||
case ntfMessage(user: UserRef, connEntity: ConnectionEntity, ntfMessage: NtfMsgAckInfo)
|
||||
case cmdOk(user_: UserRef?)
|
||||
|
||||
|
||||
@@ -22,12 +22,6 @@ let nseSuspendSchedule: SuspendSchedule = (2, 4)
|
||||
|
||||
let fastNSESuspendSchedule: SuspendSchedule = (1, 1)
|
||||
|
||||
enum NSENotification {
|
||||
case nse(UNMutableNotificationContent)
|
||||
case callkit(RcvCallInvitation)
|
||||
case empty
|
||||
}
|
||||
|
||||
public enum NSENotificationData {
|
||||
case connectionEvent(_ user: User, _ connEntity: ConnectionEntity)
|
||||
case contactConnected(_ user: any UserLike, _ contact: Contact)
|
||||
@@ -37,6 +31,7 @@ public enum NSENotificationData {
|
||||
case msgInfo(NtfMsgAckInfo)
|
||||
case noNtf
|
||||
|
||||
@inline(__always)
|
||||
var callInvitation: RcvCallInvitation? {
|
||||
switch self {
|
||||
case let .callInvitation(invitation): invitation
|
||||
@@ -56,8 +51,9 @@ public enum NSENotificationData {
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
var notificationEvent: NSENotificationData? {
|
||||
return switch self {
|
||||
switch self {
|
||||
case .connectionEvent: self
|
||||
case .contactConnected: self
|
||||
case .contactRequest: self
|
||||
@@ -68,9 +64,10 @@ public enum NSENotificationData {
|
||||
}
|
||||
}
|
||||
|
||||
var newMsgData: (any UserLike, ChatInfo)? {
|
||||
return switch self {
|
||||
case let .messageReceived(user, cInfo, _): (user, cInfo)
|
||||
@inline(__always)
|
||||
var newMsgNtf: NSENotificationData? {
|
||||
switch self {
|
||||
case .messageReceived: self
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
@@ -81,20 +78,25 @@ public enum NSENotificationData {
|
||||
// or when background notification is received.
|
||||
class NSEThreads {
|
||||
static let shared = NSEThreads()
|
||||
static let queue = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.notification-threads.lock")
|
||||
private let queue = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.notification-threads.lock")
|
||||
private var allThreads: Set<UUID> = []
|
||||
var activeThreads: [(UUID, NotificationService)] = []
|
||||
var droppedNotifications: [(ChatId, NSENotificationData)] = []
|
||||
private var activeThreads: [(threadId: UUID, nse: NotificationService)] = []
|
||||
private var droppedNotifications: [(entityId: ChatId, ntf: NSENotificationData)] = []
|
||||
|
||||
@inline(__always)
|
||||
private init() {} // only shared instance can be used
|
||||
|
||||
@inline(__always)
|
||||
func newThread() -> UUID {
|
||||
NSEThreads.queue.sync {
|
||||
queue.sync {
|
||||
let (_, t) = allThreads.insert(UUID())
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func startThread(_ t: UUID, _ service: NotificationService) {
|
||||
NSEThreads.queue.sync {
|
||||
queue.sync {
|
||||
if allThreads.contains(t) {
|
||||
activeThreads.append((t, service))
|
||||
} else {
|
||||
@@ -103,24 +105,111 @@ class NSEThreads {
|
||||
}
|
||||
}
|
||||
|
||||
// atomically:
|
||||
// - checks that passed NSE instance can start processing passed notification entity,
|
||||
// - adds it to the passed NSE instance,
|
||||
// - marks as started, if no other NSE instance is processing it.
|
||||
// Making all these steps atomic prevents a race condition between threads when both will be added and none will be started
|
||||
@inline(__always)
|
||||
func startEntity(_ nse: NotificationService, _ ntfEntity: NotificationEntity) -> Bool {
|
||||
queue.sync {
|
||||
// checking that none of activeThreads with another NSE instance processes the same entity and is not ready
|
||||
let canStart = !activeThreads.contains(where: { (tId, otherNSE) in
|
||||
tId != nse.threadId
|
||||
&& otherNSE.notificationEntities.contains(where: { (id, otherEntity) in
|
||||
id == ntfEntity.entityId
|
||||
&& otherEntity.expectedMsg != nil
|
||||
})
|
||||
})
|
||||
// atomically add entity to passed NSE instance
|
||||
let id = ntfEntity.entityId
|
||||
nse.notificationEntities[id] = ntfEntity
|
||||
if canStart {
|
||||
// and set as started, so it cannot be chosen to start by another NSE entity in nextThread
|
||||
nse.notificationEntities[id]?.startedProcessingNewMsgs = true
|
||||
}
|
||||
return canStart
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func addDroppedNtf(_ id: ChatId, _ ntf: NSENotificationData) {
|
||||
queue.sync { droppedNotifications.append((id, ntf)) }
|
||||
}
|
||||
|
||||
// atomically remove and return first dropped notification for the passed entity
|
||||
@inline(__always)
|
||||
func takeDroppedNtf(_ ntfEntity: NotificationEntity) -> (entityId: ChatId, ntf: NSENotificationData)? {
|
||||
queue.sync {
|
||||
if droppedNotifications.isEmpty {
|
||||
nil
|
||||
} else if let i = droppedNotifications.firstIndex(where: { (id, _) in id == ntfEntity.entityId }) {
|
||||
droppedNotifications.remove(at: i)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// passes notification for processing to NSE instance chosen by rcvEntityThread
|
||||
@inline(__always)
|
||||
func processNotification(_ id: ChatId, _ ntf: NSENotificationData) async -> Void {
|
||||
if let (_, nse) = rcvEntityThread(id),
|
||||
nse.expectedMessages[id]?.shouldProcessNtf ?? false {
|
||||
nse.processReceivedNtf(id, ntf, signalReady: true)
|
||||
if let (nse, ntfEntity, expectedMsg) = rcvEntityThread(id, ntf) {
|
||||
logger.debug("NotificationService processNotification \(id): found nse thread expecting message")
|
||||
if nse.processReceivedNtf(ntfEntity, expectedMsg, ntf) {
|
||||
nse.finalizeEntity(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func rcvEntityThread(_ id: ChatId) -> (UUID, NotificationService)? {
|
||||
NSEThreads.queue.sync {
|
||||
// atomically:
|
||||
// - chooses active NSE instance that is ready to process notifications and expects message for passed entity ID
|
||||
// - returns all dependencies for processing (notification entity and expected message)
|
||||
// - adds notification to droppedNotifications if no ready NSE instance is found for the entity
|
||||
@inline(__always)
|
||||
private func rcvEntityThread(_ id: ChatId, _ ntf: NSENotificationData) -> (NotificationService, NotificationEntity, NtfMsgInfo)? {
|
||||
queue.sync {
|
||||
// this selects the earliest thread that:
|
||||
// 1) has this connection in nse.expectedMessages
|
||||
// 2) has not completed processing messages for this connection (not ready)
|
||||
activeThreads.first(where: { (_, nse) in nse.expectedMessages[id]?.ready == false })
|
||||
// 1) has this connection entity in nse.notificationEntitites
|
||||
// 2) has not completed processing messages for this connection entity (not ready)
|
||||
let r = activeThreads.lazy.compactMap({ (_, nse) in
|
||||
let ntfEntity = nse.notificationEntities[id]
|
||||
return if let ntfEntity, let expectedMsg = ntfEntity.expectedMsg, ntfEntity.shouldProcessNtf {
|
||||
(nse, ntfEntity, expectedMsg)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
}).first
|
||||
if r == nil { droppedNotifications.append((id, ntf)) }
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
// Atomically mark entity in the passed NSE instance as not expecting messages,
|
||||
// and signal the next NSE instance with this entity to start its processing.
|
||||
@inline(__always)
|
||||
func signalNextThread(_ nse: NotificationService, _ id: ChatId) {
|
||||
queue.sync {
|
||||
nse.notificationEntities[id]?.expectedMsg = nil
|
||||
nse.notificationEntities[id]?.shouldProcessNtf = false
|
||||
let next = activeThreads.first(where: { (_, nseNext) in
|
||||
if let ntfEntity = nseNext.notificationEntities[id] {
|
||||
ntfEntity.expectedMsg != nil && !ntfEntity.startedProcessingNewMsgs
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
if let (tNext, nseNext) = next {
|
||||
if let t = nse.threadId { logger.debug("NotificationService thread \(t): signalNextThread: signal next thread \(tNext) for entity \(id)") }
|
||||
nseNext.notificationEntities[id]?.startedProcessingNewMsgs = true
|
||||
nseNext.notificationEntities[id]?.semaphore.signal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func endThread(_ t: UUID) -> Bool {
|
||||
NSEThreads.queue.sync {
|
||||
queue.sync {
|
||||
let tActive: UUID? = if let index = activeThreads.firstIndex(where: { $0.0 == t }) {
|
||||
activeThreads.remove(at: index).0
|
||||
} else {
|
||||
@@ -137,24 +226,49 @@ class NSEThreads {
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
var noThreads: Bool {
|
||||
allThreads.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
struct ExpectedMessage {
|
||||
// NotificationEntity is a processing state for notifications from a single connection entity (message queue).
|
||||
// Each NSE instance within NSE process can have more than one NotificationEntity.
|
||||
// NotificationEntities of an NSE instance are processed concurrently, as messages arrive in any order.
|
||||
// NotificationEntities for the same connection across multiple NSE instances (NSEThreads) are processed sequentially, so that the earliest NSE instance receives the earliest messages.
|
||||
// The reason for this complexity is to process all required messages within allotted 30 seconds,
|
||||
// accounting for the possibility that multiple notifications may be delivered concurrently.
|
||||
struct NotificationEntity {
|
||||
var ntfConn: NtfConn
|
||||
var expectedMsgId: String?
|
||||
var allowedGetNextAttempts: Int
|
||||
var msgBestAttemptNtf: NSENotificationData?
|
||||
var ready: Bool
|
||||
var shouldProcessNtf: Bool
|
||||
var startedProcessingNewMsgs: Bool
|
||||
var semaphore: DispatchSemaphore
|
||||
|
||||
var entityId: ChatId
|
||||
|
||||
// expectedMsg == nil means that entity already has the best attempt to deliver, and no more messages are expected.
|
||||
// It happens when:
|
||||
// - the user is muted (set to nil in mkNotificationEntity)
|
||||
// - apiGetNtfConns returns that there are no new messages (msgId in notification matches previously received),
|
||||
// - messaging server fails to respond or replies that there are no messages (apiGetConnNtfMessages / getConnNtfMessage),
|
||||
// - the message is received with the correct ID or timestamp (set to nil in signalNextThread).
|
||||
var expectedMsg: NtfMsgInfo?
|
||||
var allowedGetNextAttempts: Int = 3
|
||||
var msgBestAttemptNtf: NSENotificationData
|
||||
|
||||
// startedProcessingNewMsgs determines that the entity stared processing events once it processed dropped notifications.
|
||||
// It remains true when shouldProcessNtf is set to false, to prevent NSE from being chosen as the next for the entity.
|
||||
// It is atomically set to true by startThead or by nextThread
|
||||
var startedProcessingNewMsgs: Bool = false
|
||||
|
||||
// shouldProcessNtf determines that NSE should process events for this entity,
|
||||
// it is atomically set:
|
||||
// - to true in processDroppedNotifications in case dropped notification is not chosen for delivery, and more messages are needed.
|
||||
// - to false in nextThread
|
||||
var shouldProcessNtf: Bool = false
|
||||
|
||||
// this semaphone is used to wait for another NSE instance processing events for the same entity
|
||||
var semaphore: DispatchSemaphore = DispatchSemaphore(value: 0)
|
||||
|
||||
var connMsgReq: ConnMsgReq? {
|
||||
if let expectedMsg_ = ntfConn.expectedMsg_ {
|
||||
ConnMsgReq(msgConnId: ntfConn.agentConnId, msgDbQueueId: ntfConn.agentDbQueueId, msgTs: expectedMsg_.msgTs)
|
||||
if let expectedMsg {
|
||||
ConnMsgReq(msgConnId: ntfConn.agentConnId, msgDbQueueId: ntfConn.agentDbQueueId, msgTs: expectedMsg.msgTs)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
@@ -168,12 +282,12 @@ struct ExpectedMessage {
|
||||
class NotificationService: UNNotificationServiceExtension {
|
||||
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||
// served as notification if no message attempts (msgBestAttemptNtf) could be produced
|
||||
var serviceBestAttemptNtf: NSENotification?
|
||||
var serviceBestAttemptNtf: UNMutableNotificationContent?
|
||||
var badgeCount: Int = 0
|
||||
// thread is added to allThreads here - if thread did not start chat,
|
||||
// chat does not need to be suspended but NSE state still needs to be set to "suspended".
|
||||
var threadId: UUID? = NSEThreads.shared.newThread()
|
||||
var expectedMessages: Dictionary<String, ExpectedMessage> = [:] // key is receiveEntityId
|
||||
var notificationEntities: Dictionary<String, NotificationEntity> = [:] // key is entityId
|
||||
var appSubscriber: AppSubscriber?
|
||||
var returnedSuspension = false
|
||||
|
||||
@@ -199,12 +313,15 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
setExpirationTimer()
|
||||
receiveNtfMessages(request)
|
||||
case .suspending:
|
||||
// while application is suspending, the current instance will be waiting
|
||||
setExpirationTimer()
|
||||
Task {
|
||||
let state: AppState = await withCheckedContinuation { cont in
|
||||
// this subscriber uses message delivery via NSFileCoordinator to communicate between the app and NSE
|
||||
appSubscriber = appStateSubscriber { s in
|
||||
if s == .suspended { appSuspension(s) }
|
||||
}
|
||||
// this is a fallback timeout, in case message from the app does not arrive
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + Double(appSuspendTimeout) + 1) {
|
||||
logger.debug("NotificationService: appSuspension timeout")
|
||||
appSuspension(appStateGroupDefault.get())
|
||||
@@ -232,12 +349,18 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
}
|
||||
}
|
||||
|
||||
// This timer compensates for the scenarios when serviceExtensionTimeWillExpire does not fire at all.
|
||||
// It is not clear why in some cases it does not fire, possibly it is a bug,
|
||||
// or it depends on what the current thread is doing at the moment.
|
||||
// If notification is not delivered and not cancelled, no further notifications will be processed.
|
||||
@inline(__always)
|
||||
private func setExpirationTimer() -> Void {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
|
||||
self.deliverBestAttemptNtf(urgent: true)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
private func ntfRequestData(_ request: UNNotificationRequest) -> (nonce: String, encNtfInfo: String)? {
|
||||
if let ntfData = request.content.userInfo["notificationData"] as? [AnyHashable : Any],
|
||||
let nonce = ntfData["nonce"] as? String,
|
||||
@@ -247,7 +370,30 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function triggers notification message delivery for connection entities referenced in the notification.
|
||||
// Notification may reference multiple connection entities (message queues) in order to compensate for Apple servers
|
||||
// only delivering the latest notification, so it allows receiving messages from up to 6 contacts and groups from a
|
||||
// single notification. This aggregation is handled by a notification server and is delivered via APNS servers in
|
||||
// e2e encrypted envelope, and the app core prevents duplicate processing by keeping track of the last processed message.
|
||||
|
||||
// The process steps:
|
||||
// 0. apiGetConnNtfMessages or getConnNtfMessage get messages from the server for passed connection entities.
|
||||
// We don't know in advance which chat events will be delivered from app core for a given notification,
|
||||
// it may be a message, but it can also be contact request, various protocol confirmations, calls, etc.,
|
||||
// this function only returns metadata for the expected chat events.
|
||||
// This metadata is correlated with .ntfMessage core event / .msgInfo notification marker -
|
||||
// this marker allows determining when some message completed processing.
|
||||
// 1. receiveMessages: singleton loop receiving events from core.
|
||||
// 2. receivedMsgNtf: maps core events to notification events.
|
||||
// 3. NSEThreads.shared.processNotification: chooses which notification service instance in the current process should process notification.
|
||||
// While most of the time we observe that notifications are delivered sequentially, nothing in the documentation confirms it is sequential,
|
||||
// and from various sources it follows that each instance executes in its own thread, so concurrency is expected.
|
||||
// 4. processReceivedNtf: one of the instances of NSE processes notification event, deciding whether to request further messages
|
||||
// for a given connection entity (via getConnNtfMessage) or that the correct message was received and notification can be delivered (deliverBestAttemptNtf).
|
||||
// It is based on .msgInfo markers that indicate that message with a given timestamp was processed.
|
||||
// 5. deliverBestAttemptNtf: is called multiple times, once each connection receives enough messages (based on .msgInfo marker).
|
||||
// If further messages are expected, this function does nothing (unless it is called with urgent flag from timeout/expiration handlers).
|
||||
func receiveNtfMessages(_ request: UNNotificationRequest) {
|
||||
logger.debug("NotificationService: receiveNtfMessages")
|
||||
if case .documents = dbContainerGroupDefault.get() {
|
||||
@@ -255,95 +401,115 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
return
|
||||
}
|
||||
if let nrData = ntfRequestData(request),
|
||||
// check it here again
|
||||
// Check that the app is still inactive before starting the core.
|
||||
appStateGroupDefault.get().inactive {
|
||||
// thread is added to activeThreads tracking set here - if thread started chat it needs to be suspended
|
||||
if let t = threadId { NSEThreads.shared.startThread(t, self) }
|
||||
guard let t = threadId else { return }
|
||||
NSEThreads.shared.startThread(t, self)
|
||||
let dbStatus = startChat()
|
||||
// If database is opened successfully, get the list of connection entities (group members, contacts)
|
||||
// that are referenced in the encrypted notification metadata.
|
||||
if case .ok = dbStatus,
|
||||
let ntfConns = apiGetNtfConns(nonce: nrData.nonce, encNtfInfo: nrData.encNtfInfo) {
|
||||
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfConns ntfConns count = \(ntfConns.count)")
|
||||
// logger.debug("NotificationService: receiveNtfMessages: apiGetNtfConns ntfConns \(String(describing: ntfConns.map { $0.connEntity.id }))")
|
||||
for ntfConn in ntfConns {
|
||||
addExpectedMessage(ntfConn: ntfConn)
|
||||
}
|
||||
// uncomment localDisplayName in ConnectionEntity
|
||||
// logger.debug("NotificationService: receiveNtfMessages: apiGetNtfConns ntfConns \(String(describing: ntfConns.map { $0.connEntity.localDisplayName }))")
|
||||
|
||||
let connMsgReqs = expectedMessages.compactMap { (id, _) in
|
||||
let started = NSEThreads.queue.sync {
|
||||
let canStart = checkCanStart(id)
|
||||
if let t = threadId { logger.debug("NotificationService thread \(t, privacy: .private): receiveNtfMessages: can start: \(canStart)") }
|
||||
if canStart {
|
||||
processDroppedNotifications(id)
|
||||
expectedMessages[id]?.startedProcessingNewMsgs = true
|
||||
expectedMessages[id]?.shouldProcessNtf = true
|
||||
}
|
||||
return canStart
|
||||
}
|
||||
if started {
|
||||
return expectedMessages[id]?.connMsgReq
|
||||
} else {
|
||||
if let t = threadId { logger.debug("NotificationService thread \(t, privacy: .private): receiveNtfMessages: entity \(id, privacy: .private) waiting on semaphore") }
|
||||
expectedMessages[id]?.semaphore.wait()
|
||||
if let t = threadId { logger.debug("NotificationService thread \(t, privacy: .private): receiveNtfMessages: entity \(id, privacy: .private) proceeding after semaphore") }
|
||||
Task {
|
||||
NSEThreads.queue.sync {
|
||||
processDroppedNotifications(id)
|
||||
expectedMessages[id]?.startedProcessingNewMsgs = true
|
||||
expectedMessages[id]?.shouldProcessNtf = true
|
||||
// Prepare expected messages - they will be delivered to the reception loop in this chain:
|
||||
// They are atomically added to the instance notificationEntities inside msgReqs loop, to avoid any race conditions.
|
||||
let ntfEntities = ntfConns.compactMap(mkNotificationEntity)
|
||||
|
||||
// collect notification message requests for all connection entities
|
||||
let msgReqs: [(chatId: String, connMsgReq: ConnMsgReq)] = ntfEntities.compactMap { ntfEntity -> (chatId: String, connMsgReq: ConnMsgReq)? in
|
||||
// No need to request messages for connection entities that are "ready",
|
||||
// e.g. for muted users or when the message is not expected based on notification.
|
||||
let id = ntfEntity.entityId
|
||||
if let expectedMsg = ntfEntity.expectedMsg {
|
||||
if NSEThreads.shared.startEntity(self, ntfEntity) { // atomically checks and adds ntfEntity to NSE
|
||||
// process any notifications "postponed" by the previous instance
|
||||
let completed = processDroppedNotifications(ntfEntity, expectedMsg)
|
||||
return if !completed, let connMsgReq = notificationEntities[id]?.connMsgReq {
|
||||
(id, connMsgReq)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
if let connMsgReq = expectedMessages[id]?.connMsgReq {
|
||||
let _ = getConnNtfMessage(connMsgReq: connMsgReq)
|
||||
} else {
|
||||
// wait for another instance processing the same connection entity
|
||||
logger.debug("NotificationService thread \(t, privacy: .private): receiveNtfMessages: entity \(id, privacy: .private) waiting on semaphore")
|
||||
// this semaphore will be released by signalNextThread function, that looks up the instance
|
||||
// waiting for the connection entity via activeThreads in NSEThreads
|
||||
notificationEntities[id]?.semaphore.wait()
|
||||
logger.debug("NotificationService thread \(t, privacy: .private): receiveNtfMessages: entity \(id, privacy: .private) proceeding after semaphore")
|
||||
Task {
|
||||
// process any notifications "postponed" by the previous instance
|
||||
let completed = processDroppedNotifications(ntfEntity, expectedMsg)
|
||||
// Request messages from the server for this connection entity.
|
||||
// It triggers event delivery to receiveMessages loop (see above).
|
||||
if !completed, let connMsgReq = notificationEntities[id]?.connMsgReq,
|
||||
let rcvMsg = getConnNtfMessage(connMsgReq: connMsgReq),
|
||||
rcvMsg.noMsg {
|
||||
// if server returns error or "no message", deliver what we have for this connection entity.
|
||||
finalizeEntity(id) // also releases any waiting threads for this entity
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
} else { // no expected message
|
||||
notificationEntities[id] = ntfEntity
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if !connMsgReqs.isEmpty {
|
||||
if let r = apiGetConnNtfMessages(connMsgReqs: connMsgReqs) {
|
||||
logger.debug("NotificationService: receiveNtfMessages: apiGetConnNtfMessages count = \(r.count), expecting messages \(r.count { $0 != nil })")
|
||||
// Request messages for all connection entities that were not used by other instances.
|
||||
// It triggers event delivery to receiveMessages loop (see above).
|
||||
if !msgReqs.isEmpty,
|
||||
let rcvMsgs = apiGetConnNtfMessages(connMsgReqs: msgReqs.map { $0.connMsgReq }) {
|
||||
for i in 0 ..< min(msgReqs.count, rcvMsgs.count) { // a sanity check, API always returns the same size
|
||||
if rcvMsgs[i].noMsg {
|
||||
// mark entity as ready if there are no message on the server (or on error)
|
||||
finalizeEntity(msgReqs[i].chatId)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
} else if let dbStatus = dbStatus {
|
||||
setServiceBestAttemptNtf(createErrorNtf(dbStatus, badgeCount))
|
||||
}
|
||||
}
|
||||
// try to deliver the best attempt before exiting
|
||||
deliverBestAttemptNtf()
|
||||
}
|
||||
|
||||
func addExpectedMessage(ntfConn: NtfConn) {
|
||||
let expectedMsgId = ntfConn.expectedMsg_?.msgId
|
||||
if let receiveEntityId = ntfConn.connEntity.id {
|
||||
logger.debug("NotificationService: addExpectedMessage: expectedMsgId = \(expectedMsgId ?? "nil", privacy: .private)")
|
||||
expectedMessages[receiveEntityId] = ExpectedMessage(
|
||||
@inline(__always)
|
||||
func mkNotificationEntity(ntfConn: NtfConn) -> NotificationEntity? {
|
||||
if let rcvEntityId = ntfConn.connEntity.id {
|
||||
// don't receive messages for muted user profile
|
||||
let expectedMsg: NtfMsgInfo? = if ntfConn.user.showNotifications { ntfConn.expectedMsg_ } else { nil }
|
||||
return NotificationEntity(
|
||||
ntfConn: ntfConn,
|
||||
expectedMsgId: expectedMsgId,
|
||||
allowedGetNextAttempts: 3,
|
||||
msgBestAttemptNtf: defaultBestAttemptNtf(ntfConn),
|
||||
ready: ntfConn.expectedMsg_ == nil, // show defaultBestAttemptNtf(ntfConn) if there is no expected message
|
||||
shouldProcessNtf: false,
|
||||
startedProcessingNewMsgs: false,
|
||||
semaphore: DispatchSemaphore(value: 0)
|
||||
entityId: rcvEntityId,
|
||||
expectedMsg: expectedMsg,
|
||||
msgBestAttemptNtf: defaultBestAttemptNtf(ntfConn)
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkCanStart(_ entityId: String) -> Bool {
|
||||
return !NSEThreads.shared.activeThreads.contains(where: {
|
||||
(tId, nse) in tId != threadId && nse.expectedMessages.contains(where: { $0.key == entityId })
|
||||
})
|
||||
}
|
||||
|
||||
func processDroppedNotifications(_ entityId: String) {
|
||||
if !NSEThreads.shared.droppedNotifications.isEmpty {
|
||||
let messagesToProcess = NSEThreads.shared.droppedNotifications.filter { (eId, _) in eId == entityId }
|
||||
NSEThreads.shared.droppedNotifications.removeAll(where: { (eId, _) in eId == entityId })
|
||||
for (index, (_, ntf)) in messagesToProcess.enumerated() {
|
||||
if let t = threadId { logger.debug("NotificationService thread \(t, privacy: .private): entity \(entityId, privacy: .private): processing dropped notification \(index, privacy: .private)") }
|
||||
processReceivedNtf(entityId, ntf, signalReady: false)
|
||||
// Processes notifications received and postponed by the previous NSE instance
|
||||
func processDroppedNotifications(_ ntfEntity: NotificationEntity, _ expectedMsg: NtfMsgInfo) -> Bool {
|
||||
var completed = false
|
||||
while !completed {
|
||||
if let dropped = NSEThreads.shared.takeDroppedNtf(ntfEntity) {
|
||||
completed = processReceivedNtf(ntfEntity, expectedMsg, dropped.ntf)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if completed {
|
||||
finalizeEntity(ntfEntity.entityId)
|
||||
} else {
|
||||
notificationEntities[ntfEntity.entityId]?.shouldProcessNtf = true
|
||||
}
|
||||
return completed
|
||||
}
|
||||
|
||||
override func serviceExtensionTimeWillExpire() {
|
||||
@@ -351,69 +517,70 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
deliverBestAttemptNtf(urgent: true)
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
var expectingMoreMessages: Bool {
|
||||
!expectedMessages.allSatisfy { $0.value.ready }
|
||||
notificationEntities.contains { $0.value.expectedMsg != nil }
|
||||
}
|
||||
|
||||
func processReceivedNtf(_ id: ChatId, _ ntf: NSENotificationData, signalReady: Bool) {
|
||||
guard let expectedMessage = expectedMessages[id] else {
|
||||
return
|
||||
}
|
||||
guard let expectedMsgTs = expectedMessage.ntfConn.expectedMsg_?.msgTs else {
|
||||
NSEThreads.shared.droppedNotifications.append((id, ntf))
|
||||
if signalReady { entityReady(id) }
|
||||
return
|
||||
}
|
||||
// processReceivedNtf returns "completed" - true when no more messages for the passed entity should be processed by the current NSE instance.
|
||||
// This is used to call finalizeEntity(id) and by processDroppedNotifications to decide if further processing is needed.
|
||||
func processReceivedNtf(_ ntfEntity: NotificationEntity, _ expectedMsg: NtfMsgInfo, _ ntf: NSENotificationData) -> Bool {
|
||||
let id = ntfEntity.entityId
|
||||
if case let .msgInfo(info) = ntf {
|
||||
if info.msgId == expectedMessage.expectedMsgId {
|
||||
if info.msgId == expectedMsg.msgId {
|
||||
// The message for this instance is processed, no more expected, deliver.
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): expected")
|
||||
expectedMessages[id]?.expectedMsgId = nil
|
||||
if signalReady { entityReady(id) }
|
||||
self.deliverBestAttemptNtf()
|
||||
} else if let msgTs = info.msgTs_, msgTs > expectedMsgTs {
|
||||
return true
|
||||
} else if let msgTs = info.msgTs_, msgTs > expectedMsg.msgTs {
|
||||
// Otherwise check timestamp - if it is after the currently expected timestamp, preserve .msgInfo marker for the next instance.
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unexpected msgInfo, let other instance to process it, stopping this one")
|
||||
NSEThreads.shared.droppedNotifications.append((id, ntf))
|
||||
if signalReady { entityReady(id) }
|
||||
self.deliverBestAttemptNtf()
|
||||
} else if (expectedMessages[id]?.allowedGetNextAttempts ?? 0) > 0, let connMsgReq = expectedMessages[id]?.connMsgReq {
|
||||
NSEThreads.shared.addDroppedNtf(id, ntf)
|
||||
return true
|
||||
} else if ntfEntity.allowedGetNextAttempts > 0, let connMsgReq = ntfEntity.connMsgReq {
|
||||
// Otherwise this instance expects more messages, and still has allowed attempts -
|
||||
// request more messages with getConnNtfMessage.
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unexpected msgInfo, get next message")
|
||||
expectedMessages[id]?.allowedGetNextAttempts -= 1
|
||||
if let receivedMsg = getConnNtfMessage(connMsgReq: connMsgReq) {
|
||||
logger.debug("NotificationService processNtf, on getConnNtfMessage: msgInfo msgId = \(info.msgId, privacy: .private), receivedMsg msgId = \(receivedMsg.msgId, privacy: .private)")
|
||||
notificationEntities[id]?.allowedGetNextAttempts -= 1
|
||||
let receivedMsg = getConnNtfMessage(connMsgReq: connMsgReq)
|
||||
if case let .info(msg) = receivedMsg, let msg {
|
||||
// Server delivered message, it will be processed in the loop - see the comments in receiveNtfMessages.
|
||||
logger.debug("NotificationService processNtf, on getConnNtfMessage: msgInfo msgId = \(info.msgId, privacy: .private), receivedMsg msgId = \(msg.msgId, privacy: .private)")
|
||||
return false
|
||||
} else {
|
||||
// Server reported no messages or error, deliver what we have.
|
||||
logger.debug("NotificationService processNtf, on getConnNtfMessage: msgInfo msgId = \(info.msgId, privacy: .private): no next message, deliver best attempt")
|
||||
NSEThreads.shared.droppedNotifications.append((id, ntf))
|
||||
if signalReady { entityReady(id) }
|
||||
self.deliverBestAttemptNtf()
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
// Current instance needs more messages, but ran out of attempts - deliver what we have.
|
||||
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unknown message, let other instance to process it")
|
||||
NSEThreads.shared.droppedNotifications.append((id, ntf))
|
||||
if signalReady { entityReady(id) }
|
||||
self.deliverBestAttemptNtf()
|
||||
return true
|
||||
}
|
||||
} else if expectedMessage.ntfConn.user.showNotifications {
|
||||
} else if ntfEntity.ntfConn.user.showNotifications {
|
||||
// This is the notification event for the user with enabled notifications.
|
||||
logger.debug("NotificationService processNtf: setting best attempt")
|
||||
if ntf.notificationEvent != nil {
|
||||
setBadgeCount()
|
||||
}
|
||||
let prevBestAttempt = expectedMessages[id]?.msgBestAttemptNtf
|
||||
if prevBestAttempt?.callInvitation == nil || ntf.callInvitation != nil {
|
||||
expectedMessages[id]?.msgBestAttemptNtf = ntf
|
||||
// If previous "best attempt" is not a call, or if the current notification is a call, replace best attempt.
|
||||
// NOTE: we are delaying it until notification marker to make sure we are not delivering stale calls that can't be connected.
|
||||
// A better logic could be to check whether we have a call in the best attempt while processing .msgInfo marker above.
|
||||
// If the best attempt is a call, and its marker is received, and the call is recent (e.g., the last 30 seconds), it would deliver at once,
|
||||
// instead of requesting further messages.
|
||||
if ntfEntity.msgBestAttemptNtf.callInvitation == nil || ntf.callInvitation != nil {
|
||||
notificationEntities[id]?.msgBestAttemptNtf = ntf
|
||||
} // otherwise keep call as best attempt
|
||||
return false
|
||||
} else {
|
||||
NSEThreads.shared.droppedNotifications.append((id, ntf))
|
||||
if signalReady { entityReady(id) }
|
||||
// We should not get to this branch, as notifications are not delivered for muted users.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func entityReady(_ entityId: ChatId) {
|
||||
if let t = threadId { logger.debug("NotificationService thread \(t, privacy: .private): entityReady: entity \(entityId, privacy: .private)") }
|
||||
expectedMessages[entityId]?.ready = true
|
||||
if let (tNext, nse) = NSEThreads.shared.activeThreads.first(where: { (_, nse) in nse.expectedMessages[entityId]?.startedProcessingNewMsgs == false }) {
|
||||
if let t = threadId { logger.debug("NotificationService thread \(t, privacy: .private): entityReady: signal next thread \(tNext, privacy: .private) for entity \(entityId, privacy: .private)") }
|
||||
nse.expectedMessages[entityId]?.semaphore.signal()
|
||||
}
|
||||
func finalizeEntity(_ entityId: ChatId) {
|
||||
if let t = threadId { logger.debug("NotificationService thread \(t): entityReady: entity \(entityId)") }
|
||||
NSEThreads.shared.signalNextThread(self, entityId)
|
||||
deliverBestAttemptNtf()
|
||||
}
|
||||
|
||||
func setBadgeCount() {
|
||||
@@ -421,9 +588,10 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
ntfBadgeCountGroupDefault.set(badgeCount)
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func setServiceBestAttemptNtf(_ ntf: UNMutableNotificationContent) {
|
||||
logger.debug("NotificationService.setServiceBestAttemptNtf")
|
||||
serviceBestAttemptNtf = .nse(ntf)
|
||||
serviceBestAttemptNtf = ntf
|
||||
}
|
||||
|
||||
private func deliverBestAttemptNtf(urgent: Bool = false) {
|
||||
@@ -434,8 +602,8 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
}
|
||||
logger.debug("NotificationService.deliverBestAttemptNtf")
|
||||
// stop processing other messages
|
||||
for (key, _) in expectedMessages {
|
||||
expectedMessages[key]?.shouldProcessNtf = false
|
||||
for (key, _) in notificationEntities {
|
||||
notificationEntities[key]?.shouldProcessNtf = false
|
||||
}
|
||||
|
||||
let suspend: Bool
|
||||
@@ -449,22 +617,24 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
private func deliverCallkitOrNotification(urgent: Bool, suspend: Bool = false, handler: @escaping (UNNotificationContent) -> Void) {
|
||||
if useCallKit() && expectedMessages.contains(where: { $0.value.msgBestAttemptNtf?.callInvitation != nil }) {
|
||||
let callInv = notificationEntities.lazy.compactMap({ $0.value.msgBestAttemptNtf.callInvitation }).first
|
||||
if callInv != nil && useCallKit() {
|
||||
logger.debug("NotificationService.deliverCallkitOrNotification: will suspend, callkit")
|
||||
// suspending NSE even though there may be other notifications
|
||||
// to allow the app to process callkit call
|
||||
if urgent {
|
||||
// suspending NSE even though there may be other notifications
|
||||
// to allow the app to process callkit call
|
||||
suspendChat(0)
|
||||
deliverNotification(handler: handler)
|
||||
deliverNotification(handler, callInv)
|
||||
} else {
|
||||
// suspending NSE with delay and delivering after the suspension
|
||||
// when not "urgent", suspending NSE with delay and delivering after the suspension
|
||||
// because pushkit notification must be processed without delay
|
||||
// to avoid app termination
|
||||
// to avoid app termination.
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + fastNSESuspendSchedule.delay) {
|
||||
suspendChat(fastNSESuspendSchedule.timeout)
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + Double(fastNSESuspendSchedule.timeout)) {
|
||||
self.deliverNotification(handler: handler)
|
||||
self.deliverNotification(handler, callInv)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,68 +653,71 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
}
|
||||
}
|
||||
}
|
||||
deliverNotification(handler: handler)
|
||||
deliverNotification(handler, callInv)
|
||||
}
|
||||
}
|
||||
|
||||
private func deliverNotification(handler: @escaping (UNNotificationContent) -> Void) {
|
||||
if serviceBestAttemptNtf != nil, let ntf = prepareNotification() {
|
||||
contentHandler = nil
|
||||
private func deliverNotification(_ handler: @escaping (UNNotificationContent) -> Void, _ callInv: RcvCallInvitation?) {
|
||||
if let serviceNtf = serviceBestAttemptNtf {
|
||||
serviceBestAttemptNtf = nil
|
||||
switch ntf {
|
||||
case let .nse(content):
|
||||
content.badge = badgeCount as NSNumber
|
||||
handler(content)
|
||||
case let .callkit(invitation):
|
||||
logger.debug("NotificationService reportNewIncomingVoIPPushPayload for \(invitation.contact.id)")
|
||||
CXProvider.reportNewIncomingVoIPPushPayload([
|
||||
"displayName": invitation.contact.displayName,
|
||||
"contactId": invitation.contact.id,
|
||||
"callUUID": invitation.callUUID ?? "",
|
||||
"media": invitation.callType.media.rawValue,
|
||||
"callTs": invitation.callTs.timeIntervalSince1970
|
||||
]) { error in
|
||||
logger.debug("reportNewIncomingVoIPPushPayload result: \(error)")
|
||||
handler(error == nil ? UNMutableNotificationContent() : createCallInvitationNtf(invitation, self.badgeCount))
|
||||
contentHandler = nil
|
||||
if let callInv {
|
||||
if useCallKit() {
|
||||
logger.debug("NotificationService reportNewIncomingVoIPPushPayload for \(callInv.contact.id)")
|
||||
CXProvider.reportNewIncomingVoIPPushPayload([
|
||||
"displayName": callInv.contact.displayName,
|
||||
"contactId": callInv.contact.id,
|
||||
"callUUID": callInv.callUUID ?? "",
|
||||
"media": callInv.callType.media.rawValue,
|
||||
"callTs": callInv.callTs.timeIntervalSince1970
|
||||
]) { error in
|
||||
logger.debug("reportNewIncomingVoIPPushPayload result: \(error)")
|
||||
handler(error == nil ? UNMutableNotificationContent() : createCallInvitationNtf(callInv, self.badgeCount))
|
||||
}
|
||||
} else {
|
||||
handler(createCallInvitationNtf(callInv, badgeCount))
|
||||
}
|
||||
case .empty:
|
||||
handler(UNMutableNotificationContent()) // used to mute notifications that did not unsubscribe yet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func prepareNotification() -> NSENotification? {
|
||||
if expectedMessages.isEmpty {
|
||||
return serviceBestAttemptNtf
|
||||
} else if let callNtfKV = expectedMessages.first(where: { $0.value.msgBestAttemptNtf?.callInvitation != nil }),
|
||||
let callInv = callNtfKV.value.msgBestAttemptNtf?.callInvitation,
|
||||
let callNtf = callNtfKV.value.msgBestAttemptNtf {
|
||||
return useCallKit() ? .callkit(callInv) : .nse(callNtf.notificationContent(badgeCount))
|
||||
} else {
|
||||
logger.debug("NotificationService prepareNotification \(String(describing: self.expectedMessages.map { $0.key }))")
|
||||
let ntfEvents = expectedMessages.compactMap { $0.value.msgBestAttemptNtf?.notificationEvent }
|
||||
logger.debug("NotificationService prepareNotification \(ntfEvents.count)")
|
||||
if ntfEvents.isEmpty {
|
||||
return .empty
|
||||
} else if let ntfEvent = ntfEvents.count == 1 ? ntfEvents.first : nil {
|
||||
return .nse(ntfEvent.notificationContent(badgeCount))
|
||||
} else if notificationEntities.isEmpty {
|
||||
handler(serviceNtf)
|
||||
} else {
|
||||
return .nse(createJointNtf(ntfEvents))
|
||||
handler(prepareNotification())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func createJointNtf(_ ntfEvents: [NSENotificationData]) -> UNMutableNotificationContent {
|
||||
@inline(__always)
|
||||
private func prepareNotification() -> UNMutableNotificationContent {
|
||||
// uncomment localDisplayName in ConnectionEntity
|
||||
// let conns = self.notificationEntities.compactMap { $0.value.ntfConn.connEntity.localDisplayName }
|
||||
// logger.debug("NotificationService prepareNotification for \(String(describing: conns))")
|
||||
let ntfs = notificationEntities.compactMap { $0.value.msgBestAttemptNtf.notificationEvent }
|
||||
let newMsgNtfs = ntfs.compactMap({ $0.newMsgNtf })
|
||||
let useNtfs = if newMsgNtfs.isEmpty { ntfs } else { newMsgNtfs }
|
||||
return createNtf(useNtfs)
|
||||
|
||||
func createNtf(_ ntfs: [NSENotificationData]) -> UNMutableNotificationContent {
|
||||
logger.debug("NotificationService prepareNotification: \(ntfs.count) events")
|
||||
return switch ntfs.count {
|
||||
case 0: UNMutableNotificationContent() // used to mute notifications that did not unsubscribe yet
|
||||
case 1: ntfs[0].notificationContent(badgeCount)
|
||||
default: createJointNtf(ntfs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this can be improved when there are two or more connection entity events when no messages were delivered.
|
||||
// Possibly, it is better to postpone this improvement until message priority is added to prevent notifications in muted groups,
|
||||
// unless it is a mention, a reply or some other high priority message marked for notification delivery.
|
||||
@inline(__always)
|
||||
private func createJointNtf(_ ntfs: [NSENotificationData]) -> UNMutableNotificationContent {
|
||||
let previewMode = ntfPreviewModeGroupDefault.get()
|
||||
let newMsgsData: [(any UserLike, ChatInfo)] = ntfEvents.compactMap { $0.newMsgData }
|
||||
if !newMsgsData.isEmpty, let userId = newMsgsData.first?.0.userId {
|
||||
let newMsgsChats: [ChatInfo] = newMsgsData.map { $0.1 }
|
||||
let uniqueChatsNames = uniqueNewMsgsChatsNames(newMsgsChats)
|
||||
var body: String
|
||||
if previewMode == .hidden {
|
||||
body = String.localizedStringWithFormat(NSLocalizedString("New messages in %d chats", comment: "notification body"), uniqueChatsNames.count)
|
||||
logger.debug("NotificationService.createJointNtf ntfs: \(ntfs.count)")
|
||||
let (userId, chatsNames) = newMsgsChatsNames(ntfs)
|
||||
if !chatsNames.isEmpty, let userId {
|
||||
let body = if previewMode == .hidden {
|
||||
String.localizedStringWithFormat(NSLocalizedString("From %d chat(s)", comment: "notification body"), chatsNames.count)
|
||||
} else {
|
||||
body = String.localizedStringWithFormat(NSLocalizedString("From: %@", comment: "notification body"), newMsgsChatsNamesStr(uniqueChatsNames))
|
||||
String.localizedStringWithFormat(NSLocalizedString("From: %@", comment: "notification body"), newMsgsChatsNamesStr(chatsNames))
|
||||
}
|
||||
return createNotification(
|
||||
categoryIdentifier: ntfCategoryManyEvents,
|
||||
@@ -557,24 +730,32 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
return createNotification(
|
||||
categoryIdentifier: ntfCategoryManyEvents,
|
||||
title: NSLocalizedString("New events", comment: "notification"),
|
||||
body: String.localizedStringWithFormat(NSLocalizedString("%d new events", comment: "notification body"), ntfEvents.count),
|
||||
body: String.localizedStringWithFormat(NSLocalizedString("%d new events", comment: "notification body"), ntfs.count),
|
||||
badgeCount: badgeCount
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func uniqueNewMsgsChatsNames(_ newMsgsChats: [ChatInfo]) -> [String] {
|
||||
@inline(__always)
|
||||
private func newMsgsChatsNames(_ ntfs: [NSENotificationData]) -> (Int64?, [String]) {
|
||||
var seenChatIds = Set<ChatId>()
|
||||
var uniqueChatsNames: [String] = []
|
||||
for chat in newMsgsChats {
|
||||
if !seenChatIds.contains(chat.id) {
|
||||
seenChatIds.insert(chat.id)
|
||||
uniqueChatsNames.append(chat.chatViewName)
|
||||
var chatsNames: [String] = []
|
||||
var userId: Int64?
|
||||
for ntf in ntfs {
|
||||
switch ntf {
|
||||
case let .messageReceived(user, chat, _):
|
||||
if seenChatIds.isEmpty { userId = user.userId }
|
||||
if !seenChatIds.contains(chat.id) {
|
||||
seenChatIds.insert(chat.id)
|
||||
chatsNames.append(chat.chatViewName)
|
||||
}
|
||||
default: ()
|
||||
}
|
||||
}
|
||||
return uniqueChatsNames
|
||||
return (userId, chatsNames)
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
private func newMsgsChatsNamesStr(_ names: [String]) -> String {
|
||||
return switch names.count {
|
||||
case 1: names[0]
|
||||
@@ -593,9 +774,8 @@ class NSEChatState {
|
||||
static let shared = NSEChatState()
|
||||
private var value_ = NSEState.created
|
||||
|
||||
var value: NSEState {
|
||||
value_
|
||||
}
|
||||
@inline(__always)
|
||||
var value: NSEState { value_ }
|
||||
|
||||
func set(_ state: NSEState) {
|
||||
nseStateGroupDefault.set(state)
|
||||
@@ -603,7 +783,7 @@ class NSEChatState {
|
||||
value_ = state
|
||||
}
|
||||
|
||||
init() {
|
||||
private init() {
|
||||
// This is always set to .created state, as in case previous start of NSE crashed in .active state, it is stored correctly.
|
||||
// Otherwise the app will be activating slower
|
||||
set(.created)
|
||||
@@ -651,7 +831,7 @@ func startChat() -> DBMigrationResult? {
|
||||
|
||||
startLock.wait()
|
||||
defer { startLock.signal() }
|
||||
|
||||
|
||||
if hasChatCtrl() {
|
||||
return switch NSEChatState.shared.value {
|
||||
case .created: doStartChat()
|
||||
@@ -803,8 +983,11 @@ func chatRecvMsg() async -> APIResult<NSEChatEvent>? {
|
||||
}
|
||||
|
||||
private let isInChina = SKStorefront().countryCode == "CHN"
|
||||
|
||||
@inline(__always)
|
||||
private func useCallKit() -> Bool { !isInChina && callKitEnabledGroupDefault.get() }
|
||||
|
||||
@inline(__always)
|
||||
func receivedMsgNtf(_ res: NSEChatEvent) async -> (String, NSENotificationData)? {
|
||||
logger.debug("NotificationService receivedMsgNtf: \(res.responseType)")
|
||||
switch res {
|
||||
@@ -851,12 +1034,10 @@ func receivedMsgNtf(_ res: NSEChatEvent) async -> (String, NSENotificationData)?
|
||||
case .chatSuspended:
|
||||
chatSuspended()
|
||||
return nil
|
||||
default:
|
||||
logger.debug("NotificationService receivedMsgNtf ignored event: \(res.responseType)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func updateNetCfg() {
|
||||
let newNetConfig = getNetCfg()
|
||||
if newNetConfig != networkConfig {
|
||||
@@ -925,42 +1106,41 @@ func apiSetEncryptLocalFiles(_ enable: Bool) throws {
|
||||
|
||||
func apiGetNtfConns(nonce: String, encNtfInfo: String) -> [NtfConn]? {
|
||||
guard apiGetActiveUser() != nil else {
|
||||
logger.debug("no active user")
|
||||
logger.debug("NotificationService: no active user")
|
||||
return nil
|
||||
}
|
||||
let r: APIResult<NSEChatResponse> = sendSimpleXCmd(NSEChatCommand.apiGetNtfConns(nonce: nonce, encNtfInfo: encNtfInfo))
|
||||
if case let .result(.ntfConns(ntfConns)) = r {
|
||||
logger.debug("apiGetNtfConns response ntfConns: \(ntfConns.count)")
|
||||
logger.debug("NotificationService apiGetNtfConns response ntfConns: \(ntfConns.count) conections")
|
||||
return ntfConns
|
||||
} else if case let .error(error) = r {
|
||||
logger.debug("apiGetNtfMessage error response: \(String.init(describing: error))")
|
||||
logger.debug("NotificationService apiGetNtfMessage error response: \(String.init(describing: error))")
|
||||
} else {
|
||||
logger.debug("apiGetNtfMessage ignored response: \(r.responseType) \(String.init(describing: r))")
|
||||
logger.debug("NotificationService apiGetNtfMessage ignored response: \(r.responseType) \(String.init(describing: r))")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func apiGetConnNtfMessages(connMsgReqs: [ConnMsgReq]) -> [NtfMsgInfo?]? {
|
||||
func apiGetConnNtfMessages(connMsgReqs: [ConnMsgReq]) -> [RcvNtfMsgInfo]? {
|
||||
guard apiGetActiveUser() != nil else {
|
||||
logger.debug("no active user")
|
||||
return nil
|
||||
}
|
||||
logger.debug("apiGetConnNtfMessages command: \(NSEChatCommand.apiGetConnNtfMessages(connMsgReqs: connMsgReqs).cmdString)")
|
||||
// logger.debug("NotificationService apiGetConnNtfMessages command: \(NSEChatCommand.apiGetConnNtfMessages(connMsgReqs: connMsgReqs).cmdString)")
|
||||
logger.debug("NotificationService apiGetConnNtfMessages requests: \(connMsgReqs.count)")
|
||||
let r: APIResult<NSEChatResponse> = sendSimpleXCmd(NSEChatCommand.apiGetConnNtfMessages(connMsgReqs: connMsgReqs))
|
||||
if case let .result(.connNtfMessages(receivedMsgs)) = r {
|
||||
logger.debug("apiGetConnNtfMessages response receivedMsgs: total \(receivedMsgs.count), expecting messages \(receivedMsgs.count { $0 != nil })")
|
||||
return receivedMsgs
|
||||
if case let .result(.connNtfMessages(msgs)) = r {
|
||||
// logger.debug("NotificationService apiGetConnNtfMessages responses: \(String(describing: msgs))")
|
||||
logger.debug("NotificationService apiGetConnNtfMessages responses: total \(msgs.count), expecting messages \(msgs.count { !$0.noMsg }), errors \(msgs.count { $0.isError })")
|
||||
return msgs
|
||||
}
|
||||
logger.debug("apiGetConnNtfMessages error: \(responseError(r.unexpected))")
|
||||
logger.debug("NotificationService apiGetConnNtfMessages error: \(responseError(r.unexpected))")
|
||||
return nil
|
||||
}
|
||||
|
||||
func getConnNtfMessage(connMsgReq: ConnMsgReq) -> NtfMsgInfo? {
|
||||
let r_ = apiGetConnNtfMessages(connMsgReqs: [connMsgReq])
|
||||
if let r = r_, let receivedMsg = r.count == 1 ? r.first : nil {
|
||||
return receivedMsg
|
||||
}
|
||||
return nil
|
||||
func getConnNtfMessage(connMsgReq: ConnMsgReq) -> RcvNtfMsgInfo? {
|
||||
let r = apiGetConnNtfMessages(connMsgReqs: [connMsgReq])
|
||||
return if let r, r.count > 0 { r[0] } else { nil }
|
||||
}
|
||||
|
||||
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil) -> AChatItem? {
|
||||
@@ -1021,4 +1201,3 @@ func defaultBestAttemptNtf(_ ntfConn: NtfConn) -> NSENotificationData {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Neue Nachrichten";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Neue Nachrichten in %d Chats";
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Mensajes nuevos";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Mensajes nuevos en %d chat(s)";
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Nouveaux messages";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Nouveaux messages dans %d chats";
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Új üzenetek";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Új üzenetek %d csevegésben";
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Nuovi messaggi";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Nuovi messaggi in %d chat";
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Nieuwe berichten";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Nieuwe berichten in %d chats";
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Новые сообщения";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Новые сообщения в %d разговоре(ах)";
|
||||
|
||||
|
||||
@@ -10,6 +10,3 @@
|
||||
/* notification */
|
||||
"New messages" = "Нові повідомлення";
|
||||
|
||||
/* notification body */
|
||||
"New messages in %d chats" = "Нові повідомлення в чатах %d";
|
||||
|
||||
|
||||
@@ -179,8 +179,8 @@
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a */; };
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
|
||||
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
|
||||
@@ -543,8 +543,8 @@
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a"; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a"; sourceTree = "<group>"; };
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
|
||||
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
|
||||
@@ -702,8 +702,8 @@
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a in Frameworks */,
|
||||
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -788,8 +788,8 @@
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */,
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */,
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -1991,7 +1991,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -2016,7 +2016,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES_THIN;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
@@ -2041,7 +2041,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -2066,7 +2066,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
@@ -2083,11 +2083,11 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -2103,11 +2103,11 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -2128,7 +2128,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
@@ -2143,7 +2143,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -2165,7 +2165,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
@@ -2180,7 +2180,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -2202,7 +2202,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -2228,7 +2228,7 @@
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -2253,7 +2253,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -2279,7 +2279,7 @@
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -2304,7 +2304,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
@@ -2319,7 +2319,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -2338,7 +2338,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
@@ -2353,7 +2353,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
||||
@@ -311,12 +311,14 @@ public class EnumDefault<T: RawRepresentable> where T.RawValue == String {
|
||||
}
|
||||
|
||||
public class BoolDefault: Default<Bool> {
|
||||
@inline(__always)
|
||||
public func get() -> Bool {
|
||||
self.defaults.bool(forKey: self.key)
|
||||
}
|
||||
}
|
||||
|
||||
public class IntDefault: Default<Int> {
|
||||
@inline(__always)
|
||||
public func get() -> Int {
|
||||
self.defaults.integer(forKey: self.key)
|
||||
}
|
||||
@@ -326,11 +328,13 @@ public class Default<T> {
|
||||
var defaults: UserDefaults
|
||||
var key: String
|
||||
|
||||
@inline(__always)
|
||||
public init(defaults: UserDefaults = UserDefaults.standard, forKey: String) {
|
||||
self.defaults = defaults
|
||||
self.key = forKey
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public func set(_ value: T) {
|
||||
defaults.set(value, forKey: key)
|
||||
defaults.synchronize()
|
||||
|
||||
@@ -2514,6 +2514,19 @@ public enum ConnectionEntity: Decodable, Hashable {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
// public var localDisplayName: String? {
|
||||
// switch self {
|
||||
// case let .rcvDirectMsgConnection(conn, contact):
|
||||
// if let name = contact?.localDisplayName { "@\(name)" } else { conn.id }
|
||||
// case let .rcvGroupMsgConnection(_, g, m):
|
||||
// "#\(g.localDisplayName) @\(m.localDisplayName)"
|
||||
// case let .userContactConnection(_, userContact):
|
||||
// userContact.id
|
||||
// default:
|
||||
// nil
|
||||
// }
|
||||
// }
|
||||
|
||||
public var conn: Connection {
|
||||
switch self {
|
||||
@@ -2539,6 +2552,21 @@ public struct NtfMsgInfo: Decodable, Hashable {
|
||||
public var msgTs: Date
|
||||
}
|
||||
|
||||
public enum RcvNtfMsgInfo: Decodable {
|
||||
case info(ntfMsgInfo: NtfMsgInfo?)
|
||||
case error(ntfMsgError: AgentErrorType)
|
||||
|
||||
@inline(__always)
|
||||
public var noMsg: Bool {
|
||||
if case let .info(msg) = self { msg == nil } else { true }
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public var isError: Bool {
|
||||
if case .error = self { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
let iso8601DateFormatter = {
|
||||
let f = ISO8601DateFormatter()
|
||||
f.formatOptions = [.withInternetDateTime]
|
||||
|
||||
@@ -29,10 +29,10 @@ void haskell_init_nse(void) {
|
||||
char *argv[] = {
|
||||
"simplex",
|
||||
"+RTS", // requires `hs_init_with_rtsopts`
|
||||
"-A1m", // chunk size for new allocations
|
||||
"-H1m", // initial heap size
|
||||
"-A256k", // chunk size for new allocations
|
||||
"-H512k", // initial heap size
|
||||
"-F0.5", // heap growth triggering GC
|
||||
"-Fd1", // memory return
|
||||
"-Fd0.3", // memory return
|
||||
"-c", // compacting garbage collector
|
||||
0
|
||||
};
|
||||
|
||||
@@ -124,6 +124,18 @@
|
||||
/* time interval */
|
||||
"%d days" = "%d dní";
|
||||
|
||||
/* forward confirmation reason */
|
||||
"%d file(s) are still being downloaded." = "%d soubor(y) stále stahován(y).";
|
||||
|
||||
/* forward confirmation reason */
|
||||
"%d file(s) failed to download." = "%d soubor(y) se nepodařilo stáhnout.";
|
||||
|
||||
/* forward confirmation reason */
|
||||
"%d file(s) were deleted." = "%d soubor(y) smazán(y).";
|
||||
|
||||
/* forward confirmation reason */
|
||||
"%d file(s) were not downloaded." = "%d soubor(y) nestažen(y).";
|
||||
|
||||
/* time interval */
|
||||
"%d hours" = "%d hodin";
|
||||
|
||||
|
||||
@@ -4751,6 +4751,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"Share with contacts" = "Mit Kontakten teilen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Short link" = "Verkürzter Link";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show → on messages sent via private routing." = "Bei Nachrichten, die über privates Routing versendet wurden, → anzeigen.";
|
||||
|
||||
@@ -4793,6 +4796,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX address or 1-time link?" = "SimpleX-Adresse oder Einmal-Link?";
|
||||
|
||||
/* simplex link type */
|
||||
"SimpleX channel link" = "SimpleX-Kanal-Link";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "SimpleX-Chat und Flux haben vereinbart, die von Flux betriebenen Server in die App aufzunehmen.";
|
||||
|
||||
@@ -5181,6 +5187,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"This is your own SimpleX address!" = "Das ist Ihre eigene SimpleX-Adresse!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Für diesen Link wird eine neuere App-Version benötigt. Bitte aktualisieren Sie die App oder bitten Sie Ihren Kontakt einen kompatiblen Link zu senden.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link was used with another mobile device, please create a new link on the desktop." = "Dieser Link wurde schon mit einem anderen Mobiltelefon genutzt. Bitte erstellen sie einen neuen Link in der Desktop-App.";
|
||||
|
||||
@@ -5373,6 +5382,9 @@ report reason */
|
||||
/* swipe action */
|
||||
"Unread" = "Ungelesen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unsupported connection link" = "Verbindungs-Link wird nicht unterstützt";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Up to 100 last messages are sent to new members." = "Bis zu 100 der letzten Nachrichten werden an neue Mitglieder gesendet.";
|
||||
|
||||
@@ -5466,6 +5478,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"Use servers" = "Verwende Server";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use short links (BETA)" = "Kurze Links verwenden (BETA)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "Verwenden Sie SimpleX-Chat-Server?";
|
||||
|
||||
|
||||
@@ -4751,6 +4751,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"Share with contacts" = "Compartir con contactos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Short link" = "Enlace corto";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show → on messages sent via private routing." = "Mostrar → en mensajes con enrutamiento privado.";
|
||||
|
||||
@@ -4793,6 +4796,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX address or 1-time link?" = "¿Dirección SimpleX o enlace de un uso?";
|
||||
|
||||
/* simplex link type */
|
||||
"SimpleX channel link" = "Enlace de canal SimpleX";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "Simplex Chat y Flux han acordado incluir en la aplicación servidores operados por Flux.";
|
||||
|
||||
@@ -5181,6 +5187,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"This is your own SimpleX address!" = "¡Esta es tu propia dirección SimpleX!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Este enlace requiere una versión más reciente de la aplicación. Por favor, actualiza la aplicación o pide a tu contacto un enlace compatible.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link was used with another mobile device, please create a new link on the desktop." = "Este enlace ha sido usado en otro dispositivo móvil, por favor crea un enlace nuevo en el ordenador.";
|
||||
|
||||
@@ -5373,6 +5382,9 @@ report reason */
|
||||
/* swipe action */
|
||||
"Unread" = "No leído";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unsupported connection link" = "Enlace de conexión no compatible";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Up to 100 last messages are sent to new members." = "Hasta 100 últimos mensajes son enviados a los miembros nuevos.";
|
||||
|
||||
@@ -5466,6 +5478,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"Use servers" = "Usar servidores";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use short links (BETA)" = "Usar enlaces cortos (BETA)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "¿Usar servidores SimpleX Chat?";
|
||||
|
||||
|
||||
@@ -692,7 +692,7 @@ swipe action */
|
||||
"Ask" = "Mindig kérdezzen rá";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Attach" = "Csatolás";
|
||||
"Attach" = "Mellékelés";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"attempts" = "próbálkozások";
|
||||
@@ -2671,7 +2671,7 @@ snd error text */
|
||||
"Hide profile" = "Profil elrejtése";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Hide:" = "Elrejtés:";
|
||||
"Hide:" = "Elrejtve:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"History" = "Előzmények";
|
||||
@@ -3915,7 +3915,7 @@ time to disappear */
|
||||
"Privacy policy and conditions of use." = "Adatvédelmi szabályzat és felhasználási feltételek.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Privacy redefined" = "Adatvédelem újraértelmezve";
|
||||
"Privacy redefined" = "Újraértelmezett adatvédelem";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Private chats, groups and your contacts are not accessible to server operators." = "A privát csevegések, a csoportok és a partnerek nem érhetők el a szerver üzemeltetői számára.";
|
||||
@@ -4751,6 +4751,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"Share with contacts" = "Megosztás a partnerekkel";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Short link" = "Rövid hivatkozás";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show → on messages sent via private routing." = "Egy „→” jel megjelenítése a privát útválasztáson keresztül küldött üzeneteknél.";
|
||||
|
||||
@@ -4776,7 +4779,7 @@ chat item action */
|
||||
"Show QR code" = "QR-kód megjelenítése";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show:" = "Megjelenítés:";
|
||||
"Show:" = "Megjelenítve:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX" = "SimpleX";
|
||||
@@ -4793,6 +4796,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX address or 1-time link?" = "SimpleX-cím vagy egyszer használható meghívó?";
|
||||
|
||||
/* simplex link type */
|
||||
"SimpleX channel link" = "SimpleX-csatornahivatkozás";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "A SimpleX Chat és a Flux megállapodást kötött arról, hogy a Flux által üzemeltetett kiszolgálókat beépítik az alkalmazásba.";
|
||||
|
||||
@@ -5181,6 +5187,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"This is your own SimpleX address!" = "Ez a saját SimpleX-címe!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Ez a hivatkozás újabb alkalmazásverziót igényel. Frissítse az alkalmazást vagy kérjen egy kompatibilis hivatkozást a partnerétől.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link was used with another mobile device, please create a new link on the desktop." = "Ezt a hivatkozást egy másik hordozható eszközön már használták, hozzon létre egy új hivatkozást a számítógépén.";
|
||||
|
||||
@@ -5373,6 +5382,9 @@ report reason */
|
||||
/* swipe action */
|
||||
"Unread" = "Olvasatlan";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unsupported connection link" = "Nem támogatott kapcsolattartási hivatkozás";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Up to 100 last messages are sent to new members." = "Legfeljebb az utolsó 100 üzenet lesz elküldve az új tagok számára.";
|
||||
|
||||
@@ -5466,6 +5478,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"Use servers" = "Kiszolgálók használata";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use short links (BETA)" = "Rövid hivatkozások használata (béta)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "SimpleX Chat-kiszolgálók használata?";
|
||||
|
||||
|
||||
@@ -4751,6 +4751,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"Share with contacts" = "Condividi con i contatti";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Short link" = "Link breve";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show → on messages sent via private routing." = "Mostra → nei messaggi inviati via instradamento privato.";
|
||||
|
||||
@@ -4793,6 +4796,9 @@ chat item action */
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX address or 1-time link?" = "Indirizzo SimpleX o link una tantum?";
|
||||
|
||||
/* simplex link type */
|
||||
"SimpleX channel link" = "Link del canale SimpleX";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "SimpleX Chat e Flux hanno concluso un accordo per includere server gestiti da Flux nell'app.";
|
||||
|
||||
@@ -5181,6 +5187,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"This is your own SimpleX address!" = "Questo è il tuo indirizzo SimpleX!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Questo link richiede una versione più recente dell'app. Aggiornala o chiedi al tuo contatto di inviare un link compatibile.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This link was used with another mobile device, please create a new link on the desktop." = "Questo link è stato usato con un altro dispositivo mobile, creane uno nuovo sul desktop.";
|
||||
|
||||
@@ -5373,6 +5382,9 @@ report reason */
|
||||
/* swipe action */
|
||||
"Unread" = "Non letto";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unsupported connection link" = "Link di connessione non supportato";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Up to 100 last messages are sent to new members." = "Vengono inviati ai nuovi membri fino a 100 ultimi messaggi.";
|
||||
|
||||
@@ -5466,6 +5478,9 @@ report reason */
|
||||
/* No comment provided by engineer. */
|
||||
"Use servers" = "Usa i server";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use short links (BETA)" = "Usa link brevi (BETA)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "Usare i server di SimpleX Chat?";
|
||||
|
||||
|
||||
@@ -2372,4 +2372,8 @@
|
||||
<string name="short_link_button_text">رابط قصير</string>
|
||||
<string name="simplex_link_channel">رابط قناة SimpleX</string>
|
||||
<string name="unsupported_connection_link">رابط اتصال غير مدعوم</string>
|
||||
<string name="network_smp_web_port_preset_footer">استخدم منفذ TCP 443 للخوادم المُعدة مسبقًا فقط.</string>
|
||||
<string name="network_smp_web_port_off">إيقاف التشغيل</string>
|
||||
<string name="network_smp_web_port_preset">الخوادم المُعدة مسبقًا</string>
|
||||
<string name="network_smp_web_port_all">جميع الخوادم</string>
|
||||
</resources>
|
||||
|
||||
@@ -2349,4 +2349,8 @@
|
||||
<string name="privacy_short_links">Emprar enllaços curts (BETA)</string>
|
||||
<string name="full_link_button_text">Enllaç complet</string>
|
||||
<string name="short_link_button_text">Enllaç curt</string>
|
||||
<string name="network_smp_web_port_all">Tots els servidors</string>
|
||||
<string name="network_smp_web_port_off">Apagat</string>
|
||||
<string name="network_smp_web_port_preset_footer">Feu servir el port TCP 443 només per a servidors predefinits.</string>
|
||||
<string name="network_smp_web_port_preset">Servidors predefinits</string>
|
||||
</resources>
|
||||
|
||||
@@ -446,7 +446,7 @@
|
||||
<string name="integrity_msg_bad_id">špatné ID zprávy</string>
|
||||
<string name="integrity_msg_duplicate">duplicitní zpráva</string>
|
||||
<string name="alert_title_skipped_messages">Přeskočené zprávy</string>
|
||||
<string name="privacy_and_security">Ochrana osobních údajů a zabezpečení</string>
|
||||
<string name="privacy_and_security">Soukromí a zabezpečení</string>
|
||||
<string name="your_privacy">Vaše soukromí</string>
|
||||
<string name="protect_app_screen">Skrývat aplikaci</string>
|
||||
<string name="send_link_previews">Odesílat náhledy odkazů</string>
|
||||
@@ -2251,7 +2251,7 @@
|
||||
<string name="one_hand_ui_card_title">Přepnout chat seznam:</string>
|
||||
<string name="change_automatic_chat_deletion_message">Tuto akci nelze zrušit - zprávy odeslané a přijaté v tomto chatu dříve než vybraná, budou smazány.</string>
|
||||
<string name="servers_info_reset_stats_alert_message">Statistiky serverů budou obnoveny - nemůže být vráceno!</string>
|
||||
<string name="v6_3_reports">Odeslat soukromý report</string>
|
||||
<string name="v6_3_reports">Odešlete soukromý report</string>
|
||||
<string name="v6_3_reports_descr">Pomozte administrátorům moderovat své skupiny.</string>
|
||||
<string name="v6_3_faster_deletion_of_groups">Rychlejší mazání skupin.</string>
|
||||
<string name="servers_info_starting_from">Od %s.</string>
|
||||
@@ -2335,7 +2335,7 @@
|
||||
<string name="moderate_messages_will_be_deleted_warning">Zprávy budou smazány pro všechny členy.</string>
|
||||
<string name="app_will_ask_to_confirm_unknown_file_servers">Aplikace vyžaduje potvrzení stahování z neznámých serverů (s výjimkou .onion nebo při aktivaci SOCKS proxy).</string>
|
||||
<string name="you_need_to_allow_calls">Musíte povolit kontaktům volání, abyste jim mohli zavolat.</string>
|
||||
<string name="v6_3_set_message_expiration_in_chats">Nastavit expirace zpráv.</string>
|
||||
<string name="v6_3_set_message_expiration_in_chats">Nastavení expirace zpráv.</string>
|
||||
<string name="subscription_percentage">Zobrazit procenta</string>
|
||||
<string name="migrate_from_device_uploaded_archive_will_be_removed">Nahraný archiv databáze bude ze serverů trvale odstraněn.</string>
|
||||
<string name="to_protect_against_your_link_replaced_compare_codes">Pro ochranu před záměnou odkazů, můžete porovnat bezpečnostní kódy.</string>
|
||||
@@ -2370,4 +2370,14 @@
|
||||
<string name="onboarding_conditions_configure_server_operators">Nastavit operátora serveru</string>
|
||||
<string name="onboarding_conditions_privacy_policy_and_conditions_of_use">Zásady ochrany soukromí a podmínky používání.</string>
|
||||
<string name="onboarding_conditions_private_chats_not_accessible">Soukromé konverzace, skupiny a kontakty nejsou přístupné provozovatelům serverů.</string>
|
||||
<string name="unsupported_connection_link">Nepodporovaný odkaz k připojení</string>
|
||||
<string name="privacy_short_links">Používejte krátké odkazy (BETA)</string>
|
||||
<string name="link_requires_newer_app_version_please_upgrade">Tento odkaz vyžaduje novější verzi aplikace. Prosím aktualizujte aplikaci nebo požádejte kontakt o odeslání kompatibilního odkazu.</string>
|
||||
<string name="simplex_link_channel">odkaz SimpleX kanálu</string>
|
||||
<string name="full_link_button_text">Úplný odkaz</string>
|
||||
<string name="short_link_button_text">Krátký odkaz</string>
|
||||
<string name="network_smp_web_port_all">Všechny servery</string>
|
||||
<string name="network_smp_web_port_off">Vypnut</string>
|
||||
<string name="network_smp_web_port_preset">Přednastavené servery</string>
|
||||
<string name="network_smp_web_port_preset_footer">Použít TCP port 443 jen pro přednastavené servery.</string>
|
||||
</resources>
|
||||
|
||||
@@ -2453,9 +2453,13 @@
|
||||
<string name="onboarding_conditions_configure_server_operators">Server-Betreiber konfigurieren</string>
|
||||
<string name="onboarding_conditions_private_chats_not_accessible">Private Chats, Gruppen und Ihre Kontakte sind für Server-Betreiber nicht zugänglich.</string>
|
||||
<string name="unsupported_connection_link">Verbindungs-Link wird nicht unterstützt</string>
|
||||
<string name="privacy_short_links">Verkürzte Links verwenden (BETA)</string>
|
||||
<string name="privacy_short_links">Kurze Links verwenden (BETA)</string>
|
||||
<string name="short_link_button_text">Verkürzter Link</string>
|
||||
<string name="full_link_button_text">Vollständiger Link</string>
|
||||
<string name="simplex_link_channel">SimpleX-Kanal-Link</string>
|
||||
<string name="link_requires_newer_app_version_please_upgrade">Für diesen Link wird eine neuere App-Version benötigt. Bitte aktualisieren Sie die App oder bitten Sie Ihren Kontakt einen kompatiblen Link zu senden.</string>
|
||||
<string name="network_smp_web_port_all">Alle Server</string>
|
||||
<string name="network_smp_web_port_off">Aus</string>
|
||||
<string name="network_smp_web_port_preset_footer">Für voreingestellte Server nur TCP-Port 443 verwenden .</string>
|
||||
<string name="network_smp_web_port_preset">Voreingestellte Server</string>
|
||||
</resources>
|
||||
|
||||
@@ -2383,4 +2383,8 @@
|
||||
<string name="link_requires_newer_app_version_please_upgrade">Este enlace requiere una versión más reciente de la aplicación. Por favor, actualiza la aplicación o pide a tu contacto un enlace compatible.</string>
|
||||
<string name="unsupported_connection_link">Enlace de conexión no compatible</string>
|
||||
<string name="privacy_short_links">Usar enlaces cortos (BETA)</string>
|
||||
<string name="network_smp_web_port_preset_footer">Usar puerto TCP 443 solo en servidores predefinidos.</string>
|
||||
<string name="network_smp_web_port_all">Todos los servidores</string>
|
||||
<string name="network_smp_web_port_preset">Servidores predefinidos</string>
|
||||
<string name="network_smp_web_port_off">No</string>
|
||||
</resources>
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
<string name="allow_verb">Engedélyezés</string>
|
||||
<string name="bad_desktop_address">Érvénytelen számítógépcím</string>
|
||||
<string name="users_add">Profil hozzáadása</string>
|
||||
<string name="attach">Csatolás</string>
|
||||
<string name="attach">Mellékelés</string>
|
||||
<string name="v5_0_app_passcode">Alkalmazás jelkód</string>
|
||||
<string name="icon_descr_asked_to_receive">Felkérték a kép fogadására</string>
|
||||
<string name="use_camera_button">Kamera</string>
|
||||
@@ -658,7 +658,7 @@
|
||||
<string name="image_descr">Kép</string>
|
||||
<string name="files_are_prohibited_in_group">A fájlok- és a médiatartalmak küldése le van tiltva.</string>
|
||||
<string name="how_it_works">Hogyan működik</string>
|
||||
<string name="hide_dev_options">Elrejtés:</string>
|
||||
<string name="hide_dev_options">Elrejtve:</string>
|
||||
<string name="error_creating_member_contact">Hiba történt a partnerrel történő kapcsolat létrehozásában</string>
|
||||
<string name="enter_one_ICE_server_per_line">ICE-kiszolgálók (soronként egy)</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link"><![CDATA[Ha nem tud személyesen találkozni, <b>beolvashatja a QR-kódot a videohívásban</b>, vagy a partnere megoszthat egy meghívási hivatkozást.]]></string>
|
||||
@@ -1122,7 +1122,7 @@
|
||||
<string name="verify_security_code">Biztonsági kód hitelesítése</string>
|
||||
<string name="rcv_group_event_user_deleted">eltávolította Önt</string>
|
||||
<string name="simplex_address">SimpleX-cím</string>
|
||||
<string name="show_dev_options">Megjelenítés:</string>
|
||||
<string name="show_dev_options">Megjelenítve:</string>
|
||||
<string name="callstate_received_answer">válasz fogadása…</string>
|
||||
<string name="restore_database_alert_title">Visszaállítja az adatbázismentést?</string>
|
||||
<string name="simplex_service_notification_text">Üzenetek fogadása…</string>
|
||||
@@ -1175,7 +1175,7 @@
|
||||
<string name="icon_descr_sent_msg_status_sent">elküldve</string>
|
||||
<string name="network_socks_toggle_use_socks_proxy">SOCKS-proxy használata</string>
|
||||
<string name="send_live_message">Élő üzenet küldése</string>
|
||||
<string name="privacy_redefined">Adatvédelem újraértelmezve</string>
|
||||
<string name="privacy_redefined">Újraértelmezett adatvédelem</string>
|
||||
<string name="voice_message_send_text">Hangüzenet…</string>
|
||||
<string name="protect_app_screen">Alkalmazás képernyőjének védelme</string>
|
||||
<string name="show_QR_code">QR-kód megjelenítése</string>
|
||||
@@ -2350,4 +2350,8 @@
|
||||
<string name="full_link_button_text">Teljes hivatkozás</string>
|
||||
<string name="link_requires_newer_app_version_please_upgrade">Ez a hivatkozás újabb alkalmazásverziót igényel. Frissítse az alkalmazást vagy kérjen egy kompatibilis hivatkozást a partnerétől.</string>
|
||||
<string name="simplex_link_channel">SimpleX-csatornahivatkozás</string>
|
||||
<string name="network_smp_web_port_all">Összes kiszolgáló</string>
|
||||
<string name="network_smp_web_port_off">Kikapcsolva</string>
|
||||
<string name="network_smp_web_port_preset">Előre beállított kiszolgálók</string>
|
||||
<string name="network_smp_web_port_preset_footer">A 443-as TCP-port használata kizárólag az előre beállított kiszolgálokhoz.</string>
|
||||
</resources>
|
||||
|
||||
@@ -2349,4 +2349,14 @@
|
||||
<string name="onboarding_conditions_privacy_policy_and_conditions_of_use">Kebijakan privasi dan ketentuan penggunaan.</string>
|
||||
<string name="onboarding_conditions_private_chats_not_accessible">Obrolan pribadi, grup, dan kontak Anda tidak dapat diakses oleh operator server.</string>
|
||||
<string name="restore_passphrase_can_not_be_read_enter_manually_desc">Frasa sandi di Keystore tidak dapat dibaca, silakan masukkan secara manual. Hal ini mungkin terjadi setelah pembaruan sistem yang tidak kompatibel dengan aplikasi. Jika tidak demikian, silakan hubungi pengembang.</string>
|
||||
<string name="network_smp_web_port_preset_footer">Gunakan port TCP 443 hanya untuk presetel server.</string>
|
||||
<string name="network_smp_web_port_all">Semua server</string>
|
||||
<string name="network_smp_web_port_off">Mati</string>
|
||||
<string name="network_smp_web_port_preset">Presetel server</string>
|
||||
<string name="full_link_button_text">Tautan lengkap</string>
|
||||
<string name="link_requires_newer_app_version_please_upgrade">Tautan ini perlu versi aplikasi yang baru. Harap perbarui aplikasi atau minta kontak untuk kirim tautan kompatibel.</string>
|
||||
<string name="simplex_link_channel">Tautan saluran SimpleX</string>
|
||||
<string name="privacy_short_links">Gunakan tautan singkat (BETA)</string>
|
||||
<string name="unsupported_connection_link">Tautan koneksi tidak didukung</string>
|
||||
<string name="short_link_button_text">Tautan singkat</string>
|
||||
</resources>
|
||||
|
||||
@@ -2387,4 +2387,8 @@
|
||||
<string name="simplex_link_channel">Link del canale SimpleX</string>
|
||||
<string name="unsupported_connection_link">Link di connessione non supportato</string>
|
||||
<string name="privacy_short_links">Usa link brevi (BETA)</string>
|
||||
<string name="network_smp_web_port_all">Tutti i server</string>
|
||||
<string name="network_smp_web_port_off">Off</string>
|
||||
<string name="network_smp_web_port_preset">Server preimpostati</string>
|
||||
<string name="network_smp_web_port_preset_footer">Usa la porta TCP 443 solo per i server preimpostati.</string>
|
||||
</resources>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<string name="one_time_link_short">1-разове посилання</string>
|
||||
<string name="about_simplex_chat">Про SimpleX Chat</string>
|
||||
<string name="v4_3_improved_server_configuration_desc">Додавайте сервери, скануючи QR-коди.</string>
|
||||
<string name="users_delete_all_chats_deleted">Всі чати і повідомлення будуть видалені - цю дію неможливо скасувати!</string>
|
||||
<string name="users_delete_all_chats_deleted">Усі чати та повідомлення будуть видалені - цю дію неможливо скасувати!</string>
|
||||
<string name="allow_calls_only_if">Дозволити дзвінки тільки за умови, що ваш контакт дозволяє їх.</string>
|
||||
<string name="allow_irreversible_message_deletion_only_if">Дозволити безповоротне видалення повідомлень, тільки якщо ваш контакт дозволяє вам. (24 години)</string>
|
||||
<string name="allow_voice_messages_question">Дозволити голосові повідомлення\?</string>
|
||||
@@ -50,20 +50,20 @@
|
||||
<string name="allow_verb">Дозволити</string>
|
||||
<string name="network_settings">Розширені налаштування мережі</string>
|
||||
<string name="network_enable_socks_info">Отримувати доступ до серверів через SOCKS-проксі на порті %d? Проксі має бути запущено до активації цієї опції.</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Всі ваші контакти залишаться підключеними.</string>
|
||||
<string name="all_app_data_will_be_cleared">Всі дані застосунку буде видалено.</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Усі ваші контакти залишаться підключеними.</string>
|
||||
<string name="all_app_data_will_be_cleared">Усі дані застосунку буде видалено.</string>
|
||||
<string name="keychain_allows_to_receive_ntfs">Після перезапуску додатка або зміни ключової фрази буде використано сховище ключів Android для безпечного збереження ключової фрази - це дозволить отримувати сповіщення.</string>
|
||||
<string name="allow_your_contacts_to_send_voice_messages">Дозвольте вашим контактам надсилати голосові повідомлення.</string>
|
||||
<string name="accept_contact_incognito_button">Прийняти інкогніто</string>
|
||||
<string name="smp_servers_add">Додати сервер</string>
|
||||
<string name="group_member_role_admin">адміністратор</string>
|
||||
<string name="button_add_welcome_message">Додати привітання</string>
|
||||
<string name="all_group_members_will_remain_connected">Всі учасники групи залишаться підключеними.</string>
|
||||
<string name="all_group_members_will_remain_connected">Усі учасники групи залишаться підключеними.</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Дозвольте вашим контактам надсилати повідомлення, які зникають.</string>
|
||||
<string name="clear_chat_warning">Всі повідомлення будуть видалені - цю дію неможливо скасувати! Повідомлення будуть видалені ЛИШЕ для вас.</string>
|
||||
<string name="clear_chat_warning">Усі повідомлення будуть видалені - цю дію неможливо скасувати! Повідомлення будуть видалені ЛИШЕ для вас.</string>
|
||||
<string name="app_version_title">Версія додатку</string>
|
||||
<string name="add_address_to_your_profile">Додайте адресу до свого профілю, щоб ваші контакти могли поділитися нею з іншими людьми. Оновлення профілю буде відправлено вашим контактам.</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Всі ваші контакти залишаться підключеними. Оновлення профілю буде відправлено вашим контактам.</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Усі ваші контакти залишаться підключеними. Оновлення профілю буде відправлено вашим контактам.</string>
|
||||
<string name="answer_call">Відповісти на виклик</string>
|
||||
<string name="address_section_title">Адреса</string>
|
||||
<string name="users_add">Додати профіль</string>
|
||||
@@ -717,7 +717,7 @@
|
||||
<string name="share_text_disappears_at">Зникає о: %s</string>
|
||||
<string name="item_info_current">(поточне)</string>
|
||||
<string name="button_remove_member">Вилучити учасника</string>
|
||||
<string name="member_role_will_be_changed_with_notification">Роль буде змінено на "%s". Всі учасники групи будуть сповіщені.</string>
|
||||
<string name="member_role_will_be_changed_with_notification">Роль буде змінено на %s. Усі учасники групи будуть сповіщені.</string>
|
||||
<string name="member_role_will_be_changed_with_invitation">Роль буде змінено на "%s". Учасник отримає нове запрошення.</string>
|
||||
<string name="info_row_group">Група</string>
|
||||
<string name="group_welcome_title">Привітальне повідомлення</string>
|
||||
@@ -1428,7 +1428,7 @@
|
||||
<string name="connect_plan_you_have_already_requested_connection_via_this_address">Ви вже подали запит на підключення за цією адресою!</string>
|
||||
<string name="member_contact_send_direct_message">надіслати приватне повідомлення</string>
|
||||
<string name="terminal_always_visible">Показувати консоль в новому вікні</string>
|
||||
<string name="block_member_desc">Всі нові повідомлення від %s будуть приховані!</string>
|
||||
<string name="block_member_desc">Усі нові повідомлення від %s будуть приховані!</string>
|
||||
<string name="rcv_group_event_member_created_contact">підключив(лась) безпосередньо</string>
|
||||
<string name="blocked_item_description">заблоковано</string>
|
||||
<string name="v5_4_block_group_members">Блокувати учасників групи</string>
|
||||
@@ -1674,7 +1674,7 @@
|
||||
<string name="migrate_from_device_check_connection_and_try_again">Перевірте підключення до Інтернету та спробуйте ще раз</string>
|
||||
<string name="migrate_from_device_confirm_you_remember_passphrase">Переконайтеся, що ви пам\'ятаєте пароль до бази даних для її перенесення.</string>
|
||||
<string name="migrate_from_device_error_verifying_passphrase">Помилка при перевірці парольної фрази:</string>
|
||||
<string name="migrate_from_device_all_data_will_be_uploaded">Всі ваші контакти, розмови та файли будуть надійно зашифровані та завантажені частинами на налаштовані XFTP-реле.</string>
|
||||
<string name="migrate_from_device_all_data_will_be_uploaded">Усі ваші контакти, розмови та файли будуть надійно зашифровані та завантажені частинами на налаштовані XFTP-реле.</string>
|
||||
<string name="migrate_from_device_using_on_two_device_breaks_encryption"><![CDATA[<b>Please note</b>: використання однієї і тієї ж бази даних на двох пристроях порушить розшифровку повідомлень з ваших з\'єднань, як захист безпеки.]]></string>
|
||||
<string name="migrate_from_device_cancel_migration">Скасувати міграцію</string>
|
||||
<string name="migrate_to_device_chat_migrated">Чат перемістився!</string>
|
||||
@@ -2025,7 +2025,7 @@
|
||||
<string name="proxied">Проксірований</string>
|
||||
<string name="send_errors">Надіслати помилки</string>
|
||||
<string name="completed">Завершено</string>
|
||||
<string name="all_users">Всі профілі</string>
|
||||
<string name="all_users">Усі профілі</string>
|
||||
<string name="servers_info_reset_stats_alert_confirm">Скинути</string>
|
||||
<string name="servers_info_uploaded">Вивантажено</string>
|
||||
<string name="delete_members_messages__question">Видалити %d повідомлень учасників?</string>
|
||||
@@ -2384,4 +2384,8 @@
|
||||
<string name="short_link_button_text">Коротке посилання</string>
|
||||
<string name="simplex_link_channel">Посилання на канал SimpleX</string>
|
||||
<string name="unsupported_connection_link">Несумісне посилання для підключення</string>
|
||||
<string name="network_smp_web_port_all">Усі сервери</string>
|
||||
<string name="network_smp_web_port_off">Ні</string>
|
||||
<string name="network_smp_web_port_preset">Типові сервери</string>
|
||||
<string name="network_smp_web_port_preset_footer">Використовуйте TCP порт 443 лише для попередньо налаштованих серверів.</string>
|
||||
</resources>
|
||||
|
||||
@@ -1263,7 +1263,7 @@
|
||||
<string name="servers_info_subscriptions_connections_pending">Đang chờ xử lý</string>
|
||||
<string name="icon_descr_server_status_pending">Đang chờ xử lý</string>
|
||||
<string name="restore_passphrase_not_found_desc">Không tìm thấy mật khẩu trong Keystore, vui lòng nhập thủ công. Điều này có thể xảy ra nếu bạn khôi phục dữ liệu ứng dụng bằng một công cụ sao lưu. Nếu không phải như vậy, xin vui lòng liên hệ với nhà phát triển.</string>
|
||||
<string name="past_member_vName">Thành viên cũ %1$s</string>
|
||||
<string name="past_member_vName">Thành viên trước đây %1$s</string>
|
||||
<string name="v5_5_simpler_connect_ui">Dán đường dẫn để kết nối!</string>
|
||||
<string name="periodic_notifications">Thông báo định kỳ</string>
|
||||
<string name="paste_the_link_you_received">Dán đường dẫn mà bạn nhận được</string>
|
||||
@@ -2358,4 +2358,8 @@
|
||||
<string name="privacy_short_links">Sử dụng đường dẫn ngắn (BETA)</string>
|
||||
<string name="full_link_button_text">Toàn bộ đường dẫn</string>
|
||||
<string name="short_link_button_text">Đường dẫn ngắn</string>
|
||||
<string name="network_smp_web_port_off">Tắt</string>
|
||||
<string name="network_smp_web_port_preset">Các máy chủ cài sẵn</string>
|
||||
<string name="network_smp_web_port_preset_footer">Chỉ sử dụng cổng TCP 443 cho các máy chủ cài sẵn.</string>
|
||||
<string name="network_smp_web_port_all">Tất cả máy chủ</string>
|
||||
</resources>
|
||||
|
||||
@@ -2371,4 +2371,8 @@
|
||||
<string name="short_link_button_text">短链接</string>
|
||||
<string name="link_requires_newer_app_version_please_upgrade">此链接需要更新的应用版本。请升级应用或请求你的联系人发送相容的链接。</string>
|
||||
<string name="full_link_button_text">完整链接</string>
|
||||
<string name="network_smp_web_port_all">全部服务器</string>
|
||||
<string name="network_smp_web_port_off">关闭</string>
|
||||
<string name="network_smp_web_port_preset">预设服务器</string>
|
||||
<string name="network_smp_web_port_preset_footer">仅预设服务器使用 TCP 协议 443 端口。</string>
|
||||
</resources>
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: a632eea75b677cf2b146ad06ee875307d0321f23
|
||||
tag: deaec3cce286e959bd594b9620c307954b510a07
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"https://github.com/simplex-chat/simplexmq.git"."a632eea75b677cf2b146ad06ee875307d0321f23" = "03vk7214941f5jwmf7sp26lxzh4c1xl89wqmlky379d6gwypbzy6";
|
||||
"https://github.com/simplex-chat/simplexmq.git"."deaec3cce286e959bd594b9620c307954b510a07" = "0b8m4czjiwsi9169plslyk2rjw0f370vv7ha6qm2hpx14bxzz7xm";
|
||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
||||
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplex-chat
|
||||
version: 6.3.3.1
|
||||
version: 6.3.4.0
|
||||
category: Web, System, Services, Cryptography
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
author: simplex.chat
|
||||
|
||||
@@ -716,7 +716,7 @@ data ChatResponse
|
||||
| CRNtfTokenStatus {status :: NtfTknStatus}
|
||||
| CRNtfToken {token :: DeviceToken, status :: NtfTknStatus, ntfMode :: NotificationsMode, ntfServer :: NtfServer}
|
||||
| CRNtfConns {ntfConns :: [NtfConn]}
|
||||
| CRConnNtfMessages {receivedMsgs :: NonEmpty (Maybe NtfMsgInfo)}
|
||||
| CRConnNtfMessages {receivedMsgs :: NonEmpty RcvNtfMsgInfo}
|
||||
| CRContactConnectionDeleted {user :: User, connection :: PendingContactConnection}
|
||||
| CRRemoteHostList {remoteHosts :: [RemoteHostInfo]}
|
||||
| CRCurrentRemoteHost {remoteHost_ :: Maybe RemoteHostInfo}
|
||||
@@ -1147,13 +1147,20 @@ data NtfConn = NtfConn
|
||||
}
|
||||
deriving (Show)
|
||||
|
||||
-- brokerTs is the same msgTs, it is used in ConnMsgReq / APIGetConnNtfMessages
|
||||
-- msgTs is broker message timestamp, it is used in ConnMsgReq / APIGetConnNtfMessages
|
||||
-- to set it as last connection message in case queue is empty
|
||||
data NtfMsgInfo = NtfMsgInfo {msgId :: Text, msgTs :: UTCTime}
|
||||
deriving (Show)
|
||||
|
||||
receivedMsgInfo :: SMPMsgMeta -> NtfMsgInfo
|
||||
receivedMsgInfo SMPMsgMeta {msgId, msgTs} = ntfMsgInfo_ msgId msgTs
|
||||
data RcvNtfMsgInfo
|
||||
= RNMInfo {ntfMsgInfo :: Maybe NtfMsgInfo}
|
||||
| RNMError {ntfMsgError :: AgentErrorType}
|
||||
deriving (Show)
|
||||
|
||||
receivedMsgInfo :: Either AgentErrorType (Maybe SMPMsgMeta) -> RcvNtfMsgInfo
|
||||
receivedMsgInfo = \case
|
||||
Right msgMeta_ -> RNMInfo $ (\SMPMsgMeta {msgId, msgTs} -> ntfMsgInfo_ msgId msgTs) <$> msgMeta_
|
||||
Left e -> RNMError e
|
||||
|
||||
expectedMsgInfo :: NMsgMeta -> NtfMsgInfo
|
||||
expectedMsgInfo NMsgMeta {msgId, msgTs} = ntfMsgInfo_ msgId msgTs
|
||||
@@ -1650,6 +1657,8 @@ $(JQ.deriveJSON defaultJSON ''UserProfileUpdateSummary)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''NtfMsgInfo)
|
||||
|
||||
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "RNM") ''RcvNtfMsgInfo)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''NtfConn)
|
||||
|
||||
$(JQ.deriveJSON defaultJSON ''NtfMsgAckInfo)
|
||||
|
||||
@@ -1319,7 +1319,7 @@ processChatCommand' vr = \case
|
||||
$>>= \user -> fmap (mkNtfConn user) . eitherToMaybe <$> runExceptT (getConnectionEntity db vr user agentConnId)
|
||||
APIGetConnNtfMessages connMsgs -> withUser $ \_ -> do
|
||||
msgs <- lift $ withAgent' (`getConnectionMessages` connMsgs)
|
||||
let ntfMsgs = L.map (receivedMsgInfo <$>) msgs
|
||||
let ntfMsgs = L.map receivedMsgInfo msgs
|
||||
pure $ CRConnNtfMessages ntfMsgs
|
||||
GetUserProtoServers (AProtocolType p) -> withUser $ \user -> withServerProtocol p $ do
|
||||
srvs <- withFastStore (`getUserServers` user)
|
||||
|
||||
@@ -75,11 +75,11 @@ remoteFilesFolder = "simplex_v1_files"
|
||||
|
||||
-- when acting as host
|
||||
minRemoteCtrlVersion :: AppVersion
|
||||
minRemoteCtrlVersion = AppVersion [6, 3, 3, 1]
|
||||
minRemoteCtrlVersion = AppVersion [6, 3, 4, 0]
|
||||
|
||||
-- when acting as controller
|
||||
minRemoteHostVersion :: AppVersion
|
||||
minRemoteHostVersion = AppVersion [6, 3, 3, 1]
|
||||
minRemoteHostVersion = AppVersion [6, 3, 4, 0]
|
||||
|
||||
currentAppVersion :: AppVersion
|
||||
currentAppVersion = AppVersion SC.version
|
||||
|
||||
Reference in New Issue
Block a user