From 1d0d7bbd014cdd5671fa9a080ec439e1bfbc1ce8 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:43:57 +0400 Subject: [PATCH 01/21] core: batch send file descriptions (#4684) * core: batch send file descriptions * fix useMember * fix result interpretation * remove comment * refactor --------- Co-authored-by: Evgeny Poberezkin --- src/Simplex/Chat.hs | 70 ++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 54b877dc6a..2d3ed3ca84 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -3902,15 +3902,22 @@ processAgentMsgSndFile _corrId aFileId msg = do case (rfds, sfts, d, cInfo) of (rfd : extraRFDs, sft : _, SMDSnd, DirectChat ct) -> do withStore' $ \db -> createExtraSndFTDescrs db user fileId (map fileDescrText extraRFDs) - msgDeliveryId <- sendFileDescription sft rfd sharedMsgId $ sendDirectContactMessage user ct - withStore' $ \db -> updateSndFTDeliveryXFTP db sft msgDeliveryId + conn@Connection {connId} <- liftEither $ contactSendConn_ ct + sendFileDescriptions (ConnectionId connId) ((conn, sft, fileDescrText rfd) :| []) sharedMsgId >>= \case + Just rs -> case L.last rs of + Right ([msgDeliveryId], _) -> + withStore' $ \db -> updateSndFTDeliveryXFTP db sft msgDeliveryId + Right (deliveryIds, _) -> toView $ CRChatError (Just user) $ ChatError $ CEInternalError $ "SFDONE, sendFileDescriptions: expected 1 delivery id, got " <> show (length deliveryIds) + Left e -> toView $ CRChatError (Just user) e + Nothing -> toView $ CRChatError (Just user) $ ChatError $ CEInternalError "SFDONE, sendFileDescriptions: expected at least 1 result" lift $ withAgent' (`xftpDeleteSndFileInternal` aFileId) (_, _, SMDSnd, GroupChat g@GroupInfo {groupId}) -> do ms <- withStore' $ \db -> getGroupMembers db vr user g - let rfdsMemberFTs = zip rfds $ memberFTs ms + let rfdsMemberFTs = zipWith (\rfd (conn, sft) -> (conn, sft, fileDescrText rfd)) rfds (memberFTs ms) extraRFDs = drop (length rfdsMemberFTs) rfds withStore' $ \db -> createExtraSndFTDescrs db user fileId (map fileDescrText extraRFDs) - forM_ rfdsMemberFTs $ \mt -> sendToMember mt `catchChatError` (toView . CRChatError (Just user)) + forM_ (L.nonEmpty rfdsMemberFTs) $ \rfdsMemberFTs' -> + sendFileDescriptions (GroupId groupId) rfdsMemberFTs' sharedMsgId ci' <- withStore $ \db -> do liftIO $ updateCIFileStatus db user fileId CIFSSndComplete getChatItemByFileId db vr user fileId @@ -3922,15 +3929,12 @@ processAgentMsgSndFile _corrId aFileId msg = do where mConns' = mapMaybe useMember ms sfts' = mapMaybe (\sft@SndFileTransfer {groupMemberId} -> (,sft) <$> groupMemberId) sfts + -- Should match memberSendAction logic useMember GroupMember {groupMemberId, activeConn = Just conn@Connection {connStatus}} - | (connStatus == ConnReady || connStatus == ConnSndReady) && not (connDisabled conn) = Just (groupMemberId, conn) + | (connStatus == ConnReady || connStatus == ConnSndReady) && not (connDisabled conn) && not (connInactive conn) = + Just (groupMemberId, conn) | otherwise = Nothing useMember _ = Nothing - sendToMember :: (ValidFileDescription 'FRecipient, (Connection, SndFileTransfer)) -> CM () - sendToMember (rfd, (conn, sft)) = - void $ sendFileDescription sft rfd sharedMsgId $ \msg' -> do - (sndMsg, msgDeliveryId, _) <- sendDirectMemberMessage conn msg' groupId - pure (sndMsg, msgDeliveryId) _ -> pure () _ -> pure () -- TODO error? SFWARN e -> do @@ -3945,20 +3949,27 @@ processAgentMsgSndFile _corrId aFileId msg = do where fileDescrText :: FilePartyI p => ValidFileDescription p -> T.Text fileDescrText = safeDecodeUtf8 . strEncode - sendFileDescription :: SndFileTransfer -> ValidFileDescription 'FRecipient -> SharedMsgId -> (ChatMsgEvent 'Json -> CM (SndMessage, Int64)) -> CM Int64 - sendFileDescription sft rfd msgId sendMsg = do - let rfdText = fileDescrText rfd - withStore' $ \db -> updateSndFTDescrXFTP db user sft rfdText - parts <- splitFileDescr rfdText - loopSend parts + sendFileDescriptions :: ConnOrGroupId -> NonEmpty (Connection, SndFileTransfer, RcvFileDescrText) -> SharedMsgId -> CM (Maybe (NonEmpty (Either ChatError ([Int64], PQEncryption)))) + sendFileDescriptions connOrGroupId connsTransfersDescrs sharedMsgId = do + lift . void . withStoreBatch' $ \db -> L.map (\(_, sft, rfdText) -> updateSndFTDescrXFTP db user sft rfdText) connsTransfersDescrs + partSize <- asks $ xftpDescrPartSize . config + let connsIdsEvts = connDescrEvents partSize + sndMsgs_ <- lift $ createSndMessages $ L.map snd connsIdsEvts + let (errs, msgReqs) = partitionEithers . L.toList $ L.zipWith (fmap . toMsgReq) connsIdsEvts sndMsgs_ + delivered <- mapM deliverMessages (L.nonEmpty msgReqs) + let errs' = errs <> maybe [] (lefts . L.toList) delivered + unless (null errs') $ toView $ CRChatErrors (Just user) errs' + pure delivered where - -- returns msgDeliveryId of the last file description message - loopSend :: NonEmpty FileDescr -> CM Int64 - loopSend (fileDescr :| fds) = do - (_, msgDeliveryId) <- sendMsg $ XMsgFileDescr {msgId, fileDescr} - case L.nonEmpty fds of - Just fds' -> loopSend fds' - Nothing -> pure msgDeliveryId + connDescrEvents :: Int -> NonEmpty (Connection, (ConnOrGroupId, ChatMsgEvent 'Json)) + connDescrEvents partSize = L.fromList $ concatMap splitText (L.toList connsTransfersDescrs) + where + splitText :: (Connection, SndFileTransfer, RcvFileDescrText) -> [(Connection, (ConnOrGroupId, ChatMsgEvent 'Json))] + splitText (conn, _, rfdText) = + map (\fileDescr -> (conn, (connOrGroupId, XMsgFileDescr {msgId = sharedMsgId, fileDescr}))) (L.toList $ splitFileDescr partSize rfdText) + toMsgReq :: (Connection, (ConnOrGroupId, ChatMsgEvent 'Json)) -> SndMessage -> ChatMsgReq + toMsgReq (conn, _) SndMessage {msgId, msgBody} = + (conn, MsgFlags {notification = hasNotification XMsgFileDescr_}, msgBody, [msgId]) sendFileError :: FileError -> Text -> VersionRangeChat -> FileTransferMeta -> CM () sendFileError ferr err vr ft = do logError $ "Sent file error: " <> err @@ -3980,18 +3991,16 @@ agentFileError = \case SMP.TRANSPORT TEVersion -> srvErr SrvErrVersion e -> srvErr . SrvErrOther $ tshow e -splitFileDescr :: RcvFileDescrText -> CM (NonEmpty FileDescr) -splitFileDescr rfdText = do - partSize <- asks $ xftpDescrPartSize . config - pure $ splitParts 1 partSize rfdText +splitFileDescr :: Int -> RcvFileDescrText -> NonEmpty FileDescr +splitFileDescr partSize rfdText = splitParts 1 rfdText where - splitParts partNo partSize remText = + splitParts partNo remText = let (part, rest) = T.splitAt partSize remText complete = T.null rest fileDescr = FileDescr {fileDescrText = part, fileDescrPartNo = partNo, fileDescrComplete = complete} in if complete then fileDescr :| [] - else fileDescr <| splitParts (partNo + 1) partSize rest + else fileDescr <| splitParts (partNo + 1) rest processAgentMsgRcvFile :: ACorrId -> RcvFileId -> AEvent 'AERcvFile -> CM () processAgentMsgRcvFile _corrId aFileId msg = do @@ -4573,7 +4582,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = xMsgNewChatMsg = ChatMessage {chatVRange = senderVRange, msgId = itemSharedMsgId, chatMsgEvent = XMsgNew msgContainer} fileDescrEvents <- case (snd <$> fInvDescr_, itemSharedMsgId) of (Just fileDescrText, Just msgId) -> do - parts <- splitFileDescr fileDescrText + partSize <- asks $ xftpDescrPartSize . config + let parts = splitFileDescr partSize fileDescrText pure . toList $ L.map (XMsgFileDescr msgId) parts _ -> pure [] let fileDescrChatMsgs = map (ChatMessage senderVRange Nothing) fileDescrEvents From c159c2ede345aa041337c0da16fa241cb5af2e3c Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Thu, 15 Aug 2024 13:15:24 +0300 Subject: [PATCH 02/21] ios: fix pending connection sheet styling when opened via icon; fix tappable area of pending connections and contact requests (#4694) * fix new contact sheet styling * fix contact request tappable area --------- Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> --- apps/ios/Shared/Views/ChatList/ChatListNavLink.swift | 2 ++ apps/ios/Shared/Views/ChatList/ContactConnectionView.swift | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift index c8424ef332..d2a93b9bd1 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift @@ -355,6 +355,7 @@ struct ChatListNavLink: View { .tint(.red) } .frame(height: dynamicRowHeight) + .contentShape(Rectangle()) .onTapGesture { showContactRequestDialog = true } .confirmationDialog("Accept connection request?", isPresented: $showContactRequestDialog, titleVisibility: .visible) { Button("Accept") { Task { await acceptContactRequest(incognito: false, contactRequest: contactRequest) } } @@ -392,6 +393,7 @@ struct ChatListNavLink: View { } } } + .contentShape(Rectangle()) .onTapGesture { showContactConnectionInfo = true } diff --git a/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift b/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift index 3c7bf97af9..f5156d86b8 100644 --- a/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift +++ b/apps/ios/Shared/Views/ChatList/ContactConnectionView.swift @@ -16,7 +16,6 @@ struct ContactConnectionView: View { @Environment(\.dynamicTypeSize) private var userFont: DynamicTypeSize @State private var localAlias = "" @FocusState private var aliasTextFieldFocused: Bool - @State private var showContactConnectionInfo = false var body: some View { if case let .contactConnection(conn) = chat.chatInfo { @@ -32,7 +31,6 @@ struct ContactConnectionView: View { .scaledToFill() .frame(width: 48, height: 48) .foregroundColor(Color(uiColor: .tertiarySystemGroupedBackground).asAnotherColorFromSecondaryVariant(theme)) - .onTapGesture { showContactConnectionInfo = true } } .frame(width: 63, height: 63) .padding(.leading, 4) @@ -72,9 +70,6 @@ struct ContactConnectionView: View { Spacer() } .frame(maxHeight: .infinity) - .appSheet(isPresented: $showContactConnectionInfo) { - ContactConnectionInfo(contactConnection: contactConnection) - } } } } From 3c694e28417cd7feb62d42e6e2883715a5d219a6 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Thu, 15 Aug 2024 20:21:22 +0300 Subject: [PATCH 03/21] upgrade code scanner (#4650) Co-authored-by: Evgeny Poberezkin --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 0351c1c1ce..32f68f1ca3 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -2320,7 +2320,7 @@ repositoryURL = "https://github.com/twostraws/CodeScanner"; requirement = { kind = exactVersion; - version = 2.1.1; + version = 2.5.0; }; }; 8C73C1162C21E17B00892670 /* XCRemoteSwiftPackageReference "Yams" */ = { diff --git a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d3e61c88f9..c8623a95cb 100644 --- a/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/apps/ios/SimpleX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/twostraws/CodeScanner", "state" : { - "revision" : "c27a66149b7483fe42e2ec6aad61d5c3fffe522d", - "version" : "2.1.1" + "revision" : "34da57fb63b47add20de8a85da58191523ccce57", + "version" : "2.5.0" } }, { @@ -23,7 +23,6 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/kirualex/SwiftyGif", "state" : { - "branch" : "master", "revision" : "5e8619335d394901379c9add5c4c1c2f420b3800" } }, From c823a4fa6c918ea5a88a91a499686594201115e4 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Thu, 15 Aug 2024 20:43:30 +0300 Subject: [PATCH 04/21] extend chat view material behind keyboard (#4698) Co-authored-by: Evgeny Poberezkin --- apps/ios/Shared/AppDelegate.swift | 19 ----------------- apps/ios/Shared/Model/ChatModel.swift | 2 -- apps/ios/Shared/Views/Chat/ChatView.swift | 1 - .../Chat/ComposeMessage/ComposeView.swift | 6 +++++- .../Views/Chat/Group/GroupChatInfoView.swift | 1 - .../Views/Helpers/KeyboardPadding.swift | 21 ------------------- .../Shared/Views/NewChat/AddGroupView.swift | 2 +- .../Views/Onboarding/CreateProfile.swift | 2 -- apps/ios/SimpleX.xcodeproj/project.pbxproj | 4 ---- 9 files changed, 6 insertions(+), 52 deletions(-) delete mode 100644 apps/ios/Shared/Views/Helpers/KeyboardPadding.swift diff --git a/apps/ios/Shared/AppDelegate.swift b/apps/ios/Shared/AppDelegate.swift index d52c950d81..dd91d4af68 100644 --- a/apps/ios/Shared/AppDelegate.swift +++ b/apps/ios/Shared/AppDelegate.swift @@ -15,31 +15,12 @@ class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { logger.debug("AppDelegate: didFinishLaunchingWithOptions") application.registerForRemoteNotifications() - if #available(iOS 17.0, *) { trackKeyboard() } NotificationCenter.default.addObserver(self, selector: #selector(pasteboardChanged), name: UIPasteboard.changedNotification, object: nil) removePasscodesIfReinstalled() prepareForLaunch() return true } - @available(iOS 17.0, *) - private func trackKeyboard() { - NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) - } - - @available(iOS 17.0, *) - @objc func keyboardWillShow(_ notification: Notification) { - if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { - ChatModel.shared.keyboardHeight = keyboardFrame.cgRectValue.height - } - } - - @available(iOS 17.0, *) - @objc func keyboardWillHide(_ notification: Notification) { - ChatModel.shared.keyboardHeight = 0 - } - @objc func pasteboardChanged() { ChatModel.shared.pasteboardHasStrings = UIPasteboard.general.hasStrings } diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 347ffa7a8f..4b391b727e 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -183,8 +183,6 @@ final class ChatModel: ObservableObject { @Published var stopPreviousRecPlay: URL? = nil // coordinates currently playing source @Published var draft: ComposeState? @Published var draftChatId: String? - // tracks keyboard height via subscription in AppDelegate - @Published var keyboardHeight: CGFloat = 0 @Published var pasteboardHasStrings: Bool = UIPasteboard.general.hasStrings @Published var networkInfo = UserNetworkInfo(networkType: .other, online: true) diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 7bd13a3fa7..655dd8aaed 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -53,7 +53,6 @@ struct ChatView: View { if #available(iOS 16.0, *) { viewBody .scrollDismissesKeyboard(.immediately) - .keyboardPadding() .toolbarBackground(.hidden, for: .navigationBar) } else { viewBody diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index e059d72e98..78cae78cf5 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -382,7 +382,11 @@ struct ComposeView: View { } } } - .background(ToolbarMaterial.material(toolbarMaterial)) + .background { + Color.clear + .overlay(ToolbarMaterial.material(toolbarMaterial)) + .ignoresSafeArea(.all, edges: .bottom) + } .onChange(of: composeState.message) { msg in if composeState.linkPreviewAllowed { if msg.count > 0 { diff --git a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift index 50eb883e92..9385633060 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift @@ -185,7 +185,6 @@ struct GroupChatInfoView: View { logger.error("GroupChatInfoView apiGetGroupLink: \(responseError(error))") } } - .keyboardPadding() } private func groupInfoHeader() -> some View { diff --git a/apps/ios/Shared/Views/Helpers/KeyboardPadding.swift b/apps/ios/Shared/Views/Helpers/KeyboardPadding.swift deleted file mode 100644 index 45d766ddfd..0000000000 --- a/apps/ios/Shared/Views/Helpers/KeyboardPadding.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// KeyboardPadding.swift -// SimpleX (iOS) -// -// Created by Evgeny on 10/07/2023. -// Copyright © 2023 SimpleX Chat. All rights reserved. -// - -import SwiftUI - -extension View { - @ViewBuilder func keyboardPadding() -> some View { - if #available(iOS 17.0, *) { - GeometryReader { g in - self.padding(.bottom, max(0, ChatModel.shared.keyboardHeight - g.safeAreaInsets.bottom)) - } - } else { - self - } - } -} diff --git a/apps/ios/Shared/Views/NewChat/AddGroupView.swift b/apps/ios/Shared/Views/NewChat/AddGroupView.swift index 113691abb3..33c187b64b 100644 --- a/apps/ios/Shared/Views/NewChat/AddGroupView.swift +++ b/apps/ios/Shared/Views/NewChat/AddGroupView.swift @@ -59,7 +59,7 @@ struct AddGroupView: View { .navigationBarTitle("Group link") } } else { - createGroupView().keyboardPadding() + createGroupView() } } diff --git a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift index a62f609833..487f4ccdeb 100644 --- a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift +++ b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift @@ -77,7 +77,6 @@ struct CreateProfile: View { focusDisplayName = true } } - .keyboardPadding() } } @@ -128,7 +127,6 @@ struct CreateFirstProfile: View { } .padding() .frame(maxWidth: .infinity, alignment: .leading) - .keyboardPadding() } func onboardingButtons() -> some View { diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 32f68f1ca3..46cf768a9f 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -135,7 +135,6 @@ 5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE4407827ADB701007B033A /* EmojiItemView.swift */; }; 5CEACCE327DE9246000BD591 /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCE227DE9246000BD591 /* ComposeView.swift */; }; 5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */; }; - 5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */; }; 5CEBD7482A5F115D00665FE2 /* SetDeliveryReceiptsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */; }; 5CF937202B24DE8C00E1D781 /* SharedFileSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */; }; 5CF937232B2503D000E1D781 /* NSESubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF937212B25034A00E1D781 /* NSESubscriber.swift */; }; @@ -474,7 +473,6 @@ 5CE6C7B42AAB1527007F345C /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = ""; }; 5CEACCE227DE9246000BD591 /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = ""; }; 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgContentView.swift; sourceTree = ""; }; - 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPadding.swift; sourceTree = ""; }; 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDeliveryReceiptsView.swift; sourceTree = ""; }; 5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedFileSubscriber.swift; sourceTree = ""; }; 5CF937212B25034A00E1D781 /* NSESubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESubscriber.swift; sourceTree = ""; }; @@ -786,7 +784,6 @@ 18415DAAAD1ADBEDB0EDA852 /* VideoPlayerView.swift */, 64466DCB29FFE3E800E3D48D /* MailView.swift */, 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */, - 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */, 8C7F8F0D2C19C0C100D16888 /* ViewModifiers.swift */, 8C74C3ED2C1B942300039E77 /* ChatWallpaper.swift */, 8C9BC2642C240D5100875A27 /* ThemeModeEditor.swift */, @@ -1435,7 +1432,6 @@ 646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */, 8C74C3EA2C1B90AF00039E77 /* ThemeManager.swift in Sources */, 5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */, - 5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */, 5C35CFC827B2782E00FB6C6D /* BGManager.swift in Sources */, 5CB634B129E5EFEA0066AD6B /* PasscodeView.swift in Sources */, 8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */, From b0e0b0beb8e8266fcaecac814976c5b8779edee2 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Thu, 15 Aug 2024 22:08:51 +0300 Subject: [PATCH 05/21] remove text slection context menu from chat item (#4699) --- apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift index 258e2e34dc..313ec0d419 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift @@ -294,7 +294,6 @@ struct FramedItemView: View { .padding(.horizontal, 12) .overlay(DetermineWidth()) .frame(minWidth: 0, alignment: .leading) - .textSelection(.enabled) if let mediaWidth = maxMediaWidth(), mediaWidth < maxWidth { v.frame(maxWidth: mediaWidth, alignment: .leading) From 3740805125120b23cbb24c675cd6d670f3abf6a7 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Fri, 16 Aug 2024 11:55:22 +0100 Subject: [PATCH 06/21] core: batch connection subscription transactions (#4701) * core: batch connection subscription transactions * simplexmq --- cabal.project | 2 +- scripts/nix/sha256map.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cabal.project b/cabal.project index 23963491b9..642831aeb8 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 0dd52dc69f197a86f2f03e47b339bf3a94a596a3 + tag: f229e135e33ec5ee1f6d0978bd903d84b0b60efa source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 246969b98d..05253078f1 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."0dd52dc69f197a86f2f03e47b339bf3a94a596a3" = "1dzfpk9bq8y885i2z419k79f2nyagrqkqh8rw3gzmf1hy5w3fbjs"; + "https://github.com/simplex-chat/simplexmq.git"."f229e135e33ec5ee1f6d0978bd903d84b0b60efa" = "0p4n4bghg24a98py9mij6s24fvsix4a73lwkg6skqf4rx8zp392v"; "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"; From 3a0921c0936fa4fb3ffdf41c054b012f8574a594 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Sat, 17 Aug 2024 15:26:56 +0300 Subject: [PATCH 07/21] ios: asychronous subscription updates (#4707) * ios: asychronous subscription updates * cleanup --- apps/ios/Shared/Model/SimpleXAPI.swift | 4 +- .../Shared/Views/ChatList/ChatListView.swift | 39 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index df76409316..ed2c8e23d6 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1420,9 +1420,9 @@ func apiGetVersion() throws -> CoreVersionInfo { throw r } -func getAgentSubsTotal() throws -> (SMPServerSubs, Bool) { +func getAgentSubsTotal() async throws -> (SMPServerSubs, Bool) { let userId = try currentUserId("getAgentSubsTotal") - let r = chatSendCmdSync(.getAgentSubsTotal(userId: userId), log: false) + let r = await chatSendCmd(.getAgentSubsTotal(userId: userId)) if case let .agentSubsTotal(_, subsTotal, hasSession) = r { return (subsTotal, hasSession) } logger.error("getAgentSubsTotal error: \(String(describing: r))") throw r diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 8c9d090890..ec49c7b4d1 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -324,7 +324,7 @@ struct ChatListView: View { struct SubsStatusIndicator: View { @State private var subs: SMPServerSubs = SMPServerSubs.newSMPServerSubs @State private var hasSess: Bool = false - @State private var timer: Timer? = nil + @State private var task: Task? @State private var showServersSummary = false @AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false @@ -343,10 +343,10 @@ struct SubsStatusIndicator: View { } .disabled(ChatModel.shared.chatRunning != true) .onAppear { - startTimer() + startTask() } .onDisappear { - stopTimer() + stopTask() } .appSheet(isPresented: $showServersSummary) { ServersSummaryView() @@ -354,25 +354,28 @@ struct SubsStatusIndicator: View { } } - private func startTimer() { - timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in - if AppChatState.shared.value == .active { - getSubsTotal() + private func startTask() { + task = Task { + while !Task.isCancelled { + if AppChatState.shared.value == .active { + do { + let (subs, hasSess) = try await getAgentSubsTotal() + await MainActor.run { + self.subs = subs + self.hasSess = hasSess + } + } catch let error { + logger.error("getSubsTotal error: \(responseError(error))") + } + } + try? await Task.sleep(nanoseconds: 1_000_000_000) // Sleep for 1 second } } } - func stopTimer() { - timer?.invalidate() - timer = nil - } - - private func getSubsTotal() { - do { - (subs, hasSess) = try getAgentSubsTotal() - } catch let error { - logger.error("getSubsTotal error: \(responseError(error))") - } + func stopTask() { + task?.cancel() + task = nil } } From 3b98032371eef3ae1bf9bc1fad50a67dae0c2c87 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Sat, 17 Aug 2024 17:52:35 +0300 Subject: [PATCH 08/21] ios: filter agent subscriptions from chat console (#4708) --- apps/ios/Shared/Model/SimpleXAPI.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index ed2c8e23d6..00ac88b071 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -112,9 +112,9 @@ func chatSendCmdSync(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = return resp } -func chatSendCmd(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil, _ ctrl: chat_ctrl? = nil) async -> ChatResponse { +func chatSendCmd(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil, _ ctrl: chat_ctrl? = nil, log: Bool = true) async -> ChatResponse { await withCheckedContinuation { cont in - cont.resume(returning: chatSendCmdSync(cmd, bgTask: bgTask, bgDelay: bgDelay, ctrl)) + cont.resume(returning: chatSendCmdSync(cmd, bgTask: bgTask, bgDelay: bgDelay, ctrl, log: log)) } } @@ -1422,7 +1422,7 @@ func apiGetVersion() throws -> CoreVersionInfo { func getAgentSubsTotal() async throws -> (SMPServerSubs, Bool) { let userId = try currentUserId("getAgentSubsTotal") - let r = await chatSendCmd(.getAgentSubsTotal(userId: userId)) + let r = await chatSendCmd(.getAgentSubsTotal(userId: userId), log: false) if case let .agentSubsTotal(_, subsTotal, hasSession) = r { return (subsTotal, hasSession) } logger.error("getAgentSubsTotal error: \(String(describing: r))") throw r From 75a468434c43370101e9c66166456d5d165d4cce Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sun, 18 Aug 2024 23:00:34 +0100 Subject: [PATCH 09/21] core: only start message delivery workers when there are pending messages (#4713) * core: use threads instead of async (reduce memory) * simplexmq * core: only start message delivery workers when there are pending messages (#4714) * core: only start message delivery workers when there are pending messages * update tls * simplexmq * update ios, simplexmq * simplexmq --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 40 +++++++++++----------- cabal.project | 2 +- package.yaml | 2 +- scripts/nix/sha256map.nix | 2 +- simplex-chat.cabal | 14 ++++---- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 46cf768a9f..5d525004b9 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -214,15 +214,15 @@ D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; }; D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; }; E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; }; + E58C91472C72458500EADB92 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E58C91422C72458500EADB92 /* libffi.a */; }; + E58C91482C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E58C91432C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo-ghc9.6.3.a */; }; + E58C91492C72458500EADB92 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E58C91442C72458500EADB92 /* libgmpxx.a */; }; + E58C914A2C72458500EADB92 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E58C91452C72458500EADB92 /* libgmp.a */; }; + E58C914B2C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E58C91462C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo.a */; }; E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; }; E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; }; E5DCF9842C5902CE007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9822C5902CE007928CC /* Localizable.strings */; }; E5DCF9982C5906FF007928CC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9962C5906FF007928CC /* InfoPlist.strings */; }; - E5E218532C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E2184E2C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q-ghc9.6.3.a */; }; - E5E218542C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E2184F2C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q.a */; }; - E5E218552C6D4C0F0013B4C6 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E218502C6D4C0F0013B4C6 /* libgmp.a */; }; - E5E218562C6D4C0F0013B4C6 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E218512C6D4C0F0013B4C6 /* libffi.a */; }; - E5E218572C6D4C0F0013B4C6 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E218522C6D4C0F0013B4C6 /* libgmpxx.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -550,6 +550,11 @@ D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; }; D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = ""; }; + E58C91422C72458500EADB92 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + E58C91432C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo-ghc9.6.3.a"; sourceTree = ""; }; + E58C91442C72458500EADB92 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + E58C91452C72458500EADB92 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + E58C91462C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo.a"; sourceTree = ""; }; E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9732C590275007928CC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; @@ -602,11 +607,6 @@ E5DCF9A62C590731007928CC /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/InfoPlist.strings; sourceTree = ""; }; E5DCF9A72C590732007928CC /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; E5DCF9A82C590732007928CC /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = ""; }; - E5E2184E2C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q-ghc9.6.3.a"; sourceTree = ""; }; - E5E2184F2C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q.a"; sourceTree = ""; }; - E5E218502C6D4C0F0013B4C6 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - E5E218512C6D4C0F0013B4C6 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - E5E218522C6D4C0F0013B4C6 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -645,14 +645,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E58C91492C72458500EADB92 /* libgmpxx.a in Frameworks */, + E58C914B2C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo.a in Frameworks */, + E58C914A2C72458500EADB92 /* libgmp.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - E5E218542C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, + E58C91482C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo-ghc9.6.3.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, - E5E218572C6D4C0F0013B4C6 /* libgmpxx.a in Frameworks */, - E5E218562C6D4C0F0013B4C6 /* libffi.a in Frameworks */, - E5E218552C6D4C0F0013B4C6 /* libgmp.a in Frameworks */, - E5E218532C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q-ghc9.6.3.a in Frameworks */, + E58C91472C72458500EADB92 /* libffi.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -729,11 +729,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - E5E218512C6D4C0F0013B4C6 /* libffi.a */, - E5E218502C6D4C0F0013B4C6 /* libgmp.a */, - E5E218522C6D4C0F0013B4C6 /* libgmpxx.a */, - E5E2184E2C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q-ghc9.6.3.a */, - E5E2184F2C6D4C0F0013B4C6 /* libHSsimplex-chat-6.0.0.8-9fvDFLivFrv8AINTqPH03q.a */, + E58C91422C72458500EADB92 /* libffi.a */, + E58C91452C72458500EADB92 /* libgmp.a */, + E58C91442C72458500EADB92 /* libgmpxx.a */, + E58C91432C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo-ghc9.6.3.a */, + E58C91462C72458500EADB92 /* libHSsimplex-chat-6.0.0.8-GILzHAOMg84gReBIsoPFo.a */, ); path = Libraries; sourceTree = ""; diff --git a/cabal.project b/cabal.project index 642831aeb8..05f5935554 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: f229e135e33ec5ee1f6d0978bd903d84b0b60efa + tag: 571d148bdf9e29403b9bcec6f7daeff815a4db38 source-repository-package type: git diff --git a/package.yaml b/package.yaml index 80994a6a59..2455d4284e 100644 --- a/package.yaml +++ b/package.yaml @@ -45,7 +45,7 @@ dependencies: - stm == 2.5.* - terminal == 0.2.* - time == 1.12.* - - tls >= 1.7.0 && < 1.8 + - tls >= 1.9.0 && < 1.10 - unliftio == 0.2.* - unliftio-core == 0.2.* - zip == 2.0.* diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 05253078f1..2802bfda6e 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."f229e135e33ec5ee1f6d0978bd903d84b0b60efa" = "0p4n4bghg24a98py9mij6s24fvsix4a73lwkg6skqf4rx8zp392v"; + "https://github.com/simplex-chat/simplexmq.git"."571d148bdf9e29403b9bcec6f7daeff815a4db38" = "1p7m7i4wdyvd2wypm04cx4w960vnyqa9wkfnlpv72cz83k0xirxf"; "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"; diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 4566048091..0f1564f618 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -226,7 +226,7 @@ library , stm ==2.5.* , terminal ==0.2.* , time ==1.12.* - , tls >=1.7.0 && <1.8 + , tls >=1.9.0 && <1.10 , unliftio ==0.2.* , unliftio-core ==0.2.* , zip ==2.0.* @@ -289,7 +289,7 @@ executable simplex-bot , stm ==2.5.* , terminal ==0.2.* , time ==1.12.* - , tls >=1.7.0 && <1.8 + , tls >=1.9.0 && <1.10 , unliftio ==0.2.* , unliftio-core ==0.2.* , zip ==2.0.* @@ -352,7 +352,7 @@ executable simplex-bot-advanced , stm ==2.5.* , terminal ==0.2.* , time ==1.12.* - , tls >=1.7.0 && <1.8 + , tls >=1.9.0 && <1.10 , unliftio ==0.2.* , unliftio-core ==0.2.* , zip ==2.0.* @@ -418,7 +418,7 @@ executable simplex-broadcast-bot , stm ==2.5.* , terminal ==0.2.* , time ==1.12.* - , tls >=1.7.0 && <1.8 + , tls >=1.9.0 && <1.10 , unliftio ==0.2.* , unliftio-core ==0.2.* , zip ==2.0.* @@ -482,7 +482,7 @@ executable simplex-chat , stm ==2.5.* , terminal ==0.2.* , time ==1.12.* - , tls >=1.7.0 && <1.8 + , tls >=1.9.0 && <1.10 , unliftio ==0.2.* , unliftio-core ==0.2.* , websockets ==0.12.* @@ -552,7 +552,7 @@ executable simplex-directory-service , stm ==2.5.* , terminal ==0.2.* , time ==1.12.* - , tls >=1.7.0 && <1.8 + , tls >=1.9.0 && <1.10 , unliftio ==0.2.* , unliftio-core ==0.2.* , zip ==2.0.* @@ -652,7 +652,7 @@ test-suite simplex-chat-test , stm ==2.5.* , terminal ==0.2.* , time ==1.12.* - , tls >=1.7.0 && <1.8 + , tls >=1.9.0 && <1.10 , unliftio ==0.2.* , unliftio-core ==0.2.* , zip ==2.0.* From 885aa9cfa55a7ba66ff9318f40022154b9206c0c Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:43:54 +0000 Subject: [PATCH 10/21] android, desktop: scrolling moves title to app bar (#4703) * android, desktop: scrolling moves title to app bar * one place should be without padding * scroll related changes for both platforms * adapt code to universal ColumnWithScrollBar * show in center * small adjustments * new chat sheet fix * divider + mix background color for desktop * coerce * different transition * desktop title starts from left * host starts from left too * different coefficient * settings title --- .../common/platform/Resources.android.kt | 3 + .../platform/ScrollableColumn.android.kt | 62 ++++++- .../kotlin/chat/simplex/common/App.kt | 2 + .../chat/simplex/common/platform/Platform.kt | 3 - .../chat/simplex/common/platform/Resources.kt | 3 + .../common/platform/ScrollableColumn.kt | 6 +- .../chat/simplex/common/views/TerminalView.kt | 8 +- .../common/views/chat/ChatItemInfoView.kt | 4 - .../simplex/common/views/chat/ChatView.kt | 38 ++-- .../views/chat/group/GroupChatInfoView.kt | 1 - .../common/views/chatlist/ChatListView.kt | 9 +- .../views/chatlist/ServersSummaryView.kt | 32 ++-- .../views/database/DatabaseEncryptionView.kt | 165 +++++++++--------- .../common/views/helpers/CloseSheetBar.kt | 86 +++++++-- .../common/views/helpers/CollapsingAppBar.kt | 44 +++++ .../simplex/common/views/helpers/ModalView.kt | 23 ++- .../views/migration/MigrateFromDevice.kt | 14 +- .../common/views/migration/MigrateToDevice.kt | 11 +- .../common/views/newchat/NewChatSheet.kt | 14 +- .../common/views/newchat/NewChatView.kt | 118 ++++++------- .../common/views/onboarding/HowItWorks.kt | 7 +- .../usersettings/SetDeliveryReceiptsView.kt | 39 ++--- .../common/views/usersettings/SettingsView.kt | 134 +++++++------- .../usersettings/UserAddressLearnMore.kt | 9 +- .../views/usersettings/UserAddressView.kt | 2 +- .../common/platform/Resources.desktop.kt | 3 + .../platform/ScrollableColumn.desktop.kt | 129 +++++++++----- .../kotlin/chat/simplex/desktop/Main.kt | 32 ---- 28 files changed, 583 insertions(+), 418 deletions(-) create mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Resources.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Resources.android.kt index 91d19759ea..73c920b940 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Resources.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Resources.android.kt @@ -52,6 +52,9 @@ actual fun windowOrientation(): WindowOrientation = when (mainActivity.get()?.re @Composable actual fun windowWidth(): Dp = LocalConfiguration.current.screenWidthDp.dp +@Composable +actual fun windowHeight(): Dp = LocalConfiguration.current.screenHeightDp.dp + actual fun desktopExpandWindowToWidth(width: Dp) {} actual fun isRtl(text: CharSequence): Boolean = BidiFormatter.getInstance().isRtl(text) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt index 199e719703..6851970b81 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt @@ -4,14 +4,21 @@ 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.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import chat.simplex.common.views.helpers.* +import kotlinx.coroutines.flow.filter +import kotlin.math.absoluteValue @Composable actual fun LazyColumnWithScrollBar( modifier: Modifier, - state: LazyListState, + state: LazyListState?, contentPadding: PaddingValues, reverseLayout: Boolean, verticalArrangement: Arrangement.Vertical, @@ -20,7 +27,24 @@ actual fun LazyColumnWithScrollBar( userScrollEnabled: Boolean, content: LazyListScope.() -> Unit ) { - LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) + val state = state ?: LocalAppBarHandler.current?.listState ?: rememberLazyListState() + val connection = LocalAppBarHandler.current?.connection + LaunchedEffect(Unit) { + snapshotFlow { state.firstVisibleItemScrollOffset } + .filter { state.firstVisibleItemIndex == 0 } + .collect { scrollPosition -> + val offset = connection?.appBarOffset + if (offset != null && (offset + scrollPosition).absoluteValue > 1) { + connection.appBarOffset = -scrollPosition.toFloat() +// Log.d(TAG, "Scrolling position changed from $offset to ${connection.appBarOffset}") + } + } + } + if (connection != null) { + LazyColumn(modifier.nestedScroll(connection), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) + } else { + LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) + } } @Composable @@ -28,8 +52,34 @@ actual fun ColumnWithScrollBar( modifier: Modifier, verticalArrangement: Arrangement.Vertical, horizontalAlignment: Alignment.Horizontal, - state: ScrollState, - content: @Composable ColumnScope.() -> Unit + state: ScrollState?, + maxIntrinsicSize: Boolean, + content: @Composable() (ColumnScope.() -> Unit) ) { - Column(modifier.verticalScroll(rememberScrollState()), verticalArrangement, horizontalAlignment, content) + val state = state ?: LocalAppBarHandler.current?.scrollState ?: rememberScrollState() + val connection = LocalAppBarHandler.current?.connection + LaunchedEffect(Unit) { + snapshotFlow { state.value } + .collect { scrollPosition -> + val offset = connection?.appBarOffset + if (offset != null && (offset + scrollPosition).absoluteValue > 1) { + connection.appBarOffset = -scrollPosition.toFloat() +// Log.d(TAG, "Scrolling position changed from $offset to ${connection.appBarOffset}") + } + } + } + if (connection != null) { + Column( + if (maxIntrinsicSize) { + modifier.nestedScroll(connection).verticalScroll(state).height(IntrinsicSize.Max) + } else { + modifier.nestedScroll(connection).verticalScroll(state) + }, verticalArrangement, horizontalAlignment, content) + } else { + Column(if (maxIntrinsicSize) { + modifier.verticalScroll(state).height(IntrinsicSize.Max) + } else { + modifier.verticalScroll(state) + }, verticalArrangement, horizontalAlignment, content) + } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index 1486fa8314..94ca307529 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import chat.simplex.common.views.usersettings.SetDeliveryReceiptsView import chat.simplex.common.model.* @@ -50,6 +51,7 @@ data class SettingsViewState( @Composable fun AppScreen() { + AppBarHandler.appBarMaxHeightPx = with(LocalDensity.current) { AppBarHeight.roundToPx() } SimpleXTheme { ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { Surface(color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt index b48f7cebec..44fcddb54c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt @@ -28,9 +28,6 @@ interface PlatformInterface { fun androidRestartNetworkObserver() {} @Composable fun androidLockPortraitOrientation() {} suspend fun androidAskToAllowBackgroundCalls(): Boolean = true - @Composable fun desktopScrollBarComponents(): Triple, Modifier, MutableState> = remember { Triple(Animatable(0f), Modifier, mutableStateOf(Job())) } - @Composable fun desktopScrollBar(state: LazyListState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) {} - @Composable fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) {} @Composable fun desktopShowAppUpdateNotice() {} } /** diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Resources.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Resources.kt index 8e45ded4f0..fd712624bd 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Resources.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Resources.kt @@ -30,6 +30,9 @@ expect fun windowOrientation(): WindowOrientation @Composable expect fun windowWidth(): Dp +@Composable +expect fun windowHeight(): Dp + expect fun desktopExpandWindowToWidth(width: Dp) expect fun isRtl(text: CharSequence): Boolean diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt index d4fa2fe125..532bfddfcf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.unit.dp @Composable expect fun LazyColumnWithScrollBar( modifier: Modifier = Modifier, - state: LazyListState = rememberLazyListState(), + state: LazyListState? = null, contentPadding: PaddingValues = PaddingValues(0.dp), reverseLayout: Boolean = false, verticalArrangement: Arrangement.Vertical = @@ -29,6 +29,8 @@ expect fun ColumnWithScrollBar( modifier: Modifier = Modifier, verticalArrangement: Arrangement.Vertical = Arrangement.Top, horizontalAlignment: Alignment.Horizontal = Alignment.Start, - state: ScrollState = rememberScrollState(), + state: ScrollState? = null, + // set true when you want to show something in the center with respected .fillMaxSize() + maxIntrinsicSize: Boolean = false, content: @Composable ColumnScope.() -> Unit ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt index 259b7e2320..1afbb0bdcb 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt @@ -125,19 +125,13 @@ fun TerminalLayout( } } -private var lazyListState = 0 to 0 - @Composable fun TerminalLog() { - val listState = rememberLazyListState(lazyListState.first, lazyListState.second) - DisposableEffect(Unit) { - onDispose { lazyListState = listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset } - } val reversedTerminalItems by remember { derivedStateOf { chatModel.terminalItems.value.asReversed() } } val clipboard = LocalClipboardManager.current - LazyColumnWithScrollBar(state = listState, reverseLayout = true) { + LazyColumnWithScrollBar(reverseLayout = true) { items(reversedTerminalItems) { item -> val rhId = item.remoteHostId val rhIdStr = if (rhId == null) "" else "$rhId " diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt index c7df983324..a5593693c0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt @@ -277,7 +277,6 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools @Composable fun HistoryTab() { - // LALAL SCROLLBAR DOESN'T WORK ColumnWithScrollBar(Modifier.fillMaxWidth()) { Details() SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true) @@ -302,7 +301,6 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools @Composable fun QuoteTab(qi: CIQuote) { - // LALAL SCROLLBAR DOESN'T WORK ColumnWithScrollBar(Modifier.fillMaxWidth()) { Details() SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true) @@ -316,7 +314,6 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools @Composable fun ForwardedFromTab(forwardedFromItem: AChatItem) { - // LALAL SCROLLBAR DOESN'T WORK ColumnWithScrollBar(Modifier.fillMaxWidth()) { Details() SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true) @@ -379,7 +376,6 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools @Composable fun DeliveryTab(memberDeliveryStatuses: List) { - // LALAL SCROLLBAR DOESN'T WORK ColumnWithScrollBar(Modifier.fillMaxWidth()) { Details() SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index a5541a315b..e90eed547d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -504,24 +504,34 @@ fun ChatView(staleChatId: State, onComposed: suspend (chatId: String) - } is ChatInfo.ContactConnection -> { val close = { chatModel.chatId.value = null } - ModalView(close, showClose = appPlatform.isAndroid, content = { - ContactConnectionInfoView(chatModel, chatRh, chatInfo.contactConnection.connReqInv, chatInfo.contactConnection, false, close) - }) - LaunchedEffect(chatInfo.id) { - onComposed(chatInfo.id) - ModalManager.end.closeModals() - chatModel.chatItems.clear() + val handler = remember { AppBarHandler() } + CompositionLocalProvider( + LocalAppBarHandler provides handler + ) { + ModalView(close, showClose = appPlatform.isAndroid, content = { + ContactConnectionInfoView(chatModel, chatRh, chatInfo.contactConnection.connReqInv, chatInfo.contactConnection, false, close) + }) + LaunchedEffect(chatInfo.id) { + onComposed(chatInfo.id) + ModalManager.end.closeModals() + chatModel.chatItems.clear() + } } } is ChatInfo.InvalidJSON -> { val close = { chatModel.chatId.value = null } - ModalView(close, showClose = appPlatform.isAndroid, endButtons = { ShareButton { clipboard.shareText(chatInfo.json) } }, content = { - InvalidJSONView(chatInfo.json) - }) - LaunchedEffect(chatInfo.id) { - onComposed(chatInfo.id) - ModalManager.end.closeModals() - chatModel.chatItems.clear() + val handler = remember { AppBarHandler() } + CompositionLocalProvider( + LocalAppBarHandler provides handler + ) { + ModalView(close, showClose = appPlatform.isAndroid, endButtons = { ShareButton { clipboard.shareText(chatInfo.json) } }, content = { + InvalidJSONView(chatInfo.json) + }) + LaunchedEffect(chatInfo.id) { + onComposed(chatInfo.id) + ModalManager.end.closeModals() + chatModel.chatItems.clear() + } } } else -> {} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt index 6e39e8756e..ea07231eb0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt @@ -284,7 +284,6 @@ fun GroupChatInfoLayout( if (s.isEmpty()) members else members.filter { m -> m.anyNameContains(s) } } } - // LALAL strange scrolling LazyColumnWithScrollBar( Modifier .fillMaxWidth(), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index b1c353d420..6f595e2ccf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -185,7 +185,14 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf scaffoldState = scaffoldState, drawerContent = { tryOrShowError("Settings", error = { ErrorSettingsView() }) { - SettingsView(chatModel, setPerformLA, scaffoldState.drawerState) + val handler = remember { AppBarHandler() } + CompositionLocalProvider( + LocalAppBarHandler provides handler + ) { + ModalView(showClose = appPlatform.isDesktop, close = { scope.launch { scaffoldState.drawerState.close() } }) { + SettingsView(chatModel, setPerformLA, scaffoldState.drawerState) + } + } } }, contentColor = LocalContentColor.current, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt index 334335a80f..f5343efc18 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt @@ -615,14 +615,12 @@ fun ModalData.SMPServerSummaryView( ColumnWithScrollBar( Modifier.fillMaxSize(), ) { - Box(contentAlignment = Alignment.Center) { - val bottomPadding = DEFAULT_PADDING - AppBarTitle( - stringResource(MR.strings.smp_server), - hostDevice(rh?.remoteHostId), - bottomPadding = bottomPadding - ) - } + val bottomPadding = DEFAULT_PADDING + AppBarTitle( + stringResource(MR.strings.smp_server), + hostDevice(rh?.remoteHostId), + bottomPadding = bottomPadding + ) SMPServerSummaryLayout(summary, statsStartedAt, rh) } } @@ -709,7 +707,7 @@ fun ModalData.XFTPServerSummaryView( @Composable fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableState) { - Column( + ColumnWithScrollBar( Modifier.fillMaxSize(), ) { var showUserSelection by remember { mutableStateOf(false) } @@ -760,14 +758,12 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta Column( Modifier.fillMaxSize(), ) { - Box(contentAlignment = Alignment.Center) { - val bottomPadding = DEFAULT_PADDING - AppBarTitle( - stringResource(MR.strings.servers_info), - hostDevice(rh?.remoteHostId), - bottomPadding = bottomPadding - ) - } + val bottomPadding = DEFAULT_PADDING + AppBarTitle( + stringResource(MR.strings.servers_info), + hostDevice(rh?.remoteHostId), + bottomPadding = bottomPadding + ) if (serversSummary.value == null) { Box( modifier = Modifier @@ -827,7 +823,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta verticalAlignment = Alignment.Top, userScrollEnabled = appPlatform.isAndroid ) { index -> - ColumnWithScrollBar( + Column( Modifier .fillMaxSize(), verticalArrangement = Arrangement.Top diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt index a2aeac21a2..b73a0ca0bc 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt @@ -107,101 +107,104 @@ fun DatabaseEncryptionLayout( migration: Boolean, onConfirmEncrypt: () -> Unit, ) { - val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() - val scrollState = rememberScrollState() - Column( - if (!migration) Modifier.fillMaxWidth().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier) else Modifier.fillMaxWidth(), - ) { - if (!migration) { - AppBarTitle(stringResource(MR.strings.database_passphrase)) - } else { - ChatStoppedView() - SectionSpacer() - } - SectionView(if (migration) generalGetString(MR.strings.database_passphrase).uppercase() else null) { - SavePassphraseSetting( - useKeychain.value, - initialRandomDBPassphrase.value, - storedKey.value, - enabled = (!initialRandomDBPassphrase.value && !progressIndicator.value) || migration - ) { checked -> - if (checked) { - setUseKeychain(true, useKeychain, migration) - } else if (storedKey.value && !migration) { - // Don't show in migration process since it will remove the key after successful encryption - removePassphraseAlert { - removePassphraseFromKeyChain(useKeychain, storedKey, false) - } - } else { - setUseKeychain(false, useKeychain, migration) - } + @Composable + fun Layout() { + Column { + if (!migration) { + AppBarTitle(stringResource(MR.strings.database_passphrase)) + } else { + ChatStoppedView() + SectionSpacer() } + SectionView(if (migration) generalGetString(MR.strings.database_passphrase).uppercase() else null) { + SavePassphraseSetting( + useKeychain.value, + initialRandomDBPassphrase.value, + storedKey.value, + enabled = (!initialRandomDBPassphrase.value && !progressIndicator.value) || migration + ) { checked -> + if (checked) { + setUseKeychain(true, useKeychain, migration) + } else if (storedKey.value && !migration) { + // Don't show in migration process since it will remove the key after successful encryption + removePassphraseAlert { + removePassphraseFromKeyChain(useKeychain, storedKey, false) + } + } else { + setUseKeychain(false, useKeychain, migration) + } + } + + if (!initialRandomDBPassphrase.value && chatDbEncrypted == true) { + PassphraseField( + currentKey, + generalGetString(MR.strings.current_passphrase), + modifier = Modifier.padding(horizontal = DEFAULT_PADDING), + isValid = ::validKey, + keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), + ) + } - if (!initialRandomDBPassphrase.value && chatDbEncrypted == true) { PassphraseField( - currentKey, - generalGetString(MR.strings.current_passphrase), + newKey, + generalGetString(MR.strings.new_passphrase), modifier = Modifier.padding(horizontal = DEFAULT_PADDING), + showStrength = true, isValid = ::validKey, keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), ) - } - - PassphraseField( - newKey, - generalGetString(MR.strings.new_passphrase), - modifier = Modifier.padding(horizontal = DEFAULT_PADDING), - showStrength = true, - isValid = ::validKey, - keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), - ) - val onClickUpdate = { - // Don't do things concurrently. Shouldn't be here concurrently, just in case - if (!progressIndicator.value) { - if (currentKey.value == "") { - if (useKeychain.value) - encryptDatabaseSavedAlert(onConfirmEncrypt) - else - encryptDatabaseAlert(onConfirmEncrypt) - } else { - if (useKeychain.value) - changeDatabaseKeySavedAlert(onConfirmEncrypt) - else - changeDatabaseKeyAlert(onConfirmEncrypt) + val onClickUpdate = { + // Don't do things concurrently. Shouldn't be here concurrently, just in case + if (!progressIndicator.value) { + if (currentKey.value == "") { + if (useKeychain.value) + encryptDatabaseSavedAlert(onConfirmEncrypt) + else + encryptDatabaseAlert(onConfirmEncrypt) + } else { + if (useKeychain.value) + changeDatabaseKeySavedAlert(onConfirmEncrypt) + else + changeDatabaseKeyAlert(onConfirmEncrypt) + } } } + val disabled = currentKey.value == newKey.value || + newKey.value != confirmNewKey.value || + newKey.value.isEmpty() || + !validKey(currentKey.value) || + !validKey(newKey.value) || + progressIndicator.value + + PassphraseField( + confirmNewKey, + generalGetString(MR.strings.confirm_new_passphrase), + modifier = Modifier.padding(horizontal = DEFAULT_PADDING), + isValid = { confirmNewKey.value == "" || newKey.value == confirmNewKey.value }, + keyboardActions = KeyboardActions(onDone = { + if (!disabled) onClickUpdate() + defaultKeyboardAction(ImeAction.Done) + }), + ) + + SectionItemViewSpaceBetween(onClickUpdate, disabled = disabled, minHeight = TextFieldDefaults.MinHeight) { + Text(generalGetString(if (migration) MR.strings.set_passphrase else MR.strings.update_database_passphrase), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + } } - val disabled = currentKey.value == newKey.value || - newKey.value != confirmNewKey.value || - newKey.value.isEmpty() || - !validKey(currentKey.value) || - !validKey(newKey.value) || - progressIndicator.value - PassphraseField( - confirmNewKey, - generalGetString(MR.strings.confirm_new_passphrase), - modifier = Modifier.padding(horizontal = DEFAULT_PADDING), - isValid = { confirmNewKey.value == "" || newKey.value == confirmNewKey.value }, - keyboardActions = KeyboardActions(onDone = { - if (!disabled) onClickUpdate() - defaultKeyboardAction(ImeAction.Done) - }), - ) - - SectionItemViewSpaceBetween(onClickUpdate, disabled = disabled, minHeight = TextFieldDefaults.MinHeight) { - Text(generalGetString(if (migration) MR.strings.set_passphrase else MR.strings.update_database_passphrase), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Column { + DatabaseEncryptionFooter(useKeychain, chatDbEncrypted, storedKey, initialRandomDBPassphrase, migration) } + SectionBottomSpacer() } - - Column { - DatabaseEncryptionFooter(useKeychain, chatDbEncrypted, storedKey, initialRandomDBPassphrase, migration) - } - SectionBottomSpacer() } - if (appPlatform.isDesktop && !migration) { - Box(Modifier.fillMaxSize()) { - platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false) + if (migration) { + Column(Modifier.fillMaxWidth()) { + Layout() + } + } else { + ColumnWithScrollBar(Modifier.fillMaxWidth(), maxIntrinsicSize = true) { + Layout() } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt index 0ff68de3a0..080edd22b2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CloseSheetBar.kt @@ -6,59 +6,90 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.background +import androidx.compose.ui.draw.* +import androidx.compose.ui.graphics.* import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.* +import chat.simplex.common.platform.appPlatform import chat.simplex.common.ui.theme.* import chat.simplex.res.MR import dev.icerock.moko.resources.compose.painterResource +import kotlin.math.absoluteValue @Composable fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Color = if (close != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, arrangement: Arrangement.Vertical = Arrangement.Top, closeBarTitle: String? = null, barPaddingValues: PaddingValues = PaddingValues(horizontal = AppBarHorizontalPadding), endButtons: @Composable RowScope.() -> Unit = {}) { var rowModifier = Modifier .fillMaxWidth() .height(AppBarHeight * fontSizeSqrtMultiplier) - + val themeBackgroundMix = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f) if (!closeBarTitle.isNullOrEmpty()) { - rowModifier = rowModifier.background(MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f)) + rowModifier = rowModifier.background(themeBackgroundMix) } + val handler = LocalAppBarHandler.current + val connection = LocalAppBarHandler.current?.connection + val title = remember(handler?.title?.value) { handler?.title ?: mutableStateOf("") } Column( verticalArrangement = arrangement, modifier = Modifier .fillMaxWidth() .heightIn(min = AppBarHeight * fontSizeSqrtMultiplier) + .drawWithCache { + val backgroundColor = if (appPlatform.isDesktop && connection != null) themeBackgroundMix.copy(alpha = topTitleAlpha(connection)) else Color.Transparent + onDrawBehind { + if (appPlatform.isDesktop) { + drawRect(backgroundColor) + } + } + } ) { Row( modifier = Modifier.padding(barPaddingValues), content = { Row( rowModifier, - horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - if (showClose) { + if (showClose) { NavigationButtonBack(tintColor = tintColor, onButtonClicked = close) } else { Spacer(Modifier) } if (!closeBarTitle.isNullOrEmpty()) { Row( + Modifier.weight(1f), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( closeBarTitle, - color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.SemiBold, + maxLines = 1 ) } + } else if (title.value.isNotEmpty() && connection != null) { + Row( + Modifier + .padding(start = if (showClose) 0.dp else DEFAULT_PADDING_HALF) + .weight(1f) // hides the title if something wants full width (eg, search field in chat profiles screen) + .graphicsLayer { + alpha = topTitleAlpha((connection)) + } + .padding(start = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + title.value, + fontWeight = FontWeight.SemiBold, + maxLines = 1 + ) + } + } else { + Spacer(Modifier.weight(1f)) } Row { endButtons() @@ -66,11 +97,24 @@ fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Co } } ) + if (closeBarTitle.isNullOrEmpty() && title.value.isNotEmpty() && connection != null) { + Divider( + Modifier + .graphicsLayer { + alpha = topTitleAlpha(connection) + } + ) + } } } @Composable fun AppBarTitle(title: String, hostDevice: Pair? = null, withPadding: Boolean = true, bottomPadding: Dp = DEFAULT_PADDING * 1.5f + 8.dp) { + val handler = LocalAppBarHandler.current + val connection = handler?.connection + LaunchedEffect(title) { + handler?.title?.value = title + } val theme = CurrentColors.collectAsState() val titleColor = MaterialTheme.appColors.title val brush = if (theme.value.base == DefaultTheme.SIMPLEX) @@ -81,23 +125,37 @@ fun AppBarTitle(title: String, hostDevice: Pair? = null, withPad Text( title, Modifier - .fillMaxWidth() - .padding(start = if (withPadding) DEFAULT_PADDING else 0.dp, end = if (withPadding) DEFAULT_PADDING else 0.dp,), + .padding(start = if (withPadding) DEFAULT_PADDING else 0.dp, top = DEFAULT_PADDING_HALF, end = if (withPadding) DEFAULT_PADDING else 0.dp,) + .graphicsLayer { + alpha = bottomTitleAlpha(connection) + }, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.h1.copy(brush = brush), color = MaterialTheme.colors.primaryVariant, - textAlign = TextAlign.Center + textAlign = TextAlign.Start ) if (hostDevice != null) { - HostDeviceTitle(hostDevice) + Box(Modifier.padding(start = if (withPadding) DEFAULT_PADDING else 0.dp, end = if (withPadding) DEFAULT_PADDING else 0.dp).graphicsLayer { + alpha = bottomTitleAlpha(connection) + }) { + HostDeviceTitle(hostDevice) + } } Spacer(Modifier.height(bottomPadding)) } } +private fun topTitleAlpha(connection: CollapsingAppBarNestedScrollConnection) = + if (connection.appBarOffset.absoluteValue < AppBarHandler.appBarMaxHeightPx / 3) 0f + else ((-connection.appBarOffset * 1.5f) / (AppBarHandler.appBarMaxHeightPx)).coerceIn(0f, 1f) + +private fun bottomTitleAlpha(connection: CollapsingAppBarNestedScrollConnection?) = + if ((connection?.appBarOffset ?: 0f).absoluteValue < AppBarHandler.appBarMaxHeightPx / 3) 1f + else ((AppBarHandler.appBarMaxHeightPx) + (connection?.appBarOffset ?: 0f) / 1.5f).coerceAtLeast(0f) / AppBarHandler.appBarMaxHeightPx + @Composable private fun HostDeviceTitle(hostDevice: Pair, extraPadding: Boolean = false) { - Row(Modifier.fillMaxWidth().padding(top = 5.dp, bottom = if (extraPadding) DEFAULT_PADDING * 2 else DEFAULT_PADDING_HALF), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) { + Row(Modifier.fillMaxWidth().padding(top = 5.dp, bottom = if (extraPadding) DEFAULT_PADDING * 2 else DEFAULT_PADDING_HALF), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Start) { Icon(painterResource(if (hostDevice.first == null) MR.images.ic_desktop else MR.images.ic_smartphone_300), null, Modifier.size(15.dp), tint = MaterialTheme.colors.secondary) Spacer(Modifier.width(10.dp)) Text(hostDevice.second, color = MaterialTheme.colors.secondary) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt new file mode 100644 index 0000000000..4410f7ada5 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt @@ -0,0 +1,44 @@ +package chat.simplex.common.views.helpers + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.* +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.unit.Velocity + +val LocalAppBarHandler: ProvidableCompositionLocal = staticCompositionLocalOf { null } + +@Stable +class AppBarHandler( + listState: LazyListState = LazyListState(0, 0), + scrollState: ScrollState = ScrollState(initial = 0) +) { + val title = mutableStateOf("") + var listState by mutableStateOf(listState, structuralEqualityPolicy()) + internal set + + var scrollState by mutableStateOf(scrollState, structuralEqualityPolicy()) + internal set + + val connection = CollapsingAppBarNestedScrollConnection() + + companion object { + var appBarMaxHeightPx: Int = 0 + } +} + +class CollapsingAppBarNestedScrollConnection(): NestedScrollConnection { + var appBarOffset: Float by mutableFloatStateOf(0f) + + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + appBarOffset += available.y + return Offset(0f, 0f) + } + + override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset { + appBarOffset -= available.y + return Offset(x = 0f, 0f) + } +} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt index d44476b91b..bfd61a2add 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt @@ -2,11 +2,12 @@ package chat.simplex.common.views.helpers import androidx.compose.animation.* import androidx.compose.animation.core.* +import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.material.* import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import chat.simplex.common.model.ChatController.appPrefs @@ -48,13 +49,15 @@ enum class ModalPlacement { START, CENTER, END, FULLSCREEN } -class ModalData { +class ModalData() { private val state = mutableMapOf>() fun stateGetOrPut (key: String, default: () -> T): MutableState = state.getOrPut(key) { mutableStateOf(default() as Any) } as MutableState fun stateGetOrPutNullable (key: String, default: () -> T?): MutableState = state.getOrPut(key) { mutableStateOf(default() as Any?) } as MutableState + + val appBarHandler = AppBarHandler() } class ModalManager(private val placement: ModalPlacement? = null) { @@ -139,7 +142,13 @@ class ModalManager(private val placement: ModalPlacement? = null) { fun showInView() { // Without animation if (modalCount.value > 0 && modalViews.lastOrNull()?.first == false) { - modalViews.lastOrNull()?.let { it.third(it.second, ::closeModal) } + modalViews.lastOrNull()?.let { + CompositionLocalProvider( + LocalAppBarHandler provides it.second.appBarHandler + ) { + it.third(it.second, ::closeModal) + } + } return } AnimatedContent(targetState = modalCount.value, @@ -151,7 +160,13 @@ class ModalManager(private val placement: ModalPlacement? = null) { }.using(SizeTransform(clip = false)) } ) { - modalViews.getOrNull(it - 1)?.let { it.third(it.second, ::closeModal) } + modalViews.getOrNull(it - 1)?.let { + CompositionLocalProvider( + LocalAppBarHandler provides it.second.appBarHandler + ) { + it.third(it.second, ::closeModal) + } + } // This is needed because if we delete from modalViews immediately on request, animation will be bad if (toRemove.isNotEmpty() && it == modalCount.value && transition.currentState == EnterExitState.Visible && !transition.isRunning) { runAtomically { toRemove.removeIf { elem -> modalViews.removeAt(elem); true } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt index 152befb82d..dbb805971e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt @@ -4,7 +4,7 @@ import SectionBottomSpacer import SectionSpacer import SectionTextFooter import SectionView -import androidx.compose.foundation.* +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* @@ -17,7 +17,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.* -import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatController.getNetCfg import chat.simplex.common.model.ChatController.startChat import chat.simplex.common.model.ChatController.startChatWithTemporaryDatabase @@ -147,20 +146,13 @@ private fun MigrateFromDeviceLayout( ) { val tempDatabaseFile = rememberSaveable { mutableStateOf(fileForTemporaryDatabase()) } - val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() - val scrollState = rememberScrollState() - Column( - Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).height(IntrinsicSize.Max), + ColumnWithScrollBar( + Modifier.fillMaxSize(), maxIntrinsicSize = true ) { 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() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt index f8a82d010d..4fa36b06f0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt @@ -155,20 +155,13 @@ private fun ModalData.MigrateToDeviceLayout( close: () -> Unit, ) { val tempDatabaseFile = rememberSaveable { mutableStateOf(fileForTemporaryDatabase()) } - val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() - val scrollState = rememberScrollState() - Column( - Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).height(IntrinsicSize.Max), + ColumnWithScrollBar( + Modifier.fillMaxSize(), maxIntrinsicSize = true ) { 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() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 759c090bc7..3146c14589 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -68,10 +68,10 @@ fun NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) { Column(modifier = Modifier.fillMaxSize()) { NewChatSheetLayout( addContact = { - ModalManager.start.showModalCloseable { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll ) } + ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll ) } }, scanPaste = { - ModalManager.start.showModalCloseable { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll) } + ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll) } }, createGroup = { ModalManager.start.showCustomModal { close -> AddGroupView(chatModel, chatModel.currentRemoteHost.value, close, closeAll) } @@ -194,7 +194,15 @@ private fun NewChatSheetLayout( (appPlatform.isAndroid && keyboardState == KeyboardState.Opened) ) { 0 - } else if (listState.firstVisibleItemIndex == 0) offsetMultiplier * listState.firstVisibleItemScrollOffset else offsetMultiplier * 1000 + } else if (oneHandUI.value && listState.firstVisibleItemIndex == 0) { + listState.firstVisibleItemScrollOffset + } else if (!oneHandUI.value && listState.firstVisibleItemIndex == 0) { + 0 + } else if (!oneHandUI.value && listState.firstVisibleItemIndex == 1) { + -listState.firstVisibleItemScrollOffset + } else { + offsetMultiplier * 1000 + } } else { 0 } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt index 007f474265..a872f2548d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt @@ -5,6 +5,7 @@ import SectionItemView import SectionTextFooter import SectionView import androidx.compose.foundation.* +import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.pager.HorizontalPager @@ -96,66 +97,61 @@ fun ModalData.NewChatView(rh: RemoteHostInfo?, selection: NewChatOption, showQRC } } - Column( - Modifier.fillMaxSize(), - ) { - Box(contentAlignment = Alignment.Center) { - val bottomPadding = DEFAULT_PADDING - AppBarTitle(stringResource(MR.strings.new_chat), hostDevice(rh?.remoteHostId), bottomPadding = bottomPadding) - Column(Modifier.align(Alignment.CenterEnd).padding(bottom = bottomPadding, end = DEFAULT_PADDING)) { - AddContactLearnMoreButton() + BoxWithConstraints { + ColumnWithScrollBar { + AppBarTitle(stringResource(MR.strings.new_chat), hostDevice(rh?.remoteHostId), bottomPadding = DEFAULT_PADDING) + val scope = rememberCoroutineScope() + val pagerState = rememberPagerState( + initialPage = selection.value.ordinal, + initialPageOffsetFraction = 0f + ) { NewChatOption.values().size } + KeyChangeEffect(pagerState.currentPage) { + selection.value = NewChatOption.values()[pagerState.currentPage] } - } - val scope = rememberCoroutineScope() - val pagerState = rememberPagerState( - initialPage = selection.value.ordinal, - initialPageOffsetFraction = 0f - ) { NewChatOption.values().size } - KeyChangeEffect(pagerState.currentPage) { - selection.value = NewChatOption.values()[pagerState.currentPage] - } - TabRow( - selectedTabIndex = pagerState.currentPage, - backgroundColor = Color.Transparent, - contentColor = MaterialTheme.colors.primary, - ) { - tabTitles.forEachIndexed { index, it -> - LeadingIconTab( - selected = pagerState.currentPage == index, - onClick = { - scope.launch { - pagerState.animateScrollToPage(index) - } - }, - text = { Text(it, fontSize = 13.sp) }, - icon = { - Icon( - if (NewChatOption.INVITE.ordinal == index) painterResource(MR.images.ic_repeat_one) else painterResource(MR.images.ic_qr_code), - it - ) - }, - selectedContentColor = MaterialTheme.colors.primary, - unselectedContentColor = MaterialTheme.colors.secondary, - ) - } - } - - HorizontalPager(state = pagerState, Modifier.fillMaxSize(), verticalAlignment = Alignment.Top, userScrollEnabled = appPlatform.isAndroid) { index -> - // LALAL SCROLLBAR DOESN'T WORK - ColumnWithScrollBar( - Modifier - .fillMaxSize(), - verticalArrangement = if (index == NewChatOption.INVITE.ordinal && connReqInvitation.isEmpty()) Arrangement.Center else Arrangement.Top) { - Spacer(Modifier.height(DEFAULT_PADDING)) - when (index) { - NewChatOption.INVITE.ordinal -> { - PrepareAndInviteView(rh?.remoteHostId, contactConnection, connReqInvitation, creatingConnReq) - } - NewChatOption.CONNECT.ordinal -> { - ConnectView(rh?.remoteHostId, showQRCodeScanner, pastedLink, close) - } + TabRow( + selectedTabIndex = pagerState.currentPage, + backgroundColor = Color.Transparent, + contentColor = MaterialTheme.colors.primary, + ) { + tabTitles.forEachIndexed { index, it -> + LeadingIconTab( + selected = pagerState.currentPage == index, + onClick = { + scope.launch { + pagerState.animateScrollToPage(index) + } + }, + text = { Text(it, fontSize = 13.sp) }, + icon = { + Icon( + if (NewChatOption.INVITE.ordinal == index) painterResource(MR.images.ic_repeat_one) else painterResource(MR.images.ic_qr_code), + it + ) + }, + selectedContentColor = MaterialTheme.colors.primary, + unselectedContentColor = MaterialTheme.colors.secondary, + ) + } + } + + HorizontalPager(state = pagerState, Modifier, pageNestedScrollConnection = LocalAppBarHandler.current!!.connection, verticalAlignment = Alignment.Top, userScrollEnabled = appPlatform.isAndroid) { index -> + Column( + Modifier + .fillMaxWidth() + .heightIn(min = this@BoxWithConstraints.maxHeight - 150.dp), + verticalArrangement = if (index == NewChatOption.INVITE.ordinal && connReqInvitation.isEmpty()) Arrangement.Center else Arrangement.Top + ) { + Spacer(Modifier.height(DEFAULT_PADDING)) + when (index) { + NewChatOption.INVITE.ordinal -> { + PrepareAndInviteView(rh?.remoteHostId, contactConnection, connReqInvitation, creatingConnReq) + } + NewChatOption.CONNECT.ordinal -> { + ConnectView(rh?.remoteHostId, showQRCodeScanner, pastedLink, close) + } + } + SectionBottomSpacer() } - SectionBottomSpacer() } } } @@ -228,18 +224,18 @@ private fun InviteView(rhId: Long?, connReqInvitation: String, contactConnection } @Composable -private fun AddContactLearnMoreButton() { +fun AddContactLearnMoreButton() { IconButton( { ModalManager.start.showModalCloseable { close -> AddContactLearnMore(close) } - }, - Modifier.size(18.dp * fontSizeSqrtMultiplier) + } ) { Icon( painterResource(MR.images.ic_info), stringResource(MR.strings.learn_more), + tint = MaterialTheme.colors.primary ) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt index 3f2c035335..9c7e2bdce7 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt @@ -23,9 +23,10 @@ import dev.icerock.moko.resources.StringResource @Composable fun HowItWorks(user: User?, onboardingStage: SharedPreference? = null) { - ColumnWithScrollBar(Modifier - .fillMaxWidth() - .padding(DEFAULT_PADDING), + ColumnWithScrollBar( + Modifier + .fillMaxWidth() + .padding(DEFAULT_PADDING), ) { AppBarTitle(stringResource(MR.strings.how_simplex_works), withPadding = false) ReadableText(MR.strings.many_people_asked_how_can_it_deliver) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt index f0960c1511..2f6c0395ec 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt @@ -73,33 +73,30 @@ private fun SetDeliveryReceiptsLayout( skip: () -> Unit, userCount: Int, ) { + // This view located in the left panel which means it has to have a padding from right side in order + // to see scroll bar. And this padding should be applied to upper element, not scrollable column modifier val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp - val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() - val scrollState = rememberScrollState() - Column( - 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)) + Box(Modifier.padding(top = DEFAULT_PADDING, end = endPadding)) { + ColumnWithScrollBar( + Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + AppBarTitle(stringResource(MR.strings.delivery_receipts_title)) - Spacer(Modifier.weight(1f)) + Spacer(Modifier.weight(1f)) - EnableReceiptsButton(enableReceipts) - if (userCount > 1) { - TextBelowButton(stringResource(MR.strings.sending_delivery_receipts_will_be_enabled_all_profiles)) - } else { - TextBelowButton(stringResource(MR.strings.sending_delivery_receipts_will_be_enabled)) - } + EnableReceiptsButton(enableReceipts) + if (userCount > 1) { + TextBelowButton(stringResource(MR.strings.sending_delivery_receipts_will_be_enabled_all_profiles)) + } else { + TextBelowButton(stringResource(MR.strings.sending_delivery_receipts_will_be_enabled)) + } - Spacer(Modifier.weight(1f)) + Spacer(Modifier.weight(1f)) - SkipButton(skip) + SkipButton(skip) - SectionBottomSpacer() - } - if (appPlatform.isDesktop) { - Box(Modifier.fillMaxSize().padding(end = endPadding)) { - platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false) + SectionBottomSpacer() } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt index 02716fa17e..6c07a9ceeb 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt @@ -111,85 +111,73 @@ fun SettingsLayout( } val theme = CurrentColors.collectAsState() val uriHandler = LocalUriHandler.current - Box(Modifier.fillMaxSize()) { - ColumnWithScrollBar( - Modifier - .fillMaxSize() - .themedBackground(theme.value.base) - .padding(top = if (appPlatform.isAndroid) DEFAULT_PADDING else DEFAULT_PADDING * 2.8f) - ) { - AppBarTitle(stringResource(MR.strings.your_settings)) + ColumnWithScrollBar( + Modifier + .fillMaxSize() + .themedBackground(theme.value.base) + ) { + AppBarTitle(stringResource(MR.strings.your_settings)) - SectionView(stringResource(MR.strings.settings_section_title_you)) { - val profileHidden = rememberSaveable { mutableStateOf(false) } - if (profile != null) { - SectionItemView(showCustomModal { chatModel, close -> UserProfileView(chatModel, close) }, 80.dp, padding = PaddingValues(start = 16.dp, end = DEFAULT_PADDING), disabled = stopped) { - ProfilePreview(profile, stopped = stopped) - } - SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.your_chat_profiles), { withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden, drawerState) } } }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true) - ChatPreferencesItem(showCustomModal, stopped = stopped) - } else if (chatModel.localUserCreated.value == false) { - SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.create_chat_profile), { withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { ModalManager.center.showModalCloseable { close -> - LaunchedEffect(Unit) { - closeSettings() + SectionView(stringResource(MR.strings.settings_section_title_you)) { + val profileHidden = rememberSaveable { mutableStateOf(false) } + if (profile != null) { + SectionItemView(showCustomModal { chatModel, close -> UserProfileView(chatModel, close) }, 80.dp, padding = PaddingValues(start = 16.dp, end = DEFAULT_PADDING), disabled = stopped) { + ProfilePreview(profile, stopped = stopped) + } + SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.your_chat_profiles), { withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden, drawerState) } } }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true) + ChatPreferencesItem(showCustomModal, stopped = stopped) + } else if (chatModel.localUserCreated.value == false) { + SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.create_chat_profile), { + withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { + ModalManager.center.showModalCloseable { close -> + LaunchedEffect(Unit) { + closeSettings() + } + CreateProfile(chatModel, close) } - CreateProfile(chatModel, close) - } } }, disabled = stopped, extraPadding = true) - } - if (appPlatform.isDesktop) { - SettingsActionItem(painterResource(MR.images.ic_smartphone), stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles), showModal { ConnectMobileView() }, disabled = stopped, extraPadding = true) - } else { - SettingsActionItem(painterResource(MR.images.ic_desktop), stringResource(MR.strings.settings_section_title_use_from_desktop), showCustomModal{ it, close -> ConnectDesktopView(close) }, disabled = stopped, extraPadding = true) - } - SettingsActionItem(painterResource(MR.images.ic_ios_share), stringResource(MR.strings.migrate_from_device_to_another_device), { withAuth(generalGetString(MR.strings.auth_open_migration_to_another_device), generalGetString(MR.strings.auth_log_in_using_credential)) { ModalManager.fullscreen.showCustomModal { close -> MigrateFromDeviceView(close) } }}, disabled = stopped, extraPadding = true) + } + }, disabled = stopped, extraPadding = true) } - SectionDividerSpaced() - - SectionView(stringResource(MR.strings.settings_section_title_settings)) { - SettingsActionItem(painterResource(if (notificationsMode.value == NotificationsMode.OFF) MR.images.ic_bolt_off else MR.images.ic_bolt), stringResource(MR.strings.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_wifi_tethering), stringResource(MR.strings.network_and_servers), showSettingsModal { NetworkAndServersView() }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_videocam), stringResource(MR.strings.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.privacy_and_security), showSettingsModal { PrivacySettingsView(it, showSettingsModal, setPerformLA) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_light_mode), stringResource(MR.strings.appearance_settings), showSettingsModal { AppearanceView(it) }, extraPadding = true) - DatabaseItem(encrypted, passphraseSaved, showSettingsModal { DatabaseView(it, showSettingsModal) }, stopped) + if (appPlatform.isDesktop) { + SettingsActionItem(painterResource(MR.images.ic_smartphone), stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles), showModal { ConnectMobileView() }, disabled = stopped, extraPadding = true) + } else { + SettingsActionItem(painterResource(MR.images.ic_desktop), stringResource(MR.strings.settings_section_title_use_from_desktop), showCustomModal { it, close -> ConnectDesktopView(close) }, disabled = stopped, extraPadding = true) } - SectionDividerSpaced() - - SectionView(stringResource(MR.strings.settings_section_title_help)) { - SettingsActionItem(painterResource(MR.images.ic_help), stringResource(MR.strings.how_to_use_simplex_chat), showModal { HelpView(userDisplayName ?: "") }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_add), stringResource(MR.strings.whats_new), showCustomModal { _, close -> WhatsNewView(viaSettings = true, close) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_info), stringResource(MR.strings.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }, extraPadding = true) - if (!chatModel.desktopNoUserNoRemote) { - SettingsActionItem(painterResource(MR.images.ic_tag), stringResource(MR.strings.chat_with_the_founder), { uriHandler.openVerifiedSimplexUri(simplexTeamUri) }, textColor = MaterialTheme.colors.primary, disabled = stopped, extraPadding = true) - } - SettingsActionItem(painterResource(MR.images.ic_mail), stringResource(MR.strings.send_us_an_email), { uriHandler.openUriCatching("mailto:chat@simplex.chat") }, textColor = MaterialTheme.colors.primary, extraPadding = true) - } - SectionDividerSpaced() - - SectionView(stringResource(MR.strings.settings_section_title_support)) { - ContributeItem(uriHandler) - RateAppItem(uriHandler) - StarOnGithubItem(uriHandler) - } - SectionDividerSpaced() - - SettingsSectionApp(showSettingsModal, showCustomModal, showVersion, withAuth) - SectionBottomSpacer() + SettingsActionItem(painterResource(MR.images.ic_ios_share), stringResource(MR.strings.migrate_from_device_to_another_device), { withAuth(generalGetString(MR.strings.auth_open_migration_to_another_device), generalGetString(MR.strings.auth_log_in_using_credential)) { ModalManager.fullscreen.showCustomModal { close -> MigrateFromDeviceView(close) } } }, disabled = stopped, extraPadding = true) } - if (appPlatform.isDesktop) { - Box( - Modifier - .fillMaxWidth() - .height(AppBarHeight * fontSizeSqrtMultiplier) - .background(MaterialTheme.colors.background) - .background(if (isInDarkTheme()) ToolbarDark else ToolbarLight) - .padding(start = 4.dp), - contentAlignment = Alignment.CenterStart - ) { - NavigationButtonBack(closeSettings, height = 24.sp.toDp()) - } + SectionDividerSpaced() + + SectionView(stringResource(MR.strings.settings_section_title_settings)) { + SettingsActionItem(painterResource(if (notificationsMode.value == NotificationsMode.OFF) MR.images.ic_bolt_off else MR.images.ic_bolt), stringResource(MR.strings.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_wifi_tethering), stringResource(MR.strings.network_and_servers), showSettingsModal { NetworkAndServersView() }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_videocam), stringResource(MR.strings.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.privacy_and_security), showSettingsModal { PrivacySettingsView(it, showSettingsModal, setPerformLA) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_light_mode), stringResource(MR.strings.appearance_settings), showSettingsModal { AppearanceView(it) }, extraPadding = true) + DatabaseItem(encrypted, passphraseSaved, showSettingsModal { DatabaseView(it, showSettingsModal) }, stopped) } + SectionDividerSpaced() + + SectionView(stringResource(MR.strings.settings_section_title_help)) { + SettingsActionItem(painterResource(MR.images.ic_help), stringResource(MR.strings.how_to_use_simplex_chat), showModal { HelpView(userDisplayName ?: "") }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_add), stringResource(MR.strings.whats_new), showCustomModal { _, close -> WhatsNewView(viaSettings = true, close) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_info), stringResource(MR.strings.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }, extraPadding = true) + if (!chatModel.desktopNoUserNoRemote) { + SettingsActionItem(painterResource(MR.images.ic_tag), stringResource(MR.strings.chat_with_the_founder), { uriHandler.openVerifiedSimplexUri(simplexTeamUri) }, textColor = MaterialTheme.colors.primary, disabled = stopped, extraPadding = true) + } + SettingsActionItem(painterResource(MR.images.ic_mail), stringResource(MR.strings.send_us_an_email), { uriHandler.openUriCatching("mailto:chat@simplex.chat") }, textColor = MaterialTheme.colors.primary, extraPadding = true) + } + SectionDividerSpaced() + + SectionView(stringResource(MR.strings.settings_section_title_support)) { + ContributeItem(uriHandler) + RateAppItem(uriHandler) + StarOnGithubItem(uriHandler) + } + SectionDividerSpaced() + + SettingsSectionApp(showSettingsModal, showCustomModal, showVersion, withAuth) + SectionBottomSpacer() } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt index 63baece5cf..1ac0cd7ecd 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt @@ -13,11 +13,12 @@ import chat.simplex.res.MR @Composable fun UserAddressLearnMore() { - ColumnWithScrollBar(Modifier - .fillMaxHeight() - .padding(horizontal = DEFAULT_PADDING) + ColumnWithScrollBar( + Modifier + .fillMaxHeight() + .padding(horizontal = DEFAULT_PADDING) ) { - AppBarTitle(stringResource(MR.strings.simplex_address)) + AppBarTitle(stringResource(MR.strings.simplex_address), withPadding = false) ReadableText(MR.strings.you_can_share_your_address) ReadableText(MR.strings.you_wont_lose_your_contacts_if_delete_address) ReadableText(MR.strings.you_can_accept_or_reject_connection) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt index b595bd4e0e..e6d3202cd0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt @@ -174,7 +174,7 @@ private fun UserAddressLayout( saveAas: (AutoAcceptState, MutableState) -> Unit, ) { ColumnWithScrollBar { - AppBarTitle(stringResource(MR.strings.simplex_address), hostDevice(user?.remoteHostId), withPadding = false) + AppBarTitle(stringResource(MR.strings.simplex_address), hostDevice(user?.remoteHostId)) Column( Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), horizontalAlignment = Alignment.CenterHorizontally, diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Resources.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Resources.desktop.kt index 9d39753f23..951185dc98 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Resources.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Resources.desktop.kt @@ -77,6 +77,9 @@ actual fun windowOrientation(): WindowOrientation = @Composable actual fun windowWidth(): Dp = simplexWindowState.windowState.size.width +@Composable +actual fun windowHeight(): Dp = simplexWindowState.windowState.size.height + actual fun desktopExpandWindowToWidth(width: Dp) { if (simplexWindowState.windowState.size.width >= width) return simplexWindowState.windowState.size = simplexWindowState.windowState.size.copy(width = width) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt index 91e9c70a20..e6b26f9290 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt @@ -13,16 +13,18 @@ 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.nestedscroll.nestedScroll 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 chat.simplex.common.views.helpers.* import kotlinx.coroutines.* +import kotlinx.coroutines.flow.filter +import kotlin.math.absoluteValue @Composable actual fun LazyColumnWithScrollBar( modifier: Modifier, - state: LazyListState, + state: LazyListState?, contentPadding: PaddingValues, reverseLayout: Boolean, verticalArrangement: Arrangement.Vertical, @@ -30,44 +32,6 @@ actual fun LazyColumnWithScrollBar( 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 = 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) - } - } - } - } - Box { - 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) } @@ -87,20 +51,95 @@ actual fun ColumnWithScrollBar( } } } - 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) + val state = state ?: LocalAppBarHandler.current?.listState ?: rememberLazyListState() + val connection = LocalAppBarHandler.current?.connection + // When scroll bar is dragging, there is no scroll event in nested scroll modifier. So, listen for changes on lazy column state + // (only first visible row is useful because LazyColumn doesn't have absolute scroll position, only relative to row) + val scrollBarDraggingState = remember { mutableStateOf(false) } + LaunchedEffect(Unit) { + snapshotFlow { state.firstVisibleItemScrollOffset } + .filter { state.firstVisibleItemIndex == 0 } + .collect { scrollPosition -> + val offset = connection?.appBarOffset + if (offset != null && ((offset + scrollPosition).absoluteValue > 1 || scrollBarDraggingState.value)) { + connection.appBarOffset = -scrollPosition.toFloat() +// Log.d(TAG, "Scrolling position changed from $offset to ${connection.appBarOffset}") + } + } + } + Box(if (connection != null) Modifier.nestedScroll(connection) else Modifier) { + LazyColumn(modifier.then(scrollModifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) { + DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.fillMaxHeight(), scrollBarAlpha, scrollJob, reverseLayout, scrollBarDraggingState) + } } } @Composable -fun DesktopScrollBar(adapter: androidx.compose.foundation.v2.ScrollbarAdapter, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) { +actual fun ColumnWithScrollBar( + modifier: Modifier, + verticalArrangement: Arrangement.Vertical, + horizontalAlignment: Alignment.Horizontal, + state: ScrollState?, + maxIntrinsicSize: Boolean, + content: @Composable() (ColumnScope.() -> Unit) +) { + val scope = rememberCoroutineScope() + val scrollBarAlpha = remember { Animatable(0f) } + val scrollJob: MutableState = 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) + } + } + } + } + val state = state ?: LocalAppBarHandler.current?.scrollState ?: rememberScrollState() + val connection = LocalAppBarHandler.current?.connection + // When scroll bar is dragging, there is no scroll event in nested scroll modifier. So, listen for changes on column state + // (exact scroll position is available but in Int, not Float) + val scrollBarDraggingState = remember { mutableStateOf(false) } + LaunchedEffect(Unit) { + snapshotFlow { state.value } + .collect { scrollPosition -> + val offset = connection?.appBarOffset + if (offset != null && ((offset + scrollPosition).absoluteValue > 1 || scrollBarDraggingState.value)) { + connection.appBarOffset = -scrollPosition.toFloat() +// Log.d(TAG, "Scrolling position changed from $offset to ${connection.appBarOffset}") + } + } + } + Box(if (connection != null) Modifier.nestedScroll(connection) else Modifier) { + Column( + if (maxIntrinsicSize) { + modifier.verticalScroll(state).height(IntrinsicSize.Max).then(scrollModifier) + } else { + modifier.verticalScroll(state).then(scrollModifier) + }, + verticalArrangement, horizontalAlignment, content) + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) { + DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.fillMaxHeight(), scrollBarAlpha, scrollJob, false, scrollBarDraggingState) + } + } +} + +@Composable +fun DesktopScrollBar(adapter: androidx.compose.foundation.v2.ScrollbarAdapter, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean, updateDraggingState: MutableState = remember { mutableStateOf(false) }) { val scope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } val isHovered by interactionSource.collectIsHoveredAsState() val isDragged by interactionSource.collectIsDraggedAsState() LaunchedEffect(isHovered, isDragged) { scrollJob.value.cancel() + updateDraggingState.value = isDragged if (isHovered || isDragged) { scrollBarAlpha.animateTo(1f) } else { diff --git a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt index 8e1643571b..f0679c0fa1 100644 --- a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt +++ b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt @@ -48,38 +48,6 @@ private fun initHaskell() { initHS() platform = object: PlatformInterface { - @Composable - override fun desktopScrollBarComponents(): Triple, Modifier, MutableState> { - val scope = rememberCoroutineScope() - val scrollBarAlpha = remember { Animatable(0f) } - val scrollJob: MutableState = 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, scrollJob: MutableState, reversed: Boolean) { - DesktopScrollBar(rememberScrollbarAdapter(scrollState = state), modifier, scrollBarAlpha, scrollJob, reversed) - } - - @Composable - override fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) { - DesktopScrollBar(rememberScrollbarAdapter(scrollState = state), modifier, scrollBarAlpha, scrollJob, reversed) - } - @Composable override fun desktopShowAppUpdateNotice() { fun showNoticeIfNeeded() { From 70991debfd0cf3235bcce4950ca3552af8d9e608 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Tue, 20 Aug 2024 09:29:52 +0100 Subject: [PATCH 11/21] ios: optimize performance of updating chats (#4723) * ios: optimize performance of updating chats * even simpler * always use updateChats * make chats readonly from outside of model --- apps/ios/Shared/Model/ChatModel.swift | 23 +++---------------- apps/ios/Shared/Model/SimpleXAPI.swift | 9 +++----- apps/ios/Shared/SimpleXApp.swift | 2 +- .../Shared/Views/ChatList/ChatListView.swift | 10 ++++---- .../Shared/Views/Database/DatabaseView.swift | 2 +- .../Views/LocalAuth/LocalAuthView.swift | 3 +-- apps/ios/SimpleXChat/ChatTypes.swift | 6 +++++ 7 files changed, 20 insertions(+), 35 deletions(-) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 4b391b727e..0ac1a9cacb 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -143,7 +143,7 @@ final class ChatModel: ObservableObject { @Published var contentViewAccessAuthenticated: Bool = false @Published var laRequest: LocalAuthRequest? // list of chat "previews" - @Published var chats: [Chat] = [] + @Published private(set) var chats: [Chat] = [] @Published var deletedChats: Set = [] // current chat @Published var chatId: String? @@ -357,25 +357,8 @@ final class ChatModel: ObservableObject { } } - func updateChats(with newChats: [ChatData]) { - for i in 0.. some View { struct ChatListView_Previews: PreviewProvider { static var previews: some View { let chatModel = ChatModel() - chatModel.chats = [ - Chat( + chatModel.updateChats([ + ChatData( chatInfo: ChatInfo.sampleData.direct, chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello")] ), - Chat( + ChatData( chatInfo: ChatInfo.sampleData.group, chatItems: [ChatItem.getSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")] ), - Chat( + ChatData( chatInfo: ChatInfo.sampleData.contactRequest, chatItems: [] ) - ] + ]) return Group { ChatListView(showSettings: Binding.constant(false)) .environmentObject(chatModel) diff --git a/apps/ios/Shared/Views/Database/DatabaseView.swift b/apps/ios/Shared/Views/Database/DatabaseView.swift index 6b6d3796dc..f5b5287971 100644 --- a/apps/ios/Shared/Views/Database/DatabaseView.swift +++ b/apps/ios/Shared/Views/Database/DatabaseView.swift @@ -491,7 +491,7 @@ struct DatabaseView: View { appFilesCountAndSize = directoryFileCountAndSize(getAppFilesDirectory()) do { let chats = try apiGetChats() - m.updateChats(with: chats) + m.updateChats(chats) } catch let error { logger.error("apiGetChats: cannot update chats \(responseError(error))") } diff --git a/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift b/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift index 5e64f7fb0d..27bb95b599 100644 --- a/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift +++ b/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift @@ -65,8 +65,7 @@ struct LocalAuthView: View { // Clear sensitive data on screen just in case app fails to hide its views while new database is created m.chatId = nil ItemsModel.shared.reversedChatItems = [] - m.chats = [] - m.popChatCollector.clear() + m.updateChats([]) m.users = [] _ = kcAppPassword.set(password) _ = kcSelfDestructPassword.remove() diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 233f4c19ee..1a9cf4a216 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -1500,6 +1500,12 @@ public struct ChatData: Decodable, Identifiable, Hashable, ChatLike { public var id: ChatId { get { chatInfo.id } } + public init(chatInfo: ChatInfo, chatItems: [ChatItem], chatStats: ChatStats = ChatStats()) { + self.chatInfo = chatInfo + self.chatItems = chatItems + self.chatStats = chatStats + } + public static func invalidJSON(_ json: String) -> ChatData { ChatData( chatInfo: .invalidJSON(json: json), From b52dfee078c345562ab4c6339702d2dd2fa490ca Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Tue, 20 Aug 2024 13:28:06 +0300 Subject: [PATCH 12/21] ios: asynchronous api calls when entering foreground (#4710) * ios: get call invitations asynchronously * async update chats * async user list on appear * move model changes to main thread --------- Co-authored-by: Evgeny Poberezkin --- apps/ios/Shared/Model/SimpleXAPI.swift | 21 ++++++----- apps/ios/Shared/SimpleXApp.swift | 20 ++++++----- .../Shared/Views/Call/CallController.swift | 35 ++++++++++--------- .../Shared/Views/ChatList/UserPicker.swift | 15 ++++---- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 3abd1e92d1..4e24c616d9 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1218,8 +1218,8 @@ func apiEndCall(_ contact: Contact) async throws { try await sendCommandOkResp(.apiEndCall(contact: contact)) } -func apiGetCallInvitations() throws -> [RcvCallInvitation] { - let r = chatSendCmdSync(.apiGetCallInvitations) +func apiGetCallInvitations() async throws -> [RcvCallInvitation] { + let r = await chatSendCmd(.apiGetCallInvitations) if case let .callInvitations(invs) = r { return invs } throw r } @@ -1517,7 +1517,7 @@ func startChat(refreshInvitations: Bool = true) throws { try getUserChatData() NtfManager.shared.setNtfBadgeCount(m.totalUnreadCountForAllUsers()) if (refreshInvitations) { - try refreshCallInvitations() + Task { try await refreshCallInvitations() } } (m.savedToken, m.tokenStatus, m.notificationMode, m.notificationServer) = apiGetNtfToken() _ = try apiStartChat() @@ -2161,22 +2161,25 @@ func chatItemSimpleUpdate(_ user: any UserLike, _ aChatItem: AChatItem) async { } } -func refreshCallInvitations() throws { +func refreshCallInvitations() async throws { let m = ChatModel.shared - let callInvitations = try justRefreshCallInvitations() + let callInvitations = try await justRefreshCallInvitations() if let (chatId, ntfAction) = m.ntfCallInvitationAction, let invitation = m.callInvitations.removeValue(forKey: chatId) { - m.ntfCallInvitationAction = nil + await MainActor.run { m.ntfCallInvitationAction = nil } CallController.shared.callAction(invitation: invitation, action: ntfAction) } else if let invitation = callInvitations.last(where: { $0.user.showNotifications }) { activateCall(invitation) } } -func justRefreshCallInvitations() throws -> [RcvCallInvitation] { +func justRefreshCallInvitations() async throws -> [RcvCallInvitation] { let m = ChatModel.shared - let callInvitations = try apiGetCallInvitations() - m.callInvitations = callInvitations.reduce(into: [ChatId: RcvCallInvitation]()) { result, inv in result[inv.contact.id] = inv } + let callInvitations = try await apiGetCallInvitations() + await MainActor.run { + m.callInvitations = callInvitations + .reduce(into: [ChatId: RcvCallInvitation]()) { result, inv in result[inv.contact.id] = inv } + } return callInvitations } diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 621f58dc0c..7f2c3b5866 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -83,9 +83,11 @@ struct SimpleXApp: App { if appState != .stopped { startChatAndActivate { if appState.inactive && chatModel.chatRunning == true { - updateChats() - if !chatModel.showCallView && !CallController.shared.hasActiveCalls() { - updateCallInvitations() + Task { + await updateChats() + if !chatModel.showCallView && !CallController.shared.hasActiveCalls() { + await updateCallInvitations() + } } } } @@ -130,16 +132,16 @@ struct SimpleXApp: App { } } - private func updateChats() { + private func updateChats() async { do { - let chats = try apiGetChats() - chatModel.updateChats(chats) + let chats = try await apiGetChatsAsync() + await MainActor.run { chatModel.updateChats(chats) } if let id = chatModel.chatId, let chat = chatModel.getChat(id) { Task { await loadChat(chat: chat, clearItems: false) } } if let ncr = chatModel.ntfContactRequest { - chatModel.ntfContactRequest = nil + await MainActor.run { chatModel.ntfContactRequest = nil } if case let .contactRequest(contactRequest) = chatModel.getChat(ncr.chatId)?.chatInfo { Task { await acceptContactRequest(incognito: ncr.incognito, contactRequest: contactRequest) } } @@ -149,9 +151,9 @@ struct SimpleXApp: App { } } - private func updateCallInvitations() { + private func updateCallInvitations() async { do { - try refreshCallInvitations() + try await refreshCallInvitations() } catch let error { logger.error("apiGetCallInvitations: cannot update call invitations \(responseError(error))") } diff --git a/apps/ios/Shared/Views/Call/CallController.swift b/apps/ios/Shared/Views/Call/CallController.swift index 64b565e8e6..4fcc7db4e1 100644 --- a/apps/ios/Shared/Views/Call/CallController.swift +++ b/apps/ios/Shared/Views/Call/CallController.swift @@ -186,29 +186,30 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse logger.debug("CallController: started chat") self.shouldSuspendChat = true // There are no invitations in the model, as it was processed by NSE - _ = try? justRefreshCallInvitations() - logger.debug("CallController: updated call invitations chat") - // logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))") - // Extract the call information from the push notification payload - let m = ChatModel.shared - if let contactId = payload.dictionaryPayload["contactId"] as? String, - let invitation = m.callInvitations[contactId] { - let update = self.cxCallUpdate(invitation: invitation) - if let uuid = invitation.callkitUUID { - logger.debug("CallController: report pushkit call via CallKit") + Task { + _ = try? await justRefreshCallInvitations() + logger.debug("CallController: updated call invitations chat") + // logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))") + // Extract the call information from the push notification payload + let m = ChatModel.shared + if let contactId = payload.dictionaryPayload["contactId"] as? String, + let invitation = m.callInvitations[contactId] { let update = self.cxCallUpdate(invitation: invitation) - self.provider.reportNewIncomingCall(with: uuid, update: update) { error in - if error != nil { - m.callInvitations.removeValue(forKey: contactId) + if let uuid = invitation.callkitUUID { + logger.debug("CallController: report pushkit call via CallKit") + let update = self.cxCallUpdate(invitation: invitation) + do { + try await self.provider.reportNewIncomingCall(with: uuid, update: update) + } catch { + _ = await MainActor.run { m.callInvitations.removeValue(forKey: contactId) } } - // Tell PushKit that the notification is handled. completion() + } else { + self.reportExpiredCall(update: update, completion) } } else { - self.reportExpiredCall(update: update, completion) + self.reportExpiredCall(payload: payload, completion) } - } else { - self.reportExpiredCall(payload: payload, completion) } } diff --git a/apps/ios/Shared/Views/ChatList/UserPicker.swift b/apps/ios/Shared/Views/ChatList/UserPicker.swift index eeb7bf14f4..e1b2356bed 100644 --- a/apps/ios/Shared/Views/ChatList/UserPicker.swift +++ b/apps/ios/Shared/Views/ChatList/UserPicker.swift @@ -85,13 +85,16 @@ struct UserPicker: View { .padding(8) .opacity(userPickerVisible ? 1.0 : 0.0) .onAppear { - do { - // This check prevents the call of listUsers after the app is suspended, and the database is closed. - if case .active = scenePhase { - m.users = try listUsers() + // This check prevents the call of listUsers after the app is suspended, and the database is closed. + if case .active = scenePhase { + Task { + do { + let users = try await listUsersAsync() + await MainActor.run { m.users = users } + } catch { + logger.error("Error loading users \(responseError(error))") + } } - } catch let error { - logger.error("Error loading users \(responseError(error))") } } } From b2d18f69604fd54e6a50499dc3188a1dda44bf4e Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Tue, 20 Aug 2024 15:54:52 +0300 Subject: [PATCH 13/21] ios: fix visual artifacts when opening a chat on iOS15 (#4726) * ios: fix visual artifacts when opening a chat on iOS15 * fix separators * cleanup --- .../Shared/Views/ChatList/ChatListView.swift | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 041b45492d..8ad03236f1 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -217,14 +217,31 @@ struct ChatListView: View { .listRowSeparator(.hidden) .listRowBackground(Color.clear) } - ForEach(cs, id: \.viewId) { chat in - ChatListNavLink(chat: chat) + if #available(iOS 16.0, *) { + ForEach(cs, id: \.viewId) { chat in + ChatListNavLink(chat: chat) + .scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center) + .padding(.trailing, -16) + .disabled(chatModel.chatRunning != true || chatModel.deletedChats.contains(chat.chatInfo.id)) + .listRowBackground(Color.clear) + } + .offset(x: -8) + } else { + ForEach(cs, id: \.viewId) { chat in + VStack(spacing: .zero) { + Divider() + .padding(.leading, 16) + ChatListNavLink(chat: chat) + .padding(.horizontal, 8) + .padding(.vertical, 6) + } .scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center) - .padding(.trailing, -16) + .listRowSeparator(.hidden) + .listRowInsets(EdgeInsets()) + .background { theme.colors.background } // Hides default list selection colour .disabled(chatModel.chatRunning != true || chatModel.deletedChats.contains(chat.chatInfo.id)) - .listRowBackground(Color.clear) + } } - .offset(x: -8) } .listStyle(.plain) .onChange(of: chatModel.chatId) { currentChatId in From 5f0ccb9f17d403a12efbf4db5f6c6a3a791400ec Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:04:00 +0000 Subject: [PATCH 14/21] ios: fix interface color without callKit (#4727) * ios: fix interface color without callKit * call area * better hiding sheet when making a call without CallKit * invert condition --- apps/ios/Shared/ContentView.swift | 8 ++++---- apps/ios/Shared/Theme/Theme.swift | 4 ++-- apps/ios/Shared/Views/Chat/ChatInfoView.swift | 9 ++++++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/ios/Shared/ContentView.swift b/apps/ios/Shared/ContentView.swift index d93625986e..1f41e7c31d 100644 --- a/apps/ios/Shared/ContentView.swift +++ b/apps/ios/Shared/ContentView.swift @@ -36,7 +36,7 @@ struct ContentView: View { @State private var waitingForOrPassedAuth = true @State private var chatListActionSheet: ChatListActionSheet? = nil - private let callTopPadding: CGFloat = 50 + private let callTopPadding: CGFloat = 40 private enum ChatListActionSheet: Identifiable { case planAndConnectSheet(sheet: PlanAndConnectActionSheet) @@ -151,12 +151,12 @@ struct ContentView: View { } } .onAppear { - reactOnDarkThemeChanges() + reactOnDarkThemeChanges(systemInDarkThemeCurrently) } .onChange(of: colorScheme) { scheme in // It's needed to update UI colors when iOS wants to make screenshot after going to background, // so when a user changes his global theme from dark to light or back, the app will adapt to it - reactOnDarkThemeChanges() + reactOnDarkThemeChanges(scheme == .dark) } .onChange(of: theme.name) { _ in ThemeManager.adjustWindowStyle() @@ -207,7 +207,7 @@ struct ContentView: View { CallDuration(call: call) } .padding(.horizontal) - .frame(height: callTopPadding - 10) + .frame(height: callTopPadding) .background(Color(uiColor: UIColor(red: 47/255, green: 208/255, blue: 88/255, alpha: 1))) .onTapGesture { chatModel.activeCallViewIsCollapsed = false diff --git a/apps/ios/Shared/Theme/Theme.swift b/apps/ios/Shared/Theme/Theme.swift index d4dcc8097f..e2641eb8dd 100644 --- a/apps/ios/Shared/Theme/Theme.swift +++ b/apps/ios/Shared/Theme/Theme.swift @@ -91,8 +91,8 @@ var systemInDarkThemeCurrently: Bool { return UITraitCollection.current.userInterfaceStyle == .dark } -func reactOnDarkThemeChanges() { - if currentThemeDefault.get() == DefaultTheme.SYSTEM_THEME_NAME && CurrentColors.colors.isLight == systemInDarkThemeCurrently { +func reactOnDarkThemeChanges(_ inDarkNow: Bool) { + if currentThemeDefault.get() == DefaultTheme.SYSTEM_THEME_NAME && CurrentColors.colors.isLight == inDarkNow { // Change active colors from light to dark and back based on system theme ThemeManager.applyTheme(DefaultTheme.SYSTEM_THEME_NAME) } diff --git a/apps/ios/Shared/Views/Chat/ChatInfoView.swift b/apps/ios/Shared/Views/Chat/ChatInfoView.swift index ff46b9619c..ea3b04c2ff 100644 --- a/apps/ios/Shared/Views/Chat/ChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatInfoView.swift @@ -671,7 +671,14 @@ private struct CallButton: View { InfoViewButton(image: image, title: title, disabledLook: !canCall, width: width) { if canCall { - CallController.shared.startCall(contact, mediaType) + if CallController.useCallKit() { + CallController.shared.startCall(contact, mediaType) + } else { + // When CallKit is not used, colorscheme will be changed and it will be visible if not hiding sheets first + dismissAllSheets(animated: true) { + CallController.shared.startCall(contact, mediaType) + } + } } else if contact.nextSendGrpInv { showAlert(SomeAlert( alert: mkAlert( From e04f74738e82909fdfd1360e7699143b68e5ed1b Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Tue, 20 Aug 2024 18:24:53 +0100 Subject: [PATCH 15/21] Revert "ios: asynchronous api calls when entering foreground (#4710)" This reverts commit b52dfee078c345562ab4c6339702d2dd2fa490ca. --- apps/ios/Shared/Model/SimpleXAPI.swift | 21 +++++------ apps/ios/Shared/SimpleXApp.swift | 20 +++++------ .../Shared/Views/Call/CallController.swift | 35 +++++++++---------- .../Shared/Views/ChatList/UserPicker.swift | 15 ++++---- 4 files changed, 41 insertions(+), 50 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 4e24c616d9..3abd1e92d1 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1218,8 +1218,8 @@ func apiEndCall(_ contact: Contact) async throws { try await sendCommandOkResp(.apiEndCall(contact: contact)) } -func apiGetCallInvitations() async throws -> [RcvCallInvitation] { - let r = await chatSendCmd(.apiGetCallInvitations) +func apiGetCallInvitations() throws -> [RcvCallInvitation] { + let r = chatSendCmdSync(.apiGetCallInvitations) if case let .callInvitations(invs) = r { return invs } throw r } @@ -1517,7 +1517,7 @@ func startChat(refreshInvitations: Bool = true) throws { try getUserChatData() NtfManager.shared.setNtfBadgeCount(m.totalUnreadCountForAllUsers()) if (refreshInvitations) { - Task { try await refreshCallInvitations() } + try refreshCallInvitations() } (m.savedToken, m.tokenStatus, m.notificationMode, m.notificationServer) = apiGetNtfToken() _ = try apiStartChat() @@ -2161,25 +2161,22 @@ func chatItemSimpleUpdate(_ user: any UserLike, _ aChatItem: AChatItem) async { } } -func refreshCallInvitations() async throws { +func refreshCallInvitations() throws { let m = ChatModel.shared - let callInvitations = try await justRefreshCallInvitations() + let callInvitations = try justRefreshCallInvitations() if let (chatId, ntfAction) = m.ntfCallInvitationAction, let invitation = m.callInvitations.removeValue(forKey: chatId) { - await MainActor.run { m.ntfCallInvitationAction = nil } + m.ntfCallInvitationAction = nil CallController.shared.callAction(invitation: invitation, action: ntfAction) } else if let invitation = callInvitations.last(where: { $0.user.showNotifications }) { activateCall(invitation) } } -func justRefreshCallInvitations() async throws -> [RcvCallInvitation] { +func justRefreshCallInvitations() throws -> [RcvCallInvitation] { let m = ChatModel.shared - let callInvitations = try await apiGetCallInvitations() - await MainActor.run { - m.callInvitations = callInvitations - .reduce(into: [ChatId: RcvCallInvitation]()) { result, inv in result[inv.contact.id] = inv } - } + let callInvitations = try apiGetCallInvitations() + m.callInvitations = callInvitations.reduce(into: [ChatId: RcvCallInvitation]()) { result, inv in result[inv.contact.id] = inv } return callInvitations } diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 7f2c3b5866..621f58dc0c 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -83,11 +83,9 @@ struct SimpleXApp: App { if appState != .stopped { startChatAndActivate { if appState.inactive && chatModel.chatRunning == true { - Task { - await updateChats() - if !chatModel.showCallView && !CallController.shared.hasActiveCalls() { - await updateCallInvitations() - } + updateChats() + if !chatModel.showCallView && !CallController.shared.hasActiveCalls() { + updateCallInvitations() } } } @@ -132,16 +130,16 @@ struct SimpleXApp: App { } } - private func updateChats() async { + private func updateChats() { do { - let chats = try await apiGetChatsAsync() - await MainActor.run { chatModel.updateChats(chats) } + let chats = try apiGetChats() + chatModel.updateChats(chats) if let id = chatModel.chatId, let chat = chatModel.getChat(id) { Task { await loadChat(chat: chat, clearItems: false) } } if let ncr = chatModel.ntfContactRequest { - await MainActor.run { chatModel.ntfContactRequest = nil } + chatModel.ntfContactRequest = nil if case let .contactRequest(contactRequest) = chatModel.getChat(ncr.chatId)?.chatInfo { Task { await acceptContactRequest(incognito: ncr.incognito, contactRequest: contactRequest) } } @@ -151,9 +149,9 @@ struct SimpleXApp: App { } } - private func updateCallInvitations() async { + private func updateCallInvitations() { do { - try await refreshCallInvitations() + try refreshCallInvitations() } catch let error { logger.error("apiGetCallInvitations: cannot update call invitations \(responseError(error))") } diff --git a/apps/ios/Shared/Views/Call/CallController.swift b/apps/ios/Shared/Views/Call/CallController.swift index 4fcc7db4e1..64b565e8e6 100644 --- a/apps/ios/Shared/Views/Call/CallController.swift +++ b/apps/ios/Shared/Views/Call/CallController.swift @@ -186,30 +186,29 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse logger.debug("CallController: started chat") self.shouldSuspendChat = true // There are no invitations in the model, as it was processed by NSE - Task { - _ = try? await justRefreshCallInvitations() - logger.debug("CallController: updated call invitations chat") - // logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))") - // Extract the call information from the push notification payload - let m = ChatModel.shared - if let contactId = payload.dictionaryPayload["contactId"] as? String, - let invitation = m.callInvitations[contactId] { + _ = try? justRefreshCallInvitations() + logger.debug("CallController: updated call invitations chat") + // logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))") + // Extract the call information from the push notification payload + let m = ChatModel.shared + if let contactId = payload.dictionaryPayload["contactId"] as? String, + let invitation = m.callInvitations[contactId] { + let update = self.cxCallUpdate(invitation: invitation) + if let uuid = invitation.callkitUUID { + logger.debug("CallController: report pushkit call via CallKit") let update = self.cxCallUpdate(invitation: invitation) - if let uuid = invitation.callkitUUID { - logger.debug("CallController: report pushkit call via CallKit") - let update = self.cxCallUpdate(invitation: invitation) - do { - try await self.provider.reportNewIncomingCall(with: uuid, update: update) - } catch { - _ = await MainActor.run { m.callInvitations.removeValue(forKey: contactId) } + self.provider.reportNewIncomingCall(with: uuid, update: update) { error in + if error != nil { + m.callInvitations.removeValue(forKey: contactId) } + // Tell PushKit that the notification is handled. completion() - } else { - self.reportExpiredCall(update: update, completion) } } else { - self.reportExpiredCall(payload: payload, completion) + self.reportExpiredCall(update: update, completion) } + } else { + self.reportExpiredCall(payload: payload, completion) } } diff --git a/apps/ios/Shared/Views/ChatList/UserPicker.swift b/apps/ios/Shared/Views/ChatList/UserPicker.swift index e1b2356bed..eeb7bf14f4 100644 --- a/apps/ios/Shared/Views/ChatList/UserPicker.swift +++ b/apps/ios/Shared/Views/ChatList/UserPicker.swift @@ -85,16 +85,13 @@ struct UserPicker: View { .padding(8) .opacity(userPickerVisible ? 1.0 : 0.0) .onAppear { - // This check prevents the call of listUsers after the app is suspended, and the database is closed. - if case .active = scenePhase { - Task { - do { - let users = try await listUsersAsync() - await MainActor.run { m.users = users } - } catch { - logger.error("Error loading users \(responseError(error))") - } + do { + // This check prevents the call of listUsers after the app is suspended, and the database is closed. + if case .active = scenePhase { + m.users = try listUsers() } + } catch let error { + logger.error("Error loading users \(responseError(error))") } } } From d5eb7b78111a2336c668736bfc397ed4aa052ede Mon Sep 17 00:00:00 2001 From: Diogo Date: Wed, 21 Aug 2024 10:27:58 +0100 Subject: [PATCH 16/21] core: api to change user of pending connections (#4681) * core: add api that enables change of owner user id for pending connections * old user sends request, incognito handling and coverage * call agent inside set connection api * only set user id if servers match * simplify * reduce test noise * return invitation when a newone is created * add test for profile on different server * refactor namings * update simplexmq * refactor * test improvements and simplify * remove fdescribes * simplify and reduce vars scope * put if back * refactor, change error * refactor view * refactor --------- Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> --- cabal.project | 2 +- scripts/nix/sha256map.nix | 2 +- src/Simplex/Chat.hs | 35 +++++++++ src/Simplex/Chat/Controller.hs | 3 + src/Simplex/Chat/Store/Direct.hs | 14 ++++ src/Simplex/Chat/View.hs | 16 ++++ tests/ChatTests/Profiles.hs | 125 +++++++++++++++++++++++++++++++ 7 files changed, 195 insertions(+), 2 deletions(-) diff --git a/cabal.project b/cabal.project index 05f5935554..08973f9be8 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 571d148bdf9e29403b9bcec6f7daeff815a4db38 + tag: 1cbf8c0015a8014bcc9d1894055d734947176684 source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 2802bfda6e..a77e8ee167 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."571d148bdf9e29403b9bcec6f7daeff815a4db38" = "1p7m7i4wdyvd2wypm04cx4w960vnyqa9wkfnlpv72cz83k0xirxf"; + "https://github.com/simplex-chat/simplexmq.git"."1cbf8c0015a8014bcc9d1894055d734947176684" = "01x8fvwzahz32fmxc2mjvxl1z6agwr3952hl4qjswym76r1dpc1s"; "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"; diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 2d3ed3ca84..5899be6445 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -1655,6 +1655,40 @@ processChatCommand' vr = \case case conn'_ of Just conn' -> pure $ CRConnectionIncognitoUpdated user conn' Nothing -> throwChatError CEConnectionIncognitoChangeProhibited + APIChangeConnectionUser connId newUserId -> withUser $ \user@User {userId} -> do + conn <- withFastStore $ \db -> getPendingContactConnection db userId connId + let PendingContactConnection {pccConnStatus, connReqInv} = conn + case (pccConnStatus, connReqInv) of + (ConnNew, Just cReqInv) -> do + newUser <- privateGetUser newUserId + conn' <- ifM (canKeepLink cReqInv newUser) (updateConnRecord user conn newUser) (recreateConn user conn newUser) + pure $ CRConnectionUserChanged user conn conn' newUser + _ -> throwChatError CEConnectionUserChangeProhibited + where + canKeepLink :: ConnReqInvitation -> User -> CM Bool + canKeepLink (CRInvitationUri crData _) newUser = do + let ConnReqUriData {crSmpQueues = q :| _} = crData + SMPQueueUri {queueAddress = SMPQueueAddress {smpServer}} = q + cfg <- asks config + newUserServers <- L.map (\ServerCfg {server} -> protoServer server) . useServers cfg SPSMP <$> withFastStore' (`getProtocolServers` newUser) + pure $ smpServer `elem` newUserServers + updateConnRecord user@User {userId} conn@PendingContactConnection {customUserProfileId} newUser = do + withAgent $ \a -> changeConnectionUser a (aUserId user) (aConnId' conn) (aUserId newUser) + withFastStore' $ \db -> do + conn' <- updatePCCUser db userId conn newUserId + forM_ customUserProfileId $ \profileId -> + deletePCCIncognitoProfile db user profileId + pure conn' + recreateConn user conn@PendingContactConnection {customUserProfileId} newUser = do + subMode <- chatReadVar subscriptionMode + (agConnId, cReq) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation Nothing IKPQOn subMode + conn' <- withFastStore' $ \db -> do + deleteConnectionRecord db user connId + forM_ customUserProfileId $ \profileId -> + deletePCCIncognitoProfile db user profileId + createDirectConnection db newUser agConnId cReq ConnNew Nothing subMode initialChatVersion PQSupportOn + deleteAgentConnectionAsync user (aConnId' conn) + pure conn' APIConnectPlan userId cReqUri -> withUserId userId $ \user -> CRConnectionPlan user <$> connectPlan user cReqUri APIConnect userId incognito (Just (ACR SCMInvitation cReq)) -> withUserId userId $ \user -> withInvitationLock "connect" (strEncode cReq) . procCmd $ do @@ -7790,6 +7824,7 @@ chatCommandP = "/_connect " *> (APIConnect <$> A.decimal <*> incognitoOnOffP <* A.space <*> ((Just <$> strP) <|> A.takeByteString $> Nothing)), "/_connect " *> (APIAddContact <$> A.decimal <*> incognitoOnOffP), "/_set incognito :" *> (APISetConnectionIncognito <$> A.decimal <* A.space <*> onOffP), + "/_set conn user :" *> (APIChangeConnectionUser <$> A.decimal <* A.space <*> A.decimal), ("/connect" <|> "/c") *> (Connect <$> incognitoP <* A.space <*> ((Just <$> strP) <|> A.takeTill isSpace $> Nothing)), ("/connect" <|> "/c") *> (AddContact <$> incognitoP), ForwardMessage <$> chatNameP <* " <- @" <*> displayName <* A.space <*> msgTextP, diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index dbfa361c70..c4f056c778 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -403,6 +403,7 @@ data ChatCommand | APIAddContact UserId IncognitoEnabled | AddContact IncognitoEnabled | APISetConnectionIncognito Int64 IncognitoEnabled + | APIChangeConnectionUser Int64 UserId -- new user id to switch connection to | APIConnectPlan UserId AConnectionRequestUri | APIConnect UserId IncognitoEnabled (Maybe AConnectionRequestUri) | Connect IncognitoEnabled (Maybe AConnectionRequestUri) @@ -628,6 +629,7 @@ data ChatResponse | CRVersionInfo {versionInfo :: CoreVersionInfo, chatMigrations :: [UpMigration], agentMigrations :: [UpMigration]} | CRInvitation {user :: User, connReqInvitation :: ConnReqInvitation, connection :: PendingContactConnection} | CRConnectionIncognitoUpdated {user :: User, toConnection :: PendingContactConnection} + | CRConnectionUserChanged {user :: User, fromConnection :: PendingContactConnection, toConnection :: PendingContactConnection, newUser :: User} | CRConnectionPlan {user :: User, connectionPlan :: ConnectionPlan} | CRSentConfirmation {user :: User, connection :: PendingContactConnection} | CRSentInvitation {user :: User, connection :: PendingContactConnection, customUserProfile :: Maybe Profile} @@ -1191,6 +1193,7 @@ data ChatErrorType | CEAgentCommandError {message :: String} | CEInvalidFileDescription {message :: String} | CEConnectionIncognitoChangeProhibited + | CEConnectionUserChangeProhibited | CEPeerChatVRangeIncompatible | CEInternalError {message :: String} | CEException {message :: String} diff --git a/src/Simplex/Chat/Store/Direct.hs b/src/Simplex/Chat/Store/Direct.hs index 508a992543..c0f007b6ac 100644 --- a/src/Simplex/Chat/Store/Direct.hs +++ b/src/Simplex/Chat/Store/Direct.hs @@ -64,6 +64,7 @@ module Simplex.Chat.Store.Direct createAcceptedContact, getUserByContactRequestId, getPendingContactConnections, + updatePCCUser, getContactConnections, getConnectionById, getConnectionsContacts, @@ -424,6 +425,19 @@ updatePCCIncognito db User {userId} conn customUserProfileId = do (customUserProfileId, updatedAt, userId, pccConnId conn) pure (conn :: PendingContactConnection) {customUserProfileId, updatedAt} +updatePCCUser :: DB.Connection -> UserId -> PendingContactConnection -> UserId -> IO PendingContactConnection +updatePCCUser db userId conn newUserId = do + updatedAt <- getCurrentTime + DB.execute + db + [sql| + UPDATE connections + SET user_id = ?, custom_user_profile_id = NULL, updated_at = ? + WHERE user_id = ? AND connection_id = ? + |] + (newUserId, updatedAt, userId, pccConnId conn) + pure (conn :: PendingContactConnection) {customUserProfileId = Nothing, updatedAt} + deletePCCIncognitoProfile :: DB.Connection -> User -> ProfileId -> IO () deletePCCIncognitoProfile db User {userId} profileId = DB.execute diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 3d519c3b5c..e154b5b902 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -172,6 +172,7 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe CRVersionInfo info _ _ -> viewVersionInfo logLevel info CRInvitation u cReq _ -> ttyUser u $ viewConnReqInvitation cReq CRConnectionIncognitoUpdated u c -> ttyUser u $ viewConnectionIncognitoUpdated c + CRConnectionUserChanged u c c' nu -> ttyUser u $ viewConnectionUserChanged u c nu c' CRConnectionPlan u connectionPlan -> ttyUser u $ viewConnectionPlan connectionPlan CRSentConfirmation u _ -> ttyUser u ["confirmation sent!"] CRSentInvitation u _ customUserProfile -> ttyUser u $ viewSentInvitation customUserProfile testView @@ -1498,6 +1499,20 @@ viewConnectionIncognitoUpdated PendingContactConnection {pccConnId, customUserPr | isJust customUserProfileId = ["connection " <> sShow pccConnId <> " changed to incognito"] | otherwise = ["connection " <> sShow pccConnId <> " changed to non incognito"] +viewConnectionUserChanged :: User -> PendingContactConnection -> User -> PendingContactConnection -> [StyledString] +viewConnectionUserChanged User {localDisplayName = n} PendingContactConnection {pccConnId, connReqInv} User {localDisplayName = n'} PendingContactConnection {connReqInv = connReqInv'} = + case (connReqInv, connReqInv') of + (Just cReqInv, Just cReqInv') + | cReqInv /= cReqInv' -> [userChangedStr <> ", new link:"] <> newLink cReqInv' + _ -> [userChangedStr] + where + userChangedStr = "connection " <> sShow pccConnId <> " changed from user " <> plain n <> " to user " <> plain n' + newLink cReqInv = + [ "", + (plain . strEncode) (simplexChatInvitation cReqInv), + "" + ] + viewConnectionPlan :: ConnectionPlan -> [StyledString] viewConnectionPlan = \case CPInvitationLink ilp -> case ilp of @@ -2025,6 +2040,7 @@ viewChatError isCmd logLevel testView = \case CEAgentCommandError e -> ["agent command error: " <> plain e] CEInvalidFileDescription e -> ["invalid file description: " <> plain e] CEConnectionIncognitoChangeProhibited -> ["incognito mode change prohibited"] + CEConnectionUserChangeProhibited -> ["incognito mode change prohibited for user"] CEPeerChatVRangeIncompatible -> ["peer chat protocol version range incompatible"] CEInternalError e -> ["internal chat error: " <> plain e] CEException e -> ["exception: " <> plain e] diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 23004677c9..43ad5ba841 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -63,6 +63,11 @@ chatProfileTests = do describe "contact aliases" $ do it "set contact alias" testSetAlias it "set connection alias" testSetConnectionAlias + describe "pending connection users" $ do + it "change user for pending connection" testChangePCCUser + it "change from incognito profile connects as new user" testChangePCCUserFromIncognito + it "change user for pending connection and later set incognito connects as incognito in changed profile" testChangePCCUserAndThenIncognito + it "change user for user without matching servers creates new connection" testChangePCCUserDiffSrv describe "preferences" $ do it "set contact preferences" testSetContactPrefs it "feature offers" testFeatureOffers @@ -1557,6 +1562,126 @@ testSetAlias = testChat2 aliceProfile bobProfile $ alice ##> "/contacts" alice <## "bob (Bob)" +testChangePCCUser :: HasCallStack => FilePath -> IO () +testChangePCCUser = testChat2 aliceProfile bobProfile $ + \alice bob -> do + -- Create a new invite + alice ##> "/connect" + inv <- getInvitation alice + -- Create new user and go back to original user + alice ##> "/create user alisa" + showActiveUser alice "alisa" + alice ##> "/create user alisa2" + showActiveUser alice "alisa2" + alice ##> "/user alice" + showActiveUser alice "alice (Alice)" + -- Change connection to newly created user + alice ##> "/_set conn user :1 2" + alice <## "connection 1 changed from user alice to user alisa" + alice ##> "/user alisa" + showActiveUser alice "alisa" + -- Change connection back to other user + alice ##> "/_set conn user :1 3" + alice <## "connection 1 changed from user alisa to user alisa2" + alice ##> "/user alisa2" + showActiveUser alice "alisa2" + -- Connect + bob ##> ("/connect " <> inv) + bob <## "confirmation sent!" + concurrently_ + (alice <## "bob (Bob): contact is connected") + (bob <## "alisa2: contact is connected") + +testChangePCCUserFromIncognito :: HasCallStack => FilePath -> IO () +testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $ + \alice bob -> do + -- Create a new invite and set as incognito + alice ##> "/connect" + inv <- getInvitation alice + alice ##> "/_set incognito :1 on" + alice <## "connection 1 changed to incognito" + -- Create new user and go back to original user + alice ##> "/create user alisa" + showActiveUser alice "alisa" + alice ##> "/user alice" + showActiveUser alice "alice (Alice)" + -- Change connection to newly created user + alice ##> "/_set conn user :1 2" + alice <## "connection 1 changed from user alice to user alisa" + alice `hasContactProfiles` ["alice"] + alice ##> "/user alisa" + showActiveUser alice "alisa" + -- Change connection back to initial user + alice ##> "/_set conn user :1 1" + alice <## "connection 1 changed from user alisa to user alice" + alice ##> "/user alice" + showActiveUser alice "alice (Alice)" + -- Connect + bob ##> ("/connect " <> inv) + bob <## "confirmation sent!" + concurrently_ + (alice <## "bob (Bob): contact is connected") + (bob <## "alice (Alice): contact is connected") + +testChangePCCUserAndThenIncognito :: HasCallStack => FilePath -> IO () +testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ + \alice bob -> do + -- Create a new invite and set as incognito + alice ##> "/connect" + inv <- getInvitation alice + -- Create new user and go back to original user + alice ##> "/create user alisa" + showActiveUser alice "alisa" + alice ##> "/user alice" + showActiveUser alice "alice (Alice)" + -- Change connection to newly created user + alice ##> "/_set conn user :1 2" + alice <## "connection 1 changed from user alice to user alisa" + alice ##> "/user alisa" + showActiveUser alice "alisa" + -- Change connection to incognito and make sure it's attached to the newly created user profile + alice ##> "/_set incognito :1 on" + alice <## "connection 1 changed to incognito" + bob ##> ("/connect " <> inv) + bob <## "confirmation sent!" + alisaIncognito <- getTermLine alice + concurrentlyN_ + [ bob <## (alisaIncognito <> ": contact is connected"), + do + alice <## ("bob (Bob): contact is connected, your incognito profile for this contact is " <> alisaIncognito) + alice <## ("use /i bob to print out this incognito profile again") + ] + +testChangePCCUserDiffSrv :: HasCallStack => FilePath -> IO () +testChangePCCUserDiffSrv = testChat2 aliceProfile bobProfile $ + \alice bob -> do + -- Create a new invite + alice ##> "/connect" + _ <- getInvitation alice + alice ##> "/_set incognito :1 on" + alice <## "connection 1 changed to incognito" + -- Create new user with different servers + alice ##> "/create user alisa" + showActiveUser alice "alisa" + alice #$> ("/smp smp://2345-w==@smp2.example.im smp://3456-w==@smp3.example.im:5224", id, "ok") + alice ##> "/user alice" + showActiveUser alice "alice (Alice)" + -- Change connection to newly created user and use the newly created connection + alice ##> "/_set conn user :1 2" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" + alice `hasContactProfiles` ["alice"] + alice ##> "/user alisa" + showActiveUser alice "alisa" + -- Connect + bob ##> ("/connect " <> inv) + bob <## "confirmation sent!" + concurrently_ + (alice <## "bob (Bob): contact is connected") + (bob <## "alisa: contact is connected") + testSetConnectionAlias :: HasCallStack => FilePath -> IO () testSetConnectionAlias = testChat2 aliceProfile bobProfile $ \alice bob -> do From 0438f35539c9713b7f1da35d28b7b26e5afed4c0 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Wed, 21 Aug 2024 17:05:59 +0300 Subject: [PATCH 17/21] ios: fix notifying the recipient when hanging up a call in ios15 (#4731) Co-authored-by: Evgeny Poberezkin --- apps/ios/Shared/Views/Call/WebRTCClient.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/ios/Shared/Views/Call/WebRTCClient.swift b/apps/ios/Shared/Views/Call/WebRTCClient.swift index 0b4917c103..79e0dea16c 100644 --- a/apps/ios/Shared/Views/Call/WebRTCClient.swift +++ b/apps/ios/Shared/Views/Call/WebRTCClient.swift @@ -411,6 +411,15 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg } func endCall() { + if #available(iOS 16.0, *) { + _endCall() + } else { + // Fixes `connection.close()` getting locked up in iOS15 + DispatchQueue.global(qos: .utility).async { self._endCall() } + } + } + + private func _endCall() { guard let call = activeCall.wrappedValue else { return } logger.debug("WebRTCClient: ending the call") activeCall.wrappedValue = nil From 5cb8badb22ad6c749cf886ceb2d80998720006e4 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:46:42 +0000 Subject: [PATCH 18/21] android, desktop: layout changes for settings items (#4732) * android, desktop: layout changes for settings items * section paddings * toggle * padding and border * padding --------- Co-authored-by: Evgeny Poberezkin --- .../common/views/call/CallView.android.kt | 6 +- .../views/usersettings/Appearance.android.kt | 14 ++-- .../usersettings/SettingsView.android.kt | 6 +- .../chat/simplex/common/ui/theme/Theme.kt | 2 + .../simplex/common/views/chat/ChatInfoView.kt | 8 +-- .../common/views/chat/ChatItemInfoView.kt | 2 +- .../common/views/chat/ContactPreferences.kt | 8 +-- .../views/chat/SelectableChatItemToolbars.kt | 6 +- .../views/chat/group/AddGroupMembersView.kt | 14 ++-- .../views/chat/group/GroupChatInfoView.kt | 6 +- .../views/chat/group/WelcomeMessageView.kt | 8 +-- .../common/views/chatlist/ChatListView.kt | 4 +- .../views/chatlist/ServersSummaryView.kt | 26 +++++--- .../common/views/chatlist/UserPicker.kt | 6 +- .../common/views/database/DatabaseView.kt | 4 +- .../common/views/helpers/DefaultSwitch.kt | 6 +- .../helpers/ExposedDropDownSettingRow.kt | 2 +- .../simplex/common/views/helpers/Section.kt | 60 ++++++++--------- .../common/views/helpers/ThemeModeEditor.kt | 10 +-- .../newchat/ContactConnectionInfoView.kt | 2 +- .../common/views/newchat/NewChatSheet.kt | 12 ++-- .../common/views/newchat/NewChatView.kt | 2 +- .../usersettings/AdvancedNetworkSettings.kt | 4 +- .../common/views/usersettings/Appearance.kt | 6 +- .../views/usersettings/DeveloperView.kt | 3 +- .../views/usersettings/HiddenProfileView.kt | 5 +- .../views/usersettings/NetworkAndServers.kt | 40 ++++++------ .../views/usersettings/PrivacySettings.kt | 8 +-- .../views/usersettings/ProtocolServerView.kt | 4 +- .../common/views/usersettings/SettingsView.kt | 64 +++++++++---------- .../views/usersettings/UserAddressView.kt | 2 +- .../views/usersettings/UserProfilesView.kt | 3 +- .../resources/MR/images/ic_account_box.svg | 2 +- .../MR/images/ic_account_circle_filled.svg | 2 +- .../commonMain/resources/MR/images/ic_add.svg | 2 +- .../resources/MR/images/ic_add_link.svg | 2 +- .../resources/MR/images/ic_add_photo.svg | 2 +- .../resources/MR/images/ic_add_reaction.svg | 2 +- .../MR/images/ic_add_reaction_filled.svg | 2 +- .../resources/MR/images/ic_all_inclusive.svg | 2 +- .../MR/images/ic_arrow_back_ios_new.svg | 2 +- .../resources/MR/images/ic_arrow_downward.svg | 2 +- .../MR/images/ic_arrow_drop_down.svg | 1 + .../resources/MR/images/ic_arrow_drop_up.svg | 1 + .../resources/MR/images/ic_arrow_forward.svg | 2 +- .../MR/images/ic_arrow_forward_ios.svg | 2 +- .../resources/MR/images/ic_arrow_upward.svg | 2 +- .../MR/images/ic_arrows_left_right.svg | 2 +- .../resources/MR/images/ic_article.svg | 2 +- .../MR/images/ic_attach_file_filled.svg | 2 +- .../MR/images/ic_attach_file_filled_500.svg | 2 +- .../resources/MR/images/ic_avg_pace.svg | 2 +- .../resources/MR/images/ic_back_hand.svg | 2 +- .../resources/MR/images/ic_backspace.svg | 2 +- .../resources/MR/images/ic_backup.svg | 2 +- .../resources/MR/images/ic_battery_2_bar.svg | 2 +- .../resources/MR/images/ic_battery_3_bar.svg | 2 +- .../resources/MR/images/ic_bluetooth.svg | 2 +- .../resources/MR/images/ic_blur_on.svg | 2 +- .../resources/MR/images/ic_bolt.svg | 2 +- .../resources/MR/images/ic_bolt_filled.svg | 2 +- .../resources/MR/images/ic_bolt_off.svg | 4 +- .../MR/images/ic_brand_awareness_filled.svg | 2 +- .../resources/MR/images/ic_cable.svg | 2 +- .../resources/MR/images/ic_call.svg | 2 +- .../resources/MR/images/ic_call_500.svg | 2 +- .../resources/MR/images/ic_call_end.svg | 2 +- .../MR/images/ic_call_end_filled.svg | 2 +- .../resources/MR/images/ic_call_filled.svg | 2 +- .../resources/MR/images/ic_camera_enhance.svg | 2 +- .../resources/MR/images/ic_cancel_filled.svg | 2 +- .../resources/MR/images/ic_chat.svg | 2 +- .../resources/MR/images/ic_chat_bubble.svg | 2 +- .../resources/MR/images/ic_check.svg | 2 +- .../resources/MR/images/ic_check_circle.svg | 2 +- .../MR/images/ic_check_circle_filled.svg | 2 +- .../resources/MR/images/ic_check_filled.svg | 2 +- .../resources/MR/images/ic_chevron_right.svg | 2 +- .../resources/MR/images/ic_circle.svg | 2 +- .../resources/MR/images/ic_circle_filled.svg | 2 +- .../resources/MR/images/ic_close.svg | 2 +- .../resources/MR/images/ic_code.svg | 2 +- .../resources/MR/images/ic_collapse_all.svg | 2 +- .../resources/MR/images/ic_content_copy.svg | 2 +- .../resources/MR/images/ic_content_paste.svg | 2 +- .../resources/MR/images/ic_database.svg | 2 +- .../resources/MR/images/ic_delete.svg | 2 +- .../resources/MR/images/ic_delete_forever.svg | 2 +- .../MR/images/ic_delete_forever_filled.svg | 2 +- .../resources/MR/images/ic_desktop.svg | 2 +- .../commonMain/resources/MR/images/ic_dns.svg | 2 +- .../MR/images/ic_do_not_disturb_on.svg | 2 +- .../resources/MR/images/ic_do_not_touch.svg | 2 +- .../resources/MR/images/ic_done_filled.svg | 2 +- .../resources/MR/images/ic_double_check.svg | 2 +- .../resources/MR/images/ic_download.svg | 2 +- .../resources/MR/images/ic_draft.svg | 2 +- .../resources/MR/images/ic_draft_filled.svg | 2 +- .../MR/images/ic_drive_folder_upload.svg | 2 +- .../resources/MR/images/ic_edit.svg | 2 +- .../resources/MR/images/ic_edit_filled.svg | 2 +- .../resources/MR/images/ic_edit_note.svg | 2 +- .../MR/images/ic_electrical_services.svg | 2 +- .../resources/MR/images/ic_engineering.svg | 2 +- .../resources/MR/images/ic_error.svg | 2 +- .../resources/MR/images/ic_error_filled.svg | 2 +- .../resources/MR/images/ic_expand_all.svg | 2 +- .../resources/MR/images/ic_expand_less.svg | 1 - .../resources/MR/images/ic_expand_more.svg | 1 - .../resources/MR/images/ic_filter_list.svg | 2 +- .../resources/MR/images/ic_flag.svg | 2 +- .../images/ic_flip_camera_android_filled.svg | 2 +- .../resources/MR/images/ic_folder_filled.svg | 4 +- .../resources/MR/images/ic_folder_open.svg | 2 +- .../resources/MR/images/ic_folder_pen.svg | 2 +- .../resources/MR/images/ic_forum.svg | 2 +- .../resources/MR/images/ic_forward.svg | 2 +- .../resources/MR/images/ic_github.svg | 2 +- .../resources/MR/images/ic_group.svg | 2 +- .../resources/MR/images/ic_headphones.svg | 2 +- .../resources/MR/images/ic_help.svg | 2 +- .../resources/MR/images/ic_history.svg | 2 +- .../resources/MR/images/ic_id_card.svg | 2 +- .../resources/MR/images/ic_image.svg | 2 +- .../resources/MR/images/ic_info.svg | 2 +- .../resources/MR/images/ic_inventory_2.svg | 2 +- .../resources/MR/images/ic_ios_share.svg | 2 +- .../resources/MR/images/ic_keyboard.svg | 2 +- .../MR/images/ic_keyboard_arrow_down.svg | 2 +- .../resources/MR/images/ic_keyboard_voice.svg | 2 +- .../MR/images/ic_keyboard_voice_filled.svg | 2 +- .../resources/MR/images/ic_light_mode.svg | 2 +- .../resources/MR/images/ic_lightbulb.svg | 2 +- .../resources/MR/images/ic_link.svg | 2 +- .../resources/MR/images/ic_lock.svg | 2 +- .../resources/MR/images/ic_lock_filled.svg | 2 +- .../MR/images/ic_lock_open_right.svg | 2 +- .../resources/MR/images/ic_login.svg | 2 +- .../resources/MR/images/ic_logout.svg | 2 +- .../resources/MR/images/ic_mail.svg | 2 +- .../resources/MR/images/ic_mail_filled.svg | 2 +- .../MR/images/ic_manage_accounts.svg | 2 +- .../resources/MR/images/ic_maps_ugc.svg | 2 +- .../MR/images/ic_mark_chat_unread.svg | 2 +- .../resources/MR/images/ic_match_case.svg | 2 +- .../resources/MR/images/ic_menu.svg | 2 +- .../commonMain/resources/MR/images/ic_mic.svg | 2 +- .../resources/MR/images/ic_mic_filled.svg | 2 +- .../resources/MR/images/ic_mic_off.svg | 2 +- .../resources/MR/images/ic_more_horiz.svg | 2 +- .../resources/MR/images/ic_more_vert.svg | 2 +- .../resources/MR/images/ic_music_note.svg | 2 +- .../resources/MR/images/ic_note_add.svg | 2 +- .../resources/MR/images/ic_notifications.svg | 2 +- .../MR/images/ic_notifications_off.svg | 2 +- .../MR/images/ic_notifications_off_filled.svg | 2 +- .../resources/MR/images/ic_open_in_new.svg | 2 +- .../MR/images/ic_outline_terminal.svg | 2 +- .../resources/MR/images/ic_palette.svg | 2 +- .../resources/MR/images/ic_pause_filled.svg | 2 +- .../resources/MR/images/ic_pending.svg | 2 +- .../resources/MR/images/ic_pending_filled.svg | 2 +- .../resources/MR/images/ic_person.svg | 2 +- .../resources/MR/images/ic_person_add.svg | 2 +- .../resources/MR/images/ic_person_add_500.svg | 2 +- .../resources/MR/images/ic_person_off.svg | 2 +- .../MR/images/ic_phone_bluetooth_speaker.svg | 2 +- .../MR/images/ic_phone_in_talk_filled.svg | 2 +- .../resources/MR/images/ic_photo_camera.svg | 2 +- .../MR/images/ic_play_arrow_filled.svg | 2 +- .../MR/images/ic_power_settings_new.svg | 2 +- .../resources/MR/images/ic_priority_high.svg | 2 +- .../resources/MR/images/ic_qr_code.svg | 2 +- .../resources/MR/images/ic_question_mark.svg | 2 +- .../MR/images/ic_radio_button_unchecked.svg | 2 +- .../images/ic_radiowaves_up_forward_1_bar.svg | 2 +- .../images/ic_radiowaves_up_forward_2_bar.svg | 2 +- .../images/ic_radiowaves_up_forward_3_bar.svg | 2 +- .../images/ic_radiowaves_up_forward_4_bar.svg | 2 +- .../resources/MR/images/ic_redeem.svg | 2 +- .../resources/MR/images/ic_refresh.svg | 2 +- .../resources/MR/images/ic_repeat_one.svg | 2 +- .../resources/MR/images/ic_replay.svg | 2 +- .../resources/MR/images/ic_reply.svg | 2 +- .../resources/MR/images/ic_report.svg | 2 +- .../resources/MR/images/ic_report_filled.svg | 2 +- .../resources/MR/images/ic_restart_alt.svg | 2 +- .../resources/MR/images/ic_ring_volume.svg | 2 +- .../resources/MR/images/ic_safety_divider.svg | 2 +- .../resources/MR/images/ic_schedule.svg | 2 +- .../MR/images/ic_schedule_filled.svg | 2 +- .../resources/MR/images/ic_search.svg | 2 +- .../resources/MR/images/ic_search_500.svg | 2 +- .../resources/MR/images/ic_security.svg | 2 +- .../resources/MR/images/ic_settings.svg | 2 +- .../MR/images/ic_settings_backup_restore.svg | 2 +- .../MR/images/ic_settings_ethernet.svg | 2 +- .../resources/MR/images/ic_settings_phone.svg | 2 +- .../resources/MR/images/ic_share.svg | 2 +- .../resources/MR/images/ic_share_filled.svg | 2 +- .../resources/MR/images/ic_shield.svg | 2 +- .../resources/MR/images/ic_smart_display.svg | 2 +- .../resources/MR/images/ic_smartphone.svg | 2 +- .../resources/MR/images/ic_smartphone_300.svg | 2 +- .../resources/MR/images/ic_star.svg | 2 +- .../resources/MR/images/ic_star_filled.svg | 2 +- .../resources/MR/images/ic_star_off.svg | 4 +- .../resources/MR/images/ic_start.svg | 2 +- .../resources/MR/images/ic_stop_filled.svg | 2 +- .../ic_supervised_user_circle_filled.svg | 2 +- .../MR/images/ic_swap_horizontal_circle.svg | 2 +- .../ic_swap_horizontal_circle_filled.svg | 2 +- .../resources/MR/images/ic_sync_problem.svg | 2 +- .../commonMain/resources/MR/images/ic_tag.svg | 2 +- .../resources/MR/images/ic_task.svg | 2 +- .../resources/MR/images/ic_theater_comedy.svg | 2 +- .../MR/images/ic_theater_comedy_filled.svg | 2 +- .../resources/MR/images/ic_timer.svg | 2 +- .../resources/MR/images/ic_timer_filled.svg | 2 +- .../resources/MR/images/ic_toast.svg | 2 +- .../resources/MR/images/ic_toggle_on.svg | 2 +- .../resources/MR/images/ic_translate.svg | 2 +- .../resources/MR/images/ic_travel_explore.svg | 2 +- .../resources/MR/images/ic_upgrade.svg | 2 +- .../resources/MR/images/ic_upload_file.svg | 2 +- .../commonMain/resources/MR/images/ic_usb.svg | 2 +- .../resources/MR/images/ic_verified_user.svg | 2 +- .../resources/MR/images/ic_videocam.svg | 2 +- .../MR/images/ic_videocam_filled.svg | 2 +- .../resources/MR/images/ic_videocam_off.svg | 2 +- .../resources/MR/images/ic_visibility.svg | 2 +- .../MR/images/ic_visibility_filled.svg | 2 +- .../resources/MR/images/ic_visibility_off.svg | 2 +- .../MR/images/ic_visibility_off_filled.svg | 2 +- .../resources/MR/images/ic_volume_down.svg | 2 +- .../resources/MR/images/ic_volume_up.svg | 2 +- .../resources/MR/images/ic_vpn_key_filled.svg | 2 +- .../MR/images/ic_vpn_key_off_filled.svg | 2 +- .../resources/MR/images/ic_warning.svg | 2 +- .../resources/MR/images/ic_warning_filled.svg | 2 +- .../resources/MR/images/ic_wifi.svg | 2 +- .../resources/MR/images/ic_wifi_off.svg | 2 +- .../resources/MR/images/ic_wifi_tethering.svg | 2 +- .../views/usersettings/Appearance.desktop.kt | 8 +-- .../usersettings/SettingsView.desktop.kt | 10 ++- 245 files changed, 401 insertions(+), 394 deletions(-) create mode 100644 apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_down.svg create mode 100644 apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_up.svg delete mode 100644 apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_less.svg delete mode 100644 apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_more.svg diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt index 8d4ab3206a..d05172a7a1 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt @@ -457,7 +457,7 @@ private fun DisabledBackgroundCallsButton() { ) { Text(stringResource(MR.strings.system_restricted_background_in_call_title), color = WarningOrange) Spacer(Modifier.width(8.dp)) - IconButton(onClick = { show = false }, Modifier.size(24.dp)) { + IconButton(onClick = { show = false }, Modifier.size(22.dp)) { Icon(painterResource(MR.images.ic_close), null, tint = WarningOrange) } } @@ -539,7 +539,7 @@ fun CallPermissionsView(pipActive: Boolean, hasVideo: Boolean, cancel: () -> Uni Icon( painterResource(MR.images.ic_call_500), stringResource(MR.strings.permissions_record_audio), - Modifier.size(24.dp), + Modifier.size(22.dp), tint = Color(0xFFFFFFD8) ) } @@ -547,7 +547,7 @@ fun CallPermissionsView(pipActive: Boolean, hasVideo: Boolean, cancel: () -> Uni Icon( painterResource(MR.images.ic_videocam), stringResource(MR.strings.permissions_camera), - Modifier.size(24.dp), + Modifier.size(22.dp), tint = Color(0xFFFFFFD8) ) } diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt index 0c105a1da1..b985601962 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt @@ -13,12 +13,15 @@ import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme.colors import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import dev.icerock.moko.resources.compose.stringResource @@ -112,13 +115,13 @@ fun AppearanceScope.AppearanceLayout( } } - SectionDividerSpaced(maxTopPadding = true) + SectionDividerSpaced() ThemesSection(systemDarkTheme) - SectionDividerSpaced(maxTopPadding = true) + SectionDividerSpaced() ProfileImageSection() - SectionDividerSpaced() + SectionDividerSpaced(maxTopPadding = true) SectionView(stringResource(MR.strings.settings_section_title_icon), padding = PaddingValues(horizontal = DEFAULT_PADDING_HALF)) { LazyRow { @@ -129,7 +132,8 @@ fun AppearanceScope.AppearanceLayout( contentDescription = "", contentScale = ContentScale.Fit, modifier = Modifier - .shadow(if (item == icon.value) 1.dp else 0.dp, ambientColor = colors.secondaryVariant) + .border(1.dp, color = if (item == icon.value) colors.secondaryVariant else Color.Transparent, RoundedCornerShape(percent = 22)) + .clip(RoundedCornerShape(percent = 22)) .size(70.dp) .clickable { changeIcon(item) } .padding(10.dp) @@ -143,7 +147,7 @@ fun AppearanceScope.AppearanceLayout( } } - SectionDividerSpaced(maxBottomPadding = true) + SectionDividerSpaced(maxTopPadding = true) FontScaleSection() SectionBottomSpacer() diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.android.kt index f2c3d86ab5..38818a123d 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.android.kt @@ -19,9 +19,9 @@ actual fun SettingsSectionApp( withAuth: (title: String, desc: String, block: () -> Unit) -> Unit ) { SectionView(stringResource(MR.strings.settings_section_title_app)) { - SettingsActionItem(painterResource(MR.images.ic_restart_alt), stringResource(MR.strings.settings_restart_app), ::restartApp, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_power_settings_new), stringResource(MR.strings.settings_shutdown), { shutdownAppAlert(::shutdownApp) }, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_code), stringResource(MR.strings.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_restart_alt), stringResource(MR.strings.settings_restart_app), ::restartApp) + SettingsActionItem(painterResource(MR.images.ic_power_settings_new), stringResource(MR.strings.settings_shutdown), { shutdownAppAlert(::shutdownApp) }) + SettingsActionItem(painterResource(MR.images.ic_code), stringResource(MR.strings.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }) AppVersionItem(showVersion) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt index fb922fe52b..595c22e3e2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt @@ -607,6 +607,8 @@ val DEFAULT_SPACE_AFTER_ICON = 4.dp val DEFAULT_PADDING_HALF = DEFAULT_PADDING / 2 val DEFAULT_BOTTOM_PADDING = 48.dp val DEFAULT_BOTTOM_BUTTON_PADDING = 20.dp +val DEFAULT_MIN_SECTION_ITEM_HEIGHT = 50.dp +val DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL = 15.dp val DEFAULT_START_MODAL_WIDTH = 388.dp val DEFAULT_MIN_CENTER_MODAL_WIDTH = 590.dp diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt index 5d9b33d416..24416ff49e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt @@ -599,7 +599,7 @@ fun ChatInfoLayout( } } } - SectionDividerSpaced() + SectionDividerSpaced(maxBottomPadding = false) val conn = contact.activeConn if (conn != null) { @@ -616,7 +616,7 @@ fun ChatInfoLayout( ShareAddressButton { clipboard.shareText(simplexChatLink(contact.contactLink)) } SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(contact.displayName)) } - SectionDividerSpaced() + SectionDividerSpaced(maxTopPadding = true) } if (contact.ready && contact.active) { @@ -650,7 +650,7 @@ fun ChatInfoLayout( } } } - SectionDividerSpaced() + SectionDividerSpaced(maxBottomPadding = false) } SectionView { @@ -970,7 +970,7 @@ fun InfoViewActionButton( Icon( icon, contentDescription = null, - Modifier.size(24.dp * fontSizeSqrtMultiplier), + Modifier.size(22.dp * fontSizeSqrtMultiplier), tint = if (disabledLook) MaterialTheme.colors.secondary else MaterialTheme.colors.onPrimary ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt index a5593693c0..d0e972965a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt @@ -224,7 +224,7 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools Row( Modifier .fillMaxWidth() - .sizeIn(minHeight = 46.dp) + .sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT) .padding(PaddingValues(horizontal = DEFAULT_PADDING)) .clickable { expanded.value = !expanded.value }, horizontalArrangement = Arrangement.spacedBy(12.dp), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt index f7f0a55372..725367e150 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt @@ -93,22 +93,22 @@ private fun ContactPreferencesLayout( TimedMessagesFeatureSection(featuresAllowed, contact.mergedPreferences.timedMessages, timedMessages, onTTLUpdated) { allowed, ttl -> applyPrefs(featuresAllowed.copy(timedMessagesAllowed = allowed, timedMessagesTTL = ttl ?: currentFeaturesAllowed.timedMessagesTTL)) } - SectionDividerSpaced(true, maxBottomPadding = false) + SectionDividerSpaced(true) val allowFullDeletion: MutableState = remember(featuresAllowed) { mutableStateOf(featuresAllowed.fullDelete) } FeatureSection(ChatFeature.FullDelete, user.fullPreferences.fullDelete.allow, contact.mergedPreferences.fullDelete, allowFullDeletion) { applyPrefs(featuresAllowed.copy(fullDelete = it)) } - SectionDividerSpaced(true, maxBottomPadding = false) + SectionDividerSpaced(true) val allowReactions: MutableState = remember(featuresAllowed) { mutableStateOf(featuresAllowed.reactions) } FeatureSection(ChatFeature.Reactions, user.fullPreferences.reactions.allow, contact.mergedPreferences.reactions, allowReactions) { applyPrefs(featuresAllowed.copy(reactions = it)) } - SectionDividerSpaced(true, maxBottomPadding = false) + SectionDividerSpaced(true) val allowVoice: MutableState = remember(featuresAllowed) { mutableStateOf(featuresAllowed.voice) } FeatureSection(ChatFeature.Voice, user.fullPreferences.voice.allow, contact.mergedPreferences.voice, allowVoice) { applyPrefs(featuresAllowed.copy(voice = it)) } - SectionDividerSpaced(true, maxBottomPadding = false) + SectionDividerSpaced(true) val allowCalls: MutableState = remember(featuresAllowed) { mutableStateOf(featuresAllowed.calls) } FeatureSection(ChatFeature.Calls, user.fullPreferences.calls.allow, contact.mergedPreferences.calls, allowCalls) { applyPrefs(featuresAllowed.copy(calls = it)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt index 9934d853f3..2aebe07306 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SelectableChatItemToolbars.kt @@ -66,7 +66,7 @@ fun SelectedItemsBottomToolbar( Icon( painterResource(MR.images.ic_delete), null, - Modifier.size(24.dp), + Modifier.size(22.dp), tint = if (!deleteEnabled.value || allButtonsDisabled.value) MaterialTheme.colors.secondary else MaterialTheme.colors.error ) } @@ -75,7 +75,7 @@ fun SelectedItemsBottomToolbar( Icon( painterResource(MR.images.ic_flag), null, - Modifier.size(24.dp), + Modifier.size(22.dp), tint = if (!moderateEnabled.value || allButtonsDisabled.value) MaterialTheme.colors.secondary else MaterialTheme.colors.error ) } @@ -84,7 +84,7 @@ fun SelectedItemsBottomToolbar( Icon( painterResource(MR.images.ic_share), null, - Modifier.size(24.dp), + Modifier.size(22.dp), tint = if (allButtonsDisabled.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt index a7562ff3b5..18a3a0d14d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt @@ -4,6 +4,7 @@ import SectionBottomSpacer import SectionCustomFooter import SectionDividerSpaced import SectionItemView +import SectionItemViewWithoutMinPadding import SectionSpacer import SectionView import androidx.compose.foundation.* @@ -177,7 +178,7 @@ fun AddGroupMembersLayout( InviteSectionFooter(selectedContactsCount = selectedContacts.size, allowModifyMembers, clearSelection) } SectionDividerSpaced(maxTopPadding = true) - SectionView(stringResource(MR.strings.select_contacts)) { + SectionView(stringResource(MR.strings.select_contacts).uppercase()) { SectionItemView(padding = PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF)) { SearchRowView(searchText) } @@ -255,7 +256,8 @@ fun InviteSectionFooter(selectedContactsCount: Int, enabled: Boolean, clearSelec Text( String.format(generalGetString(MR.strings.num_contacts_selected), selectedContactsCount), color = MaterialTheme.colors.secondary, - fontSize = 12.sp + lineHeight = 18.sp, + fontSize = 14.sp ) Box( Modifier.clickable { if (enabled) clearSelection() } @@ -263,14 +265,16 @@ fun InviteSectionFooter(selectedContactsCount: Int, enabled: Boolean, clearSelec Text( stringResource(MR.strings.clear_contacts_selection_button), color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, - fontSize = 12.sp + lineHeight = 18.sp, + fontSize = 14.sp, ) } } else { Text( stringResource(MR.strings.no_contacts_selected), color = MaterialTheme.colors.secondary, - fontSize = 12.sp + lineHeight = 18.sp, + fontSize = 14.sp, ) } } @@ -318,7 +322,7 @@ fun ContactCheckRow( icon = painterResource(MR.images.ic_circle) iconColor = MaterialTheme.colors.secondary } - SectionItemView( + SectionItemViewWithoutMinPadding( click = if (enabled) { { if (prohibitedToInviteIncognito) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt index ea07231eb0..9b1bb45d8f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt @@ -365,7 +365,7 @@ fun GroupChatInfoLayout( SearchRowView(searchText) } } - SectionItemView(minHeight = 54.dp) { + SectionItemView(minHeight = 54.dp, padding = PaddingValues(horizontal = DEFAULT_PADDING)) { MemberRow(groupInfo.membership, user = true) } } @@ -373,7 +373,7 @@ fun GroupChatInfoLayout( items(filteredMembers.value) { member -> Divider() val showMenu = remember { mutableStateOf(false) } - SectionItemViewLongClickable({ showMemberInfo(member) }, { showMenu.value = true }, minHeight = 54.dp) { + SectionItemViewLongClickable({ showMemberInfo(member) }, { showMenu.value = true }, minHeight = 54.dp, padding = PaddingValues(horizontal = DEFAULT_PADDING)) { DropDownMenuForMember(chat.remoteHostId, member, groupInfo, showMenu) MemberRow(member, onClick = { showMemberInfo(member) }) } @@ -513,7 +513,7 @@ private fun MemberRow(member: GroupMember, user: Boolean = false, onClick: (() - verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - MemberProfileImage(size = 46.dp, member) + MemberProfileImage(size = DEFAULT_MIN_SECTION_ITEM_HEIGHT, member) Spacer(Modifier.width(DEFAULT_PADDING_HALF)) Column { Row(verticalAlignment = Alignment.CenterVertically) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt index 794d6d4a20..b6312e4d82 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt @@ -133,13 +133,7 @@ private fun GroupWelcomeLayout( val clipboard = LocalClipboardManager.current CopyTextButton { clipboard.setText(AnnotatedString(wt.value)) } - Divider( - Modifier.padding( - start = DEFAULT_PADDING_HALF, - top = 8.dp, - end = DEFAULT_PADDING_HALF, - bottom = 8.dp) - ) + SectionDividerSpaced(maxBottomPadding = false) SaveButton( save = save, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 6f595e2ccf..11b1006f41 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -219,7 +219,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf backgroundColor = if (!stopped) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, contentColor = Color.White ) { - Icon(painterResource(MR.images.ic_edit_filled), stringResource(MR.strings.add_contact_or_create_group), Modifier.size(24.dp * fontSizeSqrtMultiplier)) + Icon(painterResource(MR.images.ic_edit_filled), stringResource(MR.strings.add_contact_or_create_group), Modifier.size(22.dp * fontSizeSqrtMultiplier)) } } } @@ -520,7 +520,7 @@ private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState Icon( painterResource(MR.images.ic_search), contentDescription = null, - Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF).size(24.dp * fontSizeSqrtMultiplier), + Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF).size(22.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.secondary ) SearchTextField( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt index f5343efc18..6219252b54 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ServersSummaryView.kt @@ -546,15 +546,19 @@ fun XFTPServerSummaryLayout(summary: XFTPServerSummary, statsStartedAt: Instant, }) { Text(generalGetString(MR.strings.open_server_settings_button)) } + if (summary.stats != null || summary.sessions != null) { + SectionDividerSpaced() + } } if (summary.stats != null) { - SectionDividerSpaced() XFTPStatsView(stats = summary.stats, rh = rh, statsStartedAt = statsStartedAt) + if (summary.sessions != null) { + SectionDividerSpaced(maxTopPadding = true) + } } if (summary.sessions != null) { - SectionDividerSpaced() ServerSessionsView(summary.sessions) } } @@ -581,20 +585,24 @@ fun SMPServerSummaryLayout(summary: SMPServerSummary, statsStartedAt: Instant, r }) { Text(generalGetString(MR.strings.open_server_settings_button)) } + SectionDividerSpaced() } if (summary.stats != null) { - SectionDividerSpaced() SMPStatsView(stats = summary.stats, remoteHostInfo = rh, statsStartedAt = statsStartedAt) + if (summary.subs != null || summary.sessions != null) { + SectionDividerSpaced(maxTopPadding = true) + } } if (summary.subs != null) { - SectionDividerSpaced() SMPSubscriptionsSection(subs = summary.subs, summary = summary, rh = rh) + if (summary.sessions != null) { + SectionDividerSpaced() + } } if (summary.sessions != null) { - SectionDividerSpaced() ServerSessionsView(summary.sessions) } } @@ -854,7 +862,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta val statsStartedAt = it.statsStartedAt SMPStatsView(totals.stats, statsStartedAt, rh) - SectionDividerSpaced() + SectionDividerSpaced(maxTopPadding = true) SMPSubscriptionsSection(totals) SectionDividerSpaced() @@ -886,7 +894,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta footer = generalGetString(MR.strings.servers_info_proxied_servers_section_footer), rh = rh ) - SectionDividerSpaced() + SectionDividerSpaced(maxTopPadding = true) } ServerSessionsView(totals.sessions) @@ -903,7 +911,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta val previouslyUsedXFTPServers = xftpSummary.previouslyUsedXFTPServers XFTPStatsView(totals.stats, statsStartedAt, rh) - SectionDividerSpaced() + SectionDividerSpaced(maxTopPadding = true) if (currentlyUsedXFTPServers.isNotEmpty()) { XFTPServersListView( @@ -930,7 +938,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta } } - SectionDividerSpaced() + SectionDividerSpaced(maxBottomPadding = false) SectionView { ReconnectAllServersButton(rh) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt index dad3192e45..e15bc3863e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt @@ -262,7 +262,7 @@ fun UserProfilePickerItem( Row( Modifier .fillMaxWidth() - .sizeIn(minHeight = 46.dp) + .sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT) .combinedClickable( enabled = enabled, onClick = if (u.activeUser) openSettings else onClick, @@ -330,7 +330,7 @@ fun RemoteHostPickerItem(h: RemoteHostInfo, onLongClick: () -> Unit = {}, action Modifier .fillMaxWidth() .background(color = if (h.activeHost) MaterialTheme.colors.surface.mixWith(MaterialTheme.colors.onBackground, 0.95f) else Color.Unspecified) - .sizeIn(minHeight = 46.dp) + .sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT) .combinedClickable( onClick = onClick, onLongClick = onLongClick @@ -373,7 +373,7 @@ fun LocalDevicePickerItem(active: Boolean, onLongClick: () -> Unit = {}, onClick Modifier .fillMaxWidth() .background(color = if (active) MaterialTheme.colors.surface.mixWith(MaterialTheme.colors.onBackground, 0.95f) else Color.Unspecified) - .sizeIn(minHeight = 46.dp) + .sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT) .combinedClickable( onClick = if (active) {{}} else onClick, onLongClick = onLongClick, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt index 87ee0723f8..333fda307a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt @@ -195,7 +195,7 @@ fun DatabaseLayout( stringResource(MR.strings.stop_chat_to_enable_database_actions) } ) - SectionDividerSpaced() + SectionDividerSpaced(maxTopPadding = true) } SectionView(stringResource(MR.strings.chat_database_section)) { @@ -264,7 +264,7 @@ fun DatabaseLayout( disabled = operationsDisabled ) } - SectionDividerSpaced(maxTopPadding = true) + SectionDividerSpaced() SectionView(stringResource(MR.strings.files_and_media_section).uppercase()) { val deleteFilesDisabled = operationsDisabled || appFilesCountAndSize.value.first == 0 diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultSwitch.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultSwitch.kt index 75abc67b46..79255fb0bf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultSwitch.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultSwitch.kt @@ -25,9 +25,9 @@ fun DefaultSwitch( ) ) { val color = if (checked) MaterialTheme.colors.primary.copy(alpha = 0.3f) else MaterialTheme.colors.secondary.copy(alpha = 0.3f) - val size = with(LocalDensity.current) { Size(46.dp.toPx(), 28.dp.toPx()) } - val offset = with(LocalDensity.current) { Offset(1.dp.toPx(), 10.dp.toPx()) } - val radius = with(LocalDensity.current) { 28.dp.toPx() } + val size = with(LocalDensity.current) { Size(40.dp.toPx(), 26.dp.toPx()) } + val offset = with(LocalDensity.current) { Offset(4.dp.toPx(), 11.dp.toPx()) } + val radius = with(LocalDensity.current) { 13.dp.toPx() } Switch( checked = checked, onCheckedChange = onCheckedChange, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt index 7e57bda928..4141fd2ead 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt @@ -50,7 +50,7 @@ fun ExposedDropDownSetting( ) Spacer(Modifier.size(12.dp)) Icon( - if (!expanded.value) painterResource(MR.images.ic_expand_more) else painterResource(MR.images.ic_expand_less), + if (!expanded.value) painterResource(MR.images.ic_arrow_drop_down) else painterResource(MR.images.ic_arrow_drop_up), generalGetString(MR.strings.icon_descr_more_button), tint = MaterialTheme.colors.secondary ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt index d3a3a0ff9c..facecd2398 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt @@ -12,7 +12,6 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.* -import chat.simplex.common.model.NotificationsMode import chat.simplex.common.platform.onRightClick import chat.simplex.common.platform.windowWidth import chat.simplex.common.ui.theme.* @@ -20,7 +19,6 @@ import chat.simplex.common.views.helpers.* import chat.simplex.common.views.onboarding.SelectableCard import chat.simplex.common.views.usersettings.SettingsActionItemWithContent import chat.simplex.res.MR -import dev.icerock.moko.resources.compose.stringResource @Composable fun SectionView(title: String? = null, padding: PaddingValues = PaddingValues(), content: (@Composable ColumnScope.() -> Unit)) { @@ -28,7 +26,7 @@ fun SectionView(title: String? = null, padding: PaddingValues = PaddingValues(), if (title != null) { Text( title, color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, - modifier = Modifier.padding(start = DEFAULT_PADDING, bottom = 5.dp), fontSize = 12.sp + modifier = Modifier.padding(start = DEFAULT_PADDING, bottom = DEFAULT_PADDING), fontSize = 12.sp ) } Column(Modifier.padding(padding).fillMaxWidth()) { content() } @@ -101,13 +99,13 @@ fun SectionViewSelectableCards( @Composable fun SectionItemView( click: (() -> Unit)? = null, - minHeight: Dp = 46.dp, + minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT, disabled: Boolean = false, extraPadding: Boolean = false, padding: PaddingValues = if (extraPadding) - PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING) + PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING, top = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL, bottom = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL) else - PaddingValues(horizontal = DEFAULT_PADDING), + PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL), content: (@Composable RowScope.() -> Unit) ) { val modifier = Modifier @@ -122,10 +120,9 @@ fun SectionItemView( } @Composable -fun SectionItemViewLongClickable( - click: () -> Unit, - longClick: () -> Unit, - minHeight: Dp = 46.dp, +fun SectionItemViewWithoutMinPadding( + click: (() -> Unit)? = null, + minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT, disabled: Boolean = false, extraPadding: Boolean = false, padding: PaddingValues = if (extraPadding) @@ -133,6 +130,22 @@ fun SectionItemViewLongClickable( else PaddingValues(horizontal = DEFAULT_PADDING), content: (@Composable RowScope.() -> Unit) +) { + SectionItemView(click, minHeight, disabled, extraPadding, padding, content) +} + +@Composable +fun SectionItemViewLongClickable( + click: () -> Unit, + longClick: () -> Unit, + minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT, + disabled: Boolean = false, + extraPadding: Boolean = false, + padding: PaddingValues = if (extraPadding) + PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING, top = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL, bottom = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL) + else + PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL), + content: (@Composable RowScope.() -> Unit) ) { val modifier = Modifier .fillMaxWidth() @@ -149,30 +162,11 @@ fun SectionItemViewLongClickable( } } -@Composable -fun SectionItemViewWithIcon( - click: (() -> Unit)? = null, - minHeight: Dp = 46.dp, - disabled: Boolean = false, - padding: PaddingValues = PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING), - content: (@Composable RowScope.() -> Unit) -) { - val modifier = Modifier - .fillMaxWidth() - .sizeIn(minHeight = minHeight) - Row( - if (click == null || disabled) modifier.padding(padding) else modifier.clickable(onClick = click).padding(padding), - verticalAlignment = Alignment.CenterVertically - ) { - content() - } -} - @Composable fun SectionItemViewSpaceBetween( click: (() -> Unit)? = null, onLongClick: (() -> Unit)? = null, - minHeight: Dp = 46.dp, + minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT, padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING), disabled: Boolean = false, content: (@Composable RowScope.() -> Unit) @@ -181,7 +175,7 @@ fun SectionItemViewSpaceBetween( .fillMaxWidth() .sizeIn(minHeight = minHeight) Row( - if (click == null || disabled) modifier.padding(padding) else modifier + if (click == null || disabled) modifier.padding(padding).padding(vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL) else modifier .combinedClickable(onClick = click, onLongClick = onLongClick).padding(padding) .onRightClick { onLongClick?.invoke() }, horizontalArrangement = Arrangement.SpaceBetween, @@ -254,9 +248,9 @@ fun SectionDividerSpaced(maxTopPadding: Boolean = false, maxBottomPadding: Boole Divider( Modifier.padding( start = DEFAULT_PADDING_HALF, - top = if (maxTopPadding) 37.dp else 27.dp, + top = if (maxTopPadding) DEFAULT_PADDING + 18.dp else DEFAULT_PADDING + 2.dp, end = DEFAULT_PADDING_HALF, - bottom = if (maxBottomPadding) 37.dp else 27.dp) + bottom = if (maxBottomPadding) DEFAULT_PADDING + 18.dp else DEFAULT_PADDING + 2.dp) ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ThemeModeEditor.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ThemeModeEditor.kt index 24f9bf539b..a77290d90f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ThemeModeEditor.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ThemeModeEditor.kt @@ -1,6 +1,7 @@ package chat.simplex.common.views.helpers import SectionBottomSpacer +import SectionDividerSpaced import SectionItemView import SectionSpacer import SectionView @@ -203,11 +204,12 @@ fun ModalData.UserWallpaperEditor( } ) - SectionSpacer() + SectionDividerSpaced() AppearanceScope.CustomizeThemeColorsSection(currentTheme, editColor = editColor) - SectionSpacer() + SectionDividerSpaced(maxBottomPadding = false) + ImportExportThemeSection(null, remember { chatModel.currentUser }.value?.uiThemes) { withBGApi { themeModeOverride.value = it @@ -440,11 +442,11 @@ fun ModalData.ChatWallpaperEditor( } ) - SectionSpacer() + SectionDividerSpaced() AppearanceScope.CustomizeThemeColorsSection(currentTheme, editColor = editColor) - SectionSpacer() + SectionDividerSpaced(maxBottomPadding = false) ImportExportThemeSection(themeModeOverride.value, remember { chatModel.currentUser }.value?.uiThemes) { withBGApi { themeModeOverride.value = it diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt index 09a6c447d5..88e483e92d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt @@ -142,7 +142,7 @@ private fun ContactConnectionInfoLayout( } SectionTextFooter(sharedProfileInfo(chatModel, contactConnection.incognito)) - SectionDividerSpaced(maxBottomPadding = false) + SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false) DeleteButton(deleteConnection) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 3146c14589..0621c5509f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -262,13 +262,13 @@ private fun NewChatSheetLayout( } } } - SectionDividerSpaced(maxBottomPadding = false) val deletedContactTypes = listOf(ContactType.CHAT_DELETED) val deletedChats by remember(chatModel.chats.value, deletedContactTypes) { derivedStateOf { filterContactTypes(chatModel.chats.value, deletedContactTypes) } } if (deletedChats.isNotEmpty()) { + SectionDividerSpaced(maxBottomPadding = false) Row(modifier = sectionModifier) { SectionView { SectionItemView( @@ -295,16 +295,20 @@ private fun NewChatSheetLayout( } } } - SectionDividerSpaced(maxBottomPadding = false) } } } item { if (filteredContactChats.isNotEmpty() && !oneHandUI.value) { + if (searchText.value.text.isNotEmpty()) { + Spacer(Modifier.height(DEFAULT_PADDING)) + } else { + SectionDividerSpaced() + } Text( stringResource(MR.strings.contact_list_header_title).uppercase(), color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, - modifier = sectionModifier.padding(start = DEFAULT_PADDING, top = DEFAULT_PADDING_HALF, bottom = DEFAULT_PADDING_HALF), fontSize = 12.sp + modifier = sectionModifier.padding(start = DEFAULT_PADDING, bottom = DEFAULT_PADDING_HALF), fontSize = 12.sp ) } } @@ -364,7 +368,7 @@ private fun ContactsSearchBar( Icon( painterResource(MR.images.ic_search), contentDescription = null, - Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF).size(24.dp * fontSizeSqrtMultiplier), + Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF).size(22.dp * fontSizeSqrtMultiplier), tint = MaterialTheme.colors.secondary ) SearchTextField( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt index a872f2548d..419d3b6ed7 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt @@ -293,7 +293,7 @@ private fun PasteLinkView(rhId: Long?, pastedLink: MutableState, showQRC @Composable fun LinkTextView(link: String, share: Boolean) { val clipboard = LocalClipboardManager.current - Row(Modifier.fillMaxWidth().heightIn(min = 46.dp).padding(horizontal = DEFAULT_PADDING), verticalAlignment = Alignment.CenterVertically) { + Row(Modifier.fillMaxWidth().heightIn(min = DEFAULT_MIN_SECTION_ITEM_HEIGHT).padding(horizontal = DEFAULT_PADDING), verticalAlignment = Alignment.CenterVertically) { Box(Modifier.weight(1f).clickable { chatModel.markShowingInvitationUsed() clipboard.shareText(link) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt index ed68c7b013..3c8ab2b70a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt @@ -446,7 +446,7 @@ fun IntSettingRow(title: String, selection: MutableState, values: List ) Spacer(Modifier.size(4.dp)) Icon( - if (!expanded.value) painterResource(MR.images.ic_expand_more) else painterResource(MR.images.ic_expand_less), + if (!expanded.value) painterResource(MR.images.ic_arrow_drop_down) else painterResource(MR.images.ic_arrow_drop_up), generalGetString(MR.strings.invite_to_group_button), modifier = Modifier.padding(start = 8.dp), tint = MaterialTheme.colors.secondary @@ -506,7 +506,7 @@ fun TimeoutSettingRow(title: String, selection: MutableState, values: List ) Spacer(Modifier.size(4.dp)) Icon( - if (!expanded.value) painterResource(MR.images.ic_expand_more) else painterResource(MR.images.ic_expand_less), + if (!expanded.value) painterResource(MR.images.ic_arrow_drop_down) else painterResource(MR.images.ic_arrow_drop_up), generalGetString(MR.strings.invite_to_group_button), modifier = Modifier.padding(start = 8.dp), tint = MaterialTheme.colors.secondary diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt index 5fda4b7d1d..d8993307d2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt @@ -549,13 +549,13 @@ object AppearanceScope { }, ) } - SectionDividerSpaced(maxTopPadding = true) + SectionDividerSpaced() CustomizeThemeColorsSection(currentTheme) { name -> editColor(name) } - SectionSpacer() + SectionDividerSpaced(maxBottomPadding = false) val currentOverrides = remember(currentTheme) { ThemeManager.defaultActiveTheme(appPrefs.themeOverrides.get()) } val canResetColors = currentTheme.base.hasChangedAnyColor(currentOverrides) @@ -889,7 +889,7 @@ object AppearanceScope { val hexTrimmed = currentColor.toReadableHex().replaceFirst("#ff", "#") val savedColor by remember(wallpaperType) { mutableStateOf(initialColor) } - Row(Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).height(46.dp)) { + Row(Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).height(DEFAULT_MIN_SECTION_ITEM_HEIGHT)) { Box(Modifier.weight(1f).fillMaxHeight().background(savedColor).clickable { currentColor = savedColor onColorChange(currentColor) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt index 8a6e4efe32..9dfdf23085 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt @@ -1,6 +1,7 @@ package chat.simplex.common.views.usersettings import SectionBottomSpacer +import SectionDividerSpaced import SectionSpacer import SectionTextFooter import SectionView @@ -43,7 +44,7 @@ fun DeveloperView( ) } if (devTools.value) { - SectionSpacer() + SectionDividerSpaced(maxTopPadding = true) SectionView(stringResource(MR.strings.developer_options_section).uppercase()) { SettingsPreferenceItem(painterResource(MR.images.ic_drive_folder_upload), stringResource(MR.strings.confirm_database_upgrades), m.controller.appPrefs.confirmDBUpgrades) if (appPlatform.isDesktop) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt index c60e8e6bf4..b97a686e22 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt @@ -3,6 +3,7 @@ package chat.simplex.common.views.usersettings import SectionBottomSpacer import SectionItemView import SectionItemViewSpaceBetween +import SectionItemViewWithoutMinPadding import SectionSpacer import SectionTextFooter import SectionView @@ -74,10 +75,10 @@ private fun HiddenProfileLayout( val confirmValid by remember { derivedStateOf { confirmHidePassword.value == "" || hidePassword.value == confirmHidePassword.value } } val saveDisabled by remember { derivedStateOf { hidePassword.value == "" || !passwordValid || confirmHidePassword.value == "" || !confirmValid } } SectionView(stringResource(MR.strings.hidden_profile_password).uppercase()) { - SectionItemView { + SectionItemViewWithoutMinPadding { PassphraseField(hidePassword, generalGetString(MR.strings.password_to_show), isValid = { passwordValid }, showStrength = true) } - SectionItemView { + SectionItemViewWithoutMinPadding { PassphraseField(confirmHidePassword, stringResource(MR.strings.confirm_password), isValid = { confirmValid }, dependsOn = hidePassword) } SectionItemViewSpaceBetween({ saveProfilePassword(hidePassword.value) }, disabled = saveDisabled, minHeight = TextFieldDefaults.MinHeight) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt index 62ba287879..74e6bf5910 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt @@ -264,30 +264,26 @@ fun SocksProxySettings( .fillMaxWidth() ) { AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings)) - SectionView { - SectionItemView { - DefaultConfigurableTextField( - hostUnsaved, - stringResource(MR.strings.host_verb), - modifier = Modifier.fillMaxWidth(), - isValid = ::validHost, - keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), - keyboardType = KeyboardType.Text, - ) - } - SectionItemView { - DefaultConfigurableTextField( - portUnsaved, - stringResource(MR.strings.port_verb), - modifier = Modifier.fillMaxWidth(), - isValid = ::validPort, - keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done); save() }), - keyboardType = KeyboardType.Number, - ) - } + SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) { + DefaultConfigurableTextField( + hostUnsaved, + stringResource(MR.strings.host_verb), + modifier = Modifier.fillMaxWidth(), + isValid = ::validHost, + keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), + keyboardType = KeyboardType.Text, + ) + DefaultConfigurableTextField( + portUnsaved, + stringResource(MR.strings.port_verb), + modifier = Modifier.fillMaxWidth(), + isValid = ::validPort, + keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done); save() }), + keyboardType = KeyboardType.Number, + ) } - Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 27.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp)) + SectionDividerSpaced(maxBottomPadding = false) SectionView { SectionItemView({ diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt index 578a505e0c..084dfc20d2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt @@ -104,13 +104,13 @@ fun PrivacySettingsView( } SettingsPreferenceItem(painterResource(MR.images.ic_security), stringResource(MR.strings.protect_ip_address), chatModel.controller.appPrefs.privacyAskToApproveRelays) } - SectionCustomFooter { + SectionTextFooter( if (chatModel.controller.appPrefs.privacyAskToApproveRelays.state.value) { - Text(stringResource(MR.strings.app_will_ask_to_confirm_unknown_file_servers)) + stringResource(MR.strings.app_will_ask_to_confirm_unknown_file_servers) } else { - Text(stringResource(MR.strings.without_tor_or_vpn_ip_address_will_be_visible_to_file_servers)) + stringResource(MR.strings.without_tor_or_vpn_ip_address_will_be_visible_to_file_servers) } - } + ) val currentUser = chatModel.currentUser.value if (currentUser != null) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt index 88018dd1c9..3a1a1cb8f3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt @@ -110,7 +110,7 @@ private fun PresetServer( ) } } - SectionDividerSpaced(maxTopPadding = true) + SectionDividerSpaced() UseServerSection(true, testing, server, testServer, onUpdate, onDelete) } @@ -150,7 +150,7 @@ private fun CustomServer( } } } - SectionDividerSpaced() + SectionDividerSpaced(maxTopPadding = true) UseServerSection(valid.value, testing, server, testServer, onUpdate, onDelete) if (valid.value) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt index 6c07a9ceeb..b50e905f39 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt @@ -3,7 +3,6 @@ package chat.simplex.common.views.usersettings import SectionBottomSpacer import SectionDividerSpaced import SectionItemView -import SectionItemViewWithIcon import SectionView import TextIconSpaced import androidx.compose.desktop.ui.tooling.preview.Preview @@ -124,8 +123,8 @@ fun SettingsLayout( SectionItemView(showCustomModal { chatModel, close -> UserProfileView(chatModel, close) }, 80.dp, padding = PaddingValues(start = 16.dp, end = DEFAULT_PADDING), disabled = stopped) { ProfilePreview(profile, stopped = stopped) } - SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.your_chat_profiles), { withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden, drawerState) } } }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.your_chat_profiles), { withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden, drawerState) } } }, disabled = stopped) + SettingsActionItem(painterResource(MR.images.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped) ChatPreferencesItem(showCustomModal, stopped = stopped) } else if (chatModel.localUserCreated.value == false) { SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.create_chat_profile), { @@ -137,35 +136,35 @@ fun SettingsLayout( CreateProfile(chatModel, close) } } - }, disabled = stopped, extraPadding = true) + }, disabled = stopped) } if (appPlatform.isDesktop) { - SettingsActionItem(painterResource(MR.images.ic_smartphone), stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles), showModal { ConnectMobileView() }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_smartphone), stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles), showModal { ConnectMobileView() }, disabled = stopped) } else { - SettingsActionItem(painterResource(MR.images.ic_desktop), stringResource(MR.strings.settings_section_title_use_from_desktop), showCustomModal { it, close -> ConnectDesktopView(close) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_desktop), stringResource(MR.strings.settings_section_title_use_from_desktop), showCustomModal { it, close -> ConnectDesktopView(close) }, disabled = stopped) } - SettingsActionItem(painterResource(MR.images.ic_ios_share), stringResource(MR.strings.migrate_from_device_to_another_device), { withAuth(generalGetString(MR.strings.auth_open_migration_to_another_device), generalGetString(MR.strings.auth_log_in_using_credential)) { ModalManager.fullscreen.showCustomModal { close -> MigrateFromDeviceView(close) } } }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_ios_share), stringResource(MR.strings.migrate_from_device_to_another_device), { withAuth(generalGetString(MR.strings.auth_open_migration_to_another_device), generalGetString(MR.strings.auth_log_in_using_credential)) { ModalManager.fullscreen.showCustomModal { close -> MigrateFromDeviceView(close) } } }, disabled = stopped) } SectionDividerSpaced() SectionView(stringResource(MR.strings.settings_section_title_settings)) { - SettingsActionItem(painterResource(if (notificationsMode.value == NotificationsMode.OFF) MR.images.ic_bolt_off else MR.images.ic_bolt), stringResource(MR.strings.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_wifi_tethering), stringResource(MR.strings.network_and_servers), showSettingsModal { NetworkAndServersView() }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_videocam), stringResource(MR.strings.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.privacy_and_security), showSettingsModal { PrivacySettingsView(it, showSettingsModal, setPerformLA) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_light_mode), stringResource(MR.strings.appearance_settings), showSettingsModal { AppearanceView(it) }, extraPadding = true) + SettingsActionItem(painterResource(if (notificationsMode.value == NotificationsMode.OFF) MR.images.ic_bolt_off else MR.images.ic_bolt), stringResource(MR.strings.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped) + SettingsActionItem(painterResource(MR.images.ic_wifi_tethering), stringResource(MR.strings.network_and_servers), showSettingsModal { NetworkAndServersView() }, disabled = stopped) + SettingsActionItem(painterResource(MR.images.ic_videocam), stringResource(MR.strings.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped) + SettingsActionItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.privacy_and_security), showSettingsModal { PrivacySettingsView(it, showSettingsModal, setPerformLA) }, disabled = stopped) + SettingsActionItem(painterResource(MR.images.ic_light_mode), stringResource(MR.strings.appearance_settings), showSettingsModal { AppearanceView(it) }) DatabaseItem(encrypted, passphraseSaved, showSettingsModal { DatabaseView(it, showSettingsModal) }, stopped) } SectionDividerSpaced() SectionView(stringResource(MR.strings.settings_section_title_help)) { - SettingsActionItem(painterResource(MR.images.ic_help), stringResource(MR.strings.how_to_use_simplex_chat), showModal { HelpView(userDisplayName ?: "") }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_add), stringResource(MR.strings.whats_new), showCustomModal { _, close -> WhatsNewView(viaSettings = true, close) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(MR.images.ic_info), stringResource(MR.strings.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_help), stringResource(MR.strings.how_to_use_simplex_chat), showModal { HelpView(userDisplayName ?: "") }, disabled = stopped) + SettingsActionItem(painterResource(MR.images.ic_add), stringResource(MR.strings.whats_new), showCustomModal { _, close -> WhatsNewView(viaSettings = true, close) }, disabled = stopped) + SettingsActionItem(painterResource(MR.images.ic_info), stringResource(MR.strings.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }) if (!chatModel.desktopNoUserNoRemote) { - SettingsActionItem(painterResource(MR.images.ic_tag), stringResource(MR.strings.chat_with_the_founder), { uriHandler.openVerifiedSimplexUri(simplexTeamUri) }, textColor = MaterialTheme.colors.primary, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_tag), stringResource(MR.strings.chat_with_the_founder), { uriHandler.openVerifiedSimplexUri(simplexTeamUri) }, textColor = MaterialTheme.colors.primary, disabled = stopped) } - SettingsActionItem(painterResource(MR.images.ic_mail), stringResource(MR.strings.send_us_an_email), { uriHandler.openUriCatching("mailto:chat@simplex.chat") }, textColor = MaterialTheme.colors.primary, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_mail), stringResource(MR.strings.send_us_an_email), { uriHandler.openUriCatching("mailto:chat@simplex.chat") }, textColor = MaterialTheme.colors.primary) } SectionDividerSpaced() @@ -190,18 +189,19 @@ expect fun SettingsSectionApp( ) @Composable private fun DatabaseItem(encrypted: Boolean, saved: Boolean, openDatabaseView: () -> Unit, stopped: Boolean) { - SectionItemViewWithIcon(openDatabaseView) { + SectionItemView(openDatabaseView) { Row( Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { - Row(Modifier.weight(1f)) { + Row(Modifier.weight(1f), verticalAlignment = Alignment.CenterVertically) { Icon( painterResource(MR.images.ic_database), contentDescription = stringResource(MR.strings.database_passphrase_and_export), tint = if (encrypted && (appPlatform.isAndroid || !saved)) MaterialTheme.colors.secondary else WarningOrange, ) - TextIconSpaced(true) + TextIconSpaced(false) Text(stringResource(MR.strings.database_passphrase_and_export)) } if (stopped) { @@ -225,8 +225,7 @@ expect fun SettingsSectionApp( PreferencesView(m, m.currentUser.value ?: return@showCustomModal, close) }() }), - disabled = stopped, - extraPadding = true + disabled = stopped ) } @@ -241,27 +240,26 @@ fun ChatLockItem( click = showSettingsModal { SimplexLockView(ChatModel, currentLAMode, setPerformLA) }, icon = if (performLA.value) painterResource(MR.images.ic_lock_filled) else painterResource(MR.images.ic_lock), text = stringResource(MR.strings.chat_lock), - iconColor = if (performLA.value) SimplexGreen else MaterialTheme.colors.secondary, - extraPadding = false, + iconColor = if (performLA.value) SimplexGreen else MaterialTheme.colors.secondary ) { Text(if (performLA.value) remember { currentLAMode.state }.value.text else generalGetString(MR.strings.la_mode_off), color = MaterialTheme.colors.secondary) } } @Composable private fun ContributeItem(uriHandler: UriHandler) { - SectionItemViewWithIcon({ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat#contribute") }) { + SectionItemView({ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat#contribute") }) { Icon( painterResource(MR.images.ic_keyboard), contentDescription = "GitHub", tint = MaterialTheme.colors.secondary, ) - TextIconSpaced(extraPadding = true) + TextIconSpaced() Text(generalGetString(MR.strings.contribute), color = MaterialTheme.colors.primary) } } @Composable private fun RateAppItem(uriHandler: UriHandler) { - SectionItemViewWithIcon({ + SectionItemView({ runCatching { uriHandler.openUriCatching("market://details?id=chat.simplex.app") } .onFailure { uriHandler.openUriCatching("https://play.google.com/store/apps/details?id=chat.simplex.app") } } @@ -271,19 +269,19 @@ fun ChatLockItem( contentDescription = "Google Play", tint = MaterialTheme.colors.secondary, ) - TextIconSpaced(extraPadding = true) + TextIconSpaced() Text(generalGetString(MR.strings.rate_the_app), color = MaterialTheme.colors.primary) } } @Composable private fun StarOnGithubItem(uriHandler: UriHandler) { - SectionItemViewWithIcon({ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat") }) { + SectionItemView({ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat") }) { Icon( painter = painterResource(MR.images.ic_github), contentDescription = "GitHub", tint = MaterialTheme.colors.secondary, ) - TextIconSpaced(extraPadding = true) + TextIconSpaced() Text(generalGetString(MR.strings.star_on_github), color = MaterialTheme.colors.primary) } } @@ -301,7 +299,7 @@ fun ChatLockItem( } @Composable fun TerminalAlwaysVisibleItem(pref: SharedPreference, onChange: (Boolean) -> Unit) { - SettingsActionItemWithContent(painterResource(MR.images.ic_engineering), stringResource(MR.strings.terminal_always_visible), extraPadding = false) { + SettingsActionItemWithContent(painterResource(MR.images.ic_engineering), stringResource(MR.strings.terminal_always_visible)) { DefaultSwitch( checked = remember { pref.state }.value, onCheckedChange = onChange, @@ -348,7 +346,7 @@ fun unchangedHintPreferences(): Boolean = appPreferences.hintPreferences.all { ( @Composable fun AppVersionItem(showVersion: () -> Unit) { - SectionItemViewWithIcon(showVersion) { AppVersionText() } + SectionItemView(showVersion) { AppVersionText() } } @Composable fun AppVersionText() { @@ -439,7 +437,7 @@ fun PreferenceToggle( checked: Boolean, onChange: (Boolean) -> Unit = {}, ) { - SettingsActionItemWithContent(null, text, disabled = disabled, extraPadding = true,) { + SettingsActionItemWithContent(null, text, disabled = disabled) { DefaultSwitch( checked = checked, onCheckedChange = onChange, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt index e6d3202cd0..b357272e16 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt @@ -185,7 +185,7 @@ private fun UserAddressLayout( CreateAddressButton(createAddress) SectionTextFooter(stringResource(MR.strings.create_address_and_let_people_connect)) } - SectionDividerSpaced(maxBottomPadding = false) + SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false) SectionView { LearnMoreButton(learnMore) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt index 78a7637a14..4a9af6e822 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt @@ -4,6 +4,7 @@ import SectionBottomSpacer import SectionDivider import SectionItemView import SectionItemViewSpaceBetween +import SectionItemViewWithoutMinPadding import SectionSpacer import SectionTextFooter import SectionView @@ -277,7 +278,7 @@ private fun ProfileActionView(action: UserProfileAction, user: User, doAction: ( @Composable fun PasswordAndAction(label: StringResource, color: Color = MaterialTheme.colors.primary) { SectionView() { - SectionItemView { + SectionItemViewWithoutMinPadding { PassphraseField(actionPassword, generalGetString(MR.strings.profile_password), isValid = { passwordValid }, showStrength = true) } SectionItemViewSpaceBetween({ doAction(actionPassword.value) }, disabled = !actionEnabled, minHeight = TextFieldDefaults.MinHeight) { diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_box.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_box.svg index 9680161c4f..07f5645f79 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_box.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_box.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_circle_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_circle_filled.svg index f63966fbc8..db9ba45fab 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_circle_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_account_circle_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add.svg index 7da1daade8..da3f68daa4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_link.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_link.svg index 6e3ec1e453..1530035ead 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_link.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_link.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_photo.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_photo.svg index 3197ae8bb6..be7fcc8f54 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_photo.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_photo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction.svg index 62ee67166c..ecca4f4872 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction_filled.svg index 0475962f63..47b4790bc5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_add_reaction_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_all_inclusive.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_all_inclusive.svg index 4675bb6642..7628baecda 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_all_inclusive.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_all_inclusive.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_back_ios_new.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_back_ios_new.svg index 6940e4d004..f4f2bc772f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_back_ios_new.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_back_ios_new.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_downward.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_downward.svg index c09c1c4d66..e9bd252628 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_downward.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_downward.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_down.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_down.svg new file mode 100644 index 0000000000..f2cfb3cbdd --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_up.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_up.svg new file mode 100644 index 0000000000..90c085ae7b --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_drop_up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward.svg index d393921c05..0993b22658 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward_ios.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward_ios.svg index dd07f2bad9..58b93e79a1 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward_ios.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_forward_ios.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_upward.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_upward.svg index 88b20124f3..0a54ed27db 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_upward.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrow_upward.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrows_left_right.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrows_left_right.svg index de3a39b826..4b5a982e41 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrows_left_right.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_arrows_left_right.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_article.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_article.svg index 05d4d6fe6e..4cd46fc7cb 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_article.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_article.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled.svg index 5ff6754f22..dcebed008e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled_500.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled_500.svg index 04ef1d379f..d0897cd912 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled_500.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_attach_file_filled_500.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_avg_pace.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_avg_pace.svg index d3052a6c84..78d1b86471 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_avg_pace.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_avg_pace.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_back_hand.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_back_hand.svg index 41013ff66c..b9a3887c8f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_back_hand.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_back_hand.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backspace.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backspace.svg index 5bb12b42ca..a82b16c3ce 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backspace.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backspace.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backup.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backup.svg index 5d4b0c0dc6..e076c55993 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backup.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_backup.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_2_bar.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_2_bar.svg index fcdb3dfd50..3278d1d2dc 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_2_bar.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_2_bar.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_3_bar.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_3_bar.svg index 819fe590c9..9f73bc20f9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_3_bar.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_battery_3_bar.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bluetooth.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bluetooth.svg index 53bc5becaa..d39581566e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bluetooth.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bluetooth.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_blur_on.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_blur_on.svg index e8767ccc86..d729371159 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_blur_on.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_blur_on.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt.svg index 4c686c282a..aa276fa8c1 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_filled.svg index 012a8e2a45..2fd1fdcb38 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_off.svg index 7b003c8e7c..4278ea764a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_bolt_off.svg @@ -1,8 +1,8 @@ \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cable.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cable.svg index 1ca40515b7..f786d0c2e9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cable.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cable.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call.svg index 19c840a5cf..05577c3d0b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_500.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_500.svg index f2e1e9af6b..c18f78b148 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_500.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_500.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end.svg index 0f21f36e83..2bcb5949f9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end_filled.svg index ceb32f98f5..2d1e207e0e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_end_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_filled.svg index c0277fd5b6..100c933b7b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_call_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_camera_enhance.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_camera_enhance.svg index b07fbd7a87..baea2e28e9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_camera_enhance.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_camera_enhance.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cancel_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cancel_filled.svg index 44e901ff3c..41c39e11ef 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cancel_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_cancel_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat.svg index c263166229..82e58ead79 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat_bubble.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat_bubble.svg index 132c514e92..78e3bf42dc 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat_bubble.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chat_bubble.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check.svg index e3d6eab069..a5445b0d5f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle.svg index d44f9a2d1b..813adcea2d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle_filled.svg index 42f1a37725..ac2f200c6f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_circle_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_filled.svg index e3d6eab069..a5445b0d5f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_check_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chevron_right.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chevron_right.svg index ac6025580b..3c33462417 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chevron_right.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_chevron_right.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle.svg index d0da456188..dd6d17343d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle_filled.svg index e8eebbdc7c..65d942e3ad 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_circle_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_close.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_close.svg index f3803e3cac..b24eaf6cb9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_close.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_close.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_code.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_code.svg index 8554e557b0..918bf1a005 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_code.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_code.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_collapse_all.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_collapse_all.svg index a380594e79..673cb66084 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_collapse_all.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_collapse_all.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_copy.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_copy.svg index 2f4b964368..f8dde3e39f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_copy.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_copy.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_paste.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_paste.svg index 84a0be536b..b162257525 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_paste.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_content_paste.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_database.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_database.svg index 8b47047b60..1195169889 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_database.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_database.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete.svg index 1709888116..ea3f90edaa 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever.svg index 519fbc87fb..af3f3c5fb3 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever_filled.svg index c8c1d4cea5..8b46878258 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_delete_forever_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_desktop.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_desktop.svg index e9c30f5199..aa60447d7e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_desktop.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_desktop.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_dns.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_dns.svg index c1056cefc6..932f45e6b9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_dns.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_dns.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_disturb_on.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_disturb_on.svg index 9a0d038ba5..14df478255 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_disturb_on.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_disturb_on.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_touch.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_touch.svg index 5ea1a5f2e3..698df39e9c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_touch.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_do_not_touch.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_done_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_done_filled.svg index e3d6eab069..a5445b0d5f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_done_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_done_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_double_check.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_double_check.svg index 2c651607df..a5c0797f3e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_double_check.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_double_check.svg @@ -1,6 +1,6 @@ - + Created with Fabric.js 5.3.0 diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_download.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_download.svg index 8d62bebda6..65e1af1fb6 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_download.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_download.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft.svg index bbe311364f..edced6eb83 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft_filled.svg index 06140a055d..f40173226c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_draft_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_drive_folder_upload.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_drive_folder_upload.svg index ec3d03510e..94a21b1a9d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_drive_folder_upload.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_drive_folder_upload.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit.svg index 400707272e..143f7e8e0b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_filled.svg index e87e2eccaf..7550e08df5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_note.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_note.svg index 0c66d1bc4d..cb0488d834 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_note.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_edit_note.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_electrical_services.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_electrical_services.svg index e6ab5bb608..03e014417d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_electrical_services.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_electrical_services.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_engineering.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_engineering.svg index 0848537041..ea2c5c3843 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_engineering.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_engineering.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error.svg index 60296ca034..7a91448c9d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error_filled.svg index 6aaa01f0d3..7940dc756a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_error_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_all.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_all.svg index 75b2874d5b..ec76dfb115 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_all.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_all.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_less.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_less.svg deleted file mode 100644 index 23a6402630..0000000000 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_less.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_more.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_more.svg deleted file mode 100644 index 77becd0856..0000000000 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_expand_more.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_filter_list.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_filter_list.svg index a54ee0dc55..4a9c6e8420 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_filter_list.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_filter_list.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flag.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flag.svg index 35dd4ac780..d2f84f3b3a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flag.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flag.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flip_camera_android_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flip_camera_android_filled.svg index da9d686ce9..0244be139f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flip_camera_android_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_flip_camera_android_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_filled.svg index f4c284a5f2..ab47ff4136 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_filled.svg @@ -1,8 +1,8 @@ \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_pen.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_pen.svg index f1aba5bee6..7f2fb6e38e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_pen.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_folder_pen.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forum.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forum.svg index 0f556da867..5271a02284 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forum.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forum.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forward.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forward.svg index 7ad0b14b70..174b80bcc7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forward.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_forward.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_github.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_github.svg index 70baacb727..996fbd9743 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_github.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_github.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_group.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_group.svg index 74d6cdcc02..88c24ca67a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_group.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_group.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_headphones.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_headphones.svg index 2bda1e9d74..8487893d8d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_headphones.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_headphones.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_help.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_help.svg index 3bf2406ab8..b654c8eee5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_help.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_help.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_history.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_history.svg index f98f4db386..6edaf1512c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_history.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_history.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_id_card.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_id_card.svg index ff3b77c1d6..e2539c3608 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_id_card.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_id_card.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_image.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_image.svg index 408668d204..aa42e1a978 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_image.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_image.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_info.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_info.svg index aa3e5a2f4e..b854b30359 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_info.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_info.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_inventory_2.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_inventory_2.svg index c7e8aa21c1..20c39b2ed2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_inventory_2.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_inventory_2.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ios_share.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ios_share.svg index 099b5149bf..33f52db54b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ios_share.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ios_share.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard.svg index 35689927b1..a39e9c7e0b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_arrow_down.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_arrow_down.svg index c92d244c17..aaa188bed7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_arrow_down.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_arrow_down.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice.svg index a938a4250f..769198e13c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice_filled.svg index bd28745400..44c0f89fa0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_keyboard_voice_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_light_mode.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_light_mode.svg index 858ee788cf..44bad28fc9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_light_mode.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_light_mode.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lightbulb.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lightbulb.svg index 689e5c2d5c..e84b1bd476 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lightbulb.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lightbulb.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_link.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_link.svg index b8063c1c8c..7de4497d5d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_link.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_link.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock.svg index 2bc91dde71..cec12d0d4a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_filled.svg index 396e11fac6..798a92145a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_open_right.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_open_right.svg index 3188cf798e..0805267813 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_open_right.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_lock_open_right.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_login.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_login.svg index be56f0f451..d675b77073 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_login.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_login.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_logout.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_logout.svg index 5808094655..734242b294 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_logout.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_logout.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail.svg index 0a4b8adbd8..f45ed237f3 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail_filled.svg index 5b43f32f04..c51057b8cb 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_manage_accounts.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_manage_accounts.svg index e1cc6816b1..6a5b60424c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_manage_accounts.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_manage_accounts.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_maps_ugc.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_maps_ugc.svg index 469d44a2de..282b36ba25 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_maps_ugc.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_maps_ugc.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mark_chat_unread.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mark_chat_unread.svg index 5e1e746ee9..a89a956b29 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mark_chat_unread.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mark_chat_unread.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_match_case.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_match_case.svg index b56c8cb590..20adb34c10 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_match_case.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_match_case.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_menu.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_menu.svg index a192e32f34..28070d177d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_menu.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_menu.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic.svg index a938a4250f..769198e13c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_filled.svg index bd28745400..44c0f89fa0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_off.svg index 1ea755eb4e..f7f2c074f4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mic_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_horiz.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_horiz.svg index cc4f97431d..8d36d622c0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_horiz.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_horiz.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_vert.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_vert.svg index 9a9c7d193b..dc55c23649 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_vert.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_more_vert.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_music_note.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_music_note.svg index 766dc76be8..9e127f18f8 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_music_note.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_music_note.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_note_add.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_note_add.svg index 8459292f6e..76ba771f33 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_note_add.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_note_add.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications.svg index bcba2ae944..afe98fc544 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off.svg index 556013c364..ca1de72e82 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off_filled.svg index 647ad7dd3d..98a24503d7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_notifications_off_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_open_in_new.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_open_in_new.svg index 9669ee635e..0edc51abef 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_open_in_new.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_open_in_new.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_outline_terminal.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_outline_terminal.svg index 07f8078e0c..f384ef36bd 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_outline_terminal.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_outline_terminal.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_palette.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_palette.svg index f36ef054e0..a0da2dcca5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_palette.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_palette.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pause_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pause_filled.svg index eaa4573780..dc742eb7e8 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pause_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pause_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending.svg index 90b9dc7204..7ee6422616 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending_filled.svg index 00fe0d41a7..eee4c2c323 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_pending_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person.svg index 0830a9963b..0a87c6589e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add.svg index 4b2a249f23..4e22be2b55 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add_500.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add_500.svg index 179dce95fb..1c67f0813a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add_500.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_add_500.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_off.svg index a583950023..54cfd3e1c0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_person_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_bluetooth_speaker.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_bluetooth_speaker.svg index 513bb38c40..48fe86d1ec 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_bluetooth_speaker.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_bluetooth_speaker.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_in_talk_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_in_talk_filled.svg index b43c7d9c15..45cbd61bbd 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_in_talk_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_phone_in_talk_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_photo_camera.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_photo_camera.svg index aa99ac888a..ddb231b4bb 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_photo_camera.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_photo_camera.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_play_arrow_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_play_arrow_filled.svg index 6b3ed2a581..9b5f303e35 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_play_arrow_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_play_arrow_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_power_settings_new.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_power_settings_new.svg index 0af51ad2ab..c125143e41 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_power_settings_new.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_power_settings_new.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_priority_high.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_priority_high.svg index 42b93fba83..408b4b4376 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_priority_high.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_priority_high.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_qr_code.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_qr_code.svg index d7f8763c87..621fe3c413 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_qr_code.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_qr_code.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_question_mark.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_question_mark.svg index 9c2e7e110b..4346924f9d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_question_mark.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_question_mark.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radio_button_unchecked.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radio_button_unchecked.svg index 7433962953..7a3a36dc89 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radio_button_unchecked.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radio_button_unchecked.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_1_bar.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_1_bar.svg index db1cb48d53..a7dd37c4e6 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_1_bar.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_1_bar.svg @@ -1,5 +1,5 @@ - + diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_2_bar.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_2_bar.svg index 6f9a3211dd..cb6e344be9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_2_bar.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_2_bar.svg @@ -1,5 +1,5 @@ - + diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_3_bar.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_3_bar.svg index 1962851519..4bde8511f6 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_3_bar.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_3_bar.svg @@ -1,5 +1,5 @@ - + diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_4_bar.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_4_bar.svg index ff7a146284..131569e9bc 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_4_bar.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_radiowaves_up_forward_4_bar.svg @@ -1,5 +1,5 @@ - + diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_redeem.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_redeem.svg index a0093692cc..3178938a86 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_redeem.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_redeem.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_refresh.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_refresh.svg index a1f27d5798..bcbe9c4f34 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_refresh.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_refresh.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_repeat_one.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_repeat_one.svg index d37aa28022..014453c240 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_repeat_one.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_repeat_one.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_replay.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_replay.svg index 9f8c033f89..3e1b60666c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_replay.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_replay.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_reply.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_reply.svg index 7298dc984e..bffa9f33a2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_reply.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_reply.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report.svg index 8695857b97..c4c54f0e02 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report_filled.svg index 914c74a40a..8148ca77f2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_report_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_restart_alt.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_restart_alt.svg index a28c95673e..d2f91c991c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_restart_alt.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_restart_alt.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ring_volume.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ring_volume.svg index 92bc814040..4b01530b52 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ring_volume.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_ring_volume.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_safety_divider.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_safety_divider.svg index 5517bcd740..9b532e6420 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_safety_divider.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_safety_divider.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg index 4bd8e90cb6..2e806eb315 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg index 368e2fcc1f..b7afaf420b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search.svg index 8a74c6d43f..7a6e668cf5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search_500.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search_500.svg index 18e56def19..2e36a5dec4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search_500.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_search_500.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_security.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_security.svg index 13b5c1914e..2801bacad7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_security.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_security.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings.svg index 04b250537d..edc27762a0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_backup_restore.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_backup_restore.svg index a3cf4db7e1..22e8bcbbfb 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_backup_restore.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_backup_restore.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_ethernet.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_ethernet.svg index 828c7b8a8b..8fd3d489c9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_ethernet.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_ethernet.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_phone.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_phone.svg index 7280127ceb..6231a35d21 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_phone.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_settings_phone.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share.svg index f24d145a50..32d2875894 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share_filled.svg index 16b4c0ecf2..86424776cb 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_share_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_shield.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_shield.svg index ca1ed6828c..e99e34a8d3 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_shield.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_shield.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smart_display.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smart_display.svg index 195c3b2bea..4027f2f1f9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smart_display.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smart_display.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone.svg index 93094d1445..bb13e7f818 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone_300.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone_300.svg index 7d8553db11..6d9d70650c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone_300.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_smartphone_300.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star.svg index 2a2733830a..72d7962366 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_filled.svg index bf9bd2b4b5..22afbba02c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_filled.svg @@ -1,2 +1,2 @@ - \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_off.svg index d17a1e37d9..f353793d2a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_star_off.svg @@ -1,8 +1,8 @@ diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_start.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_start.svg index 42983718ac..f60449580b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_start.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_start.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_stop_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_stop_filled.svg index 0e8823dab5..bda4d1e10c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_stop_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_stop_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_supervised_user_circle_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_supervised_user_circle_filled.svg index ecfb7002a1..162ef06670 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_supervised_user_circle_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_supervised_user_circle_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle.svg index 0b842e8716..05de300ed2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle_filled.svg index 3509f870de..a71845eac7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_swap_horizontal_circle_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_sync_problem.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_sync_problem.svg index 79a0441792..4f85d90659 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_sync_problem.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_sync_problem.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_tag.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_tag.svg index 4b7e39b8ec..535d97a168 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_tag.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_tag.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_task.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_task.svg index eab8e8f09d..e8120529a3 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_task.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_task.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy.svg index 24267d0fa8..e6a78e6923 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy_filled.svg index 401e9affac..c1a3753674 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_theater_comedy_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer.svg index e530ef1e83..8f50769f03 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer_filled.svg index 4e0a99775a..a7576c6ee2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_timer_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toast.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toast.svg index 64f03f2fa7..dccf6dff3d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toast.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toast.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toggle_on.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toggle_on.svg index de240dce5f..02e068f30a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toggle_on.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_toggle_on.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_translate.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_translate.svg index 8ad343c088..6b05619e01 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_translate.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_translate.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_travel_explore.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_travel_explore.svg index 023ce42a26..1cacbed166 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_travel_explore.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_travel_explore.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upgrade.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upgrade.svg index c9ecd4ad87..ab8fb7d951 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upgrade.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upgrade.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upload_file.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upload_file.svg index 1840509fb1..d84e8bc513 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upload_file.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_upload_file.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_usb.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_usb.svg index 068bfc1a82..0663015ae4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_usb.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_usb.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_verified_user.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_verified_user.svg index cd6e89db86..7506004c1d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_verified_user.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_verified_user.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam.svg index 9a9edf61ce..d0ebb2fd41 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_filled.svg index 0606c6a06f..9f3b877e0d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_off.svg index 77c85ed987..992f052ed0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_videocam_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility.svg index 50095bc6e5..24c3544621 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_filled.svg index 2bc6fbd9a5..1f07b63790 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off.svg index 459ea40242..7cacfafdbf 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off_filled.svg index 7269dffdd3..9a52f493a7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_visibility_off_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_down.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_down.svg index 44b8f89e91..51f7d1a35d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_down.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_down.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_up.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_up.svg index 8d9f2ebecf..292a1fe27e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_up.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_volume_up.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_filled.svg index adb8814e12..f40ab9c6e1 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_off_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_off_filled.svg index 6ae367024e..0fe5d9a21e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_off_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_vpn_key_off_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning.svg index 7148c5740b..065e2f883c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning_filled.svg index 673b7453f6..7806a17d7f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning_filled.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_warning_filled.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi.svg index 2fb4750af5..313748293b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_off.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_off.svg index 814077e485..31354b7ed2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_off.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_tethering.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_tethering.svg index f6007d3f02..b6b6eedd9c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_tethering.svg +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_wifi_tethering.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt index 9f7f613835..38ffb137ed 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt @@ -60,16 +60,16 @@ fun AppearanceScope.AppearanceLayout( } } } - SectionDividerSpaced(maxTopPadding = true) + SectionDividerSpaced() ThemesSection(systemDarkTheme) - SectionDividerSpaced(maxTopPadding = true) + SectionDividerSpaced() ProfileImageSection() - SectionDividerSpaced(maxBottomPadding = true) + SectionDividerSpaced(maxTopPadding = true) FontScaleSection() - SectionDividerSpaced(maxBottomPadding = true) + SectionDividerSpaced(maxTopPadding = true) DensityScaleSection() SectionBottomSpacer() diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt index ed1d820259..ee8ae93de5 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt @@ -23,14 +23,12 @@ actual fun SettingsSectionApp( withAuth: (title: String, desc: String, block: () -> Unit) -> Unit ) { SectionView(stringResource(MR.strings.settings_section_title_app)) { - SettingsActionItem(painterResource(MR.images.ic_code), stringResource(MR.strings.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }, extraPadding = true) + SettingsActionItem(painterResource(MR.images.ic_code), stringResource(MR.strings.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }) val selectedChannel = remember { appPrefs.appUpdateChannel.state } val values = AppUpdatesChannel.entries.map { it to it.text } - Box(Modifier.padding(start = DEFAULT_PADDING_HALF * 1.4f)) { - ExposedDropDownSettingRow(stringResource(MR.strings.app_check_for_updates), values, selectedChannel) { - appPrefs.appUpdateChannel.set(it) - setupUpdateChecker() - } + ExposedDropDownSettingRow(stringResource(MR.strings.app_check_for_updates), values, selectedChannel) { + appPrefs.appUpdateChannel.set(it) + setupUpdateChecker() } AppVersionItem(showVersion) } From fd9c080103f6850e9d23bf7b47f578b0ad17ed29 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Wed, 21 Aug 2024 19:04:12 +0300 Subject: [PATCH 19/21] ios: fix last message being hidden on load (#4733) --- apps/ios/Shared/Views/Chat/ReverseList.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/ios/Shared/Views/Chat/ReverseList.swift b/apps/ios/Shared/Views/Chat/ReverseList.swift index 4ce6a1a065..94d160e1b4 100644 --- a/apps/ios/Shared/Views/Chat/ReverseList.swift +++ b/apps/ios/Shared/Views/Chat/ReverseList.swift @@ -180,6 +180,13 @@ struct ReverseList: UIV snapshot, animatingDifferences: itemCount != 0 && abs(items.count - itemCount) == 1 ) + // Sets content offset on initial load + if itemCount == 0 { + tableView.setContentOffset( + CGPoint(x: 0, y: -InvertedTableView.inset), + animated: false + ) + } itemCount = items.count } } From 996c6efddd441994e8fe55ef3b77d4b2c3d251d5 Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Wed, 21 Aug 2024 21:16:57 +0300 Subject: [PATCH 20/21] ios: prevent hangs when opening app from background with async api calls (#4730) * ios: async api calls on entering foreground * rename --------- Co-authored-by: Evgeny Poberezkin --- apps/ios/Shared/Model/SimpleXAPI.swift | 43 ++++++++++++------- apps/ios/Shared/SimpleXApp.swift | 20 +++++---- .../Shared/Views/Call/CallController.swift | 2 +- .../Shared/Views/ChatList/UserPicker.swift | 21 +++++---- 4 files changed, 52 insertions(+), 34 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 3abd1e92d1..ebc58c6a05 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1218,12 +1218,18 @@ func apiEndCall(_ contact: Contact) async throws { try await sendCommandOkResp(.apiEndCall(contact: contact)) } -func apiGetCallInvitations() throws -> [RcvCallInvitation] { +func apiGetCallInvitationsSync() throws -> [RcvCallInvitation] { let r = chatSendCmdSync(.apiGetCallInvitations) if case let .callInvitations(invs) = r { return invs } throw r } +func apiGetCallInvitations() async throws -> [RcvCallInvitation] { + let r = await chatSendCmd(.apiGetCallInvitations) + if case let .callInvitations(invs) = r { return invs } + throw r +} + func apiCallStatus(_ contact: Contact, _ status: String) async throws { if let callStatus = WebRTCCallStatus.init(rawValue: status) { try await sendCommandOkResp(.apiCallStatus(contact: contact, callStatus: callStatus)) @@ -1517,7 +1523,7 @@ func startChat(refreshInvitations: Bool = true) throws { try getUserChatData() NtfManager.shared.setNtfBadgeCount(m.totalUnreadCountForAllUsers()) if (refreshInvitations) { - try refreshCallInvitations() + Task { try await refreshCallInvitations() } } (m.savedToken, m.tokenStatus, m.notificationMode, m.notificationServer) = apiGetNtfToken() _ = try apiStartChat() @@ -2161,23 +2167,30 @@ func chatItemSimpleUpdate(_ user: any UserLike, _ aChatItem: AChatItem) async { } } -func refreshCallInvitations() throws { +func refreshCallInvitations() async throws { let m = ChatModel.shared - let callInvitations = try justRefreshCallInvitations() - if let (chatId, ntfAction) = m.ntfCallInvitationAction, - let invitation = m.callInvitations.removeValue(forKey: chatId) { - m.ntfCallInvitationAction = nil - CallController.shared.callAction(invitation: invitation, action: ntfAction) - } else if let invitation = callInvitations.last(where: { $0.user.showNotifications }) { - activateCall(invitation) + let callInvitations = try await apiGetCallInvitations() + await MainActor.run { + m.callInvitations = callsByChat(callInvitations) + if let (chatId, ntfAction) = m.ntfCallInvitationAction, + let invitation = m.callInvitations.removeValue(forKey: chatId) { + m.ntfCallInvitationAction = nil + CallController.shared.callAction(invitation: invitation, action: ntfAction) + } else if let invitation = callInvitations.last(where: { $0.user.showNotifications }) { + activateCall(invitation) + } } } -func justRefreshCallInvitations() throws -> [RcvCallInvitation] { - let m = ChatModel.shared - let callInvitations = try apiGetCallInvitations() - m.callInvitations = callInvitations.reduce(into: [ChatId: RcvCallInvitation]()) { result, inv in result[inv.contact.id] = inv } - return callInvitations +func justRefreshCallInvitations() throws { + let callInvitations = try apiGetCallInvitationsSync() + ChatModel.shared.callInvitations = callsByChat(callInvitations) +} + +private func callsByChat(_ callInvitations: [RcvCallInvitation]) -> [ChatId: RcvCallInvitation] { + callInvitations.reduce(into: [ChatId: RcvCallInvitation]()) { + result, inv in result[inv.contact.id] = inv + } } func activateCall(_ callInvitation: RcvCallInvitation) { diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 621f58dc0c..7f2c3b5866 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -83,9 +83,11 @@ struct SimpleXApp: App { if appState != .stopped { startChatAndActivate { if appState.inactive && chatModel.chatRunning == true { - updateChats() - if !chatModel.showCallView && !CallController.shared.hasActiveCalls() { - updateCallInvitations() + Task { + await updateChats() + if !chatModel.showCallView && !CallController.shared.hasActiveCalls() { + await updateCallInvitations() + } } } } @@ -130,16 +132,16 @@ struct SimpleXApp: App { } } - private func updateChats() { + private func updateChats() async { do { - let chats = try apiGetChats() - chatModel.updateChats(chats) + let chats = try await apiGetChatsAsync() + await MainActor.run { chatModel.updateChats(chats) } if let id = chatModel.chatId, let chat = chatModel.getChat(id) { Task { await loadChat(chat: chat, clearItems: false) } } if let ncr = chatModel.ntfContactRequest { - chatModel.ntfContactRequest = nil + await MainActor.run { chatModel.ntfContactRequest = nil } if case let .contactRequest(contactRequest) = chatModel.getChat(ncr.chatId)?.chatInfo { Task { await acceptContactRequest(incognito: ncr.incognito, contactRequest: contactRequest) } } @@ -149,9 +151,9 @@ struct SimpleXApp: App { } } - private func updateCallInvitations() { + private func updateCallInvitations() async { do { - try refreshCallInvitations() + try await refreshCallInvitations() } catch let error { logger.error("apiGetCallInvitations: cannot update call invitations \(responseError(error))") } diff --git a/apps/ios/Shared/Views/Call/CallController.swift b/apps/ios/Shared/Views/Call/CallController.swift index 64b565e8e6..a8a91057fa 100644 --- a/apps/ios/Shared/Views/Call/CallController.swift +++ b/apps/ios/Shared/Views/Call/CallController.swift @@ -186,7 +186,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse logger.debug("CallController: started chat") self.shouldSuspendChat = true // There are no invitations in the model, as it was processed by NSE - _ = try? justRefreshCallInvitations() + try? justRefreshCallInvitations() logger.debug("CallController: updated call invitations chat") // logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))") // Extract the call information from the push notification payload diff --git a/apps/ios/Shared/Views/ChatList/UserPicker.swift b/apps/ios/Shared/Views/ChatList/UserPicker.swift index eeb7bf14f4..5041e093db 100644 --- a/apps/ios/Shared/Views/ChatList/UserPicker.swift +++ b/apps/ios/Shared/Views/ChatList/UserPicker.swift @@ -85,15 +85,18 @@ struct UserPicker: View { .padding(8) .opacity(userPickerVisible ? 1.0 : 0.0) .onAppear { - do { - // This check prevents the call of listUsers after the app is suspended, and the database is closed. - if case .active = scenePhase { - m.users = try listUsers() - } - } catch let error { - logger.error("Error loading users \(responseError(error))") - } - } + // This check prevents the call of listUsers after the app is suspended, and the database is closed. + if case .active = scenePhase { + Task { + do { + let users = try await listUsersAsync() + await MainActor.run { m.users = users } + } catch { + logger.error("Error loading users \(responseError(error))") + } + } + } + } } private func userView(_ u: UserInfo) -> some View { From 94218a1a7ef9d8101b6263de70869323ba4ba76d Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Wed, 21 Aug 2024 19:20:20 +0100 Subject: [PATCH 21/21] core: 6.0.2.0 (simplexmq 6.0.1.0) --- cabal.project | 2 +- package.yaml | 2 +- scripts/nix/sha256map.nix | 2 +- simplex-chat.cabal | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cabal.project b/cabal.project index 08973f9be8..9976edb2af 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 1cbf8c0015a8014bcc9d1894055d734947176684 + tag: 1d22608f860636f21a5557f1b3fab4a7da09c5cc source-repository-package type: git diff --git a/package.yaml b/package.yaml index 2455d4284e..df23a563a2 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: simplex-chat -version: 6.0.0.8 +version: 6.0.2.0 #synopsis: #description: homepage: https://github.com/simplex-chat/simplex-chat#readme diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index a77e8ee167..6352837e25 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."1cbf8c0015a8014bcc9d1894055d734947176684" = "01x8fvwzahz32fmxc2mjvxl1z6agwr3952hl4qjswym76r1dpc1s"; + "https://github.com/simplex-chat/simplexmq.git"."1d22608f860636f21a5557f1b3fab4a7da09c5cc" = "16kmc05avzdyd6kpj83nyqkyjks5kim5j351397f6p3yvm7iydwz"; "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"; diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 0f1564f618..7acf07c497 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: simplex-chat -version: 6.0.0.8 +version: 6.0.2.0 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat