From ea0660e7173e10f9524b7772f412554f5e5c55f5 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 27 Jul 2026 02:12:19 +0200 Subject: [PATCH] pass 2 --- .../com/bitchat/android/ui/AboutSections.kt | 15 +- .../java/com/bitchat/android/ui/AboutSheet.kt | 1 - .../java/com/bitchat/android/ui/ChatHeader.kt | 60 ++++--- .../com/bitchat/android/ui/ChatUIUtils.kt | 9 +- .../android/ui/LocationChannelsSheet.kt | 4 +- .../bitchat/android/ui/MeshPeerListSheet.kt | 4 +- .../bitchat/android/ui/MessageComponents.kt | 24 ++- .../android/ui/media/AudioMessageItem.kt | 2 +- .../android/ui/media/ImageMessageItem.kt | 2 +- app/src/main/res/values-ar/strings.xml | 5 - app/src/main/res/values-bn/strings.xml | 5 - app/src/main/res/values-de/strings.xml | 5 - app/src/main/res/values-es/strings.xml | 5 - app/src/main/res/values-fa/strings.xml | 5 - app/src/main/res/values-fil/strings.xml | 5 - app/src/main/res/values-fr/strings.xml | 5 - app/src/main/res/values-hi/strings.xml | 5 - app/src/main/res/values-id/strings.xml | 5 - app/src/main/res/values-it/strings.xml | 5 - app/src/main/res/values-ja/strings.xml | 5 - app/src/main/res/values-ka/strings.xml | 5 - app/src/main/res/values-ko/strings.xml | 5 - app/src/main/res/values-mg/strings.xml | 5 - app/src/main/res/values-ne/strings.xml | 5 - app/src/main/res/values-nl/strings.xml | 5 - app/src/main/res/values-pa-rPK/strings.xml | 5 - app/src/main/res/values-pt-rBR/strings.xml | 5 - app/src/main/res/values-pt/strings.xml | 5 - app/src/main/res/values-ru/strings.xml | 5 - app/src/main/res/values-sv/strings.xml | 5 - app/src/main/res/values-th/strings.xml | 5 - app/src/main/res/values-tr/strings.xml | 5 - app/src/main/res/values-ur/strings.xml | 5 - app/src/main/res/values-vi/strings.xml | 5 - app/src/main/res/values-zh/strings.xml | 5 - app/src/main/res/values/strings.xml | 26 +-- .../com/bitchat/android/ui/ChatUIUtilsTest.kt | 13 +- .../bitchat/android/ui/MessageGroupingTest.kt | 152 ++++++++++++++++++ 38 files changed, 240 insertions(+), 202 deletions(-) create mode 100644 app/src/test/java/com/bitchat/android/ui/MessageGroupingTest.kt diff --git a/app/src/main/java/com/bitchat/android/ui/AboutSections.kt b/app/src/main/java/com/bitchat/android/ui/AboutSections.kt index 73403b6d..ae1b79a0 100644 --- a/app/src/main/java/com/bitchat/android/ui/AboutSections.kt +++ b/app/src/main/java/com/bitchat/android/ui/AboutSections.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight @@ -206,7 +207,9 @@ internal fun AboutTabBar( HorizontalDivider(thickness = 1.dp, color = palette.outlineVariant) Box( modifier = Modifier - .offset(x = indicatorOffset) + // Lambda overload: the offset is animated every frame, and the non-lambda + // version would invalidate composition rather than just layout. + .offset { IntOffset(x = indicatorOffset.roundToPx(), y = 0) } .width(tabWidth) .height(2.dp) .background(colorScheme.primary) @@ -355,8 +358,8 @@ internal fun AboutFeatureCard(modifier: Modifier = Modifier) { val features = listOf( Triple( Icons.Filled.WifiOff, - R.string.about_offline_comm_title, - R.string.about_offline_comm_desc + R.string.about_offline_mesh_title, + R.string.about_offline_mesh_desc ), Triple( Icons.Outlined.Lock, @@ -365,8 +368,8 @@ internal fun AboutFeatureCard(modifier: Modifier = Modifier) { ), Triple( Icons.Outlined.Public, - R.string.about_local_channels_title, - R.string.about_local_channels_desc + R.string.about_online_geohash_title, + R.string.about_online_geohash_desc ), Triple( Icons.Outlined.VisibilityOff, @@ -380,7 +383,7 @@ internal fun AboutFeatureCard(modifier: Modifier = Modifier) { ), Triple( Icons.Filled.DeleteForever, - R.string.about_panic_title, + R.string.about_emergency_title, R.string.about_panic_desc ), ) diff --git a/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt b/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt index ce170343..2049b518 100644 --- a/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt @@ -246,7 +246,6 @@ fun AboutSheet( val colorScheme = MaterialTheme.colorScheme val palette = LocalBitchatPalette.current - val isDark = palette.isDark var selectedTab by remember { mutableStateOf(AboutTab.HowToUse) } if (isPresented) { diff --git a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt index 45657cef..adda2378 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt @@ -120,26 +120,30 @@ fun NoiseSessionIcon( sessionState: String?, modifier: Modifier = Modifier ) { + val palette = LocalBitchatPalette.current + // The pre-redesign colours for the first two states were `0x87878700`, i.e. alpha 0x87 with + // an all-but-transparent RGB - the icons were effectively invisible. They now use the + // palette's secondary text colour. val (icon, color, contentDescription) = when (sessionState) { "uninitialized" -> Triple( Icons.Outlined.NoEncryption, - Color(0x87878700), // Grey - ready to establish + palette.textSecondary, stringResource(R.string.cd_ready_for_handshake) ) "handshaking" -> Triple( Icons.Outlined.Sync, - Color(0x87878700), // Grey - in progress + palette.textSecondary, stringResource(R.string.cd_handshake_in_progress) ) "established" -> Triple( Icons.Filled.Lock, - Color(0xFFFF9500), // Orange - secure + palette.accentOrange, stringResource(R.string.cd_encrypted) ) else -> { // "failed" or any other state Triple( Icons.Outlined.Warning, - Color(0xFFFF4444), // Red - error + palette.accentRed, stringResource(R.string.cd_handshake_failed) ) } @@ -400,28 +404,36 @@ private fun MainHeader( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { - // MARK: - Identity cluster - BitChatBrandButton( - onClick = onTitleClick, - onTripleClick = onTripleTitleClick, - contentDescription = stringResource(R.string.cd_open_about), - ) + // MARK: - Identity cluster. + // + // Weighted so it yields space to the status cluster rather than pushing it off screen. + // Compose measures unweighted children first, so the icons on the right always get the + // width they need and a long nickname simply scrolls within what is left. + Row( + modifier = Modifier.weight(1f), + verticalAlignment = Alignment.CenterVertically + ) { + BitChatBrandButton( + onClick = onTitleClick, + onTripleClick = onTripleTitleClick, + contentDescription = stringResource(R.string.cd_open_about), + modifier = Modifier.size(HeaderTapTarget), + ) - Text( - text = "/", - style = MaterialTheme.typography.bodyMedium, - // Dimmed: the slash is a separator, not content. At full brightness it competed - // with the nickname beside it. - color = colorScheme.primary.copy(alpha = 0.45f), - modifier = Modifier.padding(horizontal = 2.dp) - ) + Text( + text = "/", + style = MaterialTheme.typography.bodyMedium, + // Dimmed: the slash is a separator, not content. At full brightness it competed + // with the nickname beside it. + color = colorScheme.primary.copy(alpha = 0.45f), + modifier = Modifier.padding(horizontal = 2.dp) + ) - NicknameEditor( - value = nickname, - onValueChange = onNicknameChange - ) - - Spacer(modifier = Modifier.weight(1f)) + NicknameEditor( + value = nickname, + onValueChange = onNicknameChange + ) + } // MARK: - Status cluster. Order matches the design: bookmark, channel, people. Row( diff --git a/app/src/main/java/com/bitchat/android/ui/ChatUIUtils.kt b/app/src/main/java/com/bitchat/android/ui/ChatUIUtils.kt index 2f945593..d1415fbe 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatUIUtils.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatUIUtils.kt @@ -7,7 +7,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.sp import com.bitchat.android.model.BitchatMessage -import com.bitchat.android.mesh.MeshService import com.bitchat.android.ui.theme.BASE_FONT_SIZE import com.bitchat.android.ui.theme.BitchatPalette import java.text.SimpleDateFormat @@ -49,11 +48,11 @@ fun getRSSIColor(rssi: Int): Color { fun formatTextMessageSender( message: BitchatMessage, currentUserNickname: String, - meshService: MeshService, + myPeerID: String, palette: BitchatPalette ): AnnotatedString { val builder = AnnotatedString.Builder() - val isSelf = message.isFromSelf(currentUserNickname, meshService.myPeerID) + val isSelf = message.isFromSelf(currentUserNickname, myPeerID) val senderColor = if (isSelf) palette.accentOrange else getPeerColor(message, palette.isDark) val senderWeight = if (isSelf) FontWeight.Bold else FontWeight.SemiBold val (baseName, suffix) = splitSuffix(message.sender) @@ -213,13 +212,13 @@ fun formatSystemMessage( fun formatMessageHeaderAnnotatedString( message: BitchatMessage, currentUserNickname: String, - meshService: MeshService, + myPeerID: String, palette: BitchatPalette, timeFormatter: SimpleDateFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault()), includeSender: Boolean = true ): AnnotatedString { val builder = AnnotatedString.Builder() - val isSelf = message.isFromSelf(currentUserNickname, meshService.myPeerID) + val isSelf = message.isFromSelf(currentUserNickname, myPeerID) if (message.sender == "system") { return formatSystemMessage(message, palette, timeFormatter) diff --git a/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt b/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt index 26cdb767..98e1fb40 100644 --- a/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt @@ -298,7 +298,7 @@ fun LocationChannelsSheet( // Bookmarked geohashes if (bookmarks.isNotEmpty()) { item(key = "bookmarked_header") { - SheetSectionLabel(text = stringResource(R.string.section_bookmarked)) + SheetSectionLabel(text = stringResource(R.string.bookmarked)) } items(bookmarks) { gh -> val level = levelForLength(gh.length) @@ -571,7 +571,7 @@ fun LocationChannelsSheet( item(key = "location_toggle") { SheetDestructiveButton( text = if (locationServicesEnabled) { - stringResource(R.string.remove_location_access) + stringResource(R.string.disable_location_services) } else { stringResource(R.string.enable_location_services) }, diff --git a/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt b/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt index 71bfc62a..a6c0d63d 100644 --- a/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt @@ -130,7 +130,7 @@ fun MeshPeerListSheet( // Channels section if (joinedChannels.isNotEmpty()) { item(key = "channels_header") { - SheetSectionLabel(text = stringResource(R.string.section_channels)) + SheetSectionLabel(text = stringResource(R.string.channels)) } items( @@ -316,7 +316,7 @@ fun PeopleSection( val palette = LocalBitchatPalette.current Column(modifier = modifier) { - SheetSectionLabel(text = stringResource(R.string.section_mesh)) + SheetSectionLabel(text = stringResource(R.string.people)) if (connectedPeers.isEmpty()) { Text( diff --git a/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt b/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt index 14f7b4f3..7457c681 100644 --- a/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt +++ b/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt @@ -300,7 +300,7 @@ fun MessageItem( val headerText = formatMessageHeaderAnnotatedString( message = message, currentUserNickname = currentUserNickname, - meshService = meshService, + myPeerID = meshService.myPeerID, palette = palette, timeFormatter = timeFormatter, includeSender = showSender @@ -368,15 +368,24 @@ fun MessageItem( .align(Alignment.TopEnd) .padding(4.dp) .size(22.dp) - .background(Color.Gray.copy(alpha = 0.6f), CircleShape) + .background(palette.surfaceVariant.copy(alpha = 0.85f), CircleShape) .clickable { onCancelTransfer?.invoke(message) }, contentAlignment = Alignment.Center ) { - Icon(imageVector = Icons.Filled.Close, contentDescription = stringResource(R.string.cd_cancel), tint = Color.White, modifier = Modifier.size(14.dp)) + Icon( + imageVector = Icons.Filled.Close, + contentDescription = stringResource(R.string.cd_cancel), + tint = palette.textPrimary, + modifier = Modifier.size(14.dp) + ) } } } else { - Text(text = stringResource(R.string.file_unavailable), fontFamily = FontFamily.Monospace, color = Color.Gray) + Text( + text = stringResource(R.string.file_unavailable), + fontFamily = FontFamily.Monospace, + color = palette.textTertiary + ) } } } @@ -468,7 +477,7 @@ internal fun TextMessageLayout( formatTextMessageSender( message = message, currentUserNickname = currentUserNickname, - meshService = meshService, + myPeerID = myPeerId, palette = palette, ) } @@ -548,6 +557,7 @@ internal fun TextMessageLayout( @Composable fun DeliveryStatusIcon(status: DeliveryStatus) { val colorScheme = MaterialTheme.colorScheme + val palette = LocalBitchatPalette.current when (status) { is DeliveryStatus.Sending -> { @@ -577,7 +587,7 @@ fun DeliveryStatusIcon(status: DeliveryStatus) { Text( text = stringResource(R.string.status_delivered), fontSize = 10.sp, - color = Color(0xFF007AFF), // Blue + color = palette.accentBlue, fontWeight = FontWeight.Bold ) } @@ -585,7 +595,7 @@ fun DeliveryStatusIcon(status: DeliveryStatus) { Text( text = stringResource(R.string.status_failed), fontSize = 10.sp, - color = Color.Red.copy(alpha = 0.8f) + color = palette.accentRed ) } is DeliveryStatus.PartiallyDelivered -> { diff --git a/app/src/main/java/com/bitchat/android/ui/media/AudioMessageItem.kt b/app/src/main/java/com/bitchat/android/ui/media/AudioMessageItem.kt index 5db41f17..dc52f845 100644 --- a/app/src/main/java/com/bitchat/android/ui/media/AudioMessageItem.kt +++ b/app/src/main/java/com/bitchat/android/ui/media/AudioMessageItem.kt @@ -53,7 +53,7 @@ fun AudioMessageItem( val headerText = com.bitchat.android.ui.formatMessageHeaderAnnotatedString( message = message, currentUserNickname = currentUserNickname, - meshService = meshService, + myPeerID = meshService.myPeerID, palette = palette, timeFormatter = timeFormatter, includeSender = showSender diff --git a/app/src/main/java/com/bitchat/android/ui/media/ImageMessageItem.kt b/app/src/main/java/com/bitchat/android/ui/media/ImageMessageItem.kt index 1691bb9b..01d119fe 100644 --- a/app/src/main/java/com/bitchat/android/ui/media/ImageMessageItem.kt +++ b/app/src/main/java/com/bitchat/android/ui/media/ImageMessageItem.kt @@ -51,7 +51,7 @@ fun ImageMessageItem( val headerText = com.bitchat.android.ui.formatMessageHeaderAnnotatedString( message = message, currentUserNickname = currentUserNickname, - meshService = meshService, + myPeerID = meshService.myPeerID, palette = palette, timeFormatter = timeFormatter, includeSender = showSender diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index bd8949cb..5ad12ff2 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -72,7 +72,6 @@ رجوع - القناة: %1$s مغادرة يمكن الوصول عبر Nostr رسائل خاصة غير مقروءة @@ -102,7 +101,6 @@ تواصل مع أشخاص بالقرب منك عبر قنوات تعتمد على geohash. وسّع الشبكة عبر مرحلات الإنترنت العامة. تشفير طرف إلى طرف الرسائل الخاصة مشفّرة. رسائل القنوات عامة. - المظهر النظام فاتح داكن @@ -126,7 +124,6 @@ حالة Tor: %1$s، التمهيد %2$d%% آخر: %1$s مسح البيانات الطارئ - تلميح: انقر ثلاث مرات على عنوان التطبيق لمسح كل البيانات المحفوظة – بما في ذلك الرسائل والمفاتيح والإعدادات. إعدادات التصحيح مفتوح المصدر • الخصوصية أولاً • لامركزي إغلاق @@ -146,7 +143,6 @@ فتح الخريطة إزالة الإشارة المرجعية انتقال - محدد مغادرة القناة يمكن الوصول عبر Nostr مفضل (غير متصل) @@ -285,7 +281,6 @@ الأذونات منح الأذونات bitchat لا يتتبع موقعك - الأشخاص لا أحد هنا… (أنت) حرّك وقرّب لاختيار geohash diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index f978e0ce..76c13dd2 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -72,7 +72,6 @@ ফিরে যান - চ্যানেল: %1$s ছেড়ে দিন Nostr এর মাধ্যমে পৌঁছানো যায় অপঠিত ব্যক্তিগত বার্তা @@ -102,7 +101,6 @@ জিওহ্যাশ-ভিত্তিক চ্যানেলের মাধ্যমে আপনার এলাকার মানুষদের সাথে সংযুক্ত হন। পাবলিক ইন্টারনেট রিলেগুলির মাধ্যমে মেশ বিস্তৃত করুন। এন্ড-টু-এন্ড এনক্রিপশন ব্যক্তিগত বার্তাগুলি এনক্রিপ্ট করা। চ্যানেল বার্তাগুলি পাবলিক। - চেহারা সিস্টেম হালকা অন্ধকার @@ -126,7 +124,6 @@ Tor অবস্থা: %1$s, বুটস্ট্র্যাপ %2$d%% শেষ: %1$s জরুরী ডেটা ক্লিয়ার - টিপ: সংরক্ষিত সমস্ত ডেটা – বার্তা, কী এবং সেটিংস সহ – সাফ করতে অ্যাপ শিরোনামে তিনবার ট্যাপ করুন। ডিবাগ সেটিংস ওপেন সোর্স • গোপনীয়তা প্রথম • বিকেন্দ্রীভূত বন্ধ করুন @@ -146,7 +143,6 @@ মানচিত্র খুলুন বুকমার্ক সরান টেলিপোর্ট - নির্বাচিত চ্যানেল ছেড়ে দিন Nostr এর মাধ্যমে পৌঁছানো যায় প্রিয় (অফলাইন) @@ -285,7 +281,6 @@ অনুমতি অনুমতি দিন bitchat আপনার অবস্থান ট্র্যাক করে না - মানুষ কেউ আশেপাশে নেই … (আপনি) জিওহ্যাশ নির্বাচন করতে প্যান এবং জুম করুন diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9fe6301e..23168837 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -72,7 +72,6 @@ zurück - Kanal: %1$s verlassen Über Nostr erreichbar Ungelesene private Nachrichten @@ -102,7 +101,6 @@ Vernetze dich mit Menschen in deiner Umgebung über geohash‑basierte Kanäle. Erweitere das Mesh über öffentliche Internet‑Relays. Ende‑zu‑Ende‑Verschlüsselung Private Nachrichten sind verschlüsselt. Kanal‑Nachrichten sind öffentlich. - Darstellung System Hell Dunkel @@ -126,7 +124,6 @@ Tor‑Status: %1$s, Bootstrap %2$d%% Zuletzt: %1$s Notfall‑Datenlöschung - Tipp: Dreifach auf den App‑Titel tippen, um alle gespeicherten Daten – einschließlich Nachrichten, Schlüssel und Einstellungen – zu löschen. Debug‑Einstellungen Open Source • Privacy First • Dezentral Schließen @@ -146,7 +143,6 @@ Karte öffnen Lesezeichen entfernen Teleportieren - Ausgewählt Kanal verlassen Über Nostr erreichbar Favorit (offline) @@ -285,7 +281,6 @@ Berechtigungen Berechtigungen erteilen bitchat verfolgt NICHT deinen Standort - PERSONEN niemand da … (du) schwenken und zoomen, um einen Geohash auszuwählen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 89d907da..836f563a 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -72,7 +72,6 @@ atrás - Canal: %1$s salir Accesible vía Nostr Mensajes privados sin leer @@ -102,7 +101,6 @@ Conéctate con personas cerca de ti a través de canales basados en geohash. Extiende la red mesh a través de repetidores de internet público. Cifrado de extremo a extremo Los mensajes privados están cifrados. Los mensajes de canal son públicos. - Apariencia Sistema Claro Oscuro @@ -126,7 +124,6 @@ Estado de Tor: %1$s, bootstrap %2$d%% Último: %1$s Borrado de datos de emergencia - Consejo: Toca tres veces en el título de la app para borrar todos los datos almacenados, incluyendo mensajes, claves y configuraciones. Configuraciones de depuración Código abierto • Privacidad primero • Descentralizado Cerrar @@ -146,7 +143,6 @@ Abrir mapa Quitar marcador Teletransportar - Seleccionado Salir del canal Accesible vía Nostr Favorito (sin conexión) @@ -285,7 +281,6 @@ Permisos Otorgar permisos bitchat NO rastrea tu ubicación - PERSONAS nadie por aquí… (tú) desplaza y hace zoom para seleccionar un geohash diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 5f895797..551ca8db 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -72,7 +72,6 @@ بازگشت - کانال: %1$s خروج قابل دسترس از طریق Nostr پیام‌های خصوصی خوانده‌نشده @@ -102,7 +101,6 @@ از طریق کانال‌های مبتنی بر geohash با افراد منطقهٔ خود ارتباط برقرار کنید. مِش را از طریق رله‌های عمومی اینترنت گسترش دهید. رمزگذاری سرتاسری پیام‌های خصوصی رمزگذاری می‌شوند. پیام‌های کانال عمومی هستند. - نما سامانه روشن تیره @@ -126,7 +124,6 @@ وضعیت Tor: %1$s، بوت‌استرپ %2$d%% آخرین: %1$s پاکسازی اضطراری داده - نکته: برای پاک کردن همهٔ داده‌های ذخیره‌شده — شامل پیام‌ها، کلیدها و تنظیمات — سه بار روی عنوان برنامه ضربه بزنید. تنظیمات اشکال‌زدایی متن‌باز • حریم خصوصی در اولویت • غیرمتمرکز بستن @@ -146,7 +143,6 @@ باز کردن نقشه حذف نشانک انتقال - انتخاب شد خروج از کانال قابل دسترس از طریق Nostr دلخواه (آفلاین) @@ -285,7 +281,6 @@ مجوزها اعطای مجوزها bitchat موقعیت شما را پیگیری نمی‌کند - افراد کسی در اطراف نیست … (شما) برای انتخاب geohash، جابه‌جا و زوم کنید diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index dc231763..526cc636 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -72,7 +72,6 @@ bumalik - channel: %1$s umalis Maabot sa Nostr Hindi nabasang pribadong mensahe @@ -102,7 +101,6 @@ Makipag‑ugnayan sa mga tao sa paligid gamit ang geohash‑based na mga channel. Palawakin ang mesh sa pampublikong internet relays. End‑to‑End Encryption Ang mga pribadong mensahe ay naka‑encrypt. Ang mga mensahe sa channel ay publiko. - hitsura system light dark @@ -126,7 +124,6 @@ katayuan ng Tor: %1$s, bootstrap %2$d%% Huli: %1$s Emergency Data Deletion - Tip: i‑tap ang pamagat ng app nang 3 beses para burahin ang lahat ng data (mga mensahe, susi, setting). Debug Settings Open Source • Privacy First • Desentralisado Isara @@ -146,7 +143,6 @@ Buksan ang mapa Alisin ang bookmark Teleport - Napili Umalis sa channel Maabot sa Nostr Paborito (offline) @@ -280,7 +276,6 @@ HINDI sinusubaybayan ng bitchat ang lokasyon mo @ · ⧉ - TAO walang tao sa paligid… (ikaw) i‑pan at i‑zoom para pumili ng geohash diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9d2b515f..8da0188f 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -72,7 +72,6 @@ retour - canal : %1$s quitter Joignable via Nostr Messages privés non lus @@ -102,7 +101,6 @@ Discute avec des personnes proches via des canaux basés sur geohash. Étends le mesh grâce à des relais internet publics. Chiffrement de bout en bout Les messages privés sont chiffrés. Les messages de canal sont publics. - apparence système clair sombre @@ -126,7 +124,6 @@ statut Tor : %1$s, bootstrap %2$d%% Dernier : %1$s Suppression d’urgence des données - Astuce : tapote 3 fois le titre de l’app pour supprimer toutes les données (messages, clés, paramètres). Paramètres de debug Open Source • Privacy First • Décentralisé Fermer @@ -146,7 +143,6 @@ Ouvrir la carte Retirer le signet Téléporter - Sélectionné Quitter le canal Joignable via Nostr Favori (hors‑ligne) @@ -281,7 +277,6 @@ bitchat ne suit PAS ta position @ · ⧉ - PERSONNES personne aux alentours… (toi) déplacer et zoomer pour choisir un geohash diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 3ec6ac27..6921ace7 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -72,7 +72,6 @@ वापस - चैनल: %1$s छोड़ें Nostr के माध्यम से उपलब्ध अपठित निजी संदेश @@ -102,7 +101,6 @@ geohash आधारित चैनलों के माध्यम से अपने आस‑पास के लोगों से जुड़ें। सार्वजनिक इंटरनेट रिले के माध्यम से मेष का विस्तार करें। एंड‑टू‑एंड एन्क्रिप्शन निजी संदेश एन्क्रिप्टेड हैं। चैनल संदेश सार्वजनिक हैं। - रूप सिस्टम लाइट डार्क @@ -126,7 +124,6 @@ Tor स्थिति: %1$s, बूटस्ट्रैप %2$d%% अंतिम: %1$s आपातकालीन डेटा मिटाना - संकेत: सभी सहेजे डेटा – संदेश, कुंजियाँ और सेटिंग्स सहित – मिटाने के लिए ऐप शीर्षक पर तीन बार टैप करें। डिबग सेटिंग्स ओपन सोर्स • गोपनीयता पहले • विकेन्द्रीकृत बंद करें @@ -146,7 +143,6 @@ मानचित्र खोलें बुकमार्क हटाएँ टेलीपोर्ट - चयनित चैनल छोड़ें Nostr के माध्यम से उपलब्ध पसंदीदा (ऑफ़लाइन) @@ -285,7 +281,6 @@ अनुमतियाँ अनुमतियाँ दें bitchat आपकी लोकेशन ट्रैक नहीं करती - लोग आस‑पास कोई नहीं… (आप) geohash चुनने के लिए पैन/ज़ूम करें diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 048d40b2..c5eb612c 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -72,7 +72,6 @@ kembali - Channel: %1$s keluar Dapat dijangkau melalui Nostr Pesan pribadi yang belum dibaca @@ -102,7 +101,6 @@ Terhubung dengan orang-orang di area Anda melalui channel berbasis geohash. Perluas mesh melalui relay Internet publik. Enkripsi end-to-end Pesan pribadi dienkripsi. Pesan channel bersifat publik. - Tampilan Sistem Terang Gelap @@ -126,7 +124,6 @@ Status Tor: %1$s, Bootstrap %2$d%% Terakhir: %1$s Hapus data darurat - Tips: Ketuk tiga kali pada judul aplikasi untuk menghapus semua data tersimpan – termasuk pesan, kunci, dan pengaturan. Pengaturan debug Sumber Terbuka • Privasi Pertama • Terdesentralisasi Tutup @@ -146,7 +143,6 @@ Buka peta Hapus bookmark Teleportasi - Dipilih Keluar dari channel Dapat dijangkau melalui Nostr Favorit (offline) @@ -285,7 +281,6 @@ Izin Berikan izin bitchat TIDAK melacak lokasi Anda - ORANG tidak ada orang di sekitar … (Anda) geser dan zoom untuk memilih geohash diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 434f1dc6..8c157300 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -72,7 +72,6 @@ indietro - canale: %1$s esci Raggiungibile via Nostr Messaggi privati non letti @@ -102,7 +101,6 @@ Connettiti con persone nella tua area usando canali basati su geohash. Estendi la rete mesh usando relay internet pubblici. Crittografia end-to-end I messaggi privati sono crittografati. I messaggi dei canali sono pubblici. - aspetto sistema chiaro scuro @@ -126,7 +124,6 @@ Stato Tor: %1$s, bootstrap %2$d%% Ultimo: %1$s Eliminazione dati di emergenza - Suggerimento: fai triplo clic sul titolo dell\'app per eliminare in emergenza tutti i dati memorizzati, inclusi messaggi, chiavi e impostazioni. Impostazioni di debug Open Source • Privacy First • Decentralizzato Chiudi @@ -146,7 +143,6 @@ Apri mappa Rimuovi segnalibro Teletrasporta - Selezionato Esci dal canale Raggiungibile via Nostr Preferito offline @@ -285,7 +281,6 @@ permessi Concedi permessi bitchat NON traccia la tua posizione - PERSONE nessuno nei dintorni… (tu) scorri e ingrandisci per selezionare un geohash diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 1a3df392..b272e51f 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -72,7 +72,6 @@ 戻る - チャンネル: %1$s 退出 Nostr 経由で到達可能 未読のプライベートメッセージ @@ -102,7 +101,6 @@ Geohash ベースのチャンネルで近くの人々とつながります。公開インターネットのリレーを介してメッシュを拡張します。 エンドツーエンド暗号化 プライベートメッセージは暗号化されます。チャンネルメッセージは公開です。 - 表示 システム ライト ダーク @@ -126,7 +124,6 @@ Tor ステータス: %1$s、ブートストラップ %2$d%% 最終: %1$s 緊急データ消去 - ヒント: アプリタイトルを 3 回タップすると、メッセージ・鍵・設定を含む保存データをすべて消去します。 デバッグ設定 オープンソース • プライバシーファースト • 分散型 閉じる @@ -146,7 +143,6 @@ 地図を開く ブックマークを削除 テレポート - 選択済み チャンネルから退出 Nostr 経由で到達可能 お気に入り (オフライン) @@ -285,7 +281,6 @@ 権限 権限を付与 bitchat はあなたの位置情報を追跡しません - 人々 誰もいません… (あなた) パン/ズームして geohash を選択 diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index cf08947b..65f27848 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -72,7 +72,6 @@ უკან - არხი: %1$s გასვლა მისაწვდომია Nostr-ით წაუკითხავი პირადი შეტყობინებები @@ -102,7 +101,6 @@ დაუკავშირდით ახლომდებარე ხალხს geohash-ზე დაფუძნებული არხებით. გააფართოვეთ mesh საჯარო ინტერნეტ რილეებით. ბოლო-მდე დაშიფვრა პირადი შეტყობინებები დაშიფრულია. არხის შეტყობინებები საჯაროა. - გარეგნობა სისტემა ღია მუქი @@ -126,7 +124,6 @@ Tor სტატუსი: %1$s, ჩატვირთვა %2$d%% ბოლო: %1$s სასწრაფო მონაცემების წაშლა - რჩევა: დააჭირეთ აპის სათაურს სამჯერ ყველა შენახული მონაცემის – შეტყობინებების, გასაღებებისა და პარამეტრების – წასაშლელად. დebug პარამეტრები ღია კოდი • კონფიდენციალობა პირველია • დეცენტრალიზებული დახურვა @@ -146,7 +143,6 @@ რუკის გახსნა სანიშნეს წაშლა ტელეპორტი - მონიშნული არხიდან გამოსვლა მისაწვდომია Nostr-ით რჩეული (ოფლაინ) @@ -285,7 +281,6 @@ ნებართვები ნებართვების მინიჭება bitchat არ აკონტროლებს თქვენს მდებარეობას - ხალხი არავინ არის ახლოს… (თქვენ) პანორამირება/ზუმი geohash-ის ასარჩევად diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 5be26395..ee2838b6 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -72,7 +72,6 @@ 뒤로 - 채널: %1$s 나가기 Nostr로 연결 가능 읽지 않은 개인 메시지 @@ -102,7 +101,6 @@ geohash 기반 채널을 통해 주변 사람들과 연결하세요. 공용 인터넷 릴레이로 메쉬를 확장합니다. 종단간 암호화 개인 메시지는 암호화됩니다. 채널 메시지는 공개입니다. - 모양 시스템 라이트 다크 @@ -126,7 +124,6 @@ Tor 상태: %1$s, 부트스트랩 %2$d%% 마지막: %1$s 긴급 데이터 삭제 - 팁: 저장된 모든 데이터(메시지, 키, 설정 포함)를 삭제하려면 앱 제목을 세 번 탭하세요. 디버그 설정 오픈 소스 • 프라이버시 우선 • 탈중앙 닫기 @@ -146,7 +143,6 @@ 지도 열기 북마크 제거 텔레포트 - 선택됨 채널 나가기 Nostr로 연결 가능 즐겨찾기 (오프라인) @@ -285,7 +281,6 @@ 권한 권한 허용 bitchat은 사용자의 위치를 추적하지 않습니다 - 사람들 주변에 아무도 없음 … (나) geohash를 선택하려면 이동하고 확대/축소하세요 diff --git a/app/src/main/res/values-mg/strings.xml b/app/src/main/res/values-mg/strings.xml index 68b640f9..ffec5957 100644 --- a/app/src/main/res/values-mg/strings.xml +++ b/app/src/main/res/values-mg/strings.xml @@ -72,7 +72,6 @@ miverina - fantsona: %1$s hiala Azo tratrarina amin\'ny alalan\'ny Nostr Hafatra manokana tsy voavaky @@ -102,7 +101,6 @@ Mifandray amin\'ny olona eo amin\'ny faritra misy anao amin\'ny fampiasana fantsona mifototra amin\'ny geohash. Manitatra ny mesh amin\'ny fampiasana relay Internet ho an\'ny daholobe. Fandokoana Farany amin\'ny Farany Voafono ny hafatra manokana. Hafatra ho an\'ny daholobe ny hafatra fantsona. - endrika rafitra mazava maizina @@ -126,7 +124,6 @@ Toe-javatra Tor: %1$s, bootstrap %2$d%% Farany: %1$s Famafana Angona Maika - Toro-hevitra: Tsindrio in-telo ny anaran\'ny fampiharana mba hamafana maika ny angona rehetra voatahiry ao anatin\'izany ny hafatra, ny lakile ary ny fametrahana. Fametrahana Debug Loharanom-baovao misokatra • Fiainana manokana voalohany • Tsy misy foibe Hanakatona @@ -146,7 +143,6 @@ Hanokatra sarintany Hanesorana bookmark Hamindra toerana - Voafidy Hiala amin\'ny fantsona Azo tratrarina amin\'ny alalan\'ny Nostr Ankafizina tsy an-tserasera @@ -289,7 +285,6 @@ Ny bitchat dia TSY manaraka ny toerananao @ · ⧉ - OLONA tsy misy olona manodidina... (ianao) ahetsika sy ataovy lehibe mba hifidianana geohash diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml index d460c037..7c2bbf26 100644 --- a/app/src/main/res/values-ne/strings.xml +++ b/app/src/main/res/values-ne/strings.xml @@ -72,7 +72,6 @@ पछाडि - च्यानल: %1$s छोड्नुहोस् Nostr मार्फत पुग्न सकिने नपढिएका निजी सन्देश @@ -102,7 +101,6 @@ Geohash आधारित च्यानलमार्फत नजिकका मानिसहरूसँग जोडिनुहोस्। सार्वजनिक इन्टरनेट रिलेलाई प्रयोग गरेर मेष विस्तार गर्नुहोस्। एन्ड‑टु‑एन्ड इन्क्रिप्सन निजी सन्देश इन्क्रिप्टेड हुन्छन्। च्यानल सन्देश सार्वजनिक हुन्छन्। - देखावट सिस्टम हल्का गाढा @@ -126,7 +124,6 @@ Tor स्थिति: %1$s, बुटस्ट्र्याप %2$d%% अन्तिम: %1$s आपतकालीन डेटा मेटाउने - सुझाव: एप शीर्षक तीन पटक ट्याप गरी सबै डेटा (सन्देश, कुञ्जी, सेटिङ) मेटाउनुहोस्। डिबग सेटिङ Open Source • Privacy First • विकेन्द्रित बन्द गर्नुहोस् @@ -146,7 +143,6 @@ नक्सा खोल्नुहोस् बुकमार्क हटाउनुहोस् टेलिपोर्ट - छानिएको च्यानल छोड्नुहोस् Nostr बाट पहुँचयोग्य मनपर्ने (अफलाइन) @@ -280,7 +276,6 @@ bitchat ले तपाईंको स्थान पछ्याउँदैन @ · ⧉ - मानिसहरू वरिपरि कोही छैन… (तपाईं) geohash छान्न प्यान र जुम गर्नुहोस् diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 4cf60a3d..d9de3a6d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -72,7 +72,6 @@ terug - kanaal: %1$s verlaten Bereikbaar via Nostr Ongelezen privéberichten @@ -102,7 +101,6 @@ Maak contact met mensen in uw omgeving met geohash-gebaseerde kanalen. Breid het mesh uit met openbare internetrelays. End-to-end-versleuteling Privéberichten zijn versleuteld. Kanaalberichten zijn openbaar. - uiterlijk systeem licht donker @@ -126,7 +124,6 @@ Tor-status: %1$s, bootstrap %2$d%% Laatste: %1$s Noodgegevensverwijdering - Tip: Driedubbel klik op de app-titel om alle opgeslagen gegevens inclusief berichten, sleutels en instellingen noodmatig te verwijderen. Debug-instellingen Open Source • Privacy First • Gedecentraliseerd Sluiten @@ -146,7 +143,6 @@ Kaart openen Bladwijzer verwijderen Teleporteren - Geselecteerd Kanaal verlaten Bereikbaar via Nostr Offline favoriet @@ -285,7 +281,6 @@ toestemmingen Toestemmingen verlenen bitchat volgt NIET uw locatie - PERSONEN niemand in de buurt… (jij) pan en zoom om een geohash te selecteren diff --git a/app/src/main/res/values-pa-rPK/strings.xml b/app/src/main/res/values-pa-rPK/strings.xml index 553e35ca..f7423ce5 100644 --- a/app/src/main/res/values-pa-rPK/strings.xml +++ b/app/src/main/res/values-pa-rPK/strings.xml @@ -72,7 +72,6 @@ واپس - چینل: %1$s باہر آؤ Nostr راہین پہنچ ممکن اے انہ پڑھیا ذاتی پیغام @@ -102,7 +101,6 @@ geohash بیسڈ چینلاں راہین اپنے علاقے دے لوکاں نال جڑو۔ پبلک انٹرنیٹ ریلے راہین میش نوں وسیع کرو۔ اینڈ ٹو اینڈ انکرپشن ذاتی پیغام انکرپٹڈ ہوندے نیں۔ چینل پیغام پبلک ہوندے نیں۔ - دِکھ سسٹم ہلکا گھُپ @@ -126,7 +124,6 @@ Tor حالت: %1$s، بوٹ اسٹرَیپ %2$d%% آخری: %1$s ایمرجنسی ڈیٹا صاف - ٹِپ: سارے محفوظ ڈیٹا (پیغام، کُنجیاں، سیٹنگا) مٹاؤن لئی ایپ دے عنوان تے تین وار ٹیپ کرو۔ ڈی بگ سیٹنگا اوپن سورس • پرائیویسی پہلے • غیر مرکزی بند کرو @@ -146,7 +143,6 @@ نقشہ کھولو بُک مارک ہٹاؤ ٹیلپورٹ - چُنے ہوۓ چینل چھوڑو Nostr راہین پہنچ ممکن اے پسندیدہ (آف لائن) @@ -285,7 +281,6 @@ اجازتاں اجازت دو bitchat توانڈی لوکیشن نئیں ٹریک کردا - لوگ کوئی وی نیڑے نئیں … (تُسی) geohash چُنن لئی پین تے زوم کرو diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 86e238cb..a350d3f7 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -72,7 +72,6 @@ voltar - Canal: %1$s sair Acessível via Nostr Mensagens privadas não lidas @@ -102,7 +101,6 @@ Conecte-se com pessoas próximas através de canais baseados em geohash. Expanda a mesh por meio de relays públicos na internet. Criptografia de ponta a ponta Mensagens privadas são criptografadas. Mensagens de canal são públicas. - Aparência Sistema Claro Escuro @@ -126,7 +124,6 @@ Status do Tor: %1$s, bootstrap %2$d%% Último: %1$s Limpeza de dados de emergência - Dica: Toque 3 vezes no título do app para apagar todos os dados salvos – incluindo mensagens, chaves e configurações. Configurações de depuração Código aberto • Privacidade em primeiro lugar • Descentralizado Fechar @@ -146,7 +143,6 @@ Abrir mapa Remover favorito Teletransportar - Selecionado Sair do canal Acessível via Nostr Favorito (offline) @@ -285,7 +281,6 @@ Permissões Conceder permissões O bitchat NÃO rastreia sua localização - PESSOAS ninguém por perto… (você) arraste/amplie para selecionar um geohash diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 2aeb5352..9751b733 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -72,7 +72,6 @@ voltar - Canal: %1$s sair Alcançável via Nostr Mensagens privadas não lidas @@ -102,7 +101,6 @@ Conecte-se com pessoas perto de si através de canais baseados em geohash. Estenda a mesh através de repetidores de internet pública. Encriptação ponto a ponto Mensagens privadas são encriptadas. Mensagens de canal são públicas. - Aparência Sistema Claro Escuro @@ -126,7 +124,6 @@ Estado do Tor: %1$s, bootstrap %2$d%% Último: %1$s Limpeza de dados de emergência - Dica: Toque três vezes no título da aplicação para apagar todos os dados guardados – incluindo mensagens, chaves e definições. Definições de depuração Código aberto • Privacidade primeiro • Descentralizado Fechar @@ -146,7 +143,6 @@ Abrir mapa Remover marcador Teletransportar - Selecionado Sair do canal Alcançável via Nostr Favorito (offline) @@ -285,7 +281,6 @@ Permissões Conceder permissões O bitchat NÃO rastreia a sua localização - PESSOAS ninguém por perto… (você) arraste e amplie para selecionar um geohash diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 76b332ff..5672cd00 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -64,7 +64,6 @@ Добавить закладку назад - канал: %1$s выйти Доступен через Nostr Непрочитанные личные @@ -92,7 +91,6 @@ Общайся с людьми поблизости через каналы на основе geohash. Расширяй mesh через публичные ретрансляторы. Сквозное шифрование Личные сообщения — зашифрованы. Канальные — публичны. - оформление система светлая тёмная @@ -116,7 +114,6 @@ статус Tor: %1$s, загрузка %2$d%% Последнее: %1$s Экстренное удаление данных - Совет: тройной тап по заголовку — удалить все данные (сообщения, ключи, настройки). Настройки отладки Open Source • Privacy First • Децентрализация Закрыть @@ -135,7 +132,6 @@ Открыть карту Удалить закладку Телепорт - Выбрано Покинуть канал Доступен через Nostr Избранное (оффлайн) @@ -264,7 +260,6 @@ bitchat НЕ отслеживает вашу геопозицию @ · ⧉ - ЛЮДИ никого рядом… (вы) прокрутите/масштабируйте для выбора geohash diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index e465e4da..a6df7a8e 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -64,7 +64,6 @@ Lägg till bokmärke tillbaka - kanal: %1$s lämna Nås via Nostr Olästa privata meddelanden @@ -92,7 +91,6 @@ Anslut med personer i närheten via geohash‑kanaler. Utöka mesh via publika internetreläer. Ända‑till‑ända‑kryptering Privata meddelanden är krypterade. Kanalmeddelanden är publika. - utseende system ljus mörk @@ -116,7 +114,6 @@ Tor‑status: %1$s, bootstrap %2$d%% Senast: %1$s Nödradering av data - Tips: tryck tre gånger på appens titel för att radera alla data (meddelanden, nycklar, inställningar). Felsökningsinställningar Open Source • Privacy First • Decentraliserad Stäng @@ -135,7 +132,6 @@ Öppna karta Ta bort bokmärke Teleportera - Vald Lämna kanal Nås via Nostr Favorit (offline) @@ -264,7 +260,6 @@ bitchat spårar INTE din plats @ · ⧉ - PERSONER ingen i närheten… (du) panorera och zooma för att välja geohash diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 33d45309..af9111fa 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -72,7 +72,6 @@ กลับ - ช่อง: %1$s ออก ติดต่อได้ผ่าน Nostr ข้อความส่วนตัวยังไม่ได้อ่าน @@ -102,7 +101,6 @@ เชื่อมต่อกับผู้คนใกล้คุณผ่านช่องที่อ้างอิง geohash ขยายเมชผ่านรีเลย์อินเทอร์เน็ตสาธารณะ การเข้ารหัสแบบปลายทางถึงปลายทาง ข้อความส่วนตัวถูกเข้ารหัส ข้อความในช่องเป็นสาธารณะ - ลักษณะ ระบบ สว่าง มืด @@ -126,7 +124,6 @@ สถานะ Tor: %1$s, การบูต %2$d%% ล่าสุด: %1$s ลบข้อมูลฉุกเฉิน - เคล็ดลับ: แตะชื่อแอปสามครั้งเพื่อลบข้อมูลที่บันทึกทั้งหมด – รวมทั้งข้อความ กุญแจ และการตั้งค่า การตั้งค่าดีบัก โอเพนซอร์ส • ความเป็นส่วนตัวมาก่อน • กระจายศูนย์ ปิด @@ -146,7 +143,6 @@ เปิดแผนที่ เอาที่คั่นหน้าออก เทเลพอร์ต - ที่เลือก ออกจากช่อง ติดต่อได้ผ่าน Nostr รายการโปรด (ออฟไลน์) @@ -285,7 +281,6 @@ สิทธิ์ ให้สิทธิ์ bitchat ไม่ติดตามตำแหน่งของคุณ - ผู้คน ไม่มีใครอยู่ใกล้… (คุณ) ลาก/ซูมเพื่อเลือก geohash diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 0eccd05f..721b50c1 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -64,7 +64,6 @@ Yer imi ekle geri - kanal: %1$s ayrıl Nostr üzerinden ulaşılabilir Okunmamış özel mesaj @@ -92,7 +91,6 @@ Geohash tabanlı kanallarla yakınındaki insanlarla bağlantı kur. Herkese açık internet röleleriyle mesh’i genişlet. Uçtan Uca Şifreleme Özel mesajlar şifrelidir. Kanal mesajları herkese açıktır. - görünüm sistem açık koyu @@ -116,7 +114,6 @@ Tor durumu: %1$s, önyükleme %2$d%% Son: %1$s Acil veri silme - İpucu: tüm verileri silmek için uygulama başlığına üç kez dokun (mesajlar, anahtarlar, ayarlar). Hata ayıklama ayarları Open Source • Privacy First • Merkezsiz Kapat @@ -135,7 +132,6 @@ Haritayı aç Yer imini kaldır Teleport - Seçildi Kanaldan ayrıl Nostr üzerinden erişilebilir Favori (çevrimdışı) @@ -264,7 +260,6 @@ bitchat konumunu takip etmez @ · ⧉ - KİŞİLER yakında kimse yok… (sen) geohash seçmek için kaydır/zoom yap diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index df6d1f4f..0f11e124 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -72,7 +72,6 @@ واپس - چینل: %1$s چھوڑیں Nostr کے ذریعے رسائی غیر پڑھے ہوئے نجی پیغامات @@ -102,7 +101,6 @@ geohash پر مبنی چینلز کے ذریعے اپنے قریب کے لوگوں سے جڑیں۔ عوامی انٹرنیٹ ریلے کے ذریعے میش کو پھیلائیں۔ اینڈ‑ٹو‑اینڈ انکرپشن نجی پیغامات انکرپٹڈ ہیں۔ چینل پیغامات عوامی ہیں۔ - ظاہری شکل سسٹم ہلکا گہرا @@ -126,7 +124,6 @@ Tor کی کیفیت: %1$s، بوٹ اسٹریپ %2$d%% آخری: %1$s ہنگامی ڈیٹا صافی - تجویز: تمام محفوظ شدہ ڈیٹا – پیغامات، کلیدیں اور سیٹنگز سمیت – صاف کرنے کے لیے ایپ کے ٹائٹل پر تین بار ٹیپ کریں۔ ڈیبگ سیٹنگز اوپن سورس • پرائیویسی پہلے • غیر مرکزی بند کریں @@ -146,7 +143,6 @@ نقشہ کھولیں بک مارک ہٹائیں ٹیلی پورٹ - منتخب چینل چھوڑیں Nostr کے ذریعے رسائی پسندیدہ (آف لائن) @@ -285,7 +281,6 @@ اجازات اجازات دیں bitchat آپ کا مقام ٹریک نہیں کرتا - لوگ یہاں کوئی نہیں… (آپ) geohash منتخب کرنے کے لیے پین/زوم کریں diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index b5cd2a6e..083a930a 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -72,7 +72,6 @@ quay lại - Kênh: %1$s rời khỏi Có thể tiếp cận qua Nostr Tin nhắn riêng chưa đọc @@ -102,7 +101,6 @@ Kết nối với những người trong khu vực của bạn qua các kênh dựa trên geohash. Mở rộng mesh qua các relay Internet công cộng. Mã hóa đầu cuối Tin nhắn riêng được mã hóa. Tin nhắn kênh là công khai. - Giao diện Hệ thống Sáng Tối @@ -126,7 +124,6 @@ Trạng thái Tor: %1$s, Bootstrap %2$d%% Cuối cùng: %1$s Xóa dữ liệu khẩn cấp - Mẹo: Nhấn ba lần vào tiêu đề ứng dụng để xóa tất cả dữ liệu đã lưu – bao gồm tin nhắn, khóa và cài đặt. Cài đặt debug Mã nguồn mở • Quyền riêng tư trước tiên • Phi tập trung Đóng @@ -146,7 +143,6 @@ Mở bản đồ Xóa bookmark Dịch chuyển - Đã chọn Rời khỏi kênh Có thể tiếp cận qua Nostr Yêu thích (ngoại tuyến) @@ -285,7 +281,6 @@ Quyền Cấp quyền bitchat KHÔNG theo dõi vị trí của bạn - MỌI NGƯỜI không có ai xung quanh … (bạn) di chuyển và zoom để chọn geohash diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 05143855..75d92b58 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -72,7 +72,6 @@ 返回 - 频道:%1$s 离开 可通过 Nostr 联系 未读私信 @@ -102,7 +101,6 @@ 使用基于 geohash 的频道与附近的人交流。通过公共互联网中继扩展 mesh。 端到端加密 私信加密;频道消息为公开。 - 外观 系统 浅色 深色 @@ -126,7 +124,6 @@ Tor 状态:%1$s,引导 %2$d%% 最近:%1$s 紧急数据删除 - 提示:三击应用标题以删除所有数据,包括消息、密钥和设置。 调试设置 Open Source • Privacy First • 去中心化 关闭 @@ -146,7 +143,6 @@ 打开地图 移除书签 传送 - 已选择 离开频道 可通过 Nostr 联系 收藏(离线) @@ -280,7 +276,6 @@ bitchat 不会跟踪你的位置 @ · ⧉ - 成员 附近无人… (你) 拖动/缩放以选择 geohash diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e20a4b49..594d6879 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -73,7 +73,6 @@ back - channel: %1$s leave Nostr reachable Unread private messages @@ -131,15 +130,10 @@ Settings - Offline Communication - Chat over a Bluetooth mesh with no internet and no servers. Messages relay through nearby devices to extend range. - Local Channels - Geohash channels connect you with people nearby, extending the mesh over public relays. No Tracking No servers, accounts, or data collection. Ephemeral Identity A new peer ID is generated regularly. - Panic Mode Triple-tap the logo to instantly clear all data. @@ -153,13 +147,12 @@ Connected (%1$d%%) Disconnected - Offline Mesh Chat - Communicate directly via Bluetooth LE without internet or servers. Messages relay through nearby devices to extend range. - Online Geohash Channels - Connect with people in your area using geohash-based channels. Extend the mesh using public internet relays. + Offline Communication + Chat over a Bluetooth mesh with no internet and no servers. Messages relay through nearby devices to extend range. + Local Channels + Geohash channels connect you with people nearby, extending the mesh over public relays. End-to-End Encryption Private messages are encrypted. Channel messages are public. - appearance system light dark @@ -182,8 +175,7 @@ route internet over tor for enhanced privacy. tor Status: %1$s, bootstrap %2$d%% Last: %1$s - Emergency Data Deletion - Tip: Triple-click the app title to emergency delete all stored data including messages, keys, and settings. + Panic Mode Debug Settings Open Source • Privacy First • Decentralized Close @@ -204,7 +196,6 @@ Open map Remove bookmark Teleport - Selected Quit bitchat run in background keep mesh active when app is closed (foreground service) @@ -260,19 +251,15 @@ chat with people near you using geohash channels. only a coarse geohash is shared, never exact gps. do not screenshot or share this screen to protect your privacy. - Bookmarked Nearby Tor Routing Hides your IP for location channels. Recommended - Remove location access People (%1$d) On location Teleported in - Channels - Mesh grant location permission location permission denied. enable in settings to use location channels. @@ -284,7 +271,7 @@ geohash invalid geohash teleport - disable location services + Remove location access enable location services mesh block @@ -433,7 +420,6 @@ @ Open About · ⧉ - PEOPLE nobody around... (you) pan and zoom to select a geohash diff --git a/app/src/test/java/com/bitchat/android/ui/ChatUIUtilsTest.kt b/app/src/test/java/com/bitchat/android/ui/ChatUIUtilsTest.kt index 44072412..e35e37f1 100644 --- a/app/src/test/java/com/bitchat/android/ui/ChatUIUtilsTest.kt +++ b/app/src/test/java/com/bitchat/android/ui/ChatUIUtilsTest.kt @@ -12,7 +12,14 @@ import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +/** + * Runs under Robolectric because URL detection in message bodies goes through + * `android.util.Patterns.WEB_URL`, which is null on a bare JVM. + */ +@RunWith(RobolectricTestRunner::class) class ChatUIUtilsTest { private val timeFormatter = SimpleDateFormat("HH:mm:ss", Locale.ROOT).apply { timeZone = java.util.TimeZone.getTimeZone("UTC") @@ -226,7 +233,7 @@ class ChatUIUtilsTest { val sender = formatTextMessageSender( message = message("hi", sender = "carol#04af"), currentUserNickname = "bob", - meshService = FakeMeshServiceIds.stub(), + myPeerID = "peer-me", palette = palette, ) @@ -246,7 +253,7 @@ class ChatUIUtilsTest { val other = formatTextMessageSender( message = message("hi", sender = "carol#04af"), currentUserNickname = "bob", - meshService = FakeMeshServiceIds.stub(), + myPeerID = "peer-me", palette = palette, ) assertEquals(1, other.getStringAnnotations("nickname_click", 0, other.length).size) @@ -254,7 +261,7 @@ class ChatUIUtilsTest { val mine = formatTextMessageSender( message = message("hi", sender = "bob"), currentUserNickname = "bob", - meshService = FakeMeshServiceIds.stub(), + myPeerID = "peer-me", palette = palette, ) assertTrue(mine.getStringAnnotations("nickname_click", 0, mine.length).isEmpty()) diff --git a/app/src/test/java/com/bitchat/android/ui/MessageGroupingTest.kt b/app/src/test/java/com/bitchat/android/ui/MessageGroupingTest.kt new file mode 100644 index 00000000..4ba8ffa0 --- /dev/null +++ b/app/src/test/java/com/bitchat/android/ui/MessageGroupingTest.kt @@ -0,0 +1,152 @@ +package com.bitchat.android.ui + +import androidx.compose.ui.unit.dp +import com.bitchat.android.model.BitchatMessage +import java.util.Date +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +/** + * Grouping decides whether a message repeats its author's name. Getting it wrong either spams + * the transcript with redundant labels or, worse, silently attributes one person's message to + * another — hence the emphasis on the negative cases here. + */ +class MessageGroupingTest { + + private val base = 1_700_000_000_000L + + private fun message( + sender: String = "alice", + senderPeerId: String? = "peer-alice", + offsetMs: Long = 0L, + isPrivate: Boolean = false, + channel: String? = null, + content: String = "hello", + ) = BitchatMessage( + sender = sender, + content = content, + timestamp = Date(base + offsetMs), + isPrivate = isPrivate, + senderPeerID = senderPeerId, + channel = channel, + ) + + @Test + fun `first message in a list never groups`() { + assertFalse(MessageGrouping.shouldGroup(previous = null, current = message())) + } + + @Test + fun `consecutive messages from the same peer group`() { + val first = message(offsetMs = 0) + val second = message(offsetMs = 30_000) + + assertTrue(MessageGrouping.shouldGroup(first, second)) + } + + @Test + fun `messages from different peers do not group`() { + val first = message(sender = "alice", senderPeerId = "peer-alice") + val second = message(sender = "bob", senderPeerId = "peer-bob", offsetMs = 1_000) + + assertFalse(MessageGrouping.shouldGroup(first, second)) + } + + @Test + fun `same nickname but different peer id does not group`() { + // Two people can pick the same nickname; peer ID is the authority. + val first = message(sender = "alice", senderPeerId = "peer-one") + val second = message(sender = "alice", senderPeerId = "peer-two", offsetMs = 1_000) + + assertFalse(MessageGrouping.shouldGroup(first, second)) + } + + @Test + fun `falls back to display name when peer ids are unavailable`() { + val first = message(sender = "alice#04af", senderPeerId = null) + val second = message(sender = "alice#04af", senderPeerId = null, offsetMs = 1_000) + val other = message(sender = "bob#1122", senderPeerId = null, offsetMs = 2_000) + + assertTrue(MessageGrouping.shouldGroup(first, second)) + assertFalse(MessageGrouping.shouldGroup(second, other)) + } + + @Test + fun `messages outside the grouping window start a new group`() { + val first = message(offsetMs = 0) + val justInside = message(offsetMs = MessageGrouping.GROUPING_WINDOW_MS) + val justOutside = message(offsetMs = MessageGrouping.GROUPING_WINDOW_MS + 1) + + assertTrue(MessageGrouping.shouldGroup(first, justInside)) + assertFalse(MessageGrouping.shouldGroup(first, justOutside)) + } + + @Test + fun `out of order timestamps do not group`() { + // Mesh delivery can surface messages out of order; a negative delta means we cannot + // reason about adjacency, so fall back to showing the sender. + val later = message(offsetMs = 60_000) + val earlier = message(offsetMs = 0) + + assertFalse(MessageGrouping.shouldGroup(later, earlier)) + } + + @Test + fun `system messages never group in either direction`() { + val system = message(sender = "system", senderPeerId = null, content = "tor started") + val user = message(offsetMs = 1_000) + + assertFalse(MessageGrouping.shouldGroup(system, user)) + assertFalse(MessageGrouping.shouldGroup(user, system.copyWithOffset(2_000))) + assertFalse(MessageGrouping.shouldGroup(system, system.copyWithOffset(1_000))) + } + + @Test + fun `grouping does not cross the public private boundary`() { + val public = message(isPrivate = false) + val private = message(isPrivate = true, offsetMs = 1_000) + + assertFalse(MessageGrouping.shouldGroup(public, private)) + } + + @Test + fun `grouping does not cross channels`() { + val inGeneral = message(channel = "#general") + val inRandom = message(channel = "#random", offsetMs = 1_000) + val inNoChannel = message(channel = null, offsetMs = 2_000) + + assertFalse(MessageGrouping.shouldGroup(inGeneral, inRandom)) + assertFalse(MessageGrouping.shouldGroup(inGeneral, inNoChannel)) + } + + @Test + fun `peer id comparison ignores case`() { + val first = message(senderPeerId = "PEER-Alice") + val second = message(senderPeerId = "peer-alice", offsetMs = 1_000) + + assertTrue(MessageGrouping.shouldGroup(first, second)) + } + + // MARK: - Spacing + + @Test + fun `spacing is zero for the very first row`() { + assertEquals(0.dp, MessageGrouping.topSpacingFor(isGrouped = false, isFirstInList = true)) + assertEquals(0.dp, MessageGrouping.topSpacingFor(isGrouped = true, isFirstInList = true)) + } + + @Test + fun `grouped rows sit tighter than the start of a new group`() { + val grouped = MessageGrouping.topSpacingFor(isGrouped = true, isFirstInList = false) + val newGroup = MessageGrouping.topSpacingFor(isGrouped = false, isFirstInList = false) + + assertEquals(MessageGrouping.GROUPED_SPACING, grouped) + assertEquals(MessageGrouping.NEW_GROUP_SPACING, newGroup) + assertTrue("a new speaker needs more air than a continuation", newGroup > grouped) + } + + private fun BitchatMessage.copyWithOffset(offsetMs: Long) = + copy(timestamp = Date(base + offsetMs)) +}