Merge branch 'master' into master-android

This commit is contained in:
Evgeny Poberezkin
2024-03-21 19:00:42 +00:00
79 changed files with 562 additions and 294 deletions
@@ -579,7 +579,7 @@ struct ChatInfoView: View {
let ct = try await apiSetContactPQ(contact.apiId, true)
contact = ct
await MainActor.run {
chatModel.updateContact(contact)
chatModel.updateContact(ct)
dismiss()
}
} catch let error {
+10 -7
View File
@@ -557,7 +557,12 @@ struct ChatView: View {
chatItemView(ci, nil, prev)
}
} else {
chatItemView(chatItem, range, prevItem)
// Switch branches just to work around context menu problem when 'revealed' changes but size of item isn't
if revealed {
chatItemView(chatItem, range, prevItem)
} else {
chatItemView(chatItem, range, prevItem)
}
}
}
}
@@ -974,9 +979,8 @@ struct ChatView: View {
title: NSLocalizedString("Hide", comment: "chat item action"),
image: UIImage(systemName: "eye.slash")
) { _ in
withAnimation {
revealed = false
}
// With animation it looks bad because of UIKit context menu involved
revealed = false
}
}
@@ -1045,9 +1049,8 @@ struct ChatView: View {
title: NSLocalizedString("Reveal", comment: "chat item action"),
image: UIImage(systemName: "eye")
) { _ in
withAnimation {
revealed = true
}
// With animation it looks bad because of UIKit context menu involved
revealed = true
}
}
@@ -150,7 +150,7 @@ struct MigrateFromDevice: View {
return Alert(
title: Text(title),
message: Text(text),
primaryButton: .destructive(Text("Delete")) {
primaryButton: .default(Text("Delete")) {
deleteChatAndDismiss()
},
secondaryButton: .cancel()
@@ -333,16 +333,16 @@ struct MigrateFromDevice: View {
ZStack {
List {
Section {
Button(action: { alert = .deleteChat() }) {
settingsRow("trash.fill") {
Text("Delete database from this device").foregroundColor(.accentColor)
}
}
Button(action: { alert = .startChat() }) {
settingsRow("play.fill") {
Text("Start chat").foregroundColor(.red)
}
}
Button(action: { alert = .deleteChat() }) {
settingsRow("trash.fill") {
Text("Delete database from this device").foregroundColor(.accentColor)
}
}
} header: {
Text("Migration complete")
} footer: {
@@ -276,6 +276,7 @@ struct UserProfilesView: View {
// Deleting the last visible user while having hidden one(s)
try await deleteUser()
try await changeActiveUserAsync_(nil, viewPwd: nil)
try? await stopChatAsync()
await MainActor.run {
onboardingStageDefault.set(.step1_SimpleXInfo)
m.onboardingStage = .step1_SimpleXInfo
+26 -26
View File
@@ -36,6 +36,11 @@
5C35CFC827B2782E00FB6C6D /* BGManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C35CFC727B2782E00FB6C6D /* BGManager.swift */; };
5C35CFCB27B2E91D00FB6C6D /* NtfManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C35CFCA27B2E91D00FB6C6D /* NtfManager.swift */; };
5C36027327F47AD5009F19D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C36027227F47AD5009F19D9 /* AppDelegate.swift */; };
5C371E6A2BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C371E652BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH.a */; };
5C371E6B2BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C371E662BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH-ghc9.6.3.a */; };
5C371E6C2BA9FDFA00100AD3 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C371E672BA9FDFA00100AD3 /* libgmpxx.a */; };
5C371E6D2BA9FDFA00100AD3 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C371E682BA9FDFA00100AD3 /* libffi.a */; };
5C371E6E2BA9FDFA00100AD3 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C371E692BA9FDFA00100AD3 /* libgmp.a */; };
5C3A88CE27DF50170060F1C2 /* DetermineWidth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A88CD27DF50170060F1C2 /* DetermineWidth.swift */; };
5C3A88D127DF57800060F1C2 /* FramedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A88D027DF57800060F1C2 /* FramedItemView.swift */; };
5C3CCFCC2AE6BD3100C3F0C3 /* ConnectDesktopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */; };
@@ -57,11 +62,6 @@
5C65F343297D45E100B67AF3 /* VersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C65F341297D3F3600B67AF3 /* VersionView.swift */; };
5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6BA666289BD954009B8ECC /* DismissSheets.swift */; };
5C7031162953C97F00150A12 /* CIFeaturePreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7031152953C97F00150A12 /* CIFeaturePreferenceView.swift */; };
5C746DB82BA0DA920049D734 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB32BA0DA920049D734 /* libffi.a */; };
5C746DB92BA0DA920049D734 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB42BA0DA920049D734 /* libgmpxx.a */; };
5C746DBA2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB52BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a */; };
5C746DBB2BA0DA920049D734 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB62BA0DA920049D734 /* libgmp.a */; };
5C746DBC2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB72BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a */; };
5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A127B65FDB00BE3227 /* CIMetaView.swift */; };
5C7505A527B679EE00BE3227 /* NavLinkPlain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */; };
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */; };
@@ -296,6 +296,11 @@
5C371E4E2BA9AAA200100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
5C371E4F2BA9AB6400100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = "hu.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5C371E502BA9AB6400100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5C371E652BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH.a"; sourceTree = "<group>"; };
5C371E662BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH-ghc9.6.3.a"; sourceTree = "<group>"; };
5C371E672BA9FDFA00100AD3 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C371E682BA9FDFA00100AD3 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C371E692BA9FDFA00100AD3 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C3A88CD27DF50170060F1C2 /* DetermineWidth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineWidth.swift; sourceTree = "<group>"; };
5C3A88D027DF57800060F1C2 /* FramedItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FramedItemView.swift; sourceTree = "<group>"; };
5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectDesktopView.swift; sourceTree = "<group>"; };
@@ -332,11 +337,6 @@
5C6D183229E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = "pl.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5C6D183329E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5C7031152953C97F00150A12 /* CIFeaturePreferenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFeaturePreferenceView.swift; sourceTree = "<group>"; };
5C746DB32BA0DA920049D734 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C746DB42BA0DA920049D734 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C746DB52BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a"; sourceTree = "<group>"; };
5C746DB62BA0DA920049D734 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C746DB72BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a"; sourceTree = "<group>"; };
5C7505A127B65FDB00BE3227 /* CIMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMetaView.swift; sourceTree = "<group>"; };
5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavLinkPlain.swift; sourceTree = "<group>"; };
5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoToolbar.swift; sourceTree = "<group>"; };
@@ -533,12 +533,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C746DB92BA0DA920049D734 /* libgmpxx.a in Frameworks */,
5C746DBA2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a in Frameworks */,
5C371E6A2BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH.a in Frameworks */,
5C371E6E2BA9FDFA00100AD3 /* libgmp.a in Frameworks */,
5C371E6D2BA9FDFA00100AD3 /* libffi.a in Frameworks */,
5C371E6C2BA9FDFA00100AD3 /* libgmpxx.a in Frameworks */,
5C371E6B2BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH-ghc9.6.3.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5C746DB82BA0DA920049D734 /* libffi.a in Frameworks */,
5C746DBC2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a in Frameworks */,
5C746DBB2BA0DA920049D734 /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -602,11 +602,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5C746DB32BA0DA920049D734 /* libffi.a */,
5C746DB62BA0DA920049D734 /* libgmp.a */,
5C746DB42BA0DA920049D734 /* libgmpxx.a */,
5C746DB72BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a */,
5C746DB52BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a */,
5C371E682BA9FDFA00100AD3 /* libffi.a */,
5C371E692BA9FDFA00100AD3 /* libgmp.a */,
5C371E672BA9FDFA00100AD3 /* libgmpxx.a */,
5C371E662BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH-ghc9.6.3.a */,
5C371E652BA9FDFA00100AD3 /* libHSsimplex-chat-5.6.0.3-4nskXXUBgQ3Bvo5v4RfruH.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1546,7 +1546,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202;
CURRENT_PROJECT_VERSION = 203;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1589,7 +1589,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202;
CURRENT_PROJECT_VERSION = 203;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1670,7 +1670,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202;
CURRENT_PROJECT_VERSION = 203;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1702,7 +1702,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202;
CURRENT_PROJECT_VERSION = 203;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1734,7 +1734,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202;
CURRENT_PROJECT_VERSION = 203;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1780,7 +1780,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202;
CURRENT_PROJECT_VERSION = 203;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -0,0 +1,35 @@
package chat.simplex.common.platform
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@Composable
actual fun LazyColumnWithScrollBar(
modifier: Modifier,
state: LazyListState,
contentPadding: PaddingValues,
reverseLayout: Boolean,
verticalArrangement: Arrangement.Vertical,
horizontalAlignment: Alignment.Horizontal,
flingBehavior: FlingBehavior,
userScrollEnabled: Boolean,
content: LazyListScope.() -> Unit
) {
LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
}
@Composable
actual fun ColumnWithScrollBar(
modifier: Modifier,
verticalArrangement: Arrangement.Vertical,
horizontalAlignment: Alignment.Horizontal,
state: ScrollState,
content: @Composable ColumnScope.() -> Unit
) {
Column(modifier.verticalScroll(rememberScrollState()), verticalArrangement, horizontalAlignment, content)
}
@@ -154,7 +154,7 @@ actual fun ActiveCallView() {
setCallSound(call.soundSpeaker, audioViaBluetooth)
}
withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) }
} catch (e: Error) {
} catch (e: Throwable) {
Log.d(TAG,"call status ${r.state.connectionState} not used")
}
is WCallResponse.Connected -> {
@@ -85,8 +85,8 @@ fun AppearanceScope.AppearanceLayout(
showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
editColor: (ThemeColor, Color) -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.appearance_settings))
SectionView(stringResource(MR.strings.settings_section_title_language), padding = PaddingValues()) {
@@ -75,7 +75,7 @@ class AppPreferences {
val value = _callOnLockScreen.get() ?: return CallOnLockScreen.default
return try {
CallOnLockScreen.valueOf(value)
} catch (e: Error) {
} catch (e: Throwable) {
CallOnLockScreen.default
}
},
@@ -95,7 +95,7 @@ class AppPreferences {
val value = _simplexLinkMode.get() ?: return SimplexLinkMode.default
return try {
SimplexLinkMode.valueOf(value)
} catch (e: Error) {
} catch (e: Throwable) {
SimplexLinkMode.default
}
},
@@ -123,7 +123,7 @@ class AppPreferences {
val value = _networkSessionMode.get() ?: return TransportSessionMode.default
return try {
TransportSessionMode.valueOf(value)
} catch (e: Error) {
} catch (e: Throwable) {
TransportSessionMode.default
}
},
@@ -393,7 +393,7 @@ object ChatController {
}
Log.d(TAG, "startChat: running")
}
} catch (e: Error) {
} catch (e: Throwable) {
Log.e(TAG, "failed starting chat $e")
throw e
}
@@ -411,7 +411,7 @@ object ChatController {
startReceiver()
setLocalDeviceName(appPrefs.deviceNameForRemoteAccess.get()!!)
Log.d(TAG, "startChat: started without user")
} catch (e: Error) {
} catch (e: Throwable) {
Log.e(TAG, "failed starting chat without user $e")
throw e
}
@@ -628,7 +628,7 @@ object ChatController {
when (r) {
is CR.ChatStarted -> return true
is CR.ChatRunning -> return false
else -> throw Error("failed starting chat: ${r.responseType} ${r.details}")
else -> throw Exception("failed starting chat: ${r.responseType} ${r.details}")
}
}
@@ -636,26 +636,26 @@ object ChatController {
val r = sendCmd(null, CC.ApiStopChat())
when (r) {
is CR.ChatStopped -> return true
else -> throw Error("failed stopping chat: ${r.responseType} ${r.details}")
else -> throw Exception("failed stopping chat: ${r.responseType} ${r.details}")
}
}
suspend fun apiSetTempFolder(tempFolder: String, ctrl: ChatCtrl? = null) {
val r = sendCmd(null, CC.SetTempFolder(tempFolder), ctrl)
if (r is CR.CmdOk) return
throw Error("failed to set temp folder: ${r.responseType} ${r.details}")
throw Exception("failed to set temp folder: ${r.responseType} ${r.details}")
}
suspend fun apiSetFilesFolder(filesFolder: String, ctrl: ChatCtrl? = null) {
val r = sendCmd(null, CC.SetFilesFolder(filesFolder), ctrl)
if (r is CR.CmdOk) return
throw Error("failed to set files folder: ${r.responseType} ${r.details}")
throw Exception("failed to set files folder: ${r.responseType} ${r.details}")
}
suspend fun apiSetRemoteHostsFolder(remoteHostsFolder: String) {
val r = sendCmd(null, CC.SetRemoteHostsFolder(remoteHostsFolder))
if (r is CR.CmdOk) return
throw Error("failed to set remote hosts folder: ${r.responseType} ${r.details}")
throw Exception("failed to set remote hosts folder: ${r.responseType} ${r.details}")
}
suspend fun apiSetEncryptLocalFiles(enable: Boolean) = sendCommandOkResp(null, CC.ApiSetEncryptLocalFiles(enable))
@@ -663,13 +663,13 @@ object ChatController {
suspend fun apiSaveAppSettings(settings: AppSettings) {
val r = sendCmd(null, CC.ApiSaveSettings(settings))
if (r is CR.CmdOk) return
throw Error("failed to set app settings: ${r.responseType} ${r.details}")
throw Exception("failed to set app settings: ${r.responseType} ${r.details}")
}
suspend fun apiGetAppSettings(settings: AppSettings): AppSettings {
val r = sendCmd(null, CC.ApiGetSettings(settings))
if (r is CR.AppSettingsR) return r.appSettings
throw Error("failed to get app settings: ${r.responseType} ${r.details}")
throw Exception("failed to get app settings: ${r.responseType} ${r.details}")
}
suspend fun apiSetPQEncryption(enable: Boolean) = sendCommandOkResp(null, CC.ApiSetPQEncryption(enable))
@@ -684,19 +684,19 @@ object ChatController {
suspend fun apiExportArchive(config: ArchiveConfig) {
val r = sendCmd(null, CC.ApiExportArchive(config))
if (r is CR.CmdOk) return
throw Error("failed to export archive: ${r.responseType} ${r.details}")
throw Exception("failed to export archive: ${r.responseType} ${r.details}")
}
suspend fun apiImportArchive(config: ArchiveConfig): List<ArchiveError> {
val r = sendCmd(null, CC.ApiImportArchive(config))
if (r is CR.ArchiveImported) return r.archiveErrors
throw Error("failed to import archive: ${r.responseType} ${r.details}")
throw Exception("failed to import archive: ${r.responseType} ${r.details}")
}
suspend fun apiDeleteStorage() {
val r = sendCmd(null, CC.ApiDeleteStorage())
if (r is CR.CmdOk) return
throw Error("failed to delete storage: ${r.responseType} ${r.details}")
throw Exception("failed to delete storage: ${r.responseType} ${r.details}")
}
suspend fun apiStorageEncryption(currentKey: String = "", newKey: String = ""): CR.ChatCmdError? {
@@ -42,7 +42,7 @@ fun copyFileToFile(from: File, to: URI, finally: () -> Unit) {
}
}
showToast(generalGetString(MR.strings.file_saved))
} catch (e: Error) {
} catch (e: Throwable) {
showToast(generalGetString(MR.strings.error_saving_file))
Log.e(TAG, "copyFileToFile error saving file $e")
} finally {
@@ -58,7 +58,7 @@ fun copyBytesToFile(bytes: ByteArrayInputStream, to: URI, finally: () -> Unit) {
}
}
showToast(generalGetString(MR.strings.file_saved))
} catch (e: Error) {
} catch (e: Throwable) {
showToast(generalGetString(MR.strings.error_saving_file))
Log.e(TAG, "copyBytesToFile error saving file $e")
} finally {
@@ -1,8 +1,14 @@
package chat.simplex.common.platform
import androidx.compose.runtime.Composable
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import chat.simplex.common.model.ChatId
import chat.simplex.common.model.NotificationsMode
import kotlinx.coroutines.Job
interface PlatformInterface {
suspend fun androidServiceStart() {}
@@ -19,6 +25,9 @@ interface PlatformInterface {
fun androidCallEnded() {}
@Composable fun androidLockPortraitOrientation() {}
suspend fun androidAskToAllowBackgroundCalls(): Boolean = true
@Composable fun desktopScrollBarComponents(): Triple<Animatable<Float, AnimationVector1D>, Modifier, MutableState<Job>> = remember { Triple(Animatable(0f), Modifier, mutableStateOf(Job())) }
@Composable fun desktopScrollBar(state: LazyListState, modifier: Modifier, scrollBarAlpha: Animatable<Float, AnimationVector1D>, scrollJob: MutableState<Job>, reversed: Boolean) {}
@Composable fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable<Float, AnimationVector1D>, scrollJob: MutableState<Job>, reversed: Boolean) {}
}
/**
* Multiplatform project has separate directories per platform + common directory that contains directories per platform + common for all of them.
@@ -0,0 +1,34 @@
package chat.simplex.common.platform
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
expect fun LazyColumnWithScrollBar(
modifier: Modifier = Modifier,
state: LazyListState = rememberLazyListState(),
contentPadding: PaddingValues = PaddingValues(0.dp),
reverseLayout: Boolean = false,
verticalArrangement: Arrangement.Vertical =
if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
userScrollEnabled: Boolean = true,
content: LazyListScope.() -> Unit
)
@Composable
expect fun ColumnWithScrollBar(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
state: ScrollState = rememberScrollState(),
content: @Composable ColumnScope.() -> Unit
)
@@ -130,7 +130,7 @@ fun TerminalLog() {
derivedStateOf { chatModel.terminalItems.value.asReversed() }
}
val clipboard = LocalClipboardManager.current
LazyColumn(state = listState, reverseLayout = true) {
LazyColumnWithScrollBar(state = listState, reverseLayout = true) {
items(reversedTerminalItems) { item ->
val rhId = item.remoteHostId
val rhIdStr = if (rhId == null) "" else "$rhId "
@@ -49,8 +49,8 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
val displayName = rememberSaveable { mutableStateOf("") }
val focusRequester = remember { FocusRequester() }
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
ColumnWithScrollBar(
modifier = Modifier.fillMaxSize()
) {
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING)
@@ -120,8 +120,8 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) {
val displayName = rememberSaveable { mutableStateOf("") }
val focusRequester = remember { FocusRequester() }
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
ColumnWithScrollBar(
modifier = Modifier.fillMaxSize()
) {
/*CloseSheetBar(close = {
if (chatModel.users.isEmpty()) {
@@ -214,7 +214,8 @@ fun createProfileOnboarding(chatModel: ChatModel, displayName: String, close: ()
) ?: return@withBGApi
chatModel.localUserCreated.value = true
val onboardingStage = chatModel.controller.appPrefs.onboardingStage
if (chatModel.users.isEmpty()) {
// No users or no visible users
if (chatModel.users.none { u -> !u.user.hidden }) {
onboardingStage.set(if (appPlatform.isDesktop && chatModel.controller.appPrefs.initialRandomDBPassphrase.get() && !chatModel.desktopOnboardingRandomPassword.value) {
OnboardingStage.Step2_5_SetupDatabasePassphrase
} else {
@@ -145,7 +145,7 @@ fun ChatInfoView(
withBGApi {
val ct = chatModel.controller.apiSetContactPQ(chatRh, contact.contactId, true)
if (ct != null) {
chatModel.updateContact(chatRh, contact)
chatModel.updateContact(chatRh, ct)
}
close.invoke()
}
@@ -319,10 +319,9 @@ fun ChatInfoLayout(
KeyChangeEffect(chat.id) {
scope.launch { scrollState.scrollTo(0) }
}
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(scrollState)
) {
Row(
Modifier.fillMaxWidth(),
@@ -24,11 +24,10 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
import chat.simplex.common.platform.onRightClick
import chat.simplex.common.platform.*
import chat.simplex.common.views.chat.item.ItemAction
import chat.simplex.common.views.chat.item.MarkdownText
import chat.simplex.common.views.helpers.*
import chat.simplex.common.platform.shareText
import chat.simplex.common.ui.theme.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.ImageResource
@@ -186,7 +185,8 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
@Composable
fun HistoryTab() {
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
// LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
Details()
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
val versions = ciInfo.itemVersions
@@ -210,7 +210,8 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
@Composable
fun QuoteTab(qi: CIQuote) {
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
// LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
Details()
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
@@ -267,7 +268,8 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
@Composable
fun DeliveryTab(memberDeliveryStatuses: List<MemberDeliveryStatus>) {
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
// LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
Details()
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
val mss = membersStatuses(chatModel, memberDeliveryStatuses)
@@ -1,5 +1,6 @@
package chat.simplex.common.views.chat
import androidx.compose.animation.core.Animatable
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.*
@@ -21,6 +22,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.text.*
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
@@ -473,7 +475,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
}
is ChatInfo.InvalidJSON -> {
val close = { chatModel.chatId.value = null }
ModalView(close, showClose = appPlatform.isAndroid, content = {
ModalView(close, showClose = appPlatform.isAndroid, endButtons = { ShareButton { clipboard.shareText(chat.chatInfo.json) } }, content = {
InvalidJSONView(chat.chatInfo.json)
})
LaunchedEffect(chat.id) {
@@ -907,7 +909,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
VideoPlayerHolder.releaseAll()
}
)
LazyColumn(Modifier.align(Alignment.BottomCenter), state = listState, reverseLayout = true) {
LazyColumnWithScrollBar(Modifier.align(Alignment.BottomCenter), state = listState, reverseLayout = true) {
itemsIndexed(reversedChatItems, key = { _, item -> item.id }) { i, cItem ->
CompositionLocalProvider(
// Makes horizontal and vertical scrolling to coexist nicely.
@@ -19,6 +19,7 @@ import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.PreferenceToggle
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.res.MR
@Composable
@@ -77,10 +78,9 @@ private fun ContactPreferencesLayout(
reset: () -> Unit,
savePrefs: () -> Unit,
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.contact_preferences))
val timedMessages: MutableState<Boolean> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.timedMessagesAllowed) }
@@ -16,8 +16,7 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.platform.appPlatform
import chat.simplex.common.platform.shareText
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.QRCode
@@ -57,10 +56,9 @@ private fun VerifyCodeLayout(
connectionVerified: Boolean,
verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit,
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING)
) {
AppBarTitle(stringResource(MR.strings.security_code), withPadding = false)
@@ -125,10 +125,9 @@ fun AddGroupMembersLayout(
}
}
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.button_add_members))
profileText()
@@ -205,7 +205,8 @@ fun GroupChatInfoLayout(
}
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
val filteredMembers = remember(members) { derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } } }
LazyColumn(
// LALAL strange scrolling
LazyColumnWithScrollBar(
Modifier
.fillMaxWidth(),
state = listState
@@ -16,6 +16,7 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.shareText
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
@@ -118,9 +119,8 @@ fun GroupLinkLayout(
)
}
Column(
Modifier
.verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier,
) {
AppBarTitle(stringResource(MR.strings.group_link))
Text(
@@ -291,10 +291,9 @@ fun GroupMemberInfoLayout(
}
}
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
.fillMaxWidth(),
) {
Row(
Modifier.fillMaxWidth(),
@@ -18,6 +18,7 @@ import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.PreferenceToggleWithIcon
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.res.MR
@Composable
@@ -72,8 +73,8 @@ private fun GroupPreferencesLayout(
reset: () -> Unit,
savePrefs: () -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.group_preferences))
val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.enable) }
@@ -95,9 +95,8 @@ fun GroupProfileLayout(
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
) {
ModalView(close = closeWithAlert) {
Column(
ColumnWithScrollBar(
Modifier
.verticalScroll(scrollState)
) {
Column(
Modifier.fillMaxWidth()
@@ -29,6 +29,7 @@ import chat.simplex.common.views.chat.item.MarkdownText
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.GroupInfo
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.chatJsonLength
import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF
import chat.simplex.res.MR
@@ -91,8 +92,8 @@ private fun GroupWelcomeLayout(
linkMode: SimplexLinkMode,
save: () -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
val editMode = remember { mutableStateOf(true) }
AppBarTitle(stringResource(MR.strings.group_welcome_title))
@@ -1,6 +1,5 @@
package chat.simplex.common.views.chat.item
import SectionView
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
@@ -8,23 +7,23 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalClipboardManager
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.shareText
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.SettingsActionItem
import chat.simplex.res.MR
@Composable
fun CIInvalidJSONView(json: String) {
val clipboard = LocalClipboardManager.current
Row(Modifier
.clickable {
ModalManager.center.closeModals()
ModalManager.end.closeModals()
ModalManager.center.showModal(true) { InvalidJSONView(json) }
ModalManager.center.showModal(true, endButtons = { ShareButton { clipboard.shareText(json) } }) { InvalidJSONView(json) }
}
.padding(horizontal = 10.dp, vertical = 6.dp)
) {
@@ -34,15 +33,8 @@ fun CIInvalidJSONView(json: String) {
@Composable
fun InvalidJSONView(json: String) {
Column {
Spacer(Modifier.height(DEFAULT_PADDING))
SectionView {
val clipboard = LocalClipboardManager.current
SettingsActionItem(painterResource(MR.images.ic_share), generalGetString(MR.strings.share_verb), click = {
clipboard.shareText(json)
})
}
Column(Modifier.padding(DEFAULT_PADDING).fillMaxWidth().verticalScroll(rememberScrollState())) {
ColumnWithScrollBar {
Column(Modifier.padding(DEFAULT_PADDING).fillMaxWidth()) {
Text(json)
}
}
@@ -460,7 +460,7 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldVal
val searchShowingSimplexLink = remember { mutableStateOf(false) }
val searchChatFilteredBySimplexLink = remember { mutableStateOf<String?>(null) }
val chats = filteredChats(showUnreadAndFavorites, searchShowingSimplexLink, searchChatFilteredBySimplexLink, searchText.value.text, allChats.toList())
LazyColumn(
LazyColumnWithScrollBar(
Modifier.fillMaxWidth(),
listState
) {
@@ -1,7 +1,6 @@
package chat.simplex.common.views.chatlist
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.*
import androidx.compose.runtime.*
@@ -14,12 +13,10 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import chat.simplex.common.SettingsViewState
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.Chat
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.BackHandler
import chat.simplex.common.platform.appPlatform
import chat.simplex.common.platform.*
import chat.simplex.res.MR
import kotlinx.coroutines.flow.MutableStateFlow
@@ -146,7 +143,7 @@ private fun ShareList(chatModel: ChatModel, search: String) {
if (search.isEmpty()) chatModel.chats.toList().filter { it.chatInfo.ready } else chatModel.chats.toList().filter { it.chatInfo.ready }.filter(filter)
}
}
LazyColumn(
LazyColumnWithScrollBar(
modifier = Modifier.fillMaxWidth()
) {
items(chats) { chat ->
@@ -46,7 +46,7 @@ fun ChatArchiveLayout(
saveArchive: () -> Unit,
deleteArchiveAlert: () -> Unit
) {
Column(
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(title)
@@ -27,7 +27,7 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.appPreferences
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.SettingsActionItem
@@ -100,8 +100,10 @@ fun DatabaseEncryptionLayout(
migration: Boolean,
onConfirmEncrypt: () -> Unit,
) {
val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents()
val scrollState = rememberScrollState()
Column(
if (!migration) Modifier.fillMaxWidth().verticalScroll(rememberScrollState()) else Modifier.fillMaxWidth(),
if (!migration) Modifier.fillMaxWidth().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier) else Modifier.fillMaxWidth(),
) {
if (!migration) {
AppBarTitle(stringResource(MR.strings.database_passphrase))
@@ -190,6 +192,11 @@ fun DatabaseEncryptionLayout(
}
SectionBottomSpacer()
}
if (appPlatform.isDesktop && !migration) {
Box(Modifier.fillMaxSize()) {
platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false)
}
}
}
expect fun encryptDatabaseSavedAlert(onConfirm: () -> Unit)
@@ -76,8 +76,8 @@ fun DatabaseErrorView(
Text(String.format(generalGetString(MR.strings.database_migrations), ms.joinToString(", ")))
}
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
) {
val buttonEnabled = validKey(dbKey.value) && !progressIndicator.value
@@ -7,8 +7,6 @@ import SectionItemView
import SectionView
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -27,7 +25,6 @@ import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.*
import chat.simplex.common.platform.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.coroutines.sync.withLock
import kotlinx.datetime.*
import java.io.*
@@ -158,8 +155,8 @@ fun DatabaseLayout(
val stopped = !runChat
val operationsDisabled = (!stopped || progressIndicator) && !chatModel.desktopNoUserNoRemote
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.your_chat_database))
@@ -391,7 +388,7 @@ fun startChat(m: ChatModel, chatLastStart: MutableState<Instant?>, chatDbChanged
m.controller.appPrefs.chatLastStart.set(ts)
chatLastStart.value = ts
platform.androidChatStartedAfterBeingOff()
} catch (e: Error) {
} catch (e: Throwable) {
m.chatRunning.value = false
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_starting_chat), e.toString())
} finally {
@@ -61,9 +61,8 @@ fun <T> SectionViewSelectable(
onSelected: (T) -> Unit,
) {
SectionView(title) {
LazyColumn {
items(values.size) { index ->
val item = values[index]
Column {
values.forEach { item ->
SectionItemViewSpaceBetween({ onSelected(item.value) }) {
Text(item.title)
if (currentValue.value == item.value) {
@@ -145,13 +145,20 @@ private fun MigrateFromDeviceLayout(
) {
val tempDatabaseFile = rememberSaveable { mutableStateOf(fileForTemporaryDatabase()) }
val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents()
val scrollState = rememberScrollState()
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).height(IntrinsicSize.Max),
Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).height(IntrinsicSize.Max),
) {
AppBarTitle(stringResource(MR.strings.migrate_from_device_title))
SectionByState(migrationState, tempDatabaseFile.value, chatReceiver)
SectionBottomSpacer()
}
if (appPlatform.isDesktop) {
Box(Modifier.fillMaxSize()) {
platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false)
}
}
platform.androidLockPortraitOrientation()
}
@@ -368,22 +375,6 @@ private fun MutableState<MigrationFromState>.LinkShownView(fileId: Long, link: S
private fun MutableState<MigrationFromState>.FinishedView(chatDeletion: Boolean) {
Box {
SectionView(stringResource(MR.strings.migrate_from_device_migration_complete).uppercase()) {
SettingsActionItemWithContent(
icon = painterResource(MR.images.ic_delete_forever),
text = stringResource(MR.strings.migrate_from_device_delete_database_from_device),
textColor = MaterialTheme.colors.primary,
click = {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.delete_chat_profile_question),
text = generalGetString(MR.strings.delete_chat_profile_action_cannot_be_undone_warning),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
deleteChatAndDismiss()
}
)
}
) {}
SettingsActionItemWithContent(
icon = painterResource(MR.images.ic_play_arrow_filled),
text = stringResource(MR.strings.migrate_from_device_start_chat),
@@ -395,6 +386,23 @@ private fun MutableState<MigrationFromState>.FinishedView(chatDeletion: Boolean)
confirmText = generalGetString(MR.strings.migrate_from_device_start_chat),
onConfirm = {
withLongRunningApi { startChatAndDismiss() }
},
destructive = true
)
}
) {}
SettingsActionItemWithContent(
icon = painterResource(MR.images.ic_delete_forever),
text = stringResource(MR.strings.migrate_from_device_delete_database_from_device),
textColor = MaterialTheme.colors.primary,
click = {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.delete_chat_profile_question),
text = generalGetString(MR.strings.delete_chat_profile_action_cannot_be_undone_warning),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
deleteChatAndDismiss()
}
)
}
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
import chat.simplex.common.model.*
@@ -154,14 +155,20 @@ private fun ModalData.MigrateToDeviceLayout(
close: () -> Unit,
) {
val tempDatabaseFile = rememberSaveable { mutableStateOf(fileForTemporaryDatabase()) }
val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents()
val scrollState = rememberScrollState()
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).height(IntrinsicSize.Max),
Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).height(IntrinsicSize.Max),
) {
AppBarTitle(stringResource(MR.strings.migrate_to_device_title))
SectionByState(migrationState, tempDatabaseFile.value, chatReceiver, close)
SectionBottomSpacer()
}
if (appPlatform.isDesktop) {
Box(Modifier.fillMaxSize()) {
platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false)
}
}
platform.androidLockPortraitOrientation()
}
@@ -1,10 +1,11 @@
package chat.simplex.common.views.newchat
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.chatModel
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.views.helpers.AppBarTitle
import chat.simplex.common.views.helpers.KeyChangeEffect
@@ -14,10 +15,10 @@ import chat.simplex.res.MR
@Composable
fun AddContactLearnMore(close: () -> Unit) {
Column(
Modifier.verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.padding(horizontal = DEFAULT_PADDING),
) {
AppBarTitle(stringResource(MR.strings.one_time_link))
AppBarTitle(stringResource(MR.strings.one_time_link), withPadding = false)
ReadableText(MR.strings.scan_qr_to_connect_to_contact)
ReadableText(MR.strings.if_you_cant_meet_in_person)
ReadableTextWithLink(MR.strings.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends")
@@ -94,10 +94,9 @@ fun AddGroupLayout(
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
) {
ModalView(close = close) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING)
) {
AppBarTitle(stringResource(MR.strings.create_secret_group_title), hostDevice(rhId))
@@ -65,14 +65,7 @@ fun ContactConnectionInfoView(
share = { if (connReqInvitation != null) clipboard.shareText(connReqInvitation) },
learnMore = {
ModalManager.end.showModalCloseable { close ->
Column(
Modifier
.fillMaxHeight()
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween
) {
AddContactLearnMore(close)
}
AddContactLearnMore(close)
}
}
)
@@ -111,9 +104,8 @@ private fun ContactConnectionInfoLayout(
}
}
Column(
Modifier
.verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier,
) {
AppBarTitle(
stringResource(
@@ -141,10 +141,10 @@ fun ModalData.NewChatView(rh: RemoteHostInfo?, selection: NewChatOption, showQRC
}
HorizontalPager(state = pagerState, Modifier.fillMaxSize(), verticalAlignment = Alignment.Top) { index ->
Column(
// LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
.fillMaxSize(),
verticalArrangement = if (index == NewChatOption.INVITE.ordinal && connReqInvitation.isEmpty()) Arrangement.Center else Arrangement.Top) {
Spacer(Modifier.height(DEFAULT_PADDING))
when (index) {
@@ -232,14 +232,7 @@ private fun AddContactLearnMoreButton() {
{
if (appPlatform.isDesktop) ModalManager.end.closeModals()
ModalManager.end.showModalCloseable { close ->
Column(
Modifier
.fillMaxHeight()
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween
) {
AddContactLearnMore(close)
}
AddContactLearnMore(close)
}
}
) {
@@ -75,8 +75,8 @@ private fun CreateSimpleXAddressLayout(
createAddress: () -> Unit,
nextStep: () -> Unit,
) {
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING),
ColumnWithScrollBar(
Modifier.fillMaxSize().padding(top = DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally,
) {
AppBarTitle(stringResource(MR.strings.simplex_address))
@@ -169,7 +169,8 @@ private fun ProgressIndicator() {
}
private fun prepareChatBeforeAddressCreation(rhId: Long?) {
if (chatModel.users.isNotEmpty()) return
// No visible users but may have hidden. In this case chat should be started anyway because it's stopped on this stage with hidden users
if (chatModel.users.any { u -> !u.user.hidden }) return
withBGApi {
val user = chatModel.controller.apiGetActiveUser(rhId) ?: return@withBGApi
chatModel.currentUser.value = user
@@ -14,6 +14,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.item.MarkdownText
import chat.simplex.common.views.helpers.*
@@ -22,7 +23,7 @@ import dev.icerock.moko.resources.StringResource
@Composable
fun HowItWorks(user: User?, onboardingStage: SharedPreference<OnboardingStage>? = null) {
Column(Modifier
ColumnWithScrollBar(Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING),
) {
@@ -15,6 +15,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.NotificationsMode
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.changeNotificationsMode
@@ -23,10 +24,9 @@ import dev.icerock.moko.resources.StringResource
@Composable
fun SetNotificationsMode(m: ChatModel) {
Column(
ColumnWithScrollBar(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(vertical = 14.dp)
) {
//CloseSheetBar(null)
@@ -98,8 +98,8 @@ private fun SetupDatabasePassphraseLayout(
onConfirmEncrypt: () -> Unit,
nextStep: () -> Unit,
) {
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING),
ColumnWithScrollBar(
Modifier.fillMaxSize().padding(top = DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally,
) {
AppBarTitle(stringResource(MR.strings.setup_database_passphrase))
@@ -16,6 +16,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.chatModel
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
@@ -39,10 +40,9 @@ fun SimpleXInfoLayout(
onboardingStage: SharedPreference<OnboardingStage>?,
showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(start = DEFAULT_PADDING , end = DEFAULT_PADDING, top = DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -18,6 +18,7 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
@@ -105,11 +106,10 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
val v = versionDescriptions[currentVersion.value]
ModalView(close = close) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxSize()
.padding(horizontal = DEFAULT_PADDING)
.verticalScroll(rememberScrollState()),
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.spacedBy(DEFAULT_PADDING.times(0.75f))
) {
AppBarTitle(String.format(generalGetString(MR.strings.new_in_version), v.version), bottomPadding = DEFAULT_PADDING)
@@ -75,8 +75,8 @@ private fun ConnectDesktopLayout(deviceName: String, close: () -> Unit) {
val sessionAddress = remember { mutableStateOf("") }
val remoteCtrls = remember { mutableStateListOf<RemoteCtrlInfo>() }
val session = remember { chatModel.remoteCtrlSession }.value
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
val discovery = if (session == null) null else session.sessionState is UIRemoteCtrlSessionState.Searching
if (discovery == true || (discovery == null && !showConnectScreen.value)) {
@@ -391,8 +391,8 @@ private fun DesktopAddressView(sessionAddress: MutableState<String>) {
@Composable
private fun LinkedDesktopsView(remoteCtrls: SnapshotStateList<RemoteCtrlInfo>) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.linked_desktops))
SectionView(stringResource(MR.strings.desktop_devices).uppercase()) {
@@ -91,8 +91,8 @@ fun ConnectMobileLayout(
connectDesktop: () -> Unit,
deleteHost: (RemoteHostInfo) -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
AppBarTitle(stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles))
@@ -181,8 +181,8 @@ private fun ConnectMobileViewLayout(
refreshQrCode: () -> Unit = {},
UnderQrLayout: @Composable () -> Unit = {},
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
if (title != null) {
@@ -23,6 +23,7 @@ import chat.simplex.common.model.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.res.MR
import java.text.DecimalFormat
@@ -141,10 +142,9 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
) {
val secondsLabel = stringResource(MR.strings.network_option_seconds_label)
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.network_settings_title))
SectionView {
@@ -57,8 +57,8 @@ object AppearanceScope {
@Composable
fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
val currentTheme by CurrentColors.collectAsState()
@@ -16,6 +16,7 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.res.MR
@Composable
@@ -35,8 +36,8 @@ fun CallSettingsLayout(
callOnLockScreen: SharedPreference<CallOnLockScreen>,
editIceServers: () -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
AppBarTitle(stringResource(MR.strings.your_calls))
@@ -12,10 +12,9 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.platform.appPlatform
import chat.simplex.common.platform.appPreferences
import chat.simplex.common.views.TerminalView
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
@@ -26,7 +25,7 @@ fun DeveloperView(
showCustomModal: (@Composable ModalData.(ChatModel, () -> Unit) -> Unit) -> (() -> Unit),
withAuth: (title: String, desc: String, block: () -> Unit) -> Unit
) {
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
val uriHandler = LocalUriHandler.current
AppBarTitle(stringResource(MR.strings.settings_developer_tools))
val developerTools = m.controller.appPrefs.developerTools
@@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.desktop.ui.tooling.preview.Preview
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import chat.simplex.common.ui.theme.SimpleXTheme
import chat.simplex.common.views.chatlist.ChatHelpView
@@ -20,10 +21,9 @@ fun HelpView(userDisplayName: String) {
@Composable
fun HelpLayout(userDisplayName: String) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING),
){
AppBarTitle(String.format(stringResource(MR.strings.personal_welcome), userDisplayName), withPadding = false)
@@ -17,6 +17,7 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.User
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chatlist.UserProfileRow
import chat.simplex.common.views.database.PassphraseField
@@ -53,10 +54,9 @@ private fun HiddenProfileLayout(
user: User,
saveProfilePassword: (String) -> Unit
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.hide_profile))
SectionView(padding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) {
@@ -1,13 +1,13 @@
package chat.simplex.common.views.usersettings
import SectionBottomSpacer
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import chat.simplex.common.views.helpers.AppBarTitle
import chat.simplex.common.views.helpers.generalGetString
@@ -21,11 +21,10 @@ fun IncognitoView() {
@Composable
fun IncognitoLayout() {
Column {
ColumnWithScrollBar {
AppBarTitle(stringResource(MR.strings.settings_section_title_incognito))
Column(
Modifier
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
@@ -25,6 +25,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.chatModel
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.item.ClickableText
@@ -151,8 +152,8 @@ fun NetworkAndServersView() {
updateSessionMode: (TransportSessionMode) -> Unit,
) {
val m = chatModel
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
AppBarTitle(stringResource(MR.strings.network_and_servers))
@@ -276,10 +277,9 @@ fun SockProxySettings(
networkProxyHostPort: SharedPreference<String?> = m.controller.appPrefs.networkProxyHostPort,
migration: Boolean,
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
) {
val defaultHostPort = remember { "localhost:9050" }
AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings))
@@ -376,7 +376,7 @@ private fun UseOnionHosts(
}
val onSelected = {
showModal {
Column(
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.network_use_onion_hosts))
@@ -430,7 +430,7 @@ private fun SessionModePicker(
icon = painterResource(MR.images.ic_safety_divider),
onSelected = {
showModal {
Column(
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.network_session_mode_transport_isolation))
@@ -56,8 +56,8 @@ fun NotificationsSettingsLayout(
val modes = remember { notificationModes() }
val previewModes = remember { notificationPreviewModes() }
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.notifications))
SectionView(null) {
@@ -90,7 +90,7 @@ fun NotificationsModeView(
onNotificationsModeSelected: (NotificationsMode) -> Unit,
) {
val modes = remember { notificationModes() }
Column(
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.settings_notifications_mode_title).lowercase().capitalize(Locale.current))
@@ -104,7 +104,7 @@ fun NotificationPreviewView(
onNotificationPreviewModeSelected: (NotificationPreviewMode) -> Unit,
) {
val previewModes = remember { notificationPreviewModes() }
Column(
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.settings_notification_preview_title))
@@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.res.MR
@Composable
@@ -62,8 +63,8 @@ private fun PreferencesLayout(
reset: () -> Unit,
savePrefs: () -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.your_preferences))
val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.allow) }
@@ -30,8 +30,7 @@ import chat.simplex.common.views.isValidDisplayName
import chat.simplex.common.views.localauth.SetAppPasscodeView
import chat.simplex.common.views.onboarding.ReadableText
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.AppPlatform
import chat.simplex.common.platform.appPlatform
import chat.simplex.common.platform.*
enum class LAMode {
SYSTEM,
@@ -55,8 +54,8 @@ fun PrivacySettingsView(
showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
setPerformLA: (Boolean) -> Unit
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
val simplexLinkMode = chatModel.controller.appPrefs.simplexLinkMode
AppBarTitle(stringResource(MR.strings.your_privacy))
@@ -473,8 +472,8 @@ fun SimplexLockView(
}
}
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.chat_lock))
SectionView {
@@ -580,8 +579,8 @@ fun SimplexLockView(
@Composable
private fun SelfDestructInfoView() {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
ColumnWithScrollBar(
Modifier.fillMaxWidth().padding(horizontal = DEFAULT_PADDING),
) {
AppBarTitle(stringResource(MR.strings.self_destruct), withPadding = false)
ReadableText(stringResource(MR.strings.if_you_enter_self_destruct_code))
@@ -5,7 +5,6 @@ import SectionDividerSpaced
import SectionItemView
import SectionItemViewSpaceBetween
import SectionView
import chat.simplex.common.platform.Log
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.selection.SelectionContainer
@@ -20,13 +19,13 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.platform.TAG
import chat.simplex.common.model.*
import chat.simplex.common.model.ServerAddress.Companion.parseServerAddress
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.QRCode
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -76,10 +75,9 @@ private fun ProtocolServerLayout(
onUpdate: (ServerCfg) -> Unit,
onDelete: () -> Unit,
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
) {
AppBarTitle(stringResource(if (server.preset) MR.strings.smp_servers_preset_server else MR.strings.smp_servers_your_server))
@@ -22,6 +22,7 @@ import androidx.compose.ui.unit.dp
import chat.simplex.common.model.ServerAddress.Companion.parseServerAddress
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.appPlatform
import chat.simplex.res.MR
@@ -191,10 +192,9 @@ private fun ProtocolServersLayout(
saveSMPServers: () -> Unit,
showServer: (ServerCfg) -> Unit,
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
) {
AppBarTitle(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.your_SMP_servers else MR.strings.your_XFTP_servers))
@@ -19,6 +19,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.call.parseRTCIceServers
import chat.simplex.common.views.helpers.*
@@ -98,12 +99,11 @@ fun RTCServersLayout(
saveRTCServers: () -> Unit,
editOn: () -> Unit,
) {
Column {
ColumnWithScrollBar {
AppBarTitle(stringResource(MR.strings.your_ICE_servers))
Column(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
@@ -74,8 +74,10 @@ private fun SetDeliveryReceiptsLayout(
userCount: Int,
) {
val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp
val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents()
val scrollState = rememberScrollState()
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING, end = endPadding),
Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).padding(top = DEFAULT_PADDING, end = endPadding),
horizontalAlignment = Alignment.CenterHorizontally,
) {
AppBarTitle(stringResource(MR.strings.delivery_receipts_title))
@@ -95,6 +97,11 @@ private fun SetDeliveryReceiptsLayout(
SectionBottomSpacer()
}
if (appPlatform.isDesktop) {
Box(Modifier.fillMaxSize().padding(end = endPadding)) {
platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false)
}
}
}
@Composable
@@ -105,10 +105,9 @@ fun SettingsLayout(
val theme = CurrentColors.collectAsState()
val uriHandler = LocalUriHandler.current
Box(Modifier.fillMaxSize()) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.themedBackground(theme.value.base)
.padding(top = if (appPlatform.isAndroid) DEFAULT_PADDING else DEFAULT_PADDING * 3)
) {
@@ -1,9 +1,10 @@
package chat.simplex.common.views.usersettings
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.onboarding.ReadableText
@@ -12,8 +13,9 @@ import chat.simplex.res.MR
@Composable
fun UserAddressLearnMore() {
Column(
Modifier.verticalScroll(rememberScrollState()),
ColumnWithScrollBar(Modifier
.fillMaxHeight()
.padding(horizontal = DEFAULT_PADDING)
) {
AppBarTitle(stringResource(MR.strings.simplex_address))
ReadableText(MR.strings.you_can_share_your_address)
@@ -7,9 +7,7 @@ import SectionTextFooter
import SectionView
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
@@ -91,14 +89,7 @@ fun UserAddressView(
},
learnMore = {
ModalManager.start.showModal {
Column(
Modifier
.fillMaxHeight()
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween
) {
UserAddressLearnMore()
}
UserAddressLearnMore()
}
},
share = { userAddress: String -> clipboard.shareText(userAddress) },
@@ -182,9 +173,7 @@ private fun UserAddressLayout(
deleteAddress: () -> Unit,
saveAas: (AutoAcceptState, MutableState<AutoAcceptState>) -> Unit,
) {
Column(
Modifier.verticalScroll(rememberScrollState()),
) {
ColumnWithScrollBar {
AppBarTitle(stringResource(MR.strings.simplex_address), hostDevice(user?.remoteHostId), withPadding = false)
Column(
Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF),
@@ -98,9 +98,8 @@ fun UserProfileLayout(
}
}
ModalView(close = closeWithAlert) {
Column(
ColumnWithScrollBar(
Modifier
.verticalScroll(scrollState)
.padding(horizontal = DEFAULT_PADDING),
) {
AppBarTitle(stringResource(MR.strings.your_current_profile))
@@ -158,10 +158,9 @@ private fun UserProfilesLayout(
unmuteUser: (User) -> Unit,
showHiddenProfile: (User) -> Unit,
) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
) {
if (profileHidden.value) {
SectionView {
@@ -260,10 +259,9 @@ enum class UserProfileAction {
@Composable
private fun ProfileActionView(action: UserProfileAction, user: User, doAction: (String) -> Unit) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
) {
val actionPassword = rememberSaveable { mutableStateOf("") }
val passwordValid by remember { derivedStateOf { actionPassword.value == actionPassword.value.trim() } }
@@ -358,6 +356,7 @@ private suspend fun doRemoveUser(m: ChatModel, user: User, users: List<User>, de
m.controller.apiDeleteUser(user, delSMPQueues, viewPwd)
m.controller.changeActiveUser_(user.remoteHostId, null, null)
if (appPlatform.isAndroid) {
m.controller.apiStopChat()
controller.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
ModalManager.closeAllModalsEverywhere()
}
@@ -0,0 +1,129 @@
package chat.simplex.common.platform
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.interaction.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.unit.dp
import chat.simplex.common.views.helpers.detectCursorMove
import chat.simplex.common.views.helpers.mixWith
import kotlinx.coroutines.*
@Composable
actual fun LazyColumnWithScrollBar(
modifier: Modifier,
state: LazyListState,
contentPadding: PaddingValues,
reverseLayout: Boolean,
verticalArrangement: Arrangement.Vertical,
horizontalAlignment: Alignment.Horizontal,
flingBehavior: FlingBehavior,
userScrollEnabled: Boolean,
content: LazyListScope.() -> Unit
) {
if (appPlatform.isAndroid) {
LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
} else {
val scope = rememberCoroutineScope()
val scrollBarAlpha = remember { Animatable(0f) }
val scrollJob: MutableState<Job> = remember { mutableStateOf(Job()) }
val scrollModifier = remember {
Modifier
.pointerInput(Unit) {
detectCursorMove {
scope.launch {
scrollBarAlpha.animateTo(1f)
}
scrollJob.value.cancel()
scrollJob.value = scope.launch {
delay(1000L)
scrollBarAlpha.animateTo(0f)
}
}
}
}
LazyColumn(modifier.then(if (appPlatform.isDesktop) scrollModifier else Modifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, reverseLayout)
}
}
}
@Composable
actual fun ColumnWithScrollBar(
modifier: Modifier,
verticalArrangement: Arrangement.Vertical,
horizontalAlignment: Alignment.Horizontal,
state: ScrollState,
content: @Composable ColumnScope.() -> Unit
) {
val scope = rememberCoroutineScope()
val scrollBarAlpha = remember { Animatable(0f) }
val scrollJob: MutableState<Job> = remember { mutableStateOf(Job()) }
val scrollModifier = remember {
Modifier
.pointerInput(Unit) {
detectCursorMove {
scope.launch {
scrollBarAlpha.animateTo(1f)
}
scrollJob.value.cancel()
scrollJob.value = scope.launch {
delay(1000L)
scrollBarAlpha.animateTo(0f)
}
}
}
}
Column(modifier.verticalScroll(state).then(scrollModifier), verticalArrangement, horizontalAlignment, content)
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false)
}
}
@Composable
fun DesktopScrollBar(adapter: androidx.compose.foundation.v2.ScrollbarAdapter, modifier: Modifier, scrollBarAlpha: Animatable<Float, AnimationVector1D>, scrollJob: MutableState<Job>, reversed: Boolean) {
val scope = rememberCoroutineScope()
val interactionSource = remember { MutableInteractionSource() }
val isHovered by interactionSource.collectIsHoveredAsState()
val isDragged by interactionSource.collectIsDraggedAsState()
LaunchedEffect(isHovered, isDragged) {
scrollJob.value.cancel()
if (isHovered || isDragged) {
scrollBarAlpha.animateTo(1f)
} else {
scrollJob.value = scope.launch {
delay(1000L)
scrollBarAlpha.animateTo(0f)
}
}
}
VerticalScrollbar(
modifier = modifier.graphicsLayer { alpha = scrollBarAlpha.value }
.onPointerEvent(PointerEventType.Enter) {
scrollJob.value.cancel()
scope.launch {
scrollBarAlpha.animateTo(1f)
}
},
reverseLayout = reversed,
style = LocalScrollbarStyle.current.copy(
thickness = if (isHovered || isDragged) 10.dp else 6.dp,
shape = RoundedCornerShape(if (isHovered || isDragged) 5.dp else 3.dp),
unhoverColor = if (MaterialTheme.colors.isLight) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.7f) else MaterialTheme.colors.onBackground.mixWith(MaterialTheme.colors.background, 0.3f),
hoverColor = if (MaterialTheme.colors.isLight) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.6f) else MaterialTheme.colors.onBackground.mixWith(MaterialTheme.colors.background, 0.4f)
),
adapter = adapter,
interactionSource = interactionSource
)
}
@@ -75,7 +75,7 @@ actual fun ActiveCallView() {
chatModel.activeCall.value = call.copy(callState = CallState.Connected, connectedAt = Clock.System.now())
}
withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) }
} catch (e: Error) {
} catch (e: Throwable) {
Log.d(TAG, "call status ${r.state.connectionState} not used")
}
is WCallResponse.Connected -> {
@@ -4,8 +4,6 @@ import SectionBottomSpacer
import SectionDividerSpaced
import SectionView
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
@@ -13,6 +11,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.SharedPreference
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.defaultLocale
import chat.simplex.common.ui.theme.ThemeColor
import chat.simplex.common.views.helpers.*
@@ -43,8 +42,8 @@ fun AppearanceScope.AppearanceLayout(
showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
editColor: (ThemeColor, Color) -> Unit,
) {
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.appearance_settings))
SectionView(stringResource(MR.strings.settings_section_title_language), padding = PaddingValues()) {
@@ -1,7 +1,19 @@
package chat.simplex.desktop
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.*
import chat.simplex.common.platform.*
import chat.simplex.common.platform.DesktopPlatform
import chat.simplex.common.showApp
import chat.simplex.common.views.helpers.*
import kotlinx.coroutines.*
import java.io.File
fun main() {
@@ -12,6 +24,7 @@ fun main() {
return showApp()
}
@OptIn(ExperimentalComposeUiApi::class)
@Suppress("UnsafeDynamicallyLoadedCode")
private fun initHaskell() {
val resourcesDir = File(System.getProperty("compose.application.resources.dir"))
@@ -27,6 +40,40 @@ private fun initHaskell() {
System.setProperty("jna.library.path", vlcDir.absolutePath)
//discoverVlcLibs(File(File(vlcDir, "vlc"), "plugins").absolutePath)
initHS()
platform = object: PlatformInterface {
@Composable
override fun desktopScrollBarComponents(): Triple<Animatable<Float, AnimationVector1D>, Modifier, MutableState<Job>> {
val scope = rememberCoroutineScope()
val scrollBarAlpha = remember { Animatable(0f) }
val scrollJob: MutableState<Job> = remember { mutableStateOf(Job()) }
val modifier = remember {
Modifier.pointerInput(Unit) {
detectCursorMove {
scope.launch {
scrollBarAlpha.animateTo(1f)
}
scrollJob.value.cancel()
scrollJob.value = scope.launch {
delay(1000L)
scrollBarAlpha.animateTo(0f)
}
}
}
}
return Triple(scrollBarAlpha, modifier, scrollJob)
}
@Composable
override fun desktopScrollBar(state: LazyListState, modifier: Modifier, scrollBarAlpha: Animatable<Float, AnimationVector1D>, scrollJob: MutableState<Job>, reversed: Boolean) {
DesktopScrollBar(rememberScrollbarAdapter(scrollState = state), modifier, scrollBarAlpha, scrollJob, reversed)
}
@Composable
override fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable<Float, AnimationVector1D>, scrollJob: MutableState<Job>, reversed: Boolean) {
DesktopScrollBar(rememberScrollbarAdapter(scrollState = state), modifier, scrollBarAlpha, scrollJob, reversed)
}
}
}
private fun windowsLoadRequiredLibs(libsTmpDir: File, vlcDir: File) {
+4 -4
View File
@@ -25,11 +25,11 @@ android.nonTransitiveRClass=true
android.enableJetifier=true
kotlin.mpp.androidSourceSetLayoutVersion=2
android.version_name=5.6-beta.0
android.version_code=189
android.version_name=5.6-beta.1
android.version_code=190
desktop.version_name=5.6-beta.0
desktop.version_code=33
desktop.version_name=5.6-beta.1
desktop.version_code=34
kotlin.version=1.8.20
gradle.plugin.version=7.4.2
+1 -1
View File
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: 7b6b80cea21c7fbafffa118f1ed268411fcb79ca
tag: 8496884b42d76bd0d934e5ae481846d9c324d3c7
source-repository-package
type: git
+1 -1
View File
@@ -1,5 +1,5 @@
name: simplex-chat
version: 5.6.0.3
version: 5.6.0.4
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
+1 -1
View File
@@ -1,5 +1,5 @@
{
"https://github.com/simplex-chat/simplexmq.git"."7b6b80cea21c7fbafffa118f1ed268411fcb79ca" = "0a665v4v1ilm2j9cxkiwqq2xlp2732h95mqaywf7qrlk03qkasfi";
"https://github.com/simplex-chat/simplexmq.git"."8496884b42d76bd0d934e5ae481846d9c324d3c7" = "0c040s00zc1qg0ilsvpv54f01xz7flh8rsar2nplcs4a4gnp78qs";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
+1 -1
View File
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
version: 5.6.0.3
version: 5.6.0.4
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat
+5 -2
View File
@@ -37,10 +37,11 @@ import Simplex.Chat.Types
import Simplex.FileTransfer.Description (kb, mb)
import Simplex.FileTransfer.Server (runXFTPServerBlocking)
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..), defaultFileExpiration)
import Simplex.Messaging.Agent (disposeAgentClient)
import Simplex.Messaging.Agent.Env.SQLite
import Simplex.Messaging.Agent.Protocol (currentSMPAgentVersion, duplexHandshakeSMPAgentVersion, pqdrSMPAgentVersion, supportedSMPAgentVRange)
import Simplex.Messaging.Agent.RetryInterval
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..))
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), closeSQLiteStore)
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
import Simplex.Messaging.Client (ProtocolClientConfig (..), defaultNetworkConfig)
import Simplex.Messaging.Crypto.Ratchet (supportedE2EEncryptVRange, pattern PQSupportOff)
@@ -250,10 +251,12 @@ startTestChat_ db cfg opts user = do
pure TestCC {chatController = cc, virtualTerminal = t, chatAsync, termAsync, termQ, printOutput = False}
stopTestChat :: TestCC -> IO ()
stopTestChat TestCC {chatController = cc, chatAsync, termAsync} = do
stopTestChat TestCC {chatController = cc@ChatController {smpAgent, chatStore}, chatAsync, termAsync} = do
stopChatController cc
uninterruptibleCancel termAsync
uninterruptibleCancel chatAsync
liftIO $ disposeAgentClient smpAgent
closeSQLiteStore chatStore
threadDelay 200000
withNewTestChat :: HasCallStack => FilePath -> String -> Profile -> (HasCallStack => TestCC -> IO a) -> IO a
+26 -6
View File
@@ -37,10 +37,10 @@
"hero-overlay-1-title": "Jak funguje SimpleX?",
"hero-overlay-2-title": "Proč jsou uživatelská ID špatná pro soukromí?",
"feature-1-title": "E2E šifrované zprávy s Markdown a editací",
"feature-3-title": "Decentralizované tajné skupiny &mdash;<br>pouze uživatelé vědí, že existují",
"feature-3-title": "E2E-šifrované decentralizované skupiny &mdash; pouze uživatelé vědí, že existují",
"feature-4-title": "Hlasové zprávy šifrované E2E",
"feature-6-title": "E2E šifrované<br>hlasové a videohovory",
"feature-7-title": "Přenosná šifrovaná databáze&mdash; přeneste svůj profil do jiného zařízení",
"feature-7-title": "Přenosné šifrované ůložiště aplikace &mdash; přeneste profil do jiného zařízení",
"feature-8-title": "režim Inkognito &mdash;<br>Unikátní pro SimpleX Chat",
"simplex-network-overlay-1-title": "Srovnání s protokoly zpráv P2P",
"simplex-private-2-title": "Další vrstva<br>šifrování serveru",
@@ -170,8 +170,8 @@
"comparison-section-list-point-1": "Založeném obvykle na telefonním čísle a v některých případech uživatelském jménu",
"comparison-section-list-point-2": "Adresy založené na DNS",
"comparison-section-list-point-3": "Veřejný klíč nebo jiné globálně jedinečné ID",
"comparison-section-list-point-4": "Pokud jsou servery operátora ohroženy",
"comparison-section-list-point-5": "Nechrání metadata uživatelů",
"comparison-section-list-point-4": "Pokud jsou servery operátora kompromitovány. Ověřte bezpečnostní kód v Signálu a nějaké jiné aplikaci ke zmírnění",
"comparison-section-list-point-5": "Nechrání soukromí metadat uživatelů",
"comparison-section-list-point-6": "Zatímco P2P jsou distribuovány, nejsou federované fungují jako jediná síť",
"comparison-section-list-point-7": "P2P sítě mají buď centrální autoritu, nebo může být ohrožena celá síť",
"see-here": "viz zde",
@@ -195,7 +195,7 @@
"simplex-explained-tab-3-p-2": "Uživatelé mohou dále zlepšit soukromí metadat pomocí Tor pro přístup k serverům, což zabraňuje korelaci podle IP adresy.",
"hero-p-1": "Jiné aplikace mají uživatelská ID: Signal, Matrix, Session, Briar, Jami, Cwtch atd.<br> SimpleX ne, <strong>ani náhodná čísla</strong>.<br> To radikálně zlepšuje vaše soukromí.",
"hero-2-header-desc": "Video ukazuje, jak se spojit se svým přítelem prostřednictvím jeho jednorázového QR kódu, osobně nebo prostřednictvím QR kódu ve videu. Můžete se také připojit sdílením pozvánky.",
"feature-2-title": "Obrázky a soubory šifrované E2E<br>",
"feature-2-title": "E2E šifrované<br>obrázky, videa a soubory",
"feature-5-title": "Mizící tajné konverzace",
"simplex-private-1-title": "2-vrstvé<br>end-to-end šifrování",
"simplex-private-8-title": "Smíchání zpráv<br>ke snížení korelace",
@@ -232,5 +232,25 @@
"on-this-page": "Na této stránce",
"back-to-top": "Zpět nahoru",
"newer-version-of-eng-msg": "V angličtině je novější verze této stránky.",
"glossary": "Rejstřík"
"glossary": "Rejstřík",
"hero-overlay-3-title": "Posouzení bezpečnosti",
"hero-overlay-3-textlink": "Posouzení bezpečnosti",
"hero-overlay-card-3-p-1": "<a href=\"https://www.trailofbits.com/about/\">Trail of Bits</a> je přední bezpečnostní a technologické poradenství, jejichž klienti zahrnují velké technologické firmy, vládní agentury a významné blockchainové projekty.",
"f-droid-page-simplex-chat-repo-section-text": "Chcete-li jej přidat do vašeho F-Droid clienta, <span class='hide-on-mobile'> naskenujte QR kód nebo</span> použijte tuto adresu URL:",
"f-droid-page-f-droid-org-repo-section-text": "SimpleX Chat a F-Droid.org repozitáře jsou podepsané různými klíči. Chcete-li přepnout, prosím <a href='/docs/guide/chat-profiles.html#move-your-chat-profiles-to-another-device'>exportujte</a> chat databázi a přeinstalujte aplikaci.",
"comparison-section-list-point-4a": "SimpleX relé nemůže ohrozit šifrování e2e. Ověřte bezpečnostní kód, který zmírňuje mimo pásmový útok na kanál",
"docs-dropdown-8": "Služba SimpleX Directory",
"please-enable-javascript": "Prosím, povolte JavaScript k zobrazení QR kódu.",
"please-use-link-in-mobile-app": "Prosím použijte odkaz v mobilní aplikaci",
"simplex-chat-via-f-droid": "SimpleX Chat přes F-Droid",
"simplex-chat-repo": "SimpleX Chat repozitář",
"stable-and-beta-versions-built-by-developers": "Stabilní a beta verze vytvořené vývojáři",
"signing-key-fingerprint": "Otisk podpisového klíče (SHA-256)",
"f-droid-org-repo": "F-Droid.org repozitář",
"stable-versions-built-by-f-droid-org": "Stabilní verze vytvořené F-Droid.org",
"releases-to-this-repo-are-done-1-2-days-later": "Vydání v tomto repozitáři se provádí o 1-2 dny později",
"jobs": "Připojit k týmu",
"hero-overlay-card-3-p-2": "Trail of Bits přezkoumala kryptografii a síťové komponenty SimpleX platformy v listopadu 2022.",
"hero-overlay-card-3-p-3": "Přečtěte si více v <a href=\"/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html\">ohlášení</a>.",
"docs-dropdown-9": "Ke stažení"
}