mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-10-25 07:41:41 +00:00
Merge 77fa81bccc7921834806b241ead452bda72e4e7a into 9b84b361225facd8e623f25d76f889d3dc54a879
This commit is contained in:
commit
708b7fbd85
@ -13579,6 +13579,936 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"thread.search.accessibility.label" : {
|
||||
"comment" : "Accessibility label for in-thread message search",
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ابحث في رسائل هذه المحادثة"
|
||||
}
|
||||
},
|
||||
"bn" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "এই কথোপকথনের বার্তা খোঁজো"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "nachrichten in dieser unterhaltung durchsuchen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "search messages in this conversation"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "buscar mensajes en esta conversación"
|
||||
}
|
||||
},
|
||||
"fa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "جستجوی پیامهای این گفتگو"
|
||||
}
|
||||
},
|
||||
"fil" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "maghanap ng mensahe sa usapang ito"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "rechercher des messages dans cette conversation"
|
||||
}
|
||||
},
|
||||
"he" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "חיפוש הודעות בשיחה הזו"
|
||||
}
|
||||
},
|
||||
"hi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "इस बातचीत के संदेश खोजें"
|
||||
}
|
||||
},
|
||||
"id" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "cari pesan di percakapan ini"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "cerca messaggi in questa conversazione"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "この会話のメッセージを検索"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "이 대화의 메시지 검색"
|
||||
}
|
||||
},
|
||||
"ms" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "cari mesej dalam perbualan ini"
|
||||
}
|
||||
},
|
||||
"ne" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "यो कुराकानीका सन्देश खोज्नुहोस्"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "berichten in dit gesprek zoeken"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "szukaj wiadomości w tej rozmowie"
|
||||
}
|
||||
},
|
||||
"pt" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "pesquisar mensagens nesta conversa"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "buscar mensagens nesta conversa"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "искать сообщения в этой переписке"
|
||||
}
|
||||
},
|
||||
"sv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "sök meddelanden i den här konversationen"
|
||||
}
|
||||
},
|
||||
"ta" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "இந்த உரையாடலின் செய்திகளைத் தேடு"
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ค้นหาข้อความในบทสนทนานี้"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "bu sohbetteki mesajlarda ara"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "шукати повідомлення в цій розмові"
|
||||
}
|
||||
},
|
||||
"ur" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "اس گفتگو کے پیغامات تلاش کریں"
|
||||
}
|
||||
},
|
||||
"vi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "tìm tin nhắn trong cuộc trò chuyện này"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "搜索此对话中的消息"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "搜尋此對話中的訊息"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"thread.search.close" : {
|
||||
"comment" : "Accessibility label for the button that closes the in-thread search field",
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "إغلاق البحث"
|
||||
}
|
||||
},
|
||||
"bn" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "খোঁজা বন্ধ করো"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "suche schließen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "close search"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "cerrar búsqueda"
|
||||
}
|
||||
},
|
||||
"fa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "بستن جستجو"
|
||||
}
|
||||
},
|
||||
"fil" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "isara ang paghahanap"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "fermer la recherche"
|
||||
}
|
||||
},
|
||||
"he" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "סגירת החיפוש"
|
||||
}
|
||||
},
|
||||
"hi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "खोज बंद करें"
|
||||
}
|
||||
},
|
||||
"id" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "tutup pencarian"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "chiudi ricerca"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "検索を閉じる"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "검색 닫기"
|
||||
}
|
||||
},
|
||||
"ms" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "tutup carian"
|
||||
}
|
||||
},
|
||||
"ne" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "खोज बन्द गर्नुहोस्"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "zoeken sluiten"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "zamknij wyszukiwanie"
|
||||
}
|
||||
},
|
||||
"pt" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "fechar pesquisa"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "fechar busca"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "закрыть поиск"
|
||||
}
|
||||
},
|
||||
"sv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "stäng sökning"
|
||||
}
|
||||
},
|
||||
"ta" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "தேடலை மூடு"
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ปิดการค้นหา"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "aramayı kapat"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "закрити пошук"
|
||||
}
|
||||
},
|
||||
"ur" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "تلاش بند کریں"
|
||||
}
|
||||
},
|
||||
"vi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "đóng tìm kiếm"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "关闭搜索"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "關閉搜尋"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"thread.search.no_results" : {
|
||||
"comment" : "Empty state when in-thread search finds no matching messages",
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "لا توجد رسائل تطابق بحثك"
|
||||
}
|
||||
},
|
||||
"bn" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "তোমার খোঁজের সাথে কোনো বার্তা মেলেনি"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "keine nachrichten passen zu deiner suche"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "no messages match your search"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ningún mensaje coincide con tu búsqueda"
|
||||
}
|
||||
},
|
||||
"fa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "پیامی با جستجوی شما همخوانی ندارد"
|
||||
}
|
||||
},
|
||||
"fil" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "walang mensaheng tumutugma sa paghahanap mo"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "aucun message ne correspond à ta recherche"
|
||||
}
|
||||
},
|
||||
"he" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "אין הודעות שתואמות לחיפוש"
|
||||
}
|
||||
},
|
||||
"hi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "आपकी खोज से कोई संदेश मेल नहीं खाता"
|
||||
}
|
||||
},
|
||||
"id" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "tidak ada pesan yang cocok"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "nessun messaggio corrisponde alla ricerca"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "検索に一致するメッセージはありません"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "검색과 일치하는 메시지가 없습니다"
|
||||
}
|
||||
},
|
||||
"ms" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "tiada mesej sepadan dengan carian anda"
|
||||
}
|
||||
},
|
||||
"ne" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "तपाईंको खोजसँग मिल्ने सन्देश छैन"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "geen berichten komen overeen met je zoekopdracht"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "żadna wiadomość nie pasuje do wyszukiwania"
|
||||
}
|
||||
},
|
||||
"pt" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "nenhuma mensagem corresponde à tua pesquisa"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "nenhuma mensagem corresponde à sua busca"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "нет сообщений по вашему запросу"
|
||||
}
|
||||
},
|
||||
"sv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "inga meddelanden matchar din sökning"
|
||||
}
|
||||
},
|
||||
"ta" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "உங்கள் தேடலுக்கு பொருந்தும் செய்திகள் இல்லை"
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ไม่มีข้อความที่ตรงกับการค้นหา"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "aramanla eşleşen mesaj yok"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "немає повідомлень за вашим запитом"
|
||||
}
|
||||
},
|
||||
"ur" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "آپ کی تلاش سے کوئی پیغام میل نہیں کھاتا"
|
||||
}
|
||||
},
|
||||
"vi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "không có tin nhắn nào khớp với tìm kiếm"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "没有匹配的消息"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "沒有相符的訊息"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"thread.search.placeholder" : {
|
||||
"comment" : "Placeholder for the in-thread message search field",
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ابحث في هذه المحادثة"
|
||||
}
|
||||
},
|
||||
"bn" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "এই কথোপকথনে খোঁজো"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "diese unterhaltung durchsuchen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "search this conversation"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "buscar en esta conversación"
|
||||
}
|
||||
},
|
||||
"fa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "در این گفتگو جستجو کنید"
|
||||
}
|
||||
},
|
||||
"fil" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "maghanap sa usapang ito"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "rechercher dans cette conversation"
|
||||
}
|
||||
},
|
||||
"he" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "חיפוש בשיחה הזו"
|
||||
}
|
||||
},
|
||||
"hi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "इस बातचीत में खोजें"
|
||||
}
|
||||
},
|
||||
"id" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "cari di percakapan ini"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "cerca in questa conversazione"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "この会話を検索"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "이 대화 검색"
|
||||
}
|
||||
},
|
||||
"ms" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "cari dalam perbualan ini"
|
||||
}
|
||||
},
|
||||
"ne" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "यो कुराकानीमा खोज्नुहोस्"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "in dit gesprek zoeken"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "szukaj w tej rozmowie"
|
||||
}
|
||||
},
|
||||
"pt" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "pesquisar nesta conversa"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "buscar nesta conversa"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "искать в этой переписке"
|
||||
}
|
||||
},
|
||||
"sv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "sök i den här konversationen"
|
||||
}
|
||||
},
|
||||
"ta" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "இந்த உரையாடலில் தேடு"
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ค้นหาในบทสนทนานี้"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "bu sohbette ara"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "шукати в цій розмові"
|
||||
}
|
||||
},
|
||||
"ur" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "اس گفتگو میں تلاش کریں"
|
||||
}
|
||||
},
|
||||
"vi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "tìm trong cuộc trò chuyện này"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "搜索此对话"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "搜尋此對話"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"thread.search.truncated" : {
|
||||
"comment" : "Shown when in-thread search results were capped; first %lld is the cap, second is the total match count",
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "عرض أحدث %lld من %lld نتيجة"
|
||||
}
|
||||
},
|
||||
"bn" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld টির মধ্যে সর্বশেষ %lld দেখানো হচ্ছে"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "die neuesten %lld von %lld treffern"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "showing the newest %lld of %lld matches"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "mostrando los %lld más recientes de %lld coincidencias"
|
||||
}
|
||||
},
|
||||
"fa" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "نمایش %lld مورد تازه از %lld"
|
||||
}
|
||||
},
|
||||
"fil" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ipinapakita ang pinakabagong %lld sa %lld tugma"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "affichage des %lld correspondances les plus récentes sur %lld"
|
||||
}
|
||||
},
|
||||
"he" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "מוצגות %lld התוצאות האחרונות מתוך %lld"
|
||||
}
|
||||
},
|
||||
"hi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld में से नवीनतम %lld दिखा रहे हैं"
|
||||
}
|
||||
},
|
||||
"id" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "menampilkan %lld terbaru dari %lld kecocokan"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "mostrate le %lld corrispondenze più recenti su %lld"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld 件中、新しい %lld 件を表示"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld개 중 최신 %lld개 표시"
|
||||
}
|
||||
},
|
||||
"ms" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "menunjukkan %lld terbaharu daripada %lld padanan"
|
||||
}
|
||||
},
|
||||
"ne" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld मध्ये नवीनतम %lld देखाइँदै"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "de nieuwste %lld van %lld overeenkomsten"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "pokazano %lld najnowszych z %lld dopasowań"
|
||||
}
|
||||
},
|
||||
"pt" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "a mostrar as %lld correspondências mais recentes de %lld"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "mostrando as %lld correspondências mais recentes de %lld"
|
||||
}
|
||||
},
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "показаны последние %lld из %lld совпадений"
|
||||
}
|
||||
},
|
||||
"sv" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "visar de %lld senaste av %lld träffar"
|
||||
}
|
||||
},
|
||||
"ta" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld இல் புதிய %lld காட்டப்படுகிறது"
|
||||
}
|
||||
},
|
||||
"th" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "แสดง %lld รายการล่าสุดจาก %lld รายการ"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld eşleşmeden en yeni %lld tanesi gösteriliyor"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "показано останні %lld із %lld збігів"
|
||||
}
|
||||
},
|
||||
"ur" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld میں سے تازہ ترین %lld دکھائے جا رہے ہیں"
|
||||
}
|
||||
},
|
||||
"vi" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "hiển thị %lld kết quả mới nhất trong %lld"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "显示 %lld 条匹配中最新的 %lld 条"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "顯示 %lld 條相符中最新的 %lld 條"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notification.nearby.body_many" : {
|
||||
"comment" : "Body of the nearby notification; placeholder is the peer count",
|
||||
"extractionState" : "manual",
|
||||
|
||||
54
bitchat/Utils/ThreadMessageSearch.swift
Normal file
54
bitchat/Utils/ThreadMessageSearch.swift
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// ThreadMessageSearch.swift
|
||||
// bitchat
|
||||
//
|
||||
// Filters the visible timeline for in-thread search.
|
||||
//
|
||||
|
||||
import BitFoundation
|
||||
import Foundation
|
||||
|
||||
enum ThreadMessageSearch {
|
||||
/// Most matches rendered at once.
|
||||
///
|
||||
/// Searching bypasses the message window, so without a cap a common term
|
||||
/// in a long thread renders every match in full history in one pass —
|
||||
/// unbounded work on the main thread. The newest matches are kept, which
|
||||
/// is the end of the thread people are usually looking at.
|
||||
static let resultLimit = 200
|
||||
|
||||
/// Returns messages whose body or sender name contains `query`
|
||||
/// (case-insensitive), newest-biased and capped at `resultLimit`. An empty
|
||||
/// or whitespace-only query returns the original list unchanged.
|
||||
static func matchingMessages(
|
||||
in messages: [BitchatMessage],
|
||||
query: String,
|
||||
limit: Int = ThreadMessageSearch.resultLimit
|
||||
) -> [BitchatMessage] {
|
||||
let trimmed = query.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmed.isEmpty else { return messages }
|
||||
|
||||
let needle = trimmed.lowercased()
|
||||
let matches = messages.filter { message in
|
||||
guard !message.content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
|
||||
return false
|
||||
}
|
||||
if message.content.lowercased().contains(needle) { return true }
|
||||
if message.sender.lowercased().contains(needle) { return true }
|
||||
return false
|
||||
}
|
||||
guard limit > 0, matches.count > limit else { return matches }
|
||||
// Keep the tail: `messages` is oldest-first, so the newest matches are
|
||||
// the ones a reader is most likely to want.
|
||||
return Array(matches.suffix(limit))
|
||||
}
|
||||
|
||||
/// Whether a result set was truncated, so the UI can say so instead of
|
||||
/// quietly showing a partial list.
|
||||
static func didTruncate(
|
||||
matchCount: Int,
|
||||
limit: Int = ThreadMessageSearch.resultLimit
|
||||
) -> Bool {
|
||||
limit > 0 && matchCount > limit
|
||||
}
|
||||
}
|
||||
@ -51,9 +51,15 @@ struct MessageListView: View {
|
||||
/// Whether this instance holds the nearby-notes counter active (mesh
|
||||
/// public timeline only); balanced against activate/deactivate.
|
||||
@State private var holdsNotesCounter = false
|
||||
@State private var threadSearchQuery = ""
|
||||
@State private var isThreadSearchFieldVisible = false
|
||||
|
||||
@ThemedPalette private var palette
|
||||
|
||||
private var isThreadSearching: Bool {
|
||||
!threadSearchQuery.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let currentWindowCount: Int = {
|
||||
if let peer = privatePeer {
|
||||
@ -62,8 +68,20 @@ struct MessageListView: View {
|
||||
return windowCountPublic
|
||||
}()
|
||||
|
||||
let messages = conversationMessages(for: privatePeer)
|
||||
let windowedMessages = Array(messages.suffix(currentWindowCount))
|
||||
let allMessages = conversationMessages(for: privatePeer)
|
||||
// Uncapped so the count is known, then capped for rendering — a common
|
||||
// term in a long thread would otherwise render every historical match
|
||||
// in one pass.
|
||||
let searchMatches: [BitchatMessage] = isThreadSearching
|
||||
? ThreadMessageSearch.matchingMessages(in: allMessages, query: threadSearchQuery, limit: 0)
|
||||
: []
|
||||
let searchTruncated = ThreadMessageSearch.didTruncate(matchCount: searchMatches.count)
|
||||
let displayedMessages: [BitchatMessage] = {
|
||||
if isThreadSearching {
|
||||
return Array(searchMatches.suffix(ThreadMessageSearch.resultLimit))
|
||||
}
|
||||
return Array(allMessages.suffix(currentWindowCount))
|
||||
}()
|
||||
|
||||
let contextKey: String = {
|
||||
if let peer = privatePeer {
|
||||
@ -73,12 +91,16 @@ struct MessageListView: View {
|
||||
}
|
||||
}()
|
||||
|
||||
let messageItems: [MessageDisplayItem] = windowedMessages.compactMap { message in
|
||||
let messageItems: [MessageDisplayItem] = displayedMessages.compactMap { message in
|
||||
guard !message.content.trimmed.isEmpty else { return nil }
|
||||
return MessageDisplayItem(id: "\(contextKey)|\(message.id)", message: message)
|
||||
}
|
||||
|
||||
VStack(spacing: 0) {
|
||||
threadSearchBar
|
||||
if searchTruncated {
|
||||
threadSearchTruncationNotice(matchCount: searchMatches.count)
|
||||
}
|
||||
// Notes pinned to this place stay visible while chatting — a
|
||||
// conversation starting must not hide what's left here.
|
||||
if privatePeer == nil,
|
||||
@ -89,30 +111,33 @@ struct MessageListView: View {
|
||||
GeometryReader { geometry in
|
||||
ScrollViewReader { proxy in
|
||||
ScrollView {
|
||||
if messageItems.isEmpty && privatePeer == nil {
|
||||
if messageItems.isEmpty && privatePeer == nil && !isThreadSearching {
|
||||
publicEmptyState(fillHeight: geometry.size.height)
|
||||
} else if messageItems.isEmpty && isThreadSearching {
|
||||
threadSearchEmptyState(fillHeight: geometry.size.height)
|
||||
}
|
||||
LazyVStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(messageItems) { item in
|
||||
let message = item.message
|
||||
messageRow(for: message)
|
||||
.onAppear {
|
||||
if message.id == windowedMessages.last?.id {
|
||||
if message.id == displayedMessages.last?.id {
|
||||
isAtBottom = true
|
||||
unseenCount = 0
|
||||
}
|
||||
if message.id == windowedMessages.first?.id,
|
||||
messages.count > windowedMessages.count {
|
||||
if !isThreadSearching,
|
||||
message.id == displayedMessages.first?.id,
|
||||
allMessages.count > displayedMessages.count {
|
||||
expandWindow(
|
||||
ifNeededFor: message,
|
||||
allMessages: messages,
|
||||
allMessages: allMessages,
|
||||
privatePeer: privatePeer,
|
||||
proxy: proxy
|
||||
)
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
if message.id == windowedMessages.last?.id {
|
||||
if message.id == displayedMessages.last?.id {
|
||||
isAtBottom = false
|
||||
}
|
||||
}
|
||||
@ -278,8 +303,14 @@ struct MessageListView: View {
|
||||
}
|
||||
.onAppear { updateNotesCounterHold() }
|
||||
.onDisappear { releaseNotesCounterHold() }
|
||||
.onChange(of: locationChannelsModel.selectedChannel) { _ in updateNotesCounterHold() }
|
||||
.onChange(of: privatePeer) { _ in updateNotesCounterHold() }
|
||||
.onChange(of: locationChannelsModel.selectedChannel) { _ in
|
||||
resetThreadSearch()
|
||||
updateNotesCounterHold()
|
||||
}
|
||||
.onChange(of: privatePeer) { _ in
|
||||
resetThreadSearch()
|
||||
updateNotesCounterHold()
|
||||
}
|
||||
.environment(\.openURL, OpenURLAction { url in
|
||||
// Intercept custom cashu: links created in attributed text
|
||||
if let scheme = url.scheme?.lowercased(), scheme == "cashu" || scheme == "lightning" {
|
||||
@ -403,6 +434,17 @@ private extension MessageListView {
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
func threadSearchEmptyState(fillHeight: CGFloat) -> some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
emptyStateLine(
|
||||
String(localized: "thread.search.no_results", comment: "Empty state when in-thread search finds no matching messages")
|
||||
)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.top, 12)
|
||||
.frame(maxWidth: .infinity, minHeight: max(0, fillHeight - 24), alignment: .topLeading)
|
||||
}
|
||||
|
||||
func emptyStateLine(_ text: String) -> some View {
|
||||
// Non-breaking space before the closing asterisk so a tight wrap
|
||||
// can't orphan a lone "*" onto its own line.
|
||||
@ -506,6 +548,109 @@ private extension MessageListView {
|
||||
return "\(base), \(count)"
|
||||
}
|
||||
|
||||
/// Search is per-conversation: switching threads drops the query and the
|
||||
/// field so a stale filter never applies to a different conversation.
|
||||
func resetThreadSearch() {
|
||||
threadSearchQuery = ""
|
||||
isThreadSearchFieldVisible = false
|
||||
}
|
||||
|
||||
/// Says plainly that older matches are not shown, rather than presenting a
|
||||
/// capped list as if it were everything.
|
||||
@ViewBuilder
|
||||
func threadSearchTruncationNotice(matchCount: Int) -> some View {
|
||||
Text(
|
||||
String(
|
||||
format: String(
|
||||
localized: "thread.search.truncated",
|
||||
defaultValue: "showing the newest %lld of %lld matches",
|
||||
comment: "Shown when in-thread search results were capped; first %lld is the cap, second is the total match count"
|
||||
),
|
||||
locale: .current,
|
||||
ThreadMessageSearch.resultLimit,
|
||||
matchCount
|
||||
)
|
||||
)
|
||||
.bitchatFont(size: 11)
|
||||
.foregroundColor(palette.secondary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.bottom, 4)
|
||||
}
|
||||
|
||||
/// Collapsed affordance plus the expanded field. Kept inside the message
|
||||
/// list so the feature needs no changes to either header, and so the same
|
||||
/// code serves the public timeline and the DM sheet.
|
||||
@ViewBuilder
|
||||
var threadSearchBar: some View {
|
||||
if isThreadSearchFieldVisible {
|
||||
threadSearchField
|
||||
} else {
|
||||
HStack {
|
||||
Spacer()
|
||||
Button {
|
||||
isThreadSearchFieldVisible = true
|
||||
} label: {
|
||||
Image(systemName: "magnifyingglass")
|
||||
.font(.bitchatSystem(size: 12))
|
||||
.foregroundColor(palette.secondary)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(
|
||||
String(localized: "thread.search.accessibility.label", comment: "Accessibility label for in-thread message search")
|
||||
)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
}
|
||||
|
||||
/// Inline search field for the current conversation.
|
||||
///
|
||||
/// Deliberately not `.searchable`: that modifier only renders inside a
|
||||
/// `NavigationStack`/`NavigationSplitView`, and the public timeline
|
||||
/// (`ContentView` → `MessageListView`) has no navigation ancestor, so the
|
||||
/// field silently did not appear where most conversation happens. A plain
|
||||
/// field has no such dependency and renders identically in both placements.
|
||||
@ViewBuilder
|
||||
var threadSearchField: some View {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "magnifyingglass")
|
||||
.font(.bitchatSystem(size: 12))
|
||||
.foregroundColor(palette.secondary)
|
||||
TextField(
|
||||
String(localized: "thread.search.placeholder", comment: "Placeholder for the in-thread message search field"),
|
||||
text: $threadSearchQuery
|
||||
)
|
||||
.textFieldStyle(.plain)
|
||||
.bitchatFont(size: 13)
|
||||
.foregroundColor(palette.primary)
|
||||
.autocorrectionDisabled(true)
|
||||
#if os(iOS)
|
||||
.textInputAutocapitalization(.never)
|
||||
#endif
|
||||
// Scoped to the field: applying this to the list chain relabelled
|
||||
// the whole message list for VoiceOver.
|
||||
.accessibilityLabel(
|
||||
String(localized: "thread.search.accessibility.label", comment: "Accessibility label for in-thread message search")
|
||||
)
|
||||
Button {
|
||||
threadSearchQuery = ""
|
||||
isThreadSearchFieldVisible = false
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.font(.bitchatSystem(size: 12))
|
||||
.foregroundColor(palette.secondary)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(
|
||||
String(localized: "thread.search.close", defaultValue: "close search", comment: "Accessibility label for the button that closes the in-thread search field")
|
||||
)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func messageRow(for message: BitchatMessage) -> some View {
|
||||
Group {
|
||||
|
||||
113
bitchatTests/ThreadMessageSearchTests.swift
Normal file
113
bitchatTests/ThreadMessageSearchTests.swift
Normal file
@ -0,0 +1,113 @@
|
||||
import BitFoundation
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import bitchat
|
||||
|
||||
struct ThreadMessageSearchTests {
|
||||
private func message(
|
||||
id: String,
|
||||
sender: String,
|
||||
content: String
|
||||
) -> BitchatMessage {
|
||||
BitchatMessage(
|
||||
id: id,
|
||||
sender: sender,
|
||||
content: content,
|
||||
timestamp: Date(),
|
||||
isRelay: false,
|
||||
senderPeerID: PeerID(str: "0011223344556677")
|
||||
)
|
||||
}
|
||||
|
||||
@Test("empty query returns the original timeline")
|
||||
func emptyQueryReturnsAll() {
|
||||
let messages = [
|
||||
message(id: "1", sender: "alice", content: "hello mesh"),
|
||||
message(id: "2", sender: "bob", content: "wave back")
|
||||
]
|
||||
|
||||
let result = ThreadMessageSearch.matchingMessages(in: messages, query: " ")
|
||||
#expect(result == messages)
|
||||
}
|
||||
|
||||
@Test("matches message body case-insensitively")
|
||||
func matchesContent() {
|
||||
let messages = [
|
||||
message(id: "1", sender: "alice", content: "Meet at NOON"),
|
||||
message(id: "2", sender: "bob", content: "see you later")
|
||||
]
|
||||
|
||||
let result = ThreadMessageSearch.matchingMessages(in: messages, query: "noon")
|
||||
#expect(result.map(\.id) == ["1"])
|
||||
}
|
||||
|
||||
@Test("matches sender nickname")
|
||||
func matchesSender() {
|
||||
let messages = [
|
||||
message(id: "1", sender: "alice", content: "ping"),
|
||||
message(id: "2", sender: "mallory", content: "pong")
|
||||
]
|
||||
|
||||
let result = ThreadMessageSearch.matchingMessages(in: messages, query: "MALL")
|
||||
#expect(result.map(\.id) == ["2"])
|
||||
}
|
||||
|
||||
@Test("skips whitespace-only message bodies")
|
||||
func skipsBlankBodies() {
|
||||
let messages = [
|
||||
message(id: "1", sender: "alice", content: " "),
|
||||
message(id: "2", sender: "bob", content: "visible")
|
||||
]
|
||||
|
||||
let result = ThreadMessageSearch.matchingMessages(in: messages, query: "alice")
|
||||
#expect(result.isEmpty)
|
||||
}
|
||||
|
||||
@Test("returns empty when nothing matches")
|
||||
func noMatches() {
|
||||
let messages = [
|
||||
message(id: "1", sender: "alice", content: "hello")
|
||||
]
|
||||
|
||||
let result = ThreadMessageSearch.matchingMessages(in: messages, query: "missing")
|
||||
#expect(result.isEmpty)
|
||||
}
|
||||
|
||||
// MARK: - Result cap
|
||||
|
||||
/// Search bypasses the message window, so without a cap a common term in a
|
||||
/// long thread renders every historical match in one pass.
|
||||
@Test("Results are capped at the limit")
|
||||
func resultsAreCapped() {
|
||||
let messages = (0..<500).map { message(id: "m\($0)", sender: "alice", content: "needle \($0)") }
|
||||
let matches = ThreadMessageSearch.matchingMessages(in: messages, query: "needle", limit: 200)
|
||||
#expect(matches.count == 200)
|
||||
}
|
||||
|
||||
@Test("The cap keeps the newest matches")
|
||||
func capKeepsNewestMatches() {
|
||||
let messages = (0..<10).map { message(id: "m\($0)", sender: "alice", content: "needle \($0)") }
|
||||
let matches = ThreadMessageSearch.matchingMessages(in: messages, query: "needle", limit: 3)
|
||||
#expect(matches.map(\.id) == ["m7", "m8", "m9"])
|
||||
}
|
||||
|
||||
@Test("A result set under the cap is returned whole")
|
||||
func underCapIsUntouched() {
|
||||
let messages = (0..<5).map { message(id: "m\($0)", sender: "alice", content: "needle") }
|
||||
#expect(ThreadMessageSearch.matchingMessages(in: messages, query: "needle", limit: 200).count == 5)
|
||||
}
|
||||
|
||||
@Test("A non-positive limit disables the cap")
|
||||
func nonPositiveLimitIsUncapped() {
|
||||
let messages = (0..<300).map { message(id: "m\($0)", sender: "alice", content: "needle") }
|
||||
#expect(ThreadMessageSearch.matchingMessages(in: messages, query: "needle", limit: 0).count == 300)
|
||||
}
|
||||
|
||||
@Test("Truncation is reported only when it happened")
|
||||
func truncationFlag() {
|
||||
#expect(ThreadMessageSearch.didTruncate(matchCount: 201, limit: 200))
|
||||
#expect(!ThreadMessageSearch.didTruncate(matchCount: 200, limit: 200))
|
||||
#expect(!ThreadMessageSearch.didTruncate(matchCount: 5, limit: 200))
|
||||
#expect(!ThreadMessageSearch.didTruncate(matchCount: 5, limit: 0))
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user