Merge branch 'master' into master-ios

This commit is contained in:
spaced4ndy
2023-06-16 19:06:31 +04:00
38 changed files with 310 additions and 92 deletions
+5 -5
View File
@@ -16,11 +16,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone project
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Build changelog
id: build_changelog
uses: mikepenz/release-changelog-builder-action@v1
uses: mikepenz/release-changelog-builder-action@v4
with:
configuration: .github/changelog_conf.json
failOnError: true
@@ -71,16 +71,16 @@ jobs:
disk-root: "C:"
- name: Clone project
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Setup Haskell
uses: haskell/actions/setup@v1
uses: haskell/actions/setup@v2
with:
ghc-version: "8.10.7"
cabal-version: "latest"
- name: Cache dependencies
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
${{ matrix.cache_path }}
+1 -1
View File
@@ -64,7 +64,7 @@ You must:
Messages not following these rules will be deleted, the right to send messages may be revoked, and the access to the new members to the group may be temporarily restricted, to prevent re-joining under a different name - our imperfect group moderation does not have a better solution at the moment.
You can join an English-speaking users group if you want to ask any questions: [#SimpleX-Group-3](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fp-j-D_PrY2UMDchFHEUtbSES0nmzCnvD%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA3gBfMjB_GDEmKQwjNdqGbnX91yfuZ7nRJgQijsx5Khc%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%2262MvNZ_Ec2mmlS8V0QNtLQ%3D%3D%22%7D)
You can join an English-speaking users group if you want to ask any questions: [#SimpleX-Group-4](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2Fw2GlucRXtRVgYnbt_9ZP-kmt76DekxxS%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA0tJhTyMGUxznwmjb7aT24P1I1Wry_iURTuhOFlMb1Eo%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22WoPxjFqGEDlVazECOSi2dg%3D%3D%22%7D)
There are groups in other languages, that we have the apps interface translated into. These groups are for testing, and asking questions to other SimpleX Chat users:
+3 -2
View File
@@ -13,8 +13,8 @@ android {
targetSdk 32
// !!!
// skip version code after release to F-Droid, as it uses two version codes
versionCode 125
versionName "5.1.2"
versionCode 127
versionName "5.1.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@@ -170,6 +170,7 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "com.jakewharton:process-phoenix:2.1.2"
}
// Don't do anything if no compression is needed
@@ -10,6 +10,7 @@ import chat.simplex.app.ui.theme.DefaultTheme
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.onboarding.OnboardingStage
import chat.simplex.app.views.usersettings.NotificationsMode
import com.jakewharton.processphoenix.ProcessPhoenix
import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
import java.io.*
@@ -101,6 +102,9 @@ class SimplexApp: Application(), LifecycleEventObserver {
override fun onCreate() {
super.onCreate()
if (ProcessPhoenix.isPhoenixProcess(this)) {
return;
}
context = this
context.getDir("temp", MODE_PRIVATE).deleteRecursively()
withBGApi {
@@ -166,7 +166,6 @@ class SimplexService: Service() {
it.setPackage(packageName)
};
val restartServicePendingIntent: PendingIntent = PendingIntent.getService(this, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE);
applicationContext.getSystemService(Context.ALARM_SERVICE);
val alarmService: AlarmManager = applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager;
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, restartServicePendingIntent);
}
@@ -6,7 +6,7 @@ import SectionItemView
import SectionItemViewWithIcon
import SectionView
import TextIconSpaced
import android.content.Context
import android.content.*
import android.content.res.Configuration
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
@@ -25,16 +25,16 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.*
import androidx.fragment.app.FragmentActivity
import androidx.work.WorkManager
import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.database.DatabaseView
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.CreateLinkTab
import chat.simplex.app.views.newchat.CreateLinkView
import chat.simplex.app.views.onboarding.SimpleXInfo
import chat.simplex.app.views.onboarding.WhatsNewView
import com.jakewharton.processphoenix.ProcessPhoenix
@Composable
fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) -> Unit) {
@@ -181,7 +181,9 @@ fun SettingsLayout(
}
SectionDividerSpaced()
SectionView(stringResource(R.string.settings_section_title_develop)) {
SectionView(stringResource(R.string.settings_section_title_app)) {
SettingsActionItem(painterResource(R.drawable.ic_restart_alt), stringResource(R.string.settings_restart_app), ::restartApp, extraPadding = true)
SettingsActionItem(painterResource(R.drawable.ic_power_settings_new), stringResource(R.string.settings_shutdown), { shutdownAppAlert(::shutdownApp) }, extraPadding = true)
SettingsActionItem(painterResource(R.drawable.ic_code), stringResource(R.string.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }, extraPadding = true)
AppVersionItem(showVersion)
}
@@ -490,6 +492,26 @@ private fun runAuth(title: String, desc: String, context: Context, onFinish: (su
)
}
private fun restartApp() {
ProcessPhoenix.triggerRebirth(SimplexApp.context)
shutdownApp()
}
private fun shutdownApp() {
WorkManager.getInstance(SimplexApp.context).cancelAllWork()
SimplexService.safeStopService(SimplexApp.context)
Runtime.getRuntime().exit(0)
}
private fun shutdownAppAlert(onConfirm: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.shutdown_alert_question),
text = generalGetString(R.string.shutdown_alert_desc),
destructive = true,
onConfirm = onConfirm
)
}
@Preview(showBackground = true)
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="960"
android:viewportWidth="960" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M479.83,521.5q-12.32,0 -20.33,-8.38t-8,-20.63v-344q0,-11.68 8.18,-20.09 8.18,-8.41 20.5,-8.41 12.32,0 20.58,8.41Q509,136.83 509,148.5v344q0,12.25 -8.43,20.63 -8.43,8.38 -20.75,8.38ZM480.07,837.5q-74.07,0 -138.82,-28 -64.75,-28 -112.75,-76t-76,-112.7q-28,-64.7 -28,-138.8 0,-70 27.73,-133.75 27.73,-63.75 77.17,-114.06 9.1,-9.19 22.16,-9.69 13.06,-0.5 21.78,8.32 9.16,9.3 7.41,21.24Q279,266 270.5,274.5 228,316 205,369.36q-23,53.36 -23,112.76 0,124.23 86.94,211.05Q355.88,780 480.12,780t211.06,-86.93Q778,606.13 778,481.9q0,-59.4 -22.39,-112.74Q733.21,315.82 691.5,274q-9,-9 -10.25,-21.25T689,232.5q9.5,-9.5 22.75,-7.75T735,236.19q48,50.31 74.25,113.35t26.25,132.49q0,73.97 -28,138.72 -28,64.75 -76,112.75t-112.68,76q-64.68,28 -138.75,28Z"/>
</vector>
@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="960"
android:viewportWidth="960" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M421,830q-110,-20 -183.25,-107.25T164.5,520.5q0,-71 30.5,-134.25t86,-106.75q7.5,-5.5 18.25,-4.75T317.5,283q9.5,9.5 8.5,22t-13,22q-43.5,35 -67.25,86T222,520.5q0,93.5 58,163T427,772q10.5,2 18,10.5t7.5,19.5q0,13.5 -9.75,21.75T421,830ZM541,830q-12,2 -21.5,-6.25T510,802q0,-10.5 7.25,-19.25T535.5,772q90,-19 147,-88.5t57,-163q0,-108 -75,-183.25T481,262h-21l41,41q8,8 8,20.25T501,343q-9,9 -21.25,9T460,343l-91,-89.5q-5,-4.5 -7,-9.25t-2,-10.75q0,-6 2,-10.75t7,-9.25l91,-91q7.5,-8 19.75,-8t21.25,8q8,9 8,21.25t-8,19.75l-41,41h21q132,0 224,92.5t92,223.5q0,115 -73,202.25T541,830Z"/>
</vector>
@@ -723,7 +723,6 @@
\n3. Spojení je kompromitováno.</string>
<string name="settings_section_title_you">VY</string>
<string name="settings_section_title_support">PODPOŘIT SIMPLEX CHAT</string>
<string name="settings_section_title_develop">VÝVOJ</string>
<string name="settings_developer_tools">Nástroje pro vývojáře</string>
<string name="settings_section_title_incognito">inkognito mód</string>
<string name="your_chat_database">Chat databáze</string>
@@ -564,7 +564,6 @@
<string name="settings_section_title_settings">EINSTELLUNGEN</string>
<string name="settings_section_title_help">HILFE</string>
<string name="settings_section_title_support">UNTERSTÜTZUNG VON SIMPLEX CHAT</string>
<string name="settings_section_title_develop">ENTWICKLUNG</string>
<string name="settings_section_title_device">GERÄT</string>
<string name="settings_section_title_chats">CHATS</string>
<string name="settings_developer_tools">Entwicklertools</string>
@@ -114,7 +114,6 @@
<string name="encrypted_audio_call">Llamada con cifrado de extremo a extremo</string>
<string name="status_e2e_encrypted">cifrado de extremo a extremo</string>
<string name="integrity_msg_duplicate">mensaje duplicado</string>
<string name="settings_section_title_develop">DESARROLLO</string>
<string name="settings_developer_tools">Herramientas desarrollo</string>
<string name="delete_files_and_media_for_all_users">Eliminar los archivos de todos los perfiles</string>
<string name="delete_messages">Eliminar mensaje</string>
@@ -535,7 +535,6 @@
<string name="call_already_ended">Appel déjà terminé !</string>
<string name="settings_audio_video_calls">Appels audio et vidéo</string>
<string name="status_e2e_encrypted">chiffré de bout en bout</string>
<string name="settings_section_title_develop">DEVELOPPER</string>
<string name="settings_experimental_features">Fonctionnalités expérimentales</string>
<string name="settings_section_title_socks">SOCKS PROXY</string>
<string name="settings_section_title_themes">THEMES</string>
@@ -271,7 +271,6 @@
<string name="snd_conn_event_switch_queue_phase_changing_for_member">%s के लिए पता बदल रहा है…</string>
<string name="dont_show_again">दोबारा मत दिखाओ</string>
<string name="both_you_and_your_contact_can_send_voice">आप और आपका संपर्क दोनों ध्वनि संदेश भेज सकते हैं।</string>
<string name="settings_section_title_develop">विकास करना</string>
<string name="user_mute">आवाज़ बंद करना</string>
<string name="allow_your_contacts_to_send_disappearing_messages">अपने संपर्कों को गायब होने वाले संदेश भेजने की अनुमति दें।</string>
<string name="v4_6_audio_video_calls">ऑडियो और वीडियो कॉल</string>
@@ -395,7 +395,6 @@
<string name="database_passphrase">Password del database</string>
<string name="delete_chat_profile_question">Eliminare il profilo di chat\?</string>
<string name="delete_database">Elimina database</string>
<string name="settings_section_title_develop">SVILUPPA</string>
<string name="settings_developer_tools">Strumenti di sviluppo</string>
<string name="settings_section_title_device">DISPOSITIVO</string>
<string name="error_deleting_database">Errore nell\'eliminazione del database della chat</string>
@@ -328,7 +328,6 @@
<string name="button_delete_group">מחק קבוצה</string>
<string name="delete_group_question">למחוק קבוצה\?</string>
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 שולחן עבודה: סירקו את קוד ה־QR המוצג באפליקציה, באמצעות <b>סריקת קוד QR</b>.</string>
<string name="settings_section_title_develop">פיתוח</string>
<string name="settings_section_title_device">מכשיר</string>
<string name="auth_device_authentication_is_disabled_turning_off">נעילת המכשיר מושבתת. מכבה נעילת SimpleX.</string>
<string name="auth_device_authentication_is_not_enabled_you_can_turn_on_in_settings_once_enabled">נעילת המכשיר אינה מופעלת. ניתן להפעיל את נעילת SimpleX, לאחר שתפעילו את נעילת המכשיר.</string>
@@ -349,7 +349,6 @@
<string name="icon_descr_flip_camera">カメラ切り替え</string>
<string name="icon_descr_call_missed">不在着信</string>
<string name="icon_descr_call_rejected">拒否した通話</string>
<string name="settings_section_title_develop">開発</string>
<string name="integrity_msg_duplicate">重複メッセージ</string>
<string name="settings_section_title_help">ヘルプ</string>
<string name="protect_app_screen">アプリ画面を守る</string>
@@ -232,7 +232,6 @@
<string name="delete_address__question">주소를 삭제할까요\?</string>
<string name="delete_image">이미지 삭제</string>
<string name="decentralized">탈중앙화</string>
<string name="settings_section_title_develop">개발</string>
<string name="settings_developer_tools">개발자 도구</string>
<string name="settings_section_title_device">기기</string>
<string name="database_passphrase">데이터베이스 비밀번호</string>
@@ -242,7 +242,6 @@
<string name="full_deletion">Verwijderen voor iedereen</string>
<string name="delete_link">Link verwijderen</string>
<string name="conn_level_desc_direct">direct</string>
<string name="settings_section_title_develop">ONTWIKKELEN</string>
<string name="settings_section_title_device">APPARAAT</string>
<string name="delete_files_and_media_all">Verwijder alle bestanden</string>
<string name="delete_messages_after">Berichten verwijderen na</string>
@@ -515,7 +515,6 @@
<string name="settings_section_title_chats">CZATY</string>
<string name="database_passphrase">Hasło do bazy danych</string>
<string name="delete_database">Usuń bazę danych</string>
<string name="settings_section_title_develop">DEWELOPERSKIE</string>
<string name="settings_developer_tools">Narzędzia deweloperskie</string>
<string name="settings_section_title_device">URZĄDZENIE</string>
<string name="error_starting_chat">Błąd uruchamiania czatu</string>
@@ -745,7 +745,6 @@
<string name="callstatus_missed">chamada perdida</string>
<string name="you_can_use_markdown_to_format_messages__prompt">Você pode usar markdown para formatar mensagens:</string>
<string name="callstatus_rejected">chamada rejeitada</string>
<string name="settings_section_title_develop">DESENVOLVER</string>
<string name="rcv_group_event_member_left">saiu</string>
<string name="incompatible_database_version">Versão do banco de dados incompatível</string>
<string name="button_remove_member">Remover membro</string>
@@ -568,7 +568,6 @@
<string name="settings_section_title_settings">НАСТРОЙКИ</string>
<string name="settings_section_title_help">ПОМОЩЬ</string>
<string name="settings_section_title_support">ПОДДЕРЖАТЬ SIMPLEX CHAT</string>
<string name="settings_section_title_develop">ДЛЯ РАЗРАБОТЧИКОВ</string>
<string name="settings_section_title_device">УСТРОЙСТВО</string>
<string name="settings_section_title_chats">ЧАТЫ</string>
<string name="settings_developer_tools">Инструменты разработчика</string>
@@ -378,7 +378,6 @@
<string name="encrypt_database_question">加密数据库?</string>
<string name="encrypted_with_random_passphrase">数据库使用随机密码进行加密,您可以更改它。</string>
<string name="database_passphrase_is_required">打开聊天需要数据库密码。</string>
<string name="settings_section_title_develop">开发</string>
<string name="error_stopping_chat">停止聊天错误</string>
<string name="import_database_question">导入聊天数据库?</string>
<string name="error_deleting_database">删除聊天数据库错误</string>
@@ -681,7 +681,6 @@
<string name="integrity_msg_duplicate">重覆的訊息</string>
<string name="protect_app_screen">保護應用程式螢幕</string>
<string name="send_link_previews">傳送可以預覽的連結</string>
<string name="settings_section_title_develop">開發</string>
<string name="settings_section_title_device">裝置</string>
<string name="settings_section_title_help">幫助</string>
<string name="settings_section_title_settings">設定</string>
@@ -602,6 +602,8 @@
<string name="hide_dev_options">Hide:</string>
<string name="show_developer_options">Show developer options</string>
<string name="developer_options">Database IDs and Transport isolation option.</string>
<string name="shutdown_alert_question">Shutdown?</string>
<string name="shutdown_alert_desc">Notifications will stop working until you re-launch the app</string>
<!-- Address Items - UserAddressView.kt -->
<string name="create_address">Create address</string>
@@ -851,9 +853,11 @@
<string name="settings_section_title_settings">SETTINGS</string>
<string name="settings_section_title_help">HELP</string>
<string name="settings_section_title_support">SUPPORT SIMPLEX CHAT</string>
<string name="settings_section_title_develop">DEVELOP</string>
<string name="settings_section_title_app">APP</string>
<string name="settings_section_title_device">DEVICE</string>
<string name="settings_section_title_chats">CHATS</string>
<string name="settings_restart_app">Restart</string>
<string name="settings_shutdown">Shutdown</string>
<string name="settings_developer_tools">Developer tools</string>
<string name="settings_experimental_features">Experimental features</string>
<string name="settings_section_title_socks">SOCKS PROXY</string>
+39 -11
View File
@@ -537,8 +537,20 @@ struct ChatView: View {
private func menu(live: Bool) -> [UIMenuElement] {
var menu: [UIMenuElement] = []
if let mc = ci.content.msgContent, ci.meta.itemDeleted == nil || revealed {
let rs = allReactions()
if chat.chatInfo.featureEnabled(.reactions) && ci.allowAddReaction,
let rm = reactionUIMenu() {
rs.count > 0 {
var rm: UIMenu
if #available(iOS 16, *) {
var children: [UIMenuElement] = Array(rs.prefix(topReactionsCount(rs)))
if let sm = reactionUIMenu(rs) {
children.append(sm)
}
rm = UIMenu(title: "", options: .displayInline, children: children)
rm.preferredElementSize = .small
} else {
rm = reactionUIMenuPreiOS16(rs)
}
menu.append(rm)
}
if ci.meta.itemDeleted == nil && !ci.isLiveDummy && !live {
@@ -602,20 +614,36 @@ struct ChatView: View {
}
}
private func reactionUIMenu() -> UIMenu? {
let rs = MsgReaction.values.compactMap { r in
private func reactionUIMenuPreiOS16(_ rs: [UIAction]) -> UIMenu {
UIMenu(
title: NSLocalizedString("React...", comment: "chat item menu"),
image: UIImage(systemName: "face.smiling"),
children: rs
)
}
@available(iOS 16.0, *)
private func reactionUIMenu(_ rs: [UIAction]) -> UIMenu? {
var children = rs
children.removeFirst(min(rs.count, topReactionsCount(rs)))
if children.count == 0 { return nil }
return UIMenu(
title: "",
image: UIImage(systemName: "ellipsis"),
children: children
)
}
private func allReactions() -> [UIAction] {
MsgReaction.values.compactMap { r in
ci.reactions.contains(where: { $0.userReacted && $0.reaction == r })
? nil
: UIAction(title: r.text) { _ in setReaction(add: true, reaction: r) }
}
if rs.count > 0 {
return UIMenu(
title: NSLocalizedString("React...", comment: "chat item menu"),
image: UIImage(systemName: "face.smiling"),
children: rs
)
}
return nil
}
private func topReactionsCount(_ rs: [UIAction]) -> Int {
rs.count > 4 ? 3 : 4
}
private func setReaction(add: Bool, reaction: MsgReaction) {
+28 -28
View File
@@ -83,11 +83,6 @@
5CA059EB279559F40002BEB4 /* SimpleXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059C3279559F40002BEB4 /* SimpleXApp.swift */; };
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059C4279559F40002BEB4 /* ContentView.swift */; };
5CA059EF279559F40002BEB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5CA059C5279559F40002BEB4 /* Assets.xcassets */; };
5CA4874A2A228AF400409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA487452A228AF300409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB-ghc8.10.7.a */; };
5CA4874B2A228AF400409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA487462A228AF300409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB.a */; };
5CA4874C2A228AF400409F23 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA487472A228AF300409F23 /* libgmp.a */; };
5CA4874D2A228AF400409F23 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA487482A228AF300409F23 /* libffi.a */; };
5CA4874E2A228AF400409F23 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CA487492A228AF400409F23 /* libgmpxx.a */; };
5CA7DFC329302AF000F7FDDE /* AppSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA7DFC229302AF000F7FDDE /* AppSheet.swift */; };
5CADE79A29211BB900072E13 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CADE79929211BB900072E13 /* PreferencesView.swift */; };
5CADE79C292131E900072E13 /* ContactPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CADE79B292131E900072E13 /* ContactPreferencesView.swift */; };
@@ -152,6 +147,11 @@
5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; };
6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; };
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */; };
643EE9682A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9632A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a */; };
643EE9692A372E8700678085 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9642A372E8700678085 /* libffi.a */; };
643EE96A2A372E8700678085 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9652A372E8700678085 /* libgmpxx.a */; };
643EE96B2A372E8700678085 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9662A372E8700678085 /* libgmp.a */; };
643EE96C2A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9672A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a */; };
6440CA00288857A10062C672 /* CIEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440C9FF288857A10062C672 /* CIEventView.swift */; };
6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */; };
6442E0BA287F169300CEC0F9 /* AddGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6442E0B9287F169300CEC0F9 /* AddGroupView.swift */; };
@@ -344,11 +344,6 @@
5CA059D7279559F40002BEB4 /* Tests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
5CA059DB279559F40002BEB4 /* Tests_iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_iOS.swift; sourceTree = "<group>"; };
5CA059DD279559F40002BEB4 /* Tests_iOSLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_iOSLaunchTests.swift; sourceTree = "<group>"; };
5CA487452A228AF300409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB-ghc8.10.7.a"; sourceTree = "<group>"; };
5CA487462A228AF300409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB.a"; sourceTree = "<group>"; };
5CA487472A228AF300409F23 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CA487482A228AF300409F23 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CA487492A228AF400409F23 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CA7DFC229302AF000F7FDDE /* AppSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSheet.swift; sourceTree = "<group>"; };
5CA85D0A297218AA0095AF72 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
5CA85D0B297218AA0095AF72 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -427,6 +422,11 @@
5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ZoomableScrollView.swift; path = Shared/Views/ZoomableScrollView.swift; sourceTree = SOURCE_ROOT; };
6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = "<group>"; };
6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = "<group>"; };
643EE9632A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a"; sourceTree = "<group>"; };
643EE9642A372E8700678085 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
643EE9652A372E8700678085 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
643EE9662A372E8700678085 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
643EE9672A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a"; sourceTree = "<group>"; };
6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = "<group>"; };
6440CA02288AECA70062C672 /* AddGroupMembersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupMembersView.swift; sourceTree = "<group>"; };
6442E0B9287F169300CEC0F9 /* AddGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupView.swift; sourceTree = "<group>"; };
@@ -498,12 +498,12 @@
buildActionMask = 2147483647;
files = (
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5CA4874D2A228AF400409F23 /* libffi.a in Frameworks */,
5CA4874C2A228AF400409F23 /* libgmp.a in Frameworks */,
5CA4874B2A228AF400409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB.a in Frameworks */,
5CA4874A2A228AF400409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB-ghc8.10.7.a in Frameworks */,
643EE96A2A372E8700678085 /* libgmpxx.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5CA4874E2A228AF400409F23 /* libgmpxx.a in Frameworks */,
643EE9682A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a in Frameworks */,
643EE96B2A372E8700678085 /* libgmp.a in Frameworks */,
643EE9692A372E8700678085 /* libffi.a in Frameworks */,
643EE96C2A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -564,11 +564,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5CA487482A228AF300409F23 /* libffi.a */,
5CA487472A228AF300409F23 /* libgmp.a */,
5CA487492A228AF400409F23 /* libgmpxx.a */,
5CA487452A228AF300409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB-ghc8.10.7.a */,
5CA487462A228AF300409F23 /* libHSsimplex-chat-5.1.2.0-6dy8xe3EoSOA3hcKQSY0MB.a */,
643EE9642A372E8700678085 /* libffi.a */,
643EE9662A372E8700678085 /* libgmp.a */,
643EE9652A372E8700678085 /* libgmpxx.a */,
643EE9672A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a */,
643EE9632A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1470,7 +1470,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 149;
CURRENT_PROJECT_VERSION = 150;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1491,7 +1491,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.1.2;
MARKETING_VERSION = 5.1.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1512,7 +1512,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 149;
CURRENT_PROJECT_VERSION = 150;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1533,7 +1533,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.1.2;
MARKETING_VERSION = 5.1.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1592,7 +1592,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 149;
CURRENT_PROJECT_VERSION = 150;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1605,7 +1605,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.1.2;
MARKETING_VERSION = 5.1.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1624,7 +1624,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 149;
CURRENT_PROJECT_VERSION = 150;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1637,7 +1637,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.1.2;
MARKETING_VERSION = 5.1.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
+1 -1
View File
@@ -7,7 +7,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: 89caf5572980b776bd750caa3c918ae4488612d8
tag: 2efe1496d2622a56656a6a00a2cc19005e754468
source-repository-package
type: git
+1 -1
View File
@@ -1,5 +1,5 @@
{
"https://github.com/simplex-chat/simplexmq.git"."89caf5572980b776bd750caa3c918ae4488612d8" = "0glils00403s4xxl84xa22wylfsrcpjj5j3v7srqhrmikm1jds4p";
"https://github.com/simplex-chat/simplexmq.git"."2efe1496d2622a56656a6a00a2cc19005e754468" = "0syy10zn3ci1nbs00r0l5vhvqkwlqcgmmd5c196pch0xvrk5qbfi";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/kazu-yamamoto/http2.git"."b5a1b7200cf5bc7044af34ba325284271f6dff25" = "0dqb50j57an64nf4qcf5vcz4xkd1vzvghvf8bk529c1k30r9nfzb";
"https://github.com/simplex-chat/direct-sqlcipher.git"."34309410eb2069b029b8fc1872deb1e0db123294" = "0kwkmhyfsn2lixdlgl15smgr1h5gjk7fky6abzh8rng2h5ymnffd";
+36 -11
View File
@@ -112,6 +112,7 @@ defaultChatConfig =
fileChunkSize = 15780, -- do not change
xftpDescrPartSize = 14000,
inlineFiles = defaultInlineFilesConfig,
autoAcceptFileSize = 0,
xftpFileConfig = Just defaultXFTPFileConfig,
tempDir = Nothing,
showReactions = False,
@@ -158,9 +159,9 @@ createChatDatabase filePrefix key confirmMigrations = runExceptT $ do
pure ChatDatabase {chatStore, agentStore}
newChatController :: ChatDatabase -> Maybe User -> ChatConfig -> ChatOpts -> Maybe (Notification -> IO ()) -> IO ChatController
newChatController ChatDatabase {chatStore, agentStore} user cfg@ChatConfig {agentConfig = aCfg, defaultServers, inlineFiles, tempDir} ChatOpts {coreOptions = CoreChatOpts {smpServers, xftpServers, networkConfig, logLevel, logConnections, logServerHosts, logFile, tbqSize}, optFilesFolder, showReactions, allowInstantFiles} sendToast = do
let inlineFiles' = if allowInstantFiles then inlineFiles else inlineFiles {sendChunks = 0, receiveInstant = False}
config = cfg {logLevel, showReactions, tbqSize, subscriptionEvents = logConnections, hostEvents = logServerHosts, defaultServers = configServers, inlineFiles = inlineFiles'}
newChatController ChatDatabase {chatStore, agentStore} user cfg@ChatConfig {agentConfig = aCfg, defaultServers, inlineFiles, tempDir} ChatOpts {coreOptions = CoreChatOpts {smpServers, xftpServers, networkConfig, logLevel, logConnections, logServerHosts, logFile, tbqSize}, optFilesFolder, showReactions, allowInstantFiles, autoAcceptFileSize} sendToast = do
let inlineFiles' = if allowInstantFiles || autoAcceptFileSize > 0 then inlineFiles else inlineFiles {sendChunks = 0, receiveInstant = False}
config = cfg {logLevel, showReactions, tbqSize, subscriptionEvents = logConnections, hostEvents = logServerHosts, defaultServers = configServers, inlineFiles = inlineFiles', autoAcceptFileSize}
sendNotification = fromMaybe (const $ pure ()) sendToast
firstTime = dbNew chatStore
activeTo <- newTVarIO ActiveNone
@@ -1109,6 +1110,17 @@ processChatCommand = \case
case memberConnId m of
Just connId -> withAgent (\a -> switchConnectionAsync a "" connId) >> ok user
_ -> throwChatError CEGroupMemberNotActive
APIAbortSwitchContact contactId -> withUser $ \user -> do
ct <- withStore $ \db -> getContact db user contactId
connectionStats <- withAgent $ \a -> abortConnectionSwitch a $ contactConnId ct
pure $ CRContactSwitchAborted user ct connectionStats
APIAbortSwitchGroupMember gId gMemberId -> withUser $ \user -> do
(g, m) <- withStore $ \db -> (,) <$> getGroupInfo db user gId <*> getGroupMember db user gId gMemberId
case memberConnId m of
Just connId -> do
connectionStats <- withAgent $ \a -> abortConnectionSwitch a connId
pure $ CRGroupMemberSwitchAborted user g m connectionStats
_ -> throwChatError CEGroupMemberNotActive
APIGetContactCode contactId -> withUser $ \user -> do
ct@Contact {activeConn = conn@Connection {connId}} <- withStore $ \db -> getContact db user contactId
code <- getConnectionCode (contactConnId ct)
@@ -1163,6 +1175,8 @@ processChatCommand = \case
GroupMemberInfo gName mName -> withMemberName gName mName APIGroupMemberInfo
SwitchContact cName -> withContactName cName APISwitchContact
SwitchGroupMember gName mName -> withMemberName gName mName APISwitchGroupMember
AbortSwitchContact cName -> withContactName cName APIAbortSwitchContact
AbortSwitchGroupMember gName mName -> withMemberName gName mName APIAbortSwitchGroupMember
GetContactCode cName -> withContactName cName APIGetContactCode
GetGroupMemberCode gName mName -> withMemberName gName mName APIGetGroupMemberCode
VerifyContact cName code -> withContactName cName (`APIVerifyContact` code)
@@ -2809,7 +2823,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
_ -> pure ()
SWITCH qd phase cStats -> do
toView $ CRContactSwitch user ct (SwitchProgress qd phase cStats)
when (phase /= SPConfirmed) $ case qd of
when (phase `elem` [SPStarted, SPCompleted]) $ case qd of
QDRcv -> createInternalChatItem user (CDDirectSnd ct) (CISndConnEvent $ SCESwitchQueue phase Nothing) Nothing
QDSnd -> createInternalChatItem user (CDDirectRcv ct) (CIRcvConnEvent $ RCESwitchQueue phase) Nothing
OK ->
@@ -2988,7 +3002,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
checkSndInlineFTComplete conn msgId
SWITCH qd phase cStats -> do
toView $ CRGroupMemberSwitch user gInfo m (SwitchProgress qd phase cStats)
when (phase /= SPConfirmed) $ case qd of
when (phase `elem` [SPStarted, SPCompleted]) $ case qd of
QDRcv -> createInternalChatItem user (CDGroupSnd gInfo) (CISndConnEvent . SCESwitchQueue phase . Just $ groupMemberRef m) Nothing
QDSnd -> createInternalChatItem user (CDGroupRcv gInfo m) (CIRcvConnEvent $ RCESwitchQueue phase) Nothing
OK ->
@@ -3332,8 +3346,9 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
let ExtMsgContent _ _ itemTTL live_ = mcExtMsgContent mc
timed_ = rcvContactCITimed ct itemTTL
live = fromMaybe False live_
ciFile_ <- processFileInvitation fInv_ content $ \db -> createRcvFileTransfer db userId ct
ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) ciFile_ timed_ live
file_ <- processFileInvitation fInv_ content $ \db -> createRcvFileTransfer db userId ct
ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) (snd <$> file_) timed_ live
autoAcceptFile file_
whenContactNtfs user ct $ do
showMsgToast (c <> "> ") content formattedText
setActive $ ActiveC c
@@ -3344,6 +3359,11 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
toView $ CRNewChatItem user (AChatItem SCTDirect SMDRcv (DirectChat ct) ci {reactions})
pure ci
autoAcceptFile :: Maybe (RcvFileTransfer, CIFile 'MDRcv) -> m ()
autoAcceptFile = mapM_ $ \(ft, CIFile {fileSize}) -> do
ChatConfig {autoAcceptFileSize = sz} <- asks config
when (sz > fileSize) $ receiveFile' user ft Nothing Nothing >>= toView
messageFileDescription :: Contact -> SharedMsgId -> FileDescr -> MsgMeta -> m ()
messageFileDescription ct@Contact {contactId} sharedMsgId fileDescr msgMeta = do
checkIntegrityCreateItem (CDDirectRcv ct) msgMeta
@@ -3380,7 +3400,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
cancelGroupMessageFile _gInfo _m _sharedMsgId _msgMeta = do
pure ()
processFileInvitation :: Maybe FileInvitation -> MsgContent -> (DB.Connection -> FileInvitation -> Maybe InlineFileMode -> Integer -> ExceptT StoreError IO RcvFileTransfer) -> m (Maybe (CIFile 'MDRcv))
processFileInvitation :: Maybe FileInvitation -> MsgContent -> (DB.Connection -> FileInvitation -> Maybe InlineFileMode -> Integer -> ExceptT StoreError IO RcvFileTransfer) -> m (Maybe (RcvFileTransfer, CIFile 'MDRcv))
processFileInvitation fInv_ mc createRcvFT = forM fInv_ $ \fInv@FileInvitation {fileName, fileSize} -> do
ChatConfig {fileChunkSize} <- asks config
inline <- receiveInlineMode fInv (Just mc) fileChunkSize
@@ -3392,7 +3412,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
withStore' $ \db -> startRcvInlineFT db user ft fPath inline
pure (Just fPath, CIFSRcvAccepted)
_ -> pure (Nothing, CIFSRcvInvitation)
pure CIFile {fileId, fileName, fileSize, filePath, fileStatus, fileProtocol}
pure (ft, CIFile {fileId, fileName, fileSize, filePath, fileStatus, fileProtocol})
messageUpdate :: Contact -> SharedMsgId -> MsgContent -> RcvMessage -> MsgMeta -> Maybe Int -> Maybe Bool -> m ()
messageUpdate ct@Contact {contactId, localDisplayName = c} sharedMsgId mc msg@RcvMessage {msgId} msgMeta ttl live_ = do
@@ -3503,8 +3523,9 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
let ExtMsgContent _ _ itemTTL live_ = mcExtMsgContent mc
timed_ = rcvGroupCITimed gInfo itemTTL
live = fromMaybe False live_
ciFile_ <- processFileInvitation fInv_ content $ \db -> createRcvGroupFileTransfer db userId m
ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) ciFile_ timed_ live
file_ <- processFileInvitation fInv_ content $ \db -> createRcvGroupFileTransfer db userId m
ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) (snd <$> file_) timed_ live
autoAcceptFile file_
let g = groupName' gInfo
whenGroupNtfs user gInfo $ do
showMsgToast ("#" <> g <> " " <> c <> "> ") content formattedText
@@ -4850,8 +4871,12 @@ chatCommandP =
("/info " <|> "/i ") *> char_ '@' *> (ContactInfo <$> displayName),
"/_switch #" *> (APISwitchGroupMember <$> A.decimal <* A.space <*> A.decimal),
"/_switch @" *> (APISwitchContact <$> A.decimal),
"/_abort switch #" *> (APIAbortSwitchGroupMember <$> A.decimal <* A.space <*> A.decimal),
"/_abort switch @" *> (APIAbortSwitchContact <$> A.decimal),
"/switch #" *> (SwitchGroupMember <$> displayName <* A.space <* char_ '@' <*> displayName),
"/switch " *> char_ '@' *> (SwitchContact <$> displayName),
"/abort switch #" *> (AbortSwitchGroupMember <$> displayName <* A.space <* char_ '@' <*> displayName),
"/abort switch " *> char_ '@' *> (AbortSwitchContact <$> displayName),
"/_get code @" *> (APIGetContactCode <$> A.decimal),
"/_get code #" *> (APIGetGroupMemberCode <$> A.decimal <* A.space <*> A.decimal),
"/_verify code @" *> (APIVerifyContact <$> A.decimal <*> optional (A.space *> textP)),
+7
View File
@@ -103,6 +103,7 @@ data ChatConfig = ChatConfig
fileChunkSize :: Integer,
xftpDescrPartSize :: Int,
inlineFiles :: InlineFilesConfig,
autoAcceptFileSize :: Integer,
xftpFileConfig :: Maybe XFTPFileConfig, -- Nothing - XFTP is disabled
tempDir :: Maybe FilePath,
showReactions :: Bool,
@@ -283,6 +284,8 @@ data ChatCommand
| APIGroupMemberInfo GroupId GroupMemberId
| APISwitchContact ContactId
| APISwitchGroupMember GroupId GroupMemberId
| APIAbortSwitchContact ContactId
| APIAbortSwitchGroupMember GroupId GroupMemberId
| APIGetContactCode ContactId
| APIGetGroupMemberCode GroupId GroupMemberId
| APIVerifyContact ContactId (Maybe Text)
@@ -294,6 +297,8 @@ data ChatCommand
| GroupMemberInfo GroupName ContactName
| SwitchContact ContactName
| SwitchGroupMember GroupName ContactName
| AbortSwitchContact ContactName
| AbortSwitchGroupMember GroupName ContactName
| GetContactCode ContactName
| GetGroupMemberCode GroupName ContactName
| VerifyContact ContactName (Maybe Text)
@@ -402,6 +407,8 @@ data ChatResponse
| CRNetworkConfig {networkConfig :: NetworkConfig}
| CRContactInfo {user :: User, contact :: Contact, connectionStats :: ConnectionStats, customUserProfile :: Maybe Profile}
| CRGroupMemberInfo {user :: User, groupInfo :: GroupInfo, member :: GroupMember, connectionStats_ :: Maybe ConnectionStats}
| CRContactSwitchAborted {user :: User, contact :: Contact, connectionStats :: ConnectionStats}
| CRGroupMemberSwitchAborted {user :: User, groupInfo :: GroupInfo, member :: GroupMember, connectionStats :: ConnectionStats}
| CRContactSwitch {user :: User, contact :: Contact, switchProgress :: SwitchProgress}
| CRGroupMemberSwitch {user :: User, groupInfo :: GroupInfo, member :: GroupMember, switchProgress :: SwitchProgress}
| CRContactCode {user :: User, contact :: Contact, connectionCode :: Text}
+6 -2
View File
@@ -383,14 +383,18 @@ sndGroupEventToText = \case
rcvConnEventToText :: RcvConnEvent -> Text
rcvConnEventToText = \case
RCESwitchQueue phase -> case phase of
SPStarted -> "started changing address for you..."
SPConfirmed -> "confirmed changing address for you..."
SPSecured -> "secured new address for you..."
SPCompleted -> "changed address for you"
_ -> decodeLatin1 (strEncode phase) <> " changing address for you..."
sndConnEventToText :: SndConnEvent -> Text
sndConnEventToText = \case
SCESwitchQueue phase m -> case phase of
SPStarted -> "started changing address" <> forMember m <> "..."
SPConfirmed -> "confirmed changing address" <> forMember m <> "..."
SPSecured -> "secured new address" <> forMember m <> "..."
SPCompleted -> "you changed address" <> forMember m
_ -> decodeLatin1 (strEncode phase) <> " changing address" <> forMember m <> "..."
where
forMember member_ =
maybe "" (\GroupMemberRef {profile = Profile {displayName}} -> " for " <> displayName) member_
+1
View File
@@ -130,6 +130,7 @@ mobileChatOpts dbFilePrefix dbKey =
optFilesFolder = Nothing,
showReactions = False,
allowInstantFiles = True,
autoAcceptFileSize = 0,
muteNotifications = True,
maintenance = True
}
+12
View File
@@ -22,6 +22,7 @@ import qualified Data.ByteString.Char8 as B
import Numeric.Natural (Natural)
import Options.Applicative
import Simplex.Chat.Controller (ChatLogLevel (..), updateStr, versionNumber, versionString)
import Simplex.FileTransfer.Description (mb)
import Simplex.Messaging.Client (NetworkConfig (..), defaultNetworkConfig)
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (parseAll)
@@ -37,6 +38,7 @@ data ChatOpts = ChatOpts
optFilesFolder :: Maybe FilePath,
showReactions :: Bool,
allowInstantFiles :: Bool,
autoAcceptFileSize :: Integer,
muteNotifications :: Bool,
maintenance :: Bool
}
@@ -236,6 +238,15 @@ chatOptsP appDir defaultDbFileName = do
<> short 'f'
<> help "Send and receive instant files without acceptance"
)
autoAcceptFileSize <-
flag' (mb 1) (short 'a' <> help "Automatically accept files up to 1MB")
<|> option
auto
( long "auto-accept-files"
<> metavar "FILE_SIZE"
<> help "Automatically accept files up to specified size"
<> value 0
)
muteNotifications <-
switch
( long "mute"
@@ -256,6 +267,7 @@ chatOptsP appDir defaultDbFileName = do
optFilesFolder,
showReactions,
allowInstantFiles,
autoAcceptFileSize,
muteNotifications,
maintenance
}
+36 -7
View File
@@ -47,6 +47,7 @@ import qualified Simplex.FileTransfer.Protocol as XFTP
import Simplex.Messaging.Agent.Client (ProtocolTestFailure (..), ProtocolTestStep (..))
import Simplex.Messaging.Agent.Env.SQLite (NetworkConfig (..))
import Simplex.Messaging.Agent.Protocol
import Simplex.Messaging.Agent.Store (canAbortRcvSwitch)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Encoding
import Simplex.Messaging.Encoding.String
@@ -80,6 +81,8 @@ responseToView user_ ChatConfig {logLevel, showReactions, testView} liveItems ts
CRNetworkConfig cfg -> viewNetworkConfig cfg
CRContactInfo u ct cStats customUserProfile -> ttyUser u $ viewContactInfo ct cStats customUserProfile
CRGroupMemberInfo u g m cStats -> ttyUser u $ viewGroupMemberInfo g m cStats
CRContactSwitchAborted {} -> ["switch aborted"]
CRGroupMemberSwitchAborted {} -> ["switch aborted"]
CRContactSwitch u ct progress -> ttyUser u $ viewContactSwitch ct progress
CRGroupMemberSwitch u g m progress -> ttyUser u $ viewGroupMemberSwitch g m progress
CRConnectionVerified u verified code -> ttyUser u [plain $ if verified then "connection verified" else "connection not verified, current code is " <> code]
@@ -918,24 +921,46 @@ viewConnectionVerified (Just _) = "connection verified" -- TODO show verificatio
viewConnectionVerified _ = "connection not verified, use " <> highlight' "/code" <> " command to see security code"
viewConnectionStats :: ConnectionStats -> [StyledString]
viewConnectionStats ConnectionStats {rcvServers, sndServers} =
["receiving messages via: " <> viewServerHosts rcvServers | not $ null rcvServers]
<> ["sending messages via: " <> viewServerHosts sndServers | not $ null sndServers]
viewConnectionStats ConnectionStats {rcvQueuesInfo, sndQueuesInfo} =
["receiving messages via: " <> viewRcvQueuesInfo rcvQueuesInfo | not $ null rcvQueuesInfo]
<> ["sending messages via: " <> viewSndQueuesInfo sndQueuesInfo | not $ null sndQueuesInfo]
viewServers :: ProtocolTypeI p => (a -> ProtoServerWithAuth p) -> NonEmpty a -> [StyledString]
viewServers f = map (plain . B.unpack . strEncode . f) . L.toList
viewServerHosts :: [SMPServer] -> StyledString
viewServerHosts = plain . intercalate ", " . map showSMPServer
viewRcvQueuesInfo :: [RcvQueueInfo] -> StyledString
viewRcvQueuesInfo = plain . intercalate ", " . map showQueueInfo
where
showQueueInfo RcvQueueInfo {rcvServer, rcvSwitchStatus, canAbortSwitch} =
let switchCanBeAborted = if canAbortSwitch then ", can be aborted" else ""
in showSMPServer rcvServer
<> maybe "" (\s -> " (" <> showSwitchStatus s <> switchCanBeAborted <> ")") rcvSwitchStatus
showSwitchStatus = \case
RSSwitchStarted -> "switch started"
RSSendingQADD -> "switch started"
RSSendingQUSE -> "switch confirmed"
RSReceivedMessage -> "switch secured"
viewSndQueuesInfo :: [SndQueueInfo] -> StyledString
viewSndQueuesInfo = plain . intercalate ", " . map showQueueInfo
where
showQueueInfo SndQueueInfo {sndServer, sndSwitchStatus} =
showSMPServer sndServer
<> maybe "" (\s -> " (" <> showSwitchStatus s <> ")") sndSwitchStatus
showSwitchStatus = \case
SSSendingQKEY -> "switch started"
SSSendingQTEST -> "switch secured"
viewContactSwitch :: Contact -> SwitchProgress -> [StyledString]
viewContactSwitch _ (SwitchProgress _ SPConfirmed _) = []
viewContactSwitch _ (SwitchProgress _ SPSecured _) = []
viewContactSwitch ct (SwitchProgress qd phase _) = case qd of
QDRcv -> [ttyContact' ct <> ": you " <> viewSwitchPhase phase]
QDSnd -> [ttyContact' ct <> " " <> viewSwitchPhase phase <> " for you"]
viewGroupMemberSwitch :: GroupInfo -> GroupMember -> SwitchProgress -> [StyledString]
viewGroupMemberSwitch _ _ (SwitchProgress _ SPConfirmed _) = []
viewGroupMemberSwitch _ _ (SwitchProgress _ SPSecured _) = []
viewGroupMemberSwitch g m (SwitchProgress qd phase _) = case qd of
QDRcv -> [ttyGroup' g <> ": you " <> viewSwitchPhase phase <> " for " <> ttyMember m]
QDSnd -> [ttyGroup' g <> ": " <> ttyMember m <> " " <> viewSwitchPhase phase <> " for you"]
@@ -952,8 +977,11 @@ viewSecurityCode name cmd code testView
| otherwise = [name <> " security code:", plain code, "pass this code to your contact and use " <> highlight cmd <> " to verify"]
viewSwitchPhase :: SwitchPhase -> StyledString
viewSwitchPhase SPCompleted = "changed address"
viewSwitchPhase phase = plain (strEncode phase) <> " changing address"
viewSwitchPhase = \case
SPStarted -> "started changing address"
SPConfirmed -> "confirmed changing address"
SPSecured -> "secured new address"
SPCompleted -> "changed address"
viewUserProfileUpdated :: Profile -> Profile -> [StyledString]
viewUserProfileUpdated Profile {displayName = n, fullName, image, contactLink, preferences} Profile {displayName = n', fullName = fullName', image = image', contactLink = contactLink', preferences = prefs'} =
@@ -1478,6 +1506,7 @@ viewChatError logLevel = \case
DBErrorOpen e -> ["error opening database after encryption: " <> sqliteError' e]
e -> ["chat database error: " <> sShow e]
ChatErrorAgent err entity_ -> case err of
CMD PROHIBITED -> [withConnEntity <> "error: command is prohibited"]
SMP SMP.AUTH ->
[ withConnEntity
<> "error: connection authorization failed - this could happen if connection was deleted,\
+1 -1
View File
@@ -49,7 +49,7 @@ extra-deps:
# - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561
# - ../simplexmq
- github: simplex-chat/simplexmq
commit: 89caf5572980b776bd750caa3c918ae4488612d8
commit: 2efe1496d2622a56656a6a00a2cc19005e754468
- github: kazu-yamamoto/http2
commit: b5a1b7200cf5bc7044af34ba325284271f6dff25
# - ../direct-sqlcipher
+1
View File
@@ -74,6 +74,7 @@ testOpts =
optFilesFolder = Nothing,
showReactions = True,
allowInstantFiles = True,
autoAcceptFileSize = 0,
muteNotifications = True,
maintenance = False
}
+61 -1
View File
@@ -73,9 +73,11 @@ chatDirectTests = do
it "user profile privacy: hide profiles and notificaitons" testUserPrivacy
describe "chat item expiration" $ do
it "set chat item TTL" testSetChatItemTTL
describe "queue rotation" $ do
describe "connection switch" $ do
it "switch contact to a different queue" testSwitchContact
it "stop switching contact to a different queue" testAbortSwitchContact
it "switch group member to a different queue" testSwitchGroupMember
it "stop switching group member to a different queue" testAbortSwitchGroupMember
describe "connection verification code" $ do
it "verificationCode function converts ByteString to series of digits" $ \_ ->
verificationCode (C.sha256Hash "abcd") `shouldBe` "61889 38426 63934 09576 96390 79389 84124 85253 63658 69469 70853 37788 95900 68296 20156 25"
@@ -1845,6 +1847,33 @@ testSwitchContact =
bob #$> ("/_get chat @2 count=100", chat, chatFeatures <> [(0, "started changing address for you..."), (0, "changed address for you")])
alice <##> bob
testAbortSwitchContact :: HasCallStack => FilePath -> IO ()
testAbortSwitchContact tmp = do
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
withNewTestChat tmp "bob" bobProfile $ \bob -> do
connectUsers alice bob
alice #$> ("/switch bob", id, "ok")
alice <## "bob: you started changing address"
-- repeat switch is prohibited
alice ##> "/switch bob"
alice <## "error: command is prohibited"
-- stop switch
alice #$> ("/abort switch bob", id, "switch aborted")
-- repeat switch stop is prohibited
alice ##> "/abort switch bob"
alice <## "error: command is prohibited"
withTestChatContactConnected tmp "bob" $ \bob -> do
bob <## "alice started changing address for you"
-- alice changes address again
alice #$> ("/switch bob", id, "ok")
alice <## "bob: you started changing address"
bob <## "alice started changing address for you"
bob <## "alice changed address for you"
alice <## "bob: you changed address"
alice #$> ("/_get chat @2 count=100", chat, chatFeatures <> [(1, "started changing address..."), (1, "started changing address..."), (1, "you changed address")])
bob #$> ("/_get chat @2 count=100", chat, chatFeatures <> [(0, "started changing address for you..."), (0, "started changing address for you..."), (0, "changed address for you")])
alice <##> bob
testSwitchGroupMember :: HasCallStack => FilePath -> IO ()
testSwitchGroupMember =
testChat2 aliceProfile bobProfile $
@@ -1862,6 +1891,37 @@ testSwitchGroupMember =
bob #> "#team hi"
alice <# "#team bob> hi"
testAbortSwitchGroupMember :: HasCallStack => FilePath -> IO ()
testAbortSwitchGroupMember tmp = do
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
withNewTestChat tmp "bob" bobProfile $ \bob -> do
createGroup2 "team" alice bob
alice #$> ("/switch #team bob", id, "ok")
alice <## "#team: you started changing address for bob"
-- repeat switch is prohibited
alice ##> "/switch #team bob"
alice <## "error: command is prohibited"
-- stop switch
alice #$> ("/abort switch #team bob", id, "switch aborted")
-- repeat switch stop is prohibited
alice ##> "/abort switch #team bob"
alice <## "error: command is prohibited"
withTestChatContactConnected tmp "bob" $ \bob -> do
bob <## "#team: connected to server(s)"
bob <## "#team: alice started changing address for you"
-- alice changes address again
alice #$> ("/switch #team bob", id, "ok")
alice <## "#team: you started changing address for bob"
bob <## "#team: alice started changing address for you"
bob <## "#team: alice changed address for you"
alice <## "#team: you changed address for bob"
alice #$> ("/_get chat #1 count=100", chat, [(0, "connected"), (1, "started changing address for bob..."), (1, "started changing address for bob..."), (1, "you changed address for bob")])
bob #$> ("/_get chat #1 count=100", chat, groupFeatures <> [(0, "connected"), (0, "started changing address for you..."), (0, "started changing address for you..."), (0, "changed address for you")])
alice #> "#team hey"
bob <# "#team alice> hey"
bob #> "#team hi"
alice <# "#team bob> hi"
testMarkContactVerified :: HasCallStack => FilePath -> IO ()
testMarkContactVerified =
testChat2 aliceProfile bobProfile $ \alice bob -> do
+28
View File
@@ -1,3 +1,4 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PostfixOperators #-}
@@ -68,6 +69,7 @@ chatFileTests = do
xit' "receive file marked to receive on chat start" testXFTPMarkToReceive
it "error receiving file" testXFTPRcvError
it "cancel receiving file, repeat receive" testXFTPCancelRcvRepeat
it "should accept file automatically with CLI option" testAutoAcceptFile
runTestFileTransfer :: HasCallStack => TestCC -> TestCC -> IO ()
runTestFileTransfer alice bob = do
@@ -1386,6 +1388,32 @@ testXFTPCancelRcvRepeat =
where
cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"}
testAutoAcceptFile :: HasCallStack => FilePath -> IO ()
testAutoAcceptFile =
testChatCfgOpts2 cfg opts aliceProfile bobProfile $ \alice bob -> withXFTPServer $ do
connectUsers alice bob
bob ##> "/_files_folder ./tests/tmp/bob_files"
bob <## "ok"
alice #> "/f @bob ./tests/fixtures/test.jpg"
alice <## "use /fc 1 to cancel sending"
alice <## "completed uploading file 1 (test.jpg) for bob"
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
bob <## "saving file 1 from alice to test.jpg"
bob <## "started receiving file 1 (test.jpg) from alice"
bob <## "completed receiving file 1 (test.jpg) from alice"
(bob </)
alice #> "/f @bob ./tests/fixtures/test_1MB.pdf"
alice <## "use /fc 2 to cancel sending"
alice <## "completed uploading file 2 (test_1MB.pdf) for bob"
bob <# "alice> sends file test_1MB.pdf (1017.7 KiB / 1042157 bytes)"
bob <## "use /fr 2 [<dir>/ | <path>] to receive it"
-- no auto accept for large files
(bob </)
where
cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"}
opts = (testOpts :: ChatOpts) {autoAcceptFileSize = 200000}
xftpCLI :: [String] -> IO [String]
xftpCLI params = lines <$> capture_ (withArgs params xftpClientCLI)