mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-28 12:19:54 +00:00
Merge branch 'stable'
This commit is contained in:
commit
49bf3cc673
8 changed files with 99 additions and 27 deletions
|
@ -987,6 +987,7 @@ final class ChatModel: ObservableObject {
|
|||
if let i = getChatIndex(id) {
|
||||
let removed = chats.remove(at: i)
|
||||
ChatTagsModel.shared.removePresetChatTags(removed.chatInfo, removed.chatStats)
|
||||
removeWallpaperFilesFromChat(removed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1025,6 +1026,23 @@ final class ChatModel: ObservableObject {
|
|||
_ = upsertGroupMember(groupInfo, updatedMember)
|
||||
}
|
||||
}
|
||||
|
||||
func removeWallpaperFilesFromChat(_ chat: Chat) {
|
||||
if case let .direct(contact) = chat.chatInfo {
|
||||
removeWallpaperFilesFromTheme(contact.uiThemes)
|
||||
} else if case let .group(groupInfo) = chat.chatInfo {
|
||||
removeWallpaperFilesFromTheme(groupInfo.uiThemes)
|
||||
}
|
||||
}
|
||||
|
||||
func removeWallpaperFilesFromAllChats(_ user: User) {
|
||||
// Currently, only removing everything from currently active user is supported. Inactive users are TODO
|
||||
if user.userId == currentUser?.userId {
|
||||
chats.forEach {
|
||||
removeWallpaperFilesFromChat($0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ShowingInvitation {
|
||||
|
|
|
@ -298,6 +298,7 @@ struct UserProfilesView: View {
|
|||
private func removeUser(_ user: User, _ delSMPQueues: Bool, viewPwd: String?) async {
|
||||
do {
|
||||
if user.activeUser {
|
||||
ChatModel.shared.removeWallpaperFilesFromAllChats(user)
|
||||
if let newActive = m.users.first(where: { u in !u.user.activeUser && !u.user.hidden }) {
|
||||
try await changeActiveUserAsync_(newActive.user.userId, viewPwd: nil)
|
||||
try await deleteUser()
|
||||
|
@ -323,6 +324,7 @@ struct UserProfilesView: View {
|
|||
|
||||
func deleteUser() async throws {
|
||||
try await apiDeleteUser(user.userId, delSMPQueues, viewPwd: viewPwd)
|
||||
removeWallpaperFilesFromTheme(user.uiThemes)
|
||||
await MainActor.run { withAnimation { m.removeUser(user) } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -267,17 +267,26 @@ public func saveWallpaperFile(image: UIImage) -> String? {
|
|||
|
||||
public func removeWallpaperFile(fileName: String? = nil) {
|
||||
do {
|
||||
try FileManager.default.contentsOfDirectory(atPath: getWallpaperDirectory().path).forEach {
|
||||
if URL(fileURLWithPath: $0).lastPathComponent == fileName { try FileManager.default.removeItem(atPath: $0) }
|
||||
try FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: getWallpaperDirectory().path), includingPropertiesForKeys: nil, options: []).forEach { url in
|
||||
if url.lastPathComponent == fileName {
|
||||
try FileManager.default.removeItem(at: url)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
logger.error("FileUtils.removeWallpaperFile error: \(error.localizedDescription)")
|
||||
logger.error("FileUtils.removeWallpaperFile error: \(error)")
|
||||
}
|
||||
if let fileName {
|
||||
WallpaperType.cachedImages.removeValue(forKey: fileName)
|
||||
}
|
||||
}
|
||||
|
||||
public func removeWallpaperFilesFromTheme(_ theme: ThemeModeOverrides?) {
|
||||
if let theme {
|
||||
removeWallpaperFile(fileName: theme.light?.wallpaper?.imageFile)
|
||||
removeWallpaperFile(fileName: theme.dark?.wallpaper?.imageFile)
|
||||
}
|
||||
}
|
||||
|
||||
public func generateNewFileName(_ prefix: String, _ ext: String, fullPath: Bool = false) -> String {
|
||||
uniqueCombine("\(prefix)_\(getTimestamp()).\(ext)", fullPath: fullPath)
|
||||
}
|
||||
|
|
|
@ -726,17 +726,11 @@ object ChatModel {
|
|||
}
|
||||
|
||||
fun removeChat(rhId: Long?, id: String) {
|
||||
var removed: Chat? = null
|
||||
chats.removeAll {
|
||||
val found = it.id == id && it.remoteHostId == rhId
|
||||
if (found) {
|
||||
removed = it
|
||||
}
|
||||
found
|
||||
}
|
||||
|
||||
removed?.let {
|
||||
removePresetChatTags(it.chatInfo, it.chatStats)
|
||||
val i = getChatIndex(rhId, id)
|
||||
if (i != -1) {
|
||||
val chat = chats.removeAt(i)
|
||||
removePresetChatTags(chat.chatInfo, chat.chatStats)
|
||||
removeWallpaperFilesFromChat(chat)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.compose.ui.unit.*
|
|||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.ThemeModeOverrides
|
||||
import chat.simplex.common.ui.theme.ThemeOverrides
|
||||
import chat.simplex.common.views.chatlist.connectIfOpenedViaUri
|
||||
import chat.simplex.res.MR
|
||||
|
@ -316,6 +317,30 @@ fun removeWallpaperFile(fileName: String? = null) {
|
|||
WallpaperType.cachedImages.remove(fileName)
|
||||
}
|
||||
|
||||
fun removeWallpaperFilesFromTheme(theme: ThemeModeOverrides?) {
|
||||
if (theme != null) {
|
||||
removeWallpaperFile(theme.light?.wallpaper?.imageFile)
|
||||
removeWallpaperFile(theme.dark?.wallpaper?.imageFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeWallpaperFilesFromChat(chat: Chat) {
|
||||
if (chat.chatInfo is ChatInfo.Direct) {
|
||||
removeWallpaperFilesFromTheme(chat.chatInfo.contact.uiThemes)
|
||||
} else if (chat.chatInfo is ChatInfo.Group) {
|
||||
removeWallpaperFilesFromTheme(chat.chatInfo.groupInfo.uiThemes)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeWallpaperFilesFromAllChats(user: User) {
|
||||
// Currently, only removing everything from currently active user is supported. Inactive users are TODO
|
||||
if (user.userId == chatModel.currentUser.value?.userId) {
|
||||
chatModel.chats.value.forEach {
|
||||
removeWallpaperFilesFromChat(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> createTmpFileAndDelete(dir: File = tmpDir, onCreated: (File) -> T): T {
|
||||
val tmpFile = File(dir, UUID.randomUUID().toString())
|
||||
tmpFile.parentFile.mkdirs()
|
||||
|
|
|
@ -347,6 +347,7 @@ private suspend fun doRemoveUser(m: ChatModel, user: User, users: List<User>, de
|
|||
try {
|
||||
when {
|
||||
user.activeUser -> {
|
||||
removeWallpaperFilesFromAllChats(user)
|
||||
val newActive = users.firstOrNull { u -> !u.activeUser && !u.hidden }
|
||||
if (newActive != null) {
|
||||
m.controller.changeActiveUser_(user.remoteHostId, newActive.userId, null)
|
||||
|
@ -366,6 +367,7 @@ private suspend fun doRemoveUser(m: ChatModel, user: User, users: List<User>, de
|
|||
m.controller.apiDeleteUser(user, delSMPQueues, viewPwd)
|
||||
}
|
||||
}
|
||||
removeWallpaperFilesFromTheme(user.uiThemes)
|
||||
m.removeUser(user)
|
||||
ntfManager.cancelNotificationsForUser(user.userId)
|
||||
} catch (e: Exception) {
|
||||
|
|
|
@ -106,7 +106,7 @@ import Simplex.Messaging.Version
|
|||
import Simplex.RemoteControl.Invitation (RCInvitation (..), RCSignedInvitation (..))
|
||||
import Simplex.RemoteControl.Types (RCCtrlAddress (..))
|
||||
import System.Exit (ExitCode, exitSuccess)
|
||||
import System.FilePath (takeFileName, (</>))
|
||||
import System.FilePath (takeExtension, takeFileName, (</>))
|
||||
import System.IO (Handle, IOMode (..))
|
||||
import System.Random (randomRIO)
|
||||
import UnliftIO.Async
|
||||
|
@ -146,6 +146,15 @@ imageExtensions = [".jpg", ".jpeg", ".png", ".gif"]
|
|||
fixedImagePreview :: ImageData
|
||||
fixedImagePreview = ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAKVJREFUeF7t1kENACEUQ0FQhnVQ9lfGO+xggITQdvbMzArPey+8fa3tAfwAEdABZQspQStgBssEcgAIkSAJkiAJljtEgiRIgmUCSZAESZAESZAEyx0iQRIkwTKBJEiCv5fgvTd1wDmn7QAP4AeIgA4oW0gJWgEzWCZwbQ7gAA7ggLKFOIADOKBMIAeAEAmSIAmSYLlDJEiCJFgmkARJkARJ8N8S/ADTZUewBvnTOQAAAABJRU5ErkJggg=="
|
||||
|
||||
imageFilePrefix :: String
|
||||
imageFilePrefix = "IMG_"
|
||||
|
||||
voiceFilePrefix :: String
|
||||
voiceFilePrefix = "voice_"
|
||||
|
||||
videoFilePrefix :: String
|
||||
videoFilePrefix = "video_"
|
||||
|
||||
-- enableSndFiles has no effect when mainApp is True
|
||||
startChatController :: Bool -> Bool -> CM' (Async ())
|
||||
startChatController mainApp enableSndFiles = do
|
||||
|
@ -897,7 +906,8 @@ processChatCommand' vr = \case
|
|||
ifM
|
||||
(doesFileExist fsFromPath)
|
||||
( do
|
||||
fsNewPath <- liftIO $ filesFolder `uniqueCombine` fileName
|
||||
newFileName <- liftIO $ maybe (pure fileName) (generateNewFileName fileName) $ mediaFilePrefix mc
|
||||
fsNewPath <- liftIO $ filesFolder `uniqueCombine` newFileName
|
||||
liftIO $ B.writeFile fsNewPath "" -- create empty file
|
||||
encrypt <- chatReadVar encryptLocalFiles
|
||||
cfArgs <- if encrypt then Just <$> (atomically . CF.randomArgs =<< asks random) else pure Nothing
|
||||
|
@ -934,6 +944,17 @@ processChatCommand' vr = \case
|
|||
when (B.length ch /= chSize') $ throwError $ CF.FTCEFileIOError "encrypting file: unexpected EOF"
|
||||
liftIO . CF.hPut w $ LB.fromStrict ch
|
||||
when (size' > 0) $ copyChunks r w size'
|
||||
mediaFilePrefix :: MsgContent -> Maybe FilePath
|
||||
mediaFilePrefix = \case
|
||||
MCImage {} -> Just imageFilePrefix
|
||||
MCVoice {} -> Just voiceFilePrefix
|
||||
MCVideo {} -> Just videoFilePrefix
|
||||
_ -> Nothing
|
||||
generateNewFileName fileName prefix = do
|
||||
currentDate <- liftIO getCurrentTime
|
||||
let formattedDate = formatTime defaultTimeLocale "%Y%m%d_%H%M%S" currentDate
|
||||
let ext = takeExtension fileName
|
||||
pure $ prefix <> formattedDate <> ext
|
||||
APIUserRead userId -> withUserId userId $ \user -> withFastStore' (`setUserChatsRead` user) >> ok user
|
||||
UserRead -> withUser $ \User {userId} -> processChatCommand $ APIUserRead userId
|
||||
APIChatRead chatRef@(ChatRef cType chatId) -> withUser $ \_ -> case cType of
|
||||
|
|
|
@ -785,8 +785,9 @@ testMultiForwardFiles =
|
|||
bob <## " message without file"
|
||||
|
||||
bob <# "@cath <- @alice"
|
||||
bob <## " test_1.jpg"
|
||||
bob <# "/f @cath test_1.jpg"
|
||||
|
||||
jpgFileName <- T.unpack . T.strip . T.pack <$> getTermLine bob
|
||||
bob <# ("/f @cath " <> jpgFileName)
|
||||
bob <## "use /fc 5 to cancel sending"
|
||||
|
||||
bob <# "@cath <- @alice"
|
||||
|
@ -808,8 +809,8 @@ testMultiForwardFiles =
|
|||
cath <## " message without file"
|
||||
|
||||
cath <# "bob> -> forwarded"
|
||||
cath <## " test_1.jpg"
|
||||
cath <# "bob> sends file test_1.jpg (136.5 KiB / 139737 bytes)"
|
||||
cath <## (" " <> jpgFileName)
|
||||
cath <# ("bob> sends file " <> jpgFileName <> " (136.5 KiB / 139737 bytes)")
|
||||
cath <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||
|
||||
cath <# "bob> -> forwarded"
|
||||
|
@ -824,15 +825,15 @@ testMultiForwardFiles =
|
|||
cath <## ""
|
||||
|
||||
-- file transfer
|
||||
bob <## "completed uploading file 5 (test_1.jpg) for cath"
|
||||
bob <## ("completed uploading file 5 (" <> jpgFileName <> ") for cath")
|
||||
bob <## "completed uploading file 6 (test_1.pdf) for cath"
|
||||
|
||||
cath ##> "/fr 1"
|
||||
cath
|
||||
<### [ "saving file 1 from bob to test_1.jpg",
|
||||
"started receiving file 1 (test_1.jpg) from bob"
|
||||
<### [ ConsoleString $ "saving file 1 from bob to " <> jpgFileName,
|
||||
ConsoleString $ "started receiving file 1 (" <> jpgFileName <> ") from bob"
|
||||
]
|
||||
cath <## "completed receiving file 1 (test_1.jpg) from bob"
|
||||
cath <## ("completed receiving file 1 (" <> jpgFileName <> ") from bob")
|
||||
|
||||
cath ##> "/fr 2"
|
||||
cath
|
||||
|
@ -841,9 +842,9 @@ testMultiForwardFiles =
|
|||
]
|
||||
cath <## "completed receiving file 2 (test_1.pdf) from bob"
|
||||
|
||||
src1B <- B.readFile "./tests/tmp/bob_app_files/test_1.jpg"
|
||||
src1B <- B.readFile ("./tests/tmp/bob_app_files/" <> jpgFileName)
|
||||
src1B `shouldBe` dest1
|
||||
dest1C <- B.readFile "./tests/tmp/cath_app_files/test_1.jpg"
|
||||
dest1C <- B.readFile ("./tests/tmp/cath_app_files/" <> jpgFileName)
|
||||
dest1C `shouldBe` src1B
|
||||
|
||||
src2B <- B.readFile "./tests/tmp/bob_app_files/test_1.pdf"
|
||||
|
@ -886,5 +887,5 @@ testMultiForwardFiles =
|
|||
checkActionDeletesFile "./tests/tmp/bob_app_files/test.jpg" $ do
|
||||
bob ##> "/clear alice"
|
||||
bob <## "alice: all messages are removed locally ONLY"
|
||||
fwdFileExists <- doesFileExist "./tests/tmp/bob_app_files/test_1.jpg"
|
||||
fwdFileExists <- doesFileExist ("./tests/tmp/bob_app_files/" <> jpgFileName)
|
||||
fwdFileExists `shouldBe` True
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue