Compare commits
9 Commits
v5.3.0-bet
...
v5.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6b62d0c18 | ||
|
|
ba4c427bec | ||
|
|
a179154e87 | ||
|
|
5eea3da7f4 | ||
|
|
b3e880ee54 | ||
|
|
08ea5dc2e7 | ||
|
|
20f90ee865 | ||
|
|
5ca2ab6138 | ||
|
|
ba61b15225 |
@@ -440,9 +440,9 @@ struct ChatInfoView: View {
|
||||
do {
|
||||
try await apiDeleteChat(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId)
|
||||
await MainActor.run {
|
||||
chatModel.removeChat(chat.chatInfo.id)
|
||||
chatModel.chatId = nil
|
||||
dismiss()
|
||||
chatModel.chatId = nil
|
||||
chatModel.removeChat(chat.chatInfo.id)
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("deleteContactAlert apiDeleteChat error: \(responseError(error))")
|
||||
|
||||
@@ -299,9 +299,9 @@ struct GroupChatInfoView: View {
|
||||
do {
|
||||
try await apiDeleteChat(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId)
|
||||
await MainActor.run {
|
||||
chatModel.removeChat(chat.chatInfo.id)
|
||||
chatModel.chatId = nil
|
||||
dismiss()
|
||||
chatModel.chatId = nil
|
||||
chatModel.removeChat(chat.chatInfo.id)
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("deleteGroupAlert apiDeleteChat error: \(error.localizedDescription)")
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
5C55A921283CCCB700C4E99E /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */; };
|
||||
5C55A923283CEDE600C4E99E /* SoundPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A922283CEDE600C4E99E /* SoundPlayer.swift */; };
|
||||
5C55A92E283D0FDE00C4E99E /* sounds in Resources */ = {isa = PBXBuildFile; fileRef = 5C55A92D283D0FDE00C4E99E /* sounds */; };
|
||||
5C5625062ABCBD3200A21210 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C5625012ABCBD3200A21210 /* libffi.a */; };
|
||||
5C5625072ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C5625022ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo-ghc8.10.7.a */; };
|
||||
5C5625082ABCBD3200A21210 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C5625032ABCBD3200A21210 /* libgmp.a */; };
|
||||
5C5625092ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C5625042ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo.a */; };
|
||||
5C56250A2ABCBD3200A21210 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C5625052ABCBD3200A21210 /* libgmpxx.a */; };
|
||||
5C5625102ABDFA8900A21210 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C56250B2ABDFA8900A21210 /* libffi.a */; };
|
||||
5C5625112ABDFA8900A21210 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C56250C2ABDFA8900A21210 /* libgmp.a */; };
|
||||
5C5625122ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C56250D2ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m.a */; };
|
||||
5C5625132ABDFA8900A21210 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C56250E2ABDFA8900A21210 /* libgmpxx.a */; };
|
||||
5C5625142ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C56250F2ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m-ghc8.10.7.a */; };
|
||||
5C577F7D27C83AA10006112D /* MarkdownHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C577F7C27C83AA10006112D /* MarkdownHelp.swift */; };
|
||||
5C58BCD6292BEBE600AF9E4F /* CIChatFeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C58BCD5292BEBE600AF9E4F /* CIChatFeatureView.swift */; };
|
||||
5C5DB70E289ABDD200730FFF /* AppearanceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5DB70D289ABDD200730FFF /* AppearanceSettings.swift */; };
|
||||
@@ -293,11 +293,11 @@
|
||||
5C55A920283CCCB700C4E99E /* IncomingCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallView.swift; sourceTree = "<group>"; };
|
||||
5C55A922283CEDE600C4E99E /* SoundPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundPlayer.swift; sourceTree = "<group>"; };
|
||||
5C55A92D283D0FDE00C4E99E /* sounds */ = {isa = PBXFileReference; lastKnownFileType = folder; path = sounds; sourceTree = "<group>"; };
|
||||
5C5625012ABCBD3200A21210 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C5625022ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5C5625032ABCBD3200A21210 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C5625042ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo.a"; sourceTree = "<group>"; };
|
||||
5C5625052ABCBD3200A21210 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C56250B2ABDFA8900A21210 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C56250C2ABDFA8900A21210 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C56250D2ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m.a"; sourceTree = "<group>"; };
|
||||
5C56250E2ABDFA8900A21210 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C56250F2ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5C577F7C27C83AA10006112D /* MarkdownHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownHelp.swift; sourceTree = "<group>"; };
|
||||
5C58BCD5292BEBE600AF9E4F /* CIChatFeatureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIChatFeatureView.swift; sourceTree = "<group>"; };
|
||||
5C5B67912ABAF4B500DA9412 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@@ -507,13 +507,13 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C5625132ABDFA8900A21210 /* libgmpxx.a in Frameworks */,
|
||||
5C5625122ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m.a in Frameworks */,
|
||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||
5C5625082ABCBD3200A21210 /* libgmp.a in Frameworks */,
|
||||
5C5625062ABCBD3200A21210 /* libffi.a in Frameworks */,
|
||||
5C5625142ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m-ghc8.10.7.a in Frameworks */,
|
||||
5C5625102ABDFA8900A21210 /* libffi.a in Frameworks */,
|
||||
5C5625112ABDFA8900A21210 /* libgmp.a in Frameworks */,
|
||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||
5C5625092ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo.a in Frameworks */,
|
||||
5C5625072ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo-ghc8.10.7.a in Frameworks */,
|
||||
5C56250A2ABCBD3200A21210 /* libgmpxx.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -574,11 +574,11 @@
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C5625012ABCBD3200A21210 /* libffi.a */,
|
||||
5C5625032ABCBD3200A21210 /* libgmp.a */,
|
||||
5C5625052ABCBD3200A21210 /* libgmpxx.a */,
|
||||
5C5625022ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo-ghc8.10.7.a */,
|
||||
5C5625042ABCBD3200A21210 /* libHSsimplex-chat-5.3.0.9-JpoF1vnleecHyL9iiCdgEo.a */,
|
||||
5C56250B2ABDFA8900A21210 /* libffi.a */,
|
||||
5C56250C2ABDFA8900A21210 /* libgmp.a */,
|
||||
5C56250E2ABDFA8900A21210 /* libgmpxx.a */,
|
||||
5C56250F2ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m-ghc8.10.7.a */,
|
||||
5C56250D2ABDFA8900A21210 /* libHSsimplex-chat-5.3.0.10-9vCXcrdx54qEnAYPtVuU9m.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -1486,7 +1486,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 172;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1528,7 +1528,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 172;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -1608,7 +1608,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 172;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1640,7 +1640,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 172;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1672,7 +1672,7 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 172;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -1718,7 +1718,7 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 172;
|
||||
CURRENT_PROJECT_VERSION = 173;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
||||
@@ -309,7 +309,7 @@ actual suspend fun saveTempImageUncompressed(image: ImageBitmap, asPng: Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
actual fun getBitmapFromVideo(uri: URI, timestamp: Long?, random: Boolean): VideoPlayerInterface.PreviewAndDuration {
|
||||
actual suspend fun getBitmapFromVideo(uri: URI, timestamp: Long?, random: Boolean): VideoPlayerInterface.PreviewAndDuration {
|
||||
val mmr = MediaMetadataRetriever()
|
||||
mmr.setDataSource(androidAppContext, uri.toUri())
|
||||
val durationMs = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()
|
||||
|
||||
@@ -449,7 +449,7 @@ fun ChatLayout(
|
||||
val images = groups[true] ?: emptyList()
|
||||
val files = groups[false] ?: emptyList()
|
||||
if (images.isNotEmpty()) {
|
||||
composeState.processPickedMedia(images, null)
|
||||
CoroutineScope(Dispatchers.IO).launch { composeState.processPickedMedia(images, null) }
|
||||
} else if (files.isNotEmpty()) {
|
||||
composeState.processPickedFile(uris.first(), null)
|
||||
}
|
||||
@@ -459,7 +459,7 @@ fun ChatLayout(
|
||||
tmpFile.deleteOnExit()
|
||||
chatModel.filesToDelete.add(tmpFile)
|
||||
val uri = tmpFile.toURI()
|
||||
composeState.processPickedMedia(listOf(uri), null)
|
||||
CoroutineScope(Dispatchers.IO).launch { composeState.processPickedMedia(listOf(uri), null) }
|
||||
},
|
||||
onText = {
|
||||
// Need to parse HTML in order to correctly display the content
|
||||
|
||||
@@ -176,7 +176,7 @@ fun MutableState<ComposeState>.processPickedFile(uri: URI?, text: String?) {
|
||||
}
|
||||
}
|
||||
|
||||
fun MutableState<ComposeState>.processPickedMedia(uris: List<URI>, text: String?) {
|
||||
suspend fun MutableState<ComposeState>.processPickedMedia(uris: List<URI>, text: String?) {
|
||||
val content = ArrayList<UploadContent>()
|
||||
val imagesPreview = ArrayList<String>()
|
||||
uris.forEach { uri ->
|
||||
@@ -237,7 +237,7 @@ fun ComposeView(
|
||||
val textStyle = remember(MaterialTheme.colors.isLight) { mutableStateOf(smallFont) }
|
||||
val recState: MutableState<RecordingState> = remember { mutableStateOf(RecordingState.NotStarted) }
|
||||
|
||||
AttachmentSelection(composeState, attachmentOption, composeState::processPickedFile, composeState::processPickedMedia)
|
||||
AttachmentSelection(composeState, attachmentOption, composeState::processPickedFile) { uris, text -> CoroutineScope(Dispatchers.IO).launch { composeState.processPickedMedia(uris, text) } }
|
||||
|
||||
fun isSimplexLink(link: String): Boolean =
|
||||
link.startsWith("https://simplex.chat", true) || link.startsWith("http://simplex.chat", true)
|
||||
|
||||
@@ -117,9 +117,7 @@ fun groupChatAction(groupInfo: GroupInfo, chatModel: ChatModel) {
|
||||
suspend fun openDirectChat(contactId: Long, chatModel: ChatModel) {
|
||||
val chat = chatModel.controller.apiGetChat(ChatType.Direct, contactId)
|
||||
if (chat != null) {
|
||||
chatModel.chatItems.clear()
|
||||
chatModel.chatItems.addAll(chat.chatItems)
|
||||
chatModel.chatId.value = "@$contactId"
|
||||
openChat(chat, chatModel)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,11 +137,13 @@ suspend fun openChat(chat: Chat, chatModel: ChatModel) {
|
||||
suspend fun apiLoadPrevMessages(chatInfo: ChatInfo, chatModel: ChatModel, beforeChatItemId: Long, search: String) {
|
||||
val pagination = ChatPagination.Before(beforeChatItemId, ChatPagination.PRELOAD_COUNT)
|
||||
val chat = chatModel.controller.apiGetChat(chatInfo.chatType, chatInfo.apiId, pagination, search) ?: return
|
||||
if (chatModel.chatId.value != chat.id) return
|
||||
chatModel.chatItems.addAll(0, chat.chatItems)
|
||||
}
|
||||
|
||||
suspend fun apiFindMessages(chatInfo: ChatInfo, chatModel: ChatModel, search: String) {
|
||||
val chat = chatModel.controller.apiGetChat(chatInfo.chatType, chatInfo.apiId, search = search) ?: return
|
||||
if (chatModel.chatId.value != chat.id) return
|
||||
chatModel.chatItems.clear()
|
||||
chatModel.chatItems.addAll(0, chat.chatItems)
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ fun getMaxFileSize(fileProtocol: FileProtocol): Long {
|
||||
}
|
||||
}
|
||||
|
||||
expect fun getBitmapFromVideo(uri: URI, timestamp: Long? = null, random: Boolean = true): VideoPlayerInterface.PreviewAndDuration
|
||||
expect suspend fun getBitmapFromVideo(uri: URI, timestamp: Long? = null, random: Boolean = true): VideoPlayerInterface.PreviewAndDuration
|
||||
|
||||
fun Color.darker(factor: Float = 0.1f): Color =
|
||||
Color(max(red * (1 - factor), 0f), max(green * (1 - factor), 0f), max(blue * (1 - factor), 0f), alpha)
|
||||
|
||||
@@ -174,7 +174,7 @@ actual class VideoPlayer actual constructor(
|
||||
private suspend fun setPreviewAndDuration() {
|
||||
// It freezes main thread, doing it in IO thread
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val previewAndDuration = VideoPlayerHolder.previewsAndDurations.getOrPut(uri) { getBitmapFromVideo() }
|
||||
val previewAndDuration = VideoPlayerHolder.previewsAndDurations.getOrPut(uri) { getBitmapFromVideo(defaultPreview, uri) }
|
||||
withContext(Dispatchers.Main) {
|
||||
preview.value = previewAndDuration.preview ?: defaultPreview
|
||||
duration.value = (previewAndDuration.duration ?: 0)
|
||||
@@ -182,23 +182,6 @@ actual class VideoPlayer actual constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getBitmapFromVideo(): VideoPlayerInterface.PreviewAndDuration {
|
||||
val player = CallbackMediaPlayerComponent().mediaPlayer()
|
||||
val filepath = getAppFilePath(uri)
|
||||
if (filepath == null || !File(filepath).exists()) {
|
||||
return VideoPlayerInterface.PreviewAndDuration(preview = defaultPreview, timestamp = 0L, duration = 0L)
|
||||
}
|
||||
player.media().startPaused(filepath)
|
||||
val start = System.currentTimeMillis()
|
||||
while (player.snapshots()?.get() == null && start + 5000 > System.currentTimeMillis()) {
|
||||
delay(10)
|
||||
}
|
||||
val preview = player.snapshots()?.get()?.toComposeImageBitmap()
|
||||
val duration = player.duration.toLong()
|
||||
CoroutineScope(Dispatchers.IO).launch { player.release() }
|
||||
return VideoPlayerInterface.PreviewAndDuration(preview = preview, timestamp = 0L, duration = duration)
|
||||
}
|
||||
|
||||
private fun initializeMediaPlayerComponent(): Component {
|
||||
return if (desktopPlatform.isMac()) {
|
||||
CallbackMediaPlayerComponent()
|
||||
@@ -212,4 +195,22 @@ actual class VideoPlayer actual constructor(
|
||||
is EmbeddedMediaPlayerComponent -> mediaPlayer()
|
||||
else -> error("mediaPlayer() can only be called on vlcj player components")
|
||||
}
|
||||
|
||||
companion object {
|
||||
suspend fun getBitmapFromVideo(defaultPreview: ImageBitmap?, uri: URI?): VideoPlayerInterface.PreviewAndDuration {
|
||||
val player = CallbackMediaPlayerComponent().mediaPlayer()
|
||||
if (uri == null || !File(uri.rawPath).exists()) {
|
||||
return VideoPlayerInterface.PreviewAndDuration(preview = defaultPreview, timestamp = 0L, duration = 0L)
|
||||
}
|
||||
player.media().startPaused(uri.toString().replaceFirst("file:", "file://"))
|
||||
val start = System.currentTimeMillis()
|
||||
while (player.snapshots()?.get() == null && start + 5000 > System.currentTimeMillis()) {
|
||||
delay(10)
|
||||
}
|
||||
val preview = player.snapshots()?.get()?.toComposeImageBitmap()
|
||||
val duration = player.duration.toLong()
|
||||
CoroutineScope(Dispatchers.IO).launch { player.release() }
|
||||
return VideoPlayerInterface.PreviewAndDuration(preview = preview, timestamp = 0L, duration = duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,14 @@ import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
@Composable
|
||||
actual fun ChooseAttachmentButtons(attachmentOption: MutableState<AttachmentOption?>, hide: () -> Unit) {
|
||||
ActionButton(Modifier.fillMaxWidth(0.5f), null, stringResource(MR.strings.gallery_image_button), icon = painterResource(MR.images.ic_add_photo)) {
|
||||
ActionButton(Modifier.fillMaxWidth(0.33f), null, stringResource(MR.strings.gallery_image_button), icon = painterResource(MR.images.ic_add_photo)) {
|
||||
attachmentOption.value = AttachmentOption.GalleryImage
|
||||
hide()
|
||||
}
|
||||
ActionButton(Modifier.fillMaxWidth(0.5f), null, stringResource(MR.strings.gallery_video_button), icon = painterResource(MR.images.ic_smart_display)) {
|
||||
attachmentOption.value = AttachmentOption.GalleryVideo
|
||||
hide()
|
||||
}
|
||||
ActionButton(Modifier.fillMaxWidth(1f), null, stringResource(MR.strings.choose_file), icon = painterResource(MR.images.ic_note_add)) {
|
||||
attachmentOption.value = AttachmentOption.File
|
||||
hide()
|
||||
|
||||
@@ -132,8 +132,8 @@ actual suspend fun saveTempImageUncompressed(image: ImageBitmap, asPng: Boolean)
|
||||
} else null
|
||||
}
|
||||
|
||||
actual fun getBitmapFromVideo(uri: URI, timestamp: Long?, random: Boolean): VideoPlayerInterface.PreviewAndDuration {
|
||||
return VideoPlayerInterface.PreviewAndDuration(preview = null, timestamp = 0L, duration = 0L)
|
||||
actual suspend fun getBitmapFromVideo(uri: URI, timestamp: Long?, random: Boolean): VideoPlayerInterface.PreviewAndDuration {
|
||||
return VideoPlayer.getBitmapFromVideo(null, uri)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalEncodingApi::class)
|
||||
|
||||
@@ -25,11 +25,11 @@ android.nonTransitiveRClass=true
|
||||
android.enableJetifier=true
|
||||
kotlin.mpp.androidSourceSetLayoutVersion=2
|
||||
|
||||
android.version_name=5.3-beta.9
|
||||
android.version_code=151
|
||||
android.version_name=5.3
|
||||
android.version_code=152
|
||||
|
||||
desktop.version_name=1.7.0
|
||||
desktop.version_code=9
|
||||
desktop.version_name=5.3
|
||||
desktop.version_code=10
|
||||
|
||||
kotlin.version=1.8.20
|
||||
gradle.plugin.version=7.4.2
|
||||
|
||||
@@ -15,28 +15,28 @@ revision: 20.09.2023
|
||||
|
||||
<img src="/docs/images/simplex-desktop-light.png" alt="desktop app" width=500>
|
||||
|
||||
The latest version of desktop app is v5.3-beta.8 (1.6.0 in the app).
|
||||
The latest version of desktop app is v5.3-beta.9 (1.6.0 in the app).
|
||||
|
||||
Using the same profile as on mobile device is not yet supported – you need to create a separate profile to use desktop apps.
|
||||
|
||||
**Linux**: [AppImage](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-desktop-x86_64.AppImage) (most Linux distros), [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-desktop-ubuntu-20_04-x86_64.deb) (and Debian-based distros), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-desktop-ubuntu-22_04-x86_64.deb).
|
||||
**Linux**: [AppImage](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-desktop-x86_64.AppImage) (most Linux distros), [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-desktop-ubuntu-20_04-x86_64.deb) (and Debian-based distros), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-desktop-ubuntu-22_04-x86_64.deb).
|
||||
|
||||
**Mac**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-desktop-macos-x86_64.dmg) (Intel), [aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-desktop-macos-aarch64.dmg) (Apple Silicon).
|
||||
**Mac**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-desktop-macos-x86_64.dmg) (Intel), [aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-desktop-macos-aarch64.dmg) (Apple Silicon).
|
||||
|
||||
**Windows**: coming soon.
|
||||
|
||||
## Mobile apps
|
||||
|
||||
**iOS**: [App store](https://apps.apple.com/us/app/simplex-chat/id1605771084) (v5.2.3), [TestFlight](https://testflight.apple.com/join/DWuT2LQu) (v5.3-beta.8).
|
||||
**iOS**: [App store](https://apps.apple.com/us/app/simplex-chat/id1605771084) (v5.2.3), [TestFlight](https://testflight.apple.com/join/DWuT2LQu) (v5.3-beta.9).
|
||||
|
||||
**Android**: [Play store](https://play.google.com/store/apps/details?id=chat.simplex.app), [F-Droid](https://simplex.chat/fdroid/), [APK aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex.apk), [APK armv7](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-armv7a.apk).
|
||||
**Android**: [Play store](https://play.google.com/store/apps/details?id=chat.simplex.app), [F-Droid](https://simplex.chat/fdroid/), [APK aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex.apk), [APK armv7](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-armv7a.apk).
|
||||
|
||||
## Terminal (console) app
|
||||
|
||||
See [Using terminal app](/docs/CLI.md).
|
||||
|
||||
**Linux**: [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-chat-ubuntu-20_04-x86-64), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-chat-ubuntu-22_04-x86-64).
|
||||
**Linux**: [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-chat-ubuntu-20_04-x86-64), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-chat-ubuntu-22_04-x86-64).
|
||||
|
||||
**Mac** [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-chat-macos-x86-64), aarch64 - [compile from source](./CLI.md#).
|
||||
**Mac** [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-chat-macos-x86-64), aarch64 - [compile from source](./CLI.md#).
|
||||
|
||||
**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.8/simplex-chat-windows-x86-64).
|
||||
**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.0-beta.9/simplex-chat-windows-x86-64).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: simplex-chat
|
||||
version: 5.3.0.9
|
||||
version: 5.3.0.10
|
||||
#synopsis:
|
||||
#description:
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
|
||||
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplex-chat
|
||||
version: 5.3.0.9
|
||||
version: 5.3.0.10
|
||||
category: Web, System, Services, Cryptography
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
author: simplex.chat
|
||||
|
||||
@@ -14,14 +14,12 @@ import Data.Aeson (ToJSON (..))
|
||||
import qualified Data.Aeson as J
|
||||
import Data.Bifunctor (first)
|
||||
import qualified Data.ByteString.Base64.URL as U
|
||||
import Data.ByteString.Char8 (ByteString)
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import qualified Data.ByteString.Lazy.Char8 as LB
|
||||
import Data.Functor (($>))
|
||||
import Data.List (find)
|
||||
import qualified Data.List.NonEmpty as L
|
||||
import Data.Maybe (fromMaybe)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
import Data.Word (Word8)
|
||||
import Database.SQLite.Simple (SQLError (..))
|
||||
import qualified Database.SQLite.Simple as DB
|
||||
@@ -95,36 +93,36 @@ cChatMigrateInit fp key conf ctrl = do
|
||||
chatMigrateInit dbPath dbKey confirm >>= \case
|
||||
Right cc -> (newStablePtr cc >>= poke ctrl) $> DBMOk
|
||||
Left e -> pure e
|
||||
newCAString . LB.unpack $ J.encode r
|
||||
newCStringFromLazyBS $ J.encode r
|
||||
|
||||
-- | send command to chat (same syntax as in terminal for now)
|
||||
cChatSendCmd :: StablePtr ChatController -> CString -> IO CJSONString
|
||||
cChatSendCmd cPtr cCmd = do
|
||||
c <- deRefStablePtr cPtr
|
||||
cmd <- peekCAString cCmd
|
||||
newCAString =<< chatSendCmd c cmd
|
||||
cmd <- B.packCString cCmd
|
||||
newCStringFromLazyBS =<< chatSendCmd c cmd
|
||||
|
||||
-- | receive message from chat (blocking)
|
||||
cChatRecvMsg :: StablePtr ChatController -> IO CJSONString
|
||||
cChatRecvMsg cc = deRefStablePtr cc >>= chatRecvMsg >>= newCAString
|
||||
cChatRecvMsg cc = deRefStablePtr cc >>= chatRecvMsg >>= newCStringFromLazyBS
|
||||
|
||||
-- | receive message from chat (blocking up to `t` microseconds (1/10^6 sec), returns empty string if times out)
|
||||
cChatRecvMsgWait :: StablePtr ChatController -> CInt -> IO CJSONString
|
||||
cChatRecvMsgWait cc t = deRefStablePtr cc >>= (`chatRecvMsgWait` fromIntegral t) >>= newCAString
|
||||
cChatRecvMsgWait cc t = deRefStablePtr cc >>= (`chatRecvMsgWait` fromIntegral t) >>= newCStringFromLazyBS
|
||||
|
||||
-- | parse markdown - returns ParsedMarkdown type JSON
|
||||
cChatParseMarkdown :: CString -> IO CJSONString
|
||||
cChatParseMarkdown s = newCAString . chatParseMarkdown =<< peekCAString s
|
||||
cChatParseMarkdown s = newCStringFromLazyBS . chatParseMarkdown =<< B.packCString s
|
||||
|
||||
-- | parse server address - returns ParsedServerAddress JSON
|
||||
cChatParseServer :: CString -> IO CJSONString
|
||||
cChatParseServer s = newCAString . chatParseServer =<< peekCAString s
|
||||
cChatParseServer s = newCStringFromLazyBS . chatParseServer =<< B.packCString s
|
||||
|
||||
cChatPasswordHash :: CString -> CString -> IO CString
|
||||
cChatPasswordHash cPwd cSalt = do
|
||||
pwd <- peekCAString cPwd
|
||||
salt <- peekCAString cSalt
|
||||
newCAString $ chatPasswordHash pwd salt
|
||||
pwd <- B.packCString cPwd
|
||||
salt <- B.packCString cSalt
|
||||
newCStringFromBS $ chatPasswordHash pwd salt
|
||||
|
||||
mobileChatOpts :: String -> String -> ChatOpts
|
||||
mobileChatOpts dbFilePrefix dbKey =
|
||||
@@ -197,22 +195,22 @@ chatMigrateInit dbFilePrefix dbKey confirm = runExceptT $ do
|
||||
_ -> dbError e
|
||||
dbError e = Left . DBMErrorSQL dbFile $ show e
|
||||
|
||||
chatSendCmd :: ChatController -> String -> IO JSONString
|
||||
chatSendCmd cc s = LB.unpack . J.encode . APIResponse Nothing <$> runReaderT (execChatCommand $ B.pack s) cc
|
||||
chatSendCmd :: ChatController -> ByteString -> IO JSONByteString
|
||||
chatSendCmd cc s = J.encode . APIResponse Nothing <$> runReaderT (execChatCommand s) cc
|
||||
|
||||
chatRecvMsg :: ChatController -> IO JSONString
|
||||
chatRecvMsg :: ChatController -> IO JSONByteString
|
||||
chatRecvMsg ChatController {outputQ} = json <$> atomically (readTBQueue outputQ)
|
||||
where
|
||||
json (corr, resp) = LB.unpack $ J.encode APIResponse {corr, resp}
|
||||
json (corr, resp) = J.encode APIResponse {corr, resp}
|
||||
|
||||
chatRecvMsgWait :: ChatController -> Int -> IO JSONString
|
||||
chatRecvMsgWait :: ChatController -> Int -> IO JSONByteString
|
||||
chatRecvMsgWait cc time = fromMaybe "" <$> timeout time (chatRecvMsg cc)
|
||||
|
||||
chatParseMarkdown :: String -> JSONString
|
||||
chatParseMarkdown = LB.unpack . J.encode . ParsedMarkdown . parseMaybeMarkdownList . safeDecodeUtf8 . B.pack
|
||||
chatParseMarkdown :: ByteString -> JSONByteString
|
||||
chatParseMarkdown = J.encode . ParsedMarkdown . parseMaybeMarkdownList . safeDecodeUtf8
|
||||
|
||||
chatParseServer :: String -> JSONString
|
||||
chatParseServer = LB.unpack . J.encode . toServerAddress . strDecode . B.pack
|
||||
chatParseServer :: ByteString -> JSONByteString
|
||||
chatParseServer = J.encode . toServerAddress . strDecode
|
||||
where
|
||||
toServerAddress :: Either String AProtoServerWithAuth -> ParsedServerAddress
|
||||
toServerAddress = \case
|
||||
@@ -223,11 +221,11 @@ chatParseServer = LB.unpack . J.encode . toServerAddress . strDecode . B.pack
|
||||
enc :: StrEncoding a => a -> String
|
||||
enc = B.unpack . strEncode
|
||||
|
||||
chatPasswordHash :: String -> String -> String
|
||||
chatPasswordHash :: ByteString -> ByteString -> ByteString
|
||||
chatPasswordHash pwd salt = either (const "") passwordHash salt'
|
||||
where
|
||||
salt' = U.decode $ B.pack salt
|
||||
passwordHash = B.unpack . U.encode . C.sha512Hash . (encodeUtf8 (T.pack pwd) <>)
|
||||
salt' = U.decode salt
|
||||
passwordHash = U.encode . C.sha512Hash . (pwd <>)
|
||||
|
||||
data APIResponse = APIResponse {corr :: Maybe CorrId, resp :: ChatResponse}
|
||||
deriving (Generic)
|
||||
|
||||
@@ -27,11 +27,11 @@ import qualified Data.ByteString.Lazy as LB
|
||||
import qualified Data.ByteString.Lazy.Char8 as LB'
|
||||
import Data.Char (chr)
|
||||
import Data.Either (fromLeft)
|
||||
import Data.Word (Word8, Word32)
|
||||
import Data.Word (Word32, Word8)
|
||||
import Foreign.C
|
||||
import Foreign.Marshal.Alloc (mallocBytes)
|
||||
import Foreign.Ptr
|
||||
import Foreign.Storable (poke)
|
||||
import Foreign.Storable (poke, pokeByteOff)
|
||||
import GHC.Generics (Generic)
|
||||
import Simplex.Chat.Mobile.Shared
|
||||
import Simplex.Chat.Util (chunkSize, encryptFile)
|
||||
@@ -54,7 +54,7 @@ cChatWriteFile cPath ptr len = do
|
||||
path <- peekCString cPath
|
||||
s <- getByteString ptr len
|
||||
r <- chatWriteFile path s
|
||||
newCAString $ LB'.unpack $ J.encode r
|
||||
newCStringFromLazyBS $ J.encode r
|
||||
|
||||
chatWriteFile :: FilePath -> ByteString -> IO WriteFileResult
|
||||
chatWriteFile path s = do
|
||||
@@ -78,12 +78,11 @@ cChatReadFile cPath cKey cNonce = do
|
||||
chatReadFile path key nonce >>= \case
|
||||
Left e -> castPtr <$> newCString (chr 1 : e)
|
||||
Right s -> do
|
||||
let s' = LB.toStrict s
|
||||
len = B.length s'
|
||||
let len = fromIntegral $ LB.length s
|
||||
ptr <- mallocBytes $ len + 5
|
||||
poke ptr 0
|
||||
poke (ptr `plusPtr` 1) (fromIntegral len :: Word32)
|
||||
putByteString (ptr `plusPtr` 5) s'
|
||||
poke ptr (0 :: Word8)
|
||||
pokeByteOff ptr 1 (fromIntegral len :: Word32)
|
||||
putLazyByteString (ptr `plusPtr` 5) s
|
||||
pure ptr
|
||||
|
||||
chatReadFile :: FilePath -> ByteString -> ByteString -> IO (Either String LB.ByteString)
|
||||
|
||||
@@ -1,19 +1,48 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
|
||||
module Simplex.Chat.Mobile.Shared where
|
||||
|
||||
import qualified Data.ByteString as B
|
||||
import Data.ByteString.Internal (ByteString (PS), memcpy)
|
||||
import Data.ByteString.Internal (ByteString (..), memcpy)
|
||||
import qualified Data.ByteString.Lazy as LB
|
||||
import qualified Data.ByteString.Lazy.Internal as LB
|
||||
import Foreign.C (CInt, CString)
|
||||
import Foreign (Ptr, Word8, newForeignPtr_, plusPtr)
|
||||
import Foreign.ForeignPtr.Unsafe
|
||||
import Foreign
|
||||
|
||||
type CJSONString = CString
|
||||
|
||||
type JSONByteString = LB.ByteString
|
||||
|
||||
getByteString :: Ptr Word8 -> CInt -> IO ByteString
|
||||
getByteString ptr len = do
|
||||
fp <- newForeignPtr_ ptr
|
||||
pure $ PS fp 0 $ fromIntegral len
|
||||
pure $ BS fp $ fromIntegral len
|
||||
{-# INLINE getByteString #-}
|
||||
|
||||
putByteString :: Ptr Word8 -> ByteString -> IO ()
|
||||
putByteString ptr bs@(PS fp offset _) = do
|
||||
let p = unsafeForeignPtrToPtr fp `plusPtr` offset
|
||||
memcpy ptr p $ B.length bs
|
||||
putByteString ptr (BS fp len) =
|
||||
withForeignPtr fp $ \p -> memcpy ptr p len
|
||||
{-# INLINE putByteString #-}
|
||||
|
||||
putLazyByteString :: Ptr Word8 -> LB.ByteString -> IO ()
|
||||
putLazyByteString ptr = \case
|
||||
LB.Empty -> pure ()
|
||||
LB.Chunk ch s -> do
|
||||
putByteString ptr ch
|
||||
putLazyByteString (ptr `plusPtr` B.length ch) s
|
||||
|
||||
newCStringFromBS :: ByteString -> IO CString
|
||||
newCStringFromBS s = do
|
||||
let len = B.length s
|
||||
buf <- mallocBytes (len + 1)
|
||||
putByteString buf s
|
||||
pokeByteOff buf len (0 :: Word8)
|
||||
pure $ castPtr buf
|
||||
|
||||
newCStringFromLazyBS :: LB.ByteString -> IO CString
|
||||
newCStringFromLazyBS s = do
|
||||
let len = fromIntegral $ LB.length s
|
||||
buf <- mallocBytes (len + 1)
|
||||
putLazyByteString buf s
|
||||
pokeByteOff buf len (0 :: Word8)
|
||||
pure $ castPtr buf
|
||||
|
||||
@@ -1393,8 +1393,6 @@ serializeIntroStatus = \case
|
||||
|
||||
data Notification = Notification {title :: Text, text :: Text}
|
||||
|
||||
type JSONString = String
|
||||
|
||||
textParseJSON :: TextEncoding a => String -> J.Value -> JT.Parser a
|
||||
textParseJSON name = J.withText name $ maybe (fail $ "bad " <> name) pure . textDecode
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
|
||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||
@@ -61,66 +62,66 @@ mobileTests = do
|
||||
it "utf8 name 2" $ testFileEncryptionCApi "👍"
|
||||
it "no exception on missing file" testMissingFileEncryptionCApi
|
||||
|
||||
noActiveUser :: String
|
||||
noActiveUser :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
noActiveUser = "{\"resp\":{\"chatCmdError\":{\"chatError\":{\"error\":{\"errorType\":{\"noActiveUser\":{}}}}}}}"
|
||||
#else
|
||||
noActiveUser = "{\"resp\":{\"type\":\"chatCmdError\",\"chatError\":{\"type\":\"error\",\"errorType\":{\"type\":\"noActiveUser\"}}}}"
|
||||
#endif
|
||||
|
||||
activeUserExists :: String
|
||||
activeUserExists :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
activeUserExists = "{\"resp\":{\"chatCmdError\":{\"user_\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true},\"chatError\":{\"error\":{\"errorType\":{\"userExists\":{\"contactName\":\"alice\"}}}}}}}"
|
||||
#else
|
||||
activeUserExists = "{\"resp\":{\"type\":\"chatCmdError\",\"user_\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true},\"chatError\":{\"type\":\"error\",\"errorType\":{\"type\":\"userExists\",\"contactName\":\"alice\"}}}}"
|
||||
#endif
|
||||
|
||||
activeUser :: String
|
||||
activeUser :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
activeUser = "{\"resp\":{\"activeUser\":{\"user\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}}}}"
|
||||
#else
|
||||
activeUser = "{\"resp\":{\"type\":\"activeUser\",\"user\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}}}"
|
||||
#endif
|
||||
|
||||
chatStarted :: String
|
||||
chatStarted :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
chatStarted = "{\"resp\":{\"chatStarted\":{}}}"
|
||||
#else
|
||||
chatStarted = "{\"resp\":{\"type\":\"chatStarted\"}}"
|
||||
#endif
|
||||
|
||||
contactSubSummary :: String
|
||||
contactSubSummary :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
contactSubSummary = "{\"resp\":{\"contactSubSummary\":{" <> userJSON <> ",\"contactSubscriptions\":[]}}}"
|
||||
#else
|
||||
contactSubSummary = "{\"resp\":{\"type\":\"contactSubSummary\"," <> userJSON <> ",\"contactSubscriptions\":[]}}"
|
||||
#endif
|
||||
|
||||
memberSubSummary :: String
|
||||
memberSubSummary :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
memberSubSummary = "{\"resp\":{\"memberSubSummary\":{" <> userJSON <> ",\"memberSubscriptions\":[]}}}"
|
||||
#else
|
||||
memberSubSummary = "{\"resp\":{\"type\":\"memberSubSummary\"," <> userJSON <> ",\"memberSubscriptions\":[]}}"
|
||||
#endif
|
||||
|
||||
userContactSubSummary :: String
|
||||
userContactSubSummary :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
userContactSubSummary = "{\"resp\":{\"userContactSubSummary\":{" <> userJSON <> ",\"userContactSubscriptions\":[]}}}"
|
||||
#else
|
||||
userContactSubSummary = "{\"resp\":{\"type\":\"userContactSubSummary\"," <> userJSON <> ",\"userContactSubscriptions\":[]}}"
|
||||
#endif
|
||||
|
||||
pendingSubSummary :: String
|
||||
pendingSubSummary :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
pendingSubSummary = "{\"resp\":{\"pendingSubSummary\":{" <> userJSON <> ",\"pendingSubscriptions\":[]}}}"
|
||||
#else
|
||||
pendingSubSummary = "{\"resp\":{\"type\":\"pendingSubSummary\"," <> userJSON <> ",\"pendingSubscriptions\":[]}}"
|
||||
#endif
|
||||
|
||||
userJSON :: String
|
||||
userJSON :: LB.ByteString
|
||||
userJSON = "\"user\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}"
|
||||
|
||||
parsedMarkdown :: String
|
||||
parsedMarkdown :: LB.ByteString
|
||||
#if defined(darwin_HOST_OS) && defined(swiftJSON)
|
||||
parsedMarkdown = "{\"formattedText\":[{\"format\":{\"bold\":{}},\"text\":\"hello\"}]}"
|
||||
#else
|
||||
|
||||
@@ -23,6 +23,7 @@ metadata:
|
||||
<email>{{ metadata.author.email }}</email>
|
||||
</author>
|
||||
{%- for blog in collections.blogs | reverse %}
|
||||
{%- if not blog.data.draft %}
|
||||
{%- set absolutePostUrl = blog.url | absoluteUrl(metadata.url) %}
|
||||
<entry>
|
||||
<title>{{ blog.data.title }}</title>
|
||||
@@ -33,5 +34,6 @@ metadata:
|
||||
<content xml:lang="{{ metadata.language }}" type="html">{{ blog.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}</content>
|
||||
{# <content xml:lang="{{ metadata.language }}" type="html">{{ blog.templateContent | striptags | truncate(200) }}</content> #}
|
||||
</entry>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</feed>
|
||||
@@ -19,6 +19,7 @@ metadata:
|
||||
<description>{{ metadata.subtitle }}</description>
|
||||
<language>{{ metadata.language }}</language>
|
||||
{%- for blog in collections.blogs %}
|
||||
{%- if not blog.data.draft %}
|
||||
{%- set absolutePostUrl = blog.url | absoluteUrl(metadata.url) %}
|
||||
<item>
|
||||
<title>{{ blog.data.title }}</title>
|
||||
@@ -30,6 +31,7 @@ metadata:
|
||||
<dc:creator>{{ metadata.author.name }}</dc:creator>
|
||||
<guid>{{ absolutePostUrl }}</guid>
|
||||
</item>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</channel>
|
||||
</rss>
|
||||
Reference in New Issue
Block a user