diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 596b87b191..233901f41b 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -233,6 +233,7 @@ 27FEF0F40750465195C9D6D6 /* RoomSelectionScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */; }; 281BED345D59A9A6A99E9D98 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; }; 2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7310D8DFE01AF45F0689C3AA /* Publisher.swift */; }; + 28426806399E3659BEBC5918 /* NotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6ED50FE104992419310EEB /* NotificationHandler.swift */; }; 288408E6151D7BD3EBAA073A /* RoomScreenHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */; }; 28E8C44DD6E39BEB2A1599C8 /* AccessibilityTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CABD320DE5566D133890B24 /* AccessibilityTestsAppCoordinator.swift */; }; 2932570AA418974979D16DED /* UserPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E6DE144D887A254F4CAF203 /* UserPreference.swift */; }; @@ -361,6 +362,7 @@ 407DCE030E0F9B7C9861D38A /* LRUCache in Frameworks */ = {isa = PBXBuildFile; productRef = 1081D3630AAD3ACEDDEC3A98 /* LRUCache */; }; 40839665086F5DAFA55D0EED /* AnalyticsConsentState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 353024006CB726E9F9187B3A /* AnalyticsConsentState.swift */; }; 414F50CFCFEEE2611127DCFB /* RestorationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3558A15CFB934F9229301527 /* RestorationToken.swift */; }; + 41B84DF733BE6CB0180D1CC1 /* NotificationContentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F0AF1A13D358CA0BDA6065F /* NotificationContentBuilderTests.swift */; }; 41C5DA0C06F30311A221E85B /* ClientSDKMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */; }; 41CE5E1289C8768FC5B6490C /* RoomTimelineItemViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C2D52E36AD614B3C003EF6 /* RoomTimelineItemViewState.swift */; }; 41D03E23B5DC6D633632E4D8 /* DeclineAndBlockScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA38C9B58693A49A3032552 /* DeclineAndBlockScreenCoordinator.swift */; }; @@ -452,6 +454,7 @@ 4FFDC274824F7CC0BBDF581E /* BugReportScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C2BCE0BC1FC69C1B36E688 /* BugReportScreenModels.swift */; }; 50381244BA280451771BE3ED /* PINTextFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF13BFD415CA84B1272E94F8 /* PINTextFieldTests.swift */; }; 5038E69A5E6A89DE1A345E04 /* ShouldScrollOnKeyboardDidShow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832397B5C3D00A4BF52C5F0B /* ShouldScrollOnKeyboardDidShow.swift */; }; + 5044C78B1B49328F5BB1FEB8 /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDB7A9BB466C56614BB589D /* NotificationItemProxyProtocol.swift */; }; 50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0FF64B0E6470F66F42E182 /* EstimatedWaveformView.swift */; }; 5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; }; 510C4EDF826CA9C6CEEC6C95 /* ManageRoomMemberSheetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A34D9BCA1A7D9A56E1EAF1D /* ManageRoomMemberSheetViewModel.swift */; }; @@ -470,10 +473,13 @@ 53C1E7F6A7D6409D89F36ED7 /* AggregatedReactionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69CB8242D69B7E4D0B32E18D /* AggregatedReactionMock.swift */; }; 53DEF39F0C4DE02E3FC56D91 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 800631D7250B7F93195035F1 /* KeychainAccess */; }; 53F1196F9C69512306A2693F /* TextRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C19F54A0C4FC9AB7ABD583 /* TextRoomTimelineItemContent.swift */; }; + 5415236FA271AF7885D4995E /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3AB32690C6CE5C62A86D6FA /* NotificationItemProxy.swift */; }; 5470E62F65AE1803BBF3D528 /* CXProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86E1BAA7232081635662A83F /* CXProviderMock.swift */; }; 54AE8860D668AFD96E7E177B /* UITestsScreenIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */; }; 54FDA3625AACBD9E438D084D /* BlurEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07934EF08BB39353E4A94272 /* BlurEffectView.swift */; }; + 5500904C40D67D131E7E9A26 /* NotificationContentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BB243B26D54EF1A0C422C0 /* NotificationContentBuilder.swift */; }; 5518DA4A6C9B4FC4B497EA9A /* LogViewerScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B795AAAB7B8747FE2FF311 /* LogViewerScreenModels.swift */; }; + 551E03A935A6B73158A1AB4A /* NSEUserSessionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4107DE842B9E8625291033AF /* NSEUserSessionMock.swift */; }; 558E2673B04FDD06A1A12DD3 /* LogViewerScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7463464054DDF194C54F0B04 /* LogViewerScreenViewModelProtocol.swift */; }; 558F37B1A8F2C4CC9B1ACEDA /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = CAA3B9DF998B397C9EE64E8B /* Collections */; }; 55CDD3968D95D1A820B5491E /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */; }; @@ -514,7 +520,6 @@ 5D52925FEB1B780C65B0529F /* PinnedEventsTimelineScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4F6D7000EDCD187E0989E7 /* PinnedEventsTimelineScreen.swift */; }; 5D53AE9342A4C06B704247ED /* MediaLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */; }; 5D56CE09743C6B90C21B04C2 /* RoomMembersListScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E9E0929CEFA356090BE5FB8 /* RoomMembersListScreenViewModelTests.swift */; }; - 5D70FAE4D2BF4553AFFFFE41 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; }; 5D99F63CC88BB29383019FC6 /* ShareExtensionModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAC01A97A43BE07B9E94E43 /* ShareExtensionModels.swift */; }; 5DB4334CBBA142376FF5FFEC /* preview_image.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 200626E8353AB2729444F991 /* preview_image.jpg */; }; 5DD85A0FE3D85AEC3C7EFE36 /* DeveloperOptionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7C7CFA6B2A62A685FF6CE3 /* DeveloperOptionsScreenCoordinator.swift */; }; @@ -605,6 +610,7 @@ 6BAD956B909A6E29F6CC6E7C /* ButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC23C63849452BC86EA2852 /* ButtonStyle.swift */; }; 6BAE34CFA9821709CFE61E50 /* DeveloperOptionsScreenHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F60FDB3AEFC60830BD289FE /* DeveloperOptionsScreenHook.swift */; }; 6C34237AFB808E38FC8776B9 /* RoomStateEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */; }; + 6C8BAF1E91618D69E7D652B2 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27A1AD6389A4659AF0CEAE62 /* NotificationServiceExtension.swift */; }; 6C98153D60FF9B648C166C27 /* TimelineItemMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFE1F410969ECB23FE9BB2 /* TimelineItemMenu.swift */; }; 6CAADDC6318E41C7D7AA9526 /* SpaceScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646B50583A2CE6DA67F7739A /* SpaceScreen.swift */; }; 6CBC544A7CC4DDDBDED4D0A6 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 4B1F71AC585827E6C416C15A /* AppIcon.icon */; }; @@ -696,6 +702,7 @@ 7BDC3976D88D40D2A45BEB8C /* NSRegularExpresion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */; }; 7BF368A78E6D9AFD222F25AF /* SecureBackupScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE094FCB6387D268C436161 /* SecureBackupScreenViewModel.swift */; }; 7C0E29E0279866C62EC67A28 /* JoinRoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5127D6EA05B2E45D0A7D59 /* JoinRoomScreenViewModelTests.swift */; }; + 7C101936C8F3DAF8D8166124 /* DataProtectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75821CD31A4BD02B99C327A4 /* DataProtectionManager.swift */; }; 7C164A642E8932B5F9004550 /* test_voice_message.m4a in Resources */ = {isa = PBXBuildFile; fileRef = DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */; }; 7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; }; 7C545FFEC9930F7247352593 /* SecurityAndPrivacyScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978092B01BEAB39F2C4389AE /* SecurityAndPrivacyScreenViewModel.swift */; }; @@ -824,6 +831,7 @@ 9278EC51D24E57445B290521 /* AudioSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */; }; 9295F1F5E04484E10780BCE8 /* CharacterSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8C01DEEA83903D45069BBD /* CharacterSet.swift */; }; 92D9088B901CEBB1A99ECA4E /* RoomMemberProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */; }; + 9312F5A17AE59A9E910C51D6 /* NotificationItemProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */; }; 9322949BFCA6278921085862 /* DeactivateAccountScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664D3C710B4A12CE4E623645 /* DeactivateAccountScreenModels.swift */; }; 934051B17A884AB0635DF81B /* BlockedUsersScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A010B8EAD1A9F6B4686DF2F4 /* BlockedUsersScreenViewModel.swift */; }; 937985546F708339711ECDFC /* ComposerToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85666E40F7E817809B4FD787 /* ComposerToolbar.swift */; }; @@ -1034,7 +1042,6 @@ B81840E45D8746A4692DA774 /* Tracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B574805B9812C111D6215D /* Tracing.swift */; }; B818580464CFB5400A3EF6AE /* TimelineModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029D5701F80A9AF7167BB4D0 /* TimelineModels.swift */; }; B855AF29D7D8FC8DAAA73D4A /* test_voice_message.m4a in Resources */ = {isa = PBXBuildFile; fileRef = DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */; }; - B89990DD875B0B603D4D4332 /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */; }; B8D9960F77B213FD1B0B0FD3 /* JoinRoomByAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A13364350970987B93F6018 /* JoinRoomByAddressView.swift */; }; B93D7CE520088AD53FA6D53C /* SettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B663BE498BB39EADC24025D /* SettingsScreenModels.swift */; }; B93FA0DA1504B301CAEE141B /* NotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F5D66F158A6662F953733E /* NotificationSettingsProxy.swift */; }; @@ -1138,6 +1145,7 @@ CB6BCBF28E4B76EA08C2926D /* StateRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16048D30F0438731C41F775 /* StateRoomTimelineItem.swift */; }; CB99B0FA38A4AC596F38CC13 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */; }; CB9FB2BEF313072C705AC9B5 /* SecurityAndPrivacyScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0315C328FF40F84276364E66 /* SecurityAndPrivacyScreenViewModelTests.swift */; }; + CBBBE597BE74A2DF68DE2209 /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDB7A9BB466C56614BB589D /* NotificationItemProxyProtocol.swift */; }; CBD2ABE4C1A47ECD99E1488E /* NotificationSettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 421FA93BCC2840E66E4F306F /* NotificationSettingsScreenViewModelProtocol.swift */; }; CC0D088F505F33A20DC5590F /* RoomStateEventStringBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEEAFB646E583655652C3D04 /* RoomStateEventStringBuilderTests.swift */; }; CC1C948F67A5510A340FD7F0 /* SessionDirectoriesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0825EAFD47332DD459DE893F /* SessionDirectoriesTests.swift */; }; @@ -1152,7 +1160,6 @@ CE4B342F9DD747CF4BEDB5AB /* TestablePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43F773904F87FF5ADFE4DD1 /* TestablePreview.swift */; }; CE6F237360875D3D573FD0B2 /* RoomNotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */; }; CE8296D4AD30DDC6D0C67A74 /* CreateRoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFD1CFB730C7417925264F17 /* CreateRoomScreen.swift */; }; - CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; }; CEAEA57B7665C8E790599A78 /* BlockedUsersScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 240610DF32F3213BEC5611D7 /* BlockedUsersScreenViewModelTests.swift */; }; CEB8FB1269DE20536608B957 /* LoginMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41FABA2B0AEF4389986495 /* LoginMode.swift */; }; CF38B70D8C6DD42C00A56A27 /* LogViewerScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */; }; @@ -1197,6 +1204,7 @@ D6152E21036B88C44ECB22E7 /* EncryptionResetPasswordScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 303D9438EFB481F57A366E82 /* EncryptionResetPasswordScreenViewModel.swift */; }; D63974A88CF2BC721F109C77 /* Compound in Frameworks */ = {isa = PBXBuildFile; productRef = DCA3C4A997AD28E6918D4CE5 /* Compound */; }; D6DE764B17FB4A9A12C33BF4 /* MessageComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1DF3FFFE5ED2B8133F43A7 /* MessageComposer.swift */; }; + D75C591C44C2510FDFA9C3D8 /* Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = AFAD718C6621B94813B960B4 /* Dynamic */; }; D7CDBAE82782BD0529DECB5F /* AttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BD6ED18E2EB61E28C340AD /* AttributedString.swift */; }; D820B3C223E4C2E77BB2A2BF /* ElementCallServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EA2AFF6EB59FE25234D29F3 /* ElementCallServiceTests.swift */; }; D8459AAD6969B1431ECBE990 /* UnsupportedRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E535B3388755B65C34CD10 /* UnsupportedRoomTimelineView.swift */; }; @@ -1269,6 +1277,7 @@ E5E43A0CA99AF5BA11B194A2 /* EncryptionSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57AD14D3ADADE8F6A10F9E88 /* EncryptionSettingsTests.swift */; }; E5F4C992845388B50BABACAA /* ServerSelectionScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */; }; E67418DACEDBC29E988E6ACD /* message.caf in Resources */ = {isa = PBXBuildFile; fileRef = ED482057AE39D5C6D9C5F3D8 /* message.caf */; }; + E6A2F6E4795C1054025AACFF /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3AB32690C6CE5C62A86D6FA /* NotificationItemProxy.swift */; }; E6FA87F773424B27614B23E9 /* TimelineItemAccessibilityModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA7E93C2E148B96EF6A8500 /* TimelineItemAccessibilityModifier.swift */; }; E75CE800B3E64D0F7F8E228D /* TemplateScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08E9043618AE5B0BF7B07E1 /* TemplateScreenViewModelTests.swift */; }; E77FE06B165A38BF1735509F /* SecureBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF73F49E6B6683F7E2D26F0 /* SecureBackupScreenCoordinator.swift */; }; @@ -1282,6 +1291,7 @@ E8C4D9F93F0DCED211D5F187 /* HTMLParserStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3877D3CFAC1D33823359BAF /* HTMLParserStyle.swift */; }; E8C65C19F7C40EE545172DD6 /* RoomScreenFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4137900E28201C314C835C11 /* RoomScreenFooterView.swift */; }; E9347F56CF0683208F4D9249 /* RoomNotificationSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A9B5225D0881CEFA2CF7C9 /* RoomNotificationSettingsScreenViewModel.swift */; }; + E938F7A45D6A3DBBE6789A03 /* NSEUserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9651CD1066F239C7739240 /* NSEUserSession.swift */; }; E9560744F7B0292E20ECE5F2 /* RoomDetailsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E8A1E8EE094F570573B6E8 /* RoomDetailsScreenViewModelProtocol.swift */; }; E96005321849DBD7C72A28F2 /* UITestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */; }; E9985DCD1B0D026D7E8BF809 /* ServerSelectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6640DB5B9171D163E6742639 /* ServerSelectionTests.swift */; }; @@ -1406,7 +1416,6 @@ FCF95603F1D056B1B106A415 /* AdvancedSettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83E2B20431F890ED64255CA1 /* AdvancedSettingsScreenViewModelProtocol.swift */; }; FD29471C72872F8B7580E3E1 /* KeychainControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C0D861FC397AC34BCF089E /* KeychainControllerMock.swift */; }; FD439E183A48BE871AEEFAEA /* TimelineScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10765FBC83B34A3BC4ADB23 /* TimelineScrollToBottomButton.swift */; }; - FD4C21F8DA1E273DE94FCD1A /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */; }; FD573B5D665824EB79EABF06 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5327E3B3C58BEB0E65F4CF98 /* Observable.swift */; }; FD762761C5D0C30E6255C3D8 /* ServerConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */; }; FD9777315A5D9CDC47458AD1 /* MediaEventsTimelineScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A175D0FDEDBFA44C47FE13AE /* MediaEventsTimelineScreenViewModelProtocol.swift */; }; @@ -1584,6 +1593,7 @@ 0E8BDC092D817B68CD9040C5 /* UserSessionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStore.swift; sourceTree = ""; }; 0E95B3BDB80531C85CD50AE6 /* InvitedRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitedRoomProxy.swift; sourceTree = ""; }; 0EE9EAF0309A2A1D67D8FAF5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Localizable.stringsdict; sourceTree = ""; }; + 0F0AF1A13D358CA0BDA6065F /* NotificationContentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentBuilderTests.swift; sourceTree = ""; }; 0F5567A7EF6F2AB9473236F6 /* DocumentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentPicker.swift; sourceTree = ""; }; 0F60FDB3AEFC60830BD289FE /* DeveloperOptionsScreenHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenHook.swift; sourceTree = ""; }; 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenModels.swift; sourceTree = ""; }; @@ -1653,7 +1663,6 @@ 1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenModels.swift; sourceTree = ""; }; 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenModels.swift; sourceTree = ""; }; 1B8E176484A89BAC389D4076 /* RoomMembersListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreen.swift; sourceTree = ""; }; - 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxyProtocol.swift; sourceTree = ""; }; 1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreenModels.swift; sourceTree = ""; }; 1BA5A62DA4B543827FF82354 /* LAContextMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LAContextMock.swift; sourceTree = ""; }; 1BA8082E26C77A2C587B34B3 /* MockTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTimelineController.swift; sourceTree = ""; }; @@ -1717,7 +1726,6 @@ 25586C0ADB814FEE9897DCAA /* BugReportHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportHook.swift; sourceTree = ""; }; 259E5B05BDE6E20C26CF11B4 /* PollInteractionHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollInteractionHandlerProtocol.swift; sourceTree = ""; }; 25E7E9B7FEAB6169D960C206 /* QRCodeLoginScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreenViewModelTests.swift; sourceTree = ""; }; - 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = ""; }; 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = ""; }; 260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = ""; }; 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; path = PreviewTests.xctestplan; sourceTree = ""; }; @@ -1841,6 +1849,7 @@ 3D9FCE4D1E3A81AC1CC5CB91 /* AppLockSetupSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenCoordinator.swift; sourceTree = ""; }; 3DBE70FFB7936F35811772C1 /* IdentityConfirmedScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmedScreenModels.swift; sourceTree = ""; }; 3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = ""; }; + 3DDB7A9BB466C56614BB589D /* NotificationItemProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxyProtocol.swift; sourceTree = ""; }; 3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineItem.swift; sourceTree = ""; }; 3E93A1BE7D8A2EBCAD51EEB4 /* Array.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = ""; }; 3E9E0929CEFA356090BE5FB8 /* RoomMembersListScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModelTests.swift; sourceTree = ""; }; @@ -1854,6 +1863,7 @@ 40A66E8BC8D9AE4A08EFB2DF /* RoomInfoProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomInfoProxy.swift; sourceTree = ""; }; 40B21E611DADDEF00307E7AC /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; 4100DDE6BF3C566AB66B80CC /* MentionSuggestionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionSuggestionItemView.swift; sourceTree = ""; }; + 4107DE842B9E8625291033AF /* NSEUserSessionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEUserSessionMock.swift; sourceTree = ""; }; 4137900E28201C314C835C11 /* RoomScreenFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenFooterView.swift; sourceTree = ""; }; 41656BC6267D55C56A2AAC08 /* EditRoomAddressScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressScreenCoordinator.swift; sourceTree = ""; }; 4176C3E20C772DE8D182863C /* LegalInformationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreen.swift; sourceTree = ""; }; @@ -2192,6 +2202,7 @@ 83B4E3F1265581683E4997B8 /* RoomSelectionScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSelectionScreenViewModel.swift; sourceTree = ""; }; 83B574805B9812C111D6215D /* Tracing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tracing.swift; sourceTree = ""; }; 83E2B20431F890ED64255CA1 /* AdvancedSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; + 840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxyMock.swift; sourceTree = ""; }; 84311D707B09854D67F78BBF /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; 845DDBDE5A0887E73D38B826 /* InviteUsersViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersViewModelTests.swift; sourceTree = ""; }; 848F69921527D31CAACB93AF /* SecureBackupLogoutConfirmationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModelTests.swift; sourceTree = ""; }; @@ -2797,6 +2808,7 @@ F37FA1A5D55633E1942B153B /* CallScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenCoordinator.swift; sourceTree = ""; }; F3A1AB5A84D843B6AC8D5F1E /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = ""; }; F3AAC314A877DBDB6EBE1170 /* SpaceHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceHeaderView.swift; sourceTree = ""; }; + F3AB32690C6CE5C62A86D6FA /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = ""; }; F3C7252B3461D06175D975A4 /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/SAS.strings; sourceTree = ""; }; F3D94852AD5BB376CBCC3544 /* RoomPreviewProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPreviewProxy.swift; sourceTree = ""; }; F3EAE3E9D5EF4A6D5D9C6CFD /* EmojiPickerScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModel.swift; sourceTree = ""; }; @@ -2880,6 +2892,7 @@ 7FF27DA70D833CFC5724EFC5 /* MatrixRustSDK in Frameworks */, BCA5E2157CE27AB6F1D043D3 /* AsyncAlgorithms in Frameworks */, B5C40DCFFDFBA0F86E228602 /* Clocks in Frameworks */, + D75C591C44C2510FDFA9C3D8 /* Dynamic in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3129,6 +3142,15 @@ path = View; sourceTree = ""; }; + 10450069C1510FAFAEABB4AA /* NotificationItemProxy */ = { + isa = PBXGroup; + children = ( + F3AB32690C6CE5C62A86D6FA /* NotificationItemProxy.swift */, + 3DDB7A9BB466C56614BB589D /* NotificationItemProxyProtocol.swift */, + ); + path = NotificationItemProxy; + sourceTree = ""; + }; 10578D9852BA78D309A1CBDF /* ViewModel */ = { isa = PBXGroup; children = ( @@ -3547,7 +3569,9 @@ 7F957320D0EB7D7B4E30C79D /* KnockRequestProxyMock.swift */, 6F65E4BB9E82EB8373207CF8 /* MediaProviderMock.swift */, 8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */, + 840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */, 382B50F7E379B3DBBD174364 /* NotificationSettingsProxyMock.swift */, + 4107DE842B9E8625291033AF /* NSEUserSessionMock.swift */, B2AD8A56CD37E23071A2F4BF /* PHGPostHogMock.swift */, DD955A0380C287C418F1A74D /* PhotoLibraryManagerMock.swift */, D38391154120264910D19528 /* PollMock.swift */, @@ -4511,7 +4535,6 @@ children = ( C830A64609CBD152F06E0457 /* NotificationConstants.swift */, 6EE5E2BBFBC7947CFE789B4D /* Manager */, - 832FC81F760220239E285294 /* Proxy */, ); path = Notification; sourceTree = ""; @@ -4643,6 +4666,7 @@ 78913D6E120D46138E97C107 /* NavigationSplitCoordinatorTests.swift */, 9C698E30698EC59302A8EEBD /* NavigationStackCoordinatorTests.swift */, 2B67DC84B42D86035FCFF6F8 /* NavigationTabCoordinatorTests.swift */, + 0F0AF1A13D358CA0BDA6065F /* NotificationContentBuilderTests.swift */, 8544F7058D31DBEB8DBFF0F5 /* NotificationSettingsEditScreenViewModelTests.swift */, 514363244AE7D68080D44C6F /* NotificationSettingsScreenViewModelTests.swift */, FA3EB5B1848CF4F64E63C6B7 /* PermalinkTests.swift */, @@ -5017,15 +5041,6 @@ path = View; sourceTree = ""; }; - 832FC81F760220239E285294 /* Proxy */ = { - isa = PBXGroup; - children = ( - 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */, - 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */, - ); - path = Proxy; - sourceTree = ""; - }; 8428BD1821586CEE0B9C9ECA /* Messages */ = { isa = PBXGroup; children = ( @@ -5058,6 +5073,7 @@ BB6ED50FE104992419310EEB /* NotificationHandler.swift */, 27A1AD6389A4659AF0CEAE62 /* NotificationServiceExtension.swift */, 6C9651CD1066F239C7739240 /* NSEUserSession.swift */, + 10450069C1510FAFAEABB4AA /* NotificationItemProxy */, ); path = Sources; sourceTree = ""; @@ -6721,6 +6737,7 @@ C07EA60CAB296D7726210F5B /* MatrixRustSDK */, 5A8EF1A5F9629FCA309D4B2A /* AsyncAlgorithms */, FFA423B0A7BBD8AA9BB91AB0 /* Clocks */, + AFAD718C6621B94813B960B4 /* Dynamic */, ); productName = UnitTests; productReference = AAC9344689121887B74877AF /* UnitTests.xctest */; @@ -6975,6 +6992,7 @@ F76A08D0EA29A07A54F4EB4D /* XCRemoteSwiftPackageReference "swift-collections" */, 4C34425923978C97409A3EF2 /* XCRemoteSwiftPackageReference "DSWaveformImage" */, D5F7D47BBAAE0CF1DDEB3034 /* XCRemoteSwiftPackageReference "DeviceKit" */, + 75CC627F59499C9E93D8FDAD /* XCRemoteSwiftPackageReference "Dynamic" */, 8213398B60F9B660D9216ADF /* XCRemoteSwiftPackageReference "element-call-swift" */, 821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */, 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */, @@ -7311,8 +7329,8 @@ 5C02841B2A86327B2C377682 /* NotificationConstants.swift in Sources */, 2689D22EF1D10D22B0A4DAEA /* NotificationContentBuilder.swift in Sources */, A07178337F3C0B208B5A77A8 /* NotificationHandler.swift in Sources */, - 5D70FAE4D2BF4553AFFFFE41 /* NotificationItemProxy.swift in Sources */, - B89990DD875B0B603D4D4332 /* NotificationItemProxyProtocol.swift in Sources */, + 5415236FA271AF7885D4995E /* NotificationItemProxy.swift in Sources */, + CBBBE597BE74A2DF68DE2209 /* NotificationItemProxyProtocol.swift in Sources */, B14BC354E56616B6B7D9A3D7 /* NotificationServiceExtension.swift in Sources */, A5F50F36E56E5D3C241E2BE3 /* OIDCConfiguration.swift in Sources */, 761EA50B2619307AB30891B8 /* PhishingDetector.swift in Sources */, @@ -7416,6 +7434,7 @@ 69C7B956B74BEC3DB88224EA /* NavigationSplitCoordinatorTests.swift in Sources */, 4BB282209EA82015D0DF8F89 /* NavigationStackCoordinatorTests.swift in Sources */, EE17B7154DCA50677D931A94 /* NavigationTabCoordinatorTests.swift in Sources */, + 41B84DF733BE6CB0180D1CC1 /* NotificationContentBuilderTests.swift in Sources */, 1B2DADC008EE211AF1DA5292 /* NotificationManagerTests.swift in Sources */, C11939FDC40716C4387275A4 /* NotificationSettingsEditScreenViewModelTests.swift in Sources */, E3AC72E3E58F364EF15C1CC7 /* NotificationSettingsScreenViewModelTests.swift in Sources */, @@ -7752,6 +7771,7 @@ A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */, 12C867E85E6D12EEDFD0B127 /* CustomStringConvertible.swift in Sources */, 9905C1B1C6EFE38F3A6533F3 /* Data.swift in Sources */, + 7C101936C8F3DAF8D8166124 /* DataProtectionManager.swift in Sources */, C6C06DDA8881260303FBA3A0 /* Date.swift in Sources */, 99C463F12F89C99C77D02077 /* DeactivateAccountScreen.swift in Sources */, 3E3CC3D17908A3BB9F224CC5 /* DeactivateAccountScreenCoordinator.swift in Sources */, @@ -8010,6 +8030,8 @@ C97325EFDCCEE457432A9E82 /* MessageText.swift in Sources */, AF2ABA2794E376B64104C964 /* MockSoftLogoutScreenState.swift in Sources */, 530C2238E40F71223327FC95 /* MockTimelineController.swift in Sources */, + E938F7A45D6A3DBBE6789A03 /* NSEUserSession.swift in Sources */, + 551E03A935A6B73158A1AB4A /* NSEUserSessionMock.swift in Sources */, F9842667B68DC6FA1F9ECCBB /* NSItemProvider.swift in Sources */, EA01A06EEDFEF4AE7652E5F3 /* NSRegularExpresion.swift in Sources */, FA2BBAE9FC5E2E9F960C0980 /* NavigationCoordinators.swift in Sources */, @@ -8023,8 +8045,11 @@ 9408CE8B8865C0C8DD4C9869 /* NoticeRoomTimelineItemContent.swift in Sources */, 7F825CBD857D65DC986087BA /* NoticeRoomTimelineView.swift in Sources */, 3F70E237CE4C3FAB02FC227F /* NotificationConstants.swift in Sources */, - CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */, - FD4C21F8DA1E273DE94FCD1A /* NotificationItemProxyProtocol.swift in Sources */, + 5500904C40D67D131E7E9A26 /* NotificationContentBuilder.swift in Sources */, + 28426806399E3659BEBC5918 /* NotificationHandler.swift in Sources */, + E6A2F6E4795C1054025AACFF /* NotificationItemProxy.swift in Sources */, + 9312F5A17AE59A9E910C51D6 /* NotificationItemProxyMock.swift in Sources */, + 5044C78B1B49328F5BB1FEB8 /* NotificationItemProxyProtocol.swift in Sources */, 652ACCF104A8CEF30788963C /* NotificationManager.swift in Sources */, 06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */, 5139F4BD5A5DF6F8D11A9BDE /* NotificationPermissionsScreen.swift in Sources */, @@ -8032,6 +8057,7 @@ 3E7B65C2C97748D5D65AAA8B /* NotificationPermissionsScreenModels.swift in Sources */, D4D7CCECC6C0AAFC42E165BB /* NotificationPermissionsScreenViewModel.swift in Sources */, C8A9C595038AFA2D707AC8C1 /* NotificationPermissionsScreenViewModelProtocol.swift in Sources */, + 6C8BAF1E91618D69E7D652B2 /* NotificationServiceExtension.swift in Sources */, C0090506A52A1991BAF4BA68 /* NotificationSettingsChatType.swift in Sources */, AA93B3F9B5DD097DEF79F981 /* NotificationSettingsEditScreen.swift in Sources */, 53A59720F4729D9BBFFB7CAB /* NotificationSettingsEditScreenCoordinator.swift in Sources */, @@ -9484,6 +9510,14 @@ minimumVersion = 1.3.2; }; }; + 75CC627F59499C9E93D8FDAD /* XCRemoteSwiftPackageReference "Dynamic" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/mhdhejazi/Dynamic"; + requirement = { + kind = exactVersion; + version = 1.2; + }; + }; 8213398B60F9B660D9216ADF /* XCRemoteSwiftPackageReference "element-call-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/element-hq/element-call-swift"; @@ -9856,6 +9890,11 @@ package = F76A08D0EA29A07A54F4EB4D /* XCRemoteSwiftPackageReference "swift-collections" */; productName = Collections; }; + AFAD718C6621B94813B960B4 /* Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 75CC627F59499C9E93D8FDAD /* XCRemoteSwiftPackageReference "Dynamic" */; + productName = Dynamic; + }; B1E8B697DF78FE7F61FC6CA4 /* MatrixRustSDK */ = { isa = XCSwiftPackageProductDependency; package = 6FC4820D8D4559CEECA064D7 /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */; diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 172165b9d7..5d1aceab33 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -45,6 +45,15 @@ "version" : "1.7.18" } }, + { + "identity" : "dynamic", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mhdhejazi/Dynamic", + "state" : { + "revision" : "ab9a2570862d54aed2663691bb767f881226a12f", + "version" : "1.2.0" + } + }, { "identity" : "element-call-swift", "kind" : "remoteSourceControl", diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index bb004e9dc1..5bcd005cbe 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -11556,6 +11556,188 @@ class MediaProviderMock: MediaProviderProtocol, @unchecked Sendable { } } } +class NSEUserSessionMock: NSEUserSessionProtocol, @unchecked Sendable { + var inviteAvatarsVisibilityCallsCount = 0 + var inviteAvatarsVisibilityCalled: Bool { + return inviteAvatarsVisibilityCallsCount > 0 + } + + var inviteAvatarsVisibility: InviteAvatars { + get async { + inviteAvatarsVisibilityCallsCount += 1 + if let inviteAvatarsVisibilityClosure = inviteAvatarsVisibilityClosure { + return await inviteAvatarsVisibilityClosure() + } else { + return underlyingInviteAvatarsVisibility + } + } + } + var underlyingInviteAvatarsVisibility: InviteAvatars! + var inviteAvatarsVisibilityClosure: (() async -> InviteAvatars)? + var mediaPreviewVisibilityCallsCount = 0 + var mediaPreviewVisibilityCalled: Bool { + return mediaPreviewVisibilityCallsCount > 0 + } + + var mediaPreviewVisibility: MediaPreviews { + get async { + mediaPreviewVisibilityCallsCount += 1 + if let mediaPreviewVisibilityClosure = mediaPreviewVisibilityClosure { + return await mediaPreviewVisibilityClosure() + } else { + return underlyingMediaPreviewVisibility + } + } + } + var underlyingMediaPreviewVisibility: MediaPreviews! + var mediaPreviewVisibilityClosure: (() async -> MediaPreviews)? + var threadsEnabled: Bool { + get { return underlyingThreadsEnabled } + set(value) { underlyingThreadsEnabled = value } + } + var underlyingThreadsEnabled: Bool! + + //MARK: - notificationItemProxy + + var notificationItemProxyRoomIDEventIDUnderlyingCallsCount = 0 + var notificationItemProxyRoomIDEventIDCallsCount: Int { + get { + if Thread.isMainThread { + return notificationItemProxyRoomIDEventIDUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = notificationItemProxyRoomIDEventIDUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + notificationItemProxyRoomIDEventIDUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + notificationItemProxyRoomIDEventIDUnderlyingCallsCount = newValue + } + } + } + } + var notificationItemProxyRoomIDEventIDCalled: Bool { + return notificationItemProxyRoomIDEventIDCallsCount > 0 + } + var notificationItemProxyRoomIDEventIDReceivedArguments: (roomID: String, eventID: String)? + var notificationItemProxyRoomIDEventIDReceivedInvocations: [(roomID: String, eventID: String)] = [] + + var notificationItemProxyRoomIDEventIDUnderlyingReturnValue: NotificationItemProxyProtocol? + var notificationItemProxyRoomIDEventIDReturnValue: NotificationItemProxyProtocol? { + get { + if Thread.isMainThread { + return notificationItemProxyRoomIDEventIDUnderlyingReturnValue + } else { + var returnValue: NotificationItemProxyProtocol?? = nil + DispatchQueue.main.sync { + returnValue = notificationItemProxyRoomIDEventIDUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + notificationItemProxyRoomIDEventIDUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + notificationItemProxyRoomIDEventIDUnderlyingReturnValue = newValue + } + } + } + } + var notificationItemProxyRoomIDEventIDClosure: ((String, String) async -> NotificationItemProxyProtocol?)? + + func notificationItemProxy(roomID: String, eventID: String) async -> NotificationItemProxyProtocol? { + notificationItemProxyRoomIDEventIDCallsCount += 1 + notificationItemProxyRoomIDEventIDReceivedArguments = (roomID: roomID, eventID: eventID) + DispatchQueue.main.async { + self.notificationItemProxyRoomIDEventIDReceivedInvocations.append((roomID: roomID, eventID: eventID)) + } + if let notificationItemProxyRoomIDEventIDClosure = notificationItemProxyRoomIDEventIDClosure { + return await notificationItemProxyRoomIDEventIDClosure(roomID, eventID) + } else { + return notificationItemProxyRoomIDEventIDReturnValue + } + } + //MARK: - roomForIdentifier + + var roomForIdentifierUnderlyingCallsCount = 0 + var roomForIdentifierCallsCount: Int { + get { + if Thread.isMainThread { + return roomForIdentifierUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = roomForIdentifierUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + roomForIdentifierUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + roomForIdentifierUnderlyingCallsCount = newValue + } + } + } + } + var roomForIdentifierCalled: Bool { + return roomForIdentifierCallsCount > 0 + } + var roomForIdentifierReceivedRoomID: String? + var roomForIdentifierReceivedInvocations: [String] = [] + + var roomForIdentifierUnderlyingReturnValue: Room? + var roomForIdentifierReturnValue: Room? { + get { + if Thread.isMainThread { + return roomForIdentifierUnderlyingReturnValue + } else { + var returnValue: Room?? = nil + DispatchQueue.main.sync { + returnValue = roomForIdentifierUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + roomForIdentifierUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + roomForIdentifierUnderlyingReturnValue = newValue + } + } + } + } + var roomForIdentifierClosure: ((String) -> Room?)? + + func roomForIdentifier(_ roomID: String) -> Room? { + roomForIdentifierCallsCount += 1 + roomForIdentifierReceivedRoomID = roomID + DispatchQueue.main.async { + self.roomForIdentifierReceivedInvocations.append(roomID) + } + if let roomForIdentifierClosure = roomForIdentifierClosure { + return roomForIdentifierClosure(roomID) + } else { + return roomForIdentifierReturnValue + } + } +} class NetworkMonitorMock: NetworkMonitorProtocol, @unchecked Sendable { var reachabilityPublisher: CurrentValuePublisher { get { return underlyingReachabilityPublisher } @@ -11563,6 +11745,59 @@ class NetworkMonitorMock: NetworkMonitorProtocol, @unchecked Sendable { } var underlyingReachabilityPublisher: CurrentValuePublisher! +} +class NotificationItemProxyMock: NotificationItemProxyProtocol, @unchecked Sendable { + var event: NotificationEvent? + var senderID: String { + get { return underlyingSenderID } + set(value) { underlyingSenderID = value } + } + var underlyingSenderID: String! + var roomID: String { + get { return underlyingRoomID } + set(value) { underlyingRoomID = value } + } + var underlyingRoomID: String! + var receiverID: String { + get { return underlyingReceiverID } + set(value) { underlyingReceiverID = value } + } + var underlyingReceiverID: String! + var senderDisplayName: String? + var senderAvatarMediaSource: MediaSourceProxy? + var roomDisplayName: String { + get { return underlyingRoomDisplayName } + set(value) { underlyingRoomDisplayName = value } + } + var underlyingRoomDisplayName: String! + var roomAvatarMediaSource: MediaSourceProxy? + var roomJoinedMembers: Int { + get { return underlyingRoomJoinedMembers } + set(value) { underlyingRoomJoinedMembers = value } + } + var underlyingRoomJoinedMembers: Int! + var isRoomDirect: Bool { + get { return underlyingIsRoomDirect } + set(value) { underlyingIsRoomDirect = value } + } + var underlyingIsRoomDirect: Bool! + var isRoomPrivate: Bool { + get { return underlyingIsRoomPrivate } + set(value) { underlyingIsRoomPrivate = value } + } + var underlyingIsRoomPrivate: Bool! + var isNoisy: Bool { + get { return underlyingIsNoisy } + set(value) { underlyingIsNoisy = value } + } + var underlyingIsNoisy: Bool! + var hasMention: Bool { + get { return underlyingHasMention } + set(value) { underlyingHasMention = value } + } + var underlyingHasMention: Bool! + var threadRootEventID: String? + } class NotificationManagerMock: NotificationManagerProtocol, @unchecked Sendable { weak var delegate: NotificationManagerDelegate? diff --git a/ElementX/Sources/Mocks/NSEUserSessionMock.swift b/ElementX/Sources/Mocks/NSEUserSessionMock.swift new file mode 100644 index 0000000000..7cf72c9436 --- /dev/null +++ b/ElementX/Sources/Mocks/NSEUserSessionMock.swift @@ -0,0 +1,24 @@ +// +// Copyright 2025 Element Creations Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. +// Please see LICENSE files in the repository root for full details. +// + +import MatrixRustSDK + +struct NSEUserSessionMockConfiguration { + var inviteAvatarsVisibility = InviteAvatars.on + var mediaPreviewVisibility = MediaPreviews.on + var threadsEnabled = true +} + +extension NSEUserSessionMock { + convenience init(_ configuration: NSEUserSessionMockConfiguration) { + self.init() + + underlyingInviteAvatarsVisibility = configuration.inviteAvatarsVisibility + underlyingMediaPreviewVisibility = configuration.mediaPreviewVisibility + underlyingThreadsEnabled = configuration.threadsEnabled + } +} diff --git a/ElementX/Sources/Mocks/NotificationItemProxyMock.swift b/ElementX/Sources/Mocks/NotificationItemProxyMock.swift new file mode 100644 index 0000000000..30df12c4ce --- /dev/null +++ b/ElementX/Sources/Mocks/NotificationItemProxyMock.swift @@ -0,0 +1,55 @@ +// +// Copyright 2025 Element Creations Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. +// Please see LICENSE files in the repository root for full details. +// + +import Foundation +import MatrixRustSDK + +struct NotificationItemProxyMockConfiguration { + var event: NotificationEvent? = { + // This is likely the most common notification kind + // So it's also the best to use as a default test + let messageType = MessageType.text(content: TextMessageContent(body: "Hello world!", formatted: nil)) + let messageLikeContent = MessageLikeEventContent.roomMessage(messageType: messageType, inReplyToEventId: nil) + let event = TimelineEventSDKMock() + event.eventIdUnderlyingReturnValue = UUID().uuidString + event.eventTypeReturnValue = TimelineEventType.messageLike(content: messageLikeContent) + return .timeline(event: event) + }() + + var senderID: String = UUID().uuidString + var roomID: String = UUID().uuidString + var receiverID: String = UUID().uuidString + var senderDisplayName: String? + var senderAvatarMediaSource: MediaSourceProxy? + var roomAvatarMediaSource: MediaSourceProxy? + var roomDisplayName: String + var roomJoinedMembers = 2 + var isRoomDirect = false + var isRoomPrivate = false + var isNoisy = false + var hasMention = false + var threadRootEventID: String? +} + +extension NotificationItemProxyMock { + convenience init(_ configuration: NotificationItemProxyMockConfiguration) { + self.init() + event = configuration.event + underlyingSenderID = configuration.senderID + underlyingRoomID = configuration.roomID + underlyingReceiverID = configuration.receiverID + senderDisplayName = configuration.senderDisplayName + roomAvatarMediaSource = configuration.roomAvatarMediaSource + underlyingRoomDisplayName = configuration.roomDisplayName + underlyingRoomJoinedMembers = configuration.roomJoinedMembers + underlyingIsRoomDirect = configuration.isRoomDirect + underlyingIsRoomPrivate = configuration.isRoomPrivate + underlyingIsNoisy = configuration.isNoisy + underlyingHasMention = configuration.hasMention + threadRootEventID = configuration.threadRootEventID + } +} diff --git a/ElementX/SupportingFiles/target.yml b/ElementX/SupportingFiles/target.yml index cc3b6c3f9b..33afe57c3f 100644 --- a/ElementX/SupportingFiles/target.yml +++ b/ElementX/SupportingFiles/target.yml @@ -261,3 +261,10 @@ targets: - path: ../SupportingFiles - path: ../../Tools/Scripts/Templates/SimpleScreenExample/ElementX - path: ../../DevelopmentAssets/Media + + # This is required for testing purposes... The problem with unit tests is that if you + # try to `@testable import NSE` you can only get the definition of files, but due to a + # limitation in how they work, they can only compile files that are part of the main test + # target, so linking will fail. The solution is to just have the main app to reference the + # extension code, and test it directly. + - path: ../../NSE/Sources diff --git a/NSE/Sources/NSEUserSession.swift b/NSE/Sources/NSEUserSession.swift index 241e819b9a..30af779138 100644 --- a/NSE/Sources/NSEUserSession.swift +++ b/NSE/Sources/NSEUserSession.swift @@ -9,10 +9,19 @@ import Foundation import MatrixRustSDK -final class NSEUserSession { - let sessionDirectories: SessionDirectories - let appSettings: CommonSettingsProtocol +// sourcery: AutoMockable +protocol NSEUserSessionProtocol { + var inviteAvatarsVisibility: InviteAvatars { get async } + var mediaPreviewVisibility: MediaPreviews { get async } + var threadsEnabled: Bool { get } + func notificationItemProxy(roomID: String, eventID: String) async -> NotificationItemProxyProtocol? + func roomForIdentifier(_ roomID: String) -> Room? +} + +final class NSEUserSession: NSEUserSessionProtocol { + private let sessionDirectories: SessionDirectories + private let appSettings: CommonSettingsProtocol private let baseClient: Client private let notificationClient: NotificationClient private let userID: String @@ -42,6 +51,10 @@ final class NSEUserSession { } } } + + var threadsEnabled: Bool { + appSettings.threadsEnabled + } init(credentials: KeychainCredentials, roomID: String, diff --git a/NSE/Sources/NotificationContentBuilder.swift b/NSE/Sources/NotificationContentBuilder.swift index f01ebe5370..cf5306e5e1 100644 --- a/NSE/Sources/NotificationContentBuilder.swift +++ b/NSE/Sources/NotificationContentBuilder.swift @@ -16,7 +16,7 @@ import Version struct NotificationContentBuilder { let messageEventStringBuilder: RoomMessageEventStringBuilder - let userSession: NSEUserSession + let userSession: NSEUserSessionProtocol /// Process the given notification item proxy /// - Parameters: @@ -38,7 +38,7 @@ struct NotificationContentBuilder { } // So that the UI groups notification that are received for the same room/thread but also for the same user - let threadIdentifier = if userSession.appSettings.threadsEnabled, let threadRootEventID = notificationItem.threadRootEventID { + let threadIdentifier = if userSession.threadsEnabled, let threadRootEventID = notificationItem.threadRootEventID { // If a threaded message we group notifications also by thread root id "\(notificationItem.receiverID)\(notificationItem.roomID)\(threadRootEventID)" } else { @@ -110,13 +110,13 @@ struct NotificationContentBuilder { notificationContent.body = body let name = notificationItem.senderDisplayName ?? notificationItem.roomDisplayName - await addSenderIcon(notificationContent: ¬ificationContent, - senderID: notificationItem.senderID, - senderAvatarDisplayName: name, - senderDisplayName: name, - icon: icon(for: notificationItem), - forcePlaceholder: userSession.inviteAvatarsVisibility == .off, - mediaProvider: mediaProvider) + await addCommunicationContext(notificationContent: ¬ificationContent, + senderID: notificationItem.senderID, + senderAvatarDisplayName: name, + senderDisplayName: name, + icon: icon(for: notificationItem), + forcePlaceholder: userSession.inviteAvatarsVisibility == .off, + mediaProvider: mediaProvider) } private func processMessageLike(notificationContent: inout UNMutableNotificationContent, @@ -136,17 +136,17 @@ struct NotificationContentBuilder { let senderDisplayName = notificationItem.hasMention ? L10n.notificationSenderMentionReply(senderAvatarDisplayName) : senderAvatarDisplayName - await addSenderIcon(notificationContent: ¬ificationContent, - senderID: notificationItem.senderID, - senderAvatarDisplayName: senderAvatarDisplayName, - senderDisplayName: senderDisplayName, - icon: icon(for: notificationItem), - mediaProvider: mediaProvider) + await addCommunicationContext(notificationContent: ¬ificationContent, + senderID: notificationItem.senderID, + senderAvatarDisplayName: senderAvatarDisplayName, + senderDisplayName: senderDisplayName, + icon: icon(for: notificationItem), + mediaProvider: mediaProvider) } private func icon(for notificationItem: NotificationItemProxyProtocol) -> NotificationIcon { if notificationItem.isDM { - if userSession.appSettings.threadsEnabled, let threadRootEventID = notificationItem.threadRootEventID { + if userSession.threadsEnabled, let threadRootEventID = notificationItem.threadRootEventID { .init(mediaSource: notificationItem.senderAvatarMediaSource, groupInfo: .init(avatarDisplayName: notificationItem.senderDisplayName ?? notificationItem.senderID, displayName: L10n.commonThread, @@ -155,7 +155,7 @@ struct NotificationContentBuilder { .init(mediaSource: notificationItem.senderAvatarMediaSource, groupInfo: nil) } } else { - if userSession.appSettings.threadsEnabled, let threadRootEventID = notificationItem.threadRootEventID { + if userSession.threadsEnabled, let threadRootEventID = notificationItem.threadRootEventID { .init(mediaSource: notificationItem.roomAvatarMediaSource, groupInfo: .init(avatarDisplayName: notificationItem.roomDisplayName, displayName: L10n.notificationThreadInRoom(notificationItem.roomDisplayName), @@ -231,13 +231,13 @@ struct NotificationContentBuilder { } } - private func addSenderIcon(notificationContent: inout UNMutableNotificationContent, - senderID: String, - senderAvatarDisplayName: String, - senderDisplayName: String, - icon: NotificationIcon, - forcePlaceholder: Bool = false, - mediaProvider: MediaProviderProtocol) async { + private func addCommunicationContext(notificationContent: inout UNMutableNotificationContent, + senderID: String, + senderAvatarDisplayName: String, + senderDisplayName: String, + icon: NotificationIcon, + forcePlaceholder: Bool = false, + mediaProvider: MediaProviderProtocol) async { var fetchedImage: INImage? let image: INImage if !forcePlaceholder, @@ -297,7 +297,9 @@ struct NotificationContentBuilder { interaction.direction = .incoming // Donate the interaction before updating notification content. - try? await interaction.donate() + if !ProcessInfo.isRunningTests { + try? await interaction.donate() + } // Update notification content before displaying the // communication notification. diff --git a/ElementX/Sources/Services/Notification/Proxy/NotificationItemProxy.swift b/NSE/Sources/NotificationItemProxy/NotificationItemProxy.swift similarity index 100% rename from ElementX/Sources/Services/Notification/Proxy/NotificationItemProxy.swift rename to NSE/Sources/NotificationItemProxy/NotificationItemProxy.swift diff --git a/ElementX/Sources/Services/Notification/Proxy/NotificationItemProxyProtocol.swift b/NSE/Sources/NotificationItemProxy/NotificationItemProxyProtocol.swift similarity index 97% rename from ElementX/Sources/Services/Notification/Proxy/NotificationItemProxyProtocol.swift rename to NSE/Sources/NotificationItemProxy/NotificationItemProxyProtocol.swift index c82a108c76..3c2050eb1b 100644 --- a/ElementX/Sources/Services/Notification/Proxy/NotificationItemProxyProtocol.swift +++ b/NSE/Sources/NotificationItemProxy/NotificationItemProxyProtocol.swift @@ -10,6 +10,7 @@ import Foundation import MatrixRustSDK import UserNotifications +// sourcery: AutoMockable protocol NotificationItemProxyProtocol { var event: NotificationEvent? { get } diff --git a/NSE/SupportingFiles/target.yml b/NSE/SupportingFiles/target.yml index 632f6c734d..03ba2cf55a 100644 --- a/NSE/SupportingFiles/target.yml +++ b/NSE/SupportingFiles/target.yml @@ -76,7 +76,7 @@ targets: SWIFT_OBJC_INTERFACE_HEADER_NAME: GeneratedInterface-Swift.h OTHER_SWIFT_FLAGS: - "-DIS_NSE" - + sources: - path: ../Sources - path: ../SupportingFiles @@ -124,7 +124,6 @@ targets: - path: ../../ElementX/Sources/Services/Keychain/KeychainControllerProtocol.swift - path: ../../ElementX/Sources/Services/Media/Provider - path: ../../ElementX/Sources/Services/Notification/NotificationConstants.swift - - path: ../../ElementX/Sources/Services/Notification/Proxy - path: ../../ElementX/Sources/Services/Room/RoomSummary/RoomMessageEventStringBuilder.swift - path: ../../ElementX/Sources/Services/UserSession/RestorationToken.swift - path: ../../ElementX/Sources/Services/UserSession/SessionDirectories.swift diff --git a/Tools/Sourcery/AutoMockableConfig.yml b/Tools/Sourcery/AutoMockableConfig.yml index 80a2283314..16900cffd1 100644 --- a/Tools/Sourcery/AutoMockableConfig.yml +++ b/Tools/Sourcery/AutoMockableConfig.yml @@ -1,6 +1,7 @@ sources: include: - ../../ElementX + - ../../NSE exclude: - ../../ElementX/Sources/Mocks/SDK templates: diff --git a/UnitTests/Sources/NotificationContentBuilderTests.swift b/UnitTests/Sources/NotificationContentBuilderTests.swift new file mode 100644 index 0000000000..a8430b507c --- /dev/null +++ b/UnitTests/Sources/NotificationContentBuilderTests.swift @@ -0,0 +1,240 @@ +// +// Copyright 2025 Element Creations Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. +// Please see LICENSE files in the repository root for full details. +// + +import Dynamic +import MatrixRustSDK +import XCTest + +@testable import ElementX + +final class NotificationContentBuilderTests: XCTestCase { + var notificationContentBuilder: NotificationContentBuilder! + var mediaProvider: MediaProviderMock! + var notificationContent: UNMutableNotificationContent! + + override func setUp() { + notificationContent = .init() + let stringBuilder = RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(mentionBuilder: PlainMentionBuilder()), + destination: .notification) + mediaProvider = MediaProviderMock(configuration: .init()) + notificationContentBuilder = NotificationContentBuilder(messageEventStringBuilder: stringBuilder, + userSession: NSEUserSessionMock(.init())) + } + + func testDMMessageNotification() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "Alice", + roomJoinedMembers: 2, + isRoomDirect: true, + isRoomPrivate: true, + isNoisy: true)) + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + // Checking if nil without using asObject always fails + XCTAssertNil(communicationContext.displayName.asObject) + XCTAssertEqual(communicationContext.sender.displayName, "Alice") + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNil(notificationContent.threadRootEventID) + XCTAssertNotNil(notificationContent.sound) + // Remember we remove the @ due to an iOS bug + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!test:matrix.org") + XCTAssertEqual(notificationContent.attachments, []) + } + + func testDMMessageNotificationWithMention() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "Alice", + roomJoinedMembers: 2, + isRoomDirect: true, + isRoomPrivate: true, + isNoisy: true, + hasMention: true)) + + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + // Checking if nil without using asObject always fails + XCTAssertNil(communicationContext.displayName.asObject) + XCTAssertEqual(communicationContext.sender.displayName, L10n.notificationSenderMentionReply("Alice")) + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNil(notificationContent.threadRootEventID) + XCTAssertNotNil(notificationContent.sound) + // Remember we remove the @ due to an iOS bug + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!test:matrix.org") + XCTAssertEqual(notificationContent.attachments, []) + } + + func testDMMessageNotificationWithThread() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "Alice", + roomJoinedMembers: 2, + isRoomDirect: true, + isRoomPrivate: true, + isNoisy: true, + hasMention: false, + threadRootEventID: "thread")) + + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + XCTAssertEqual(communicationContext.displayName, L10n.commonThread) + XCTAssertEqual(communicationContext.sender.displayName, "Alice") + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNotNil(notificationContent.threadRootEventID) + XCTAssertNotNil(notificationContent.sound) + // Remember we remove the @ due to an iOS bug + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!test:matrix.orgthread") + XCTAssertEqual(notificationContent.attachments, []) + } + + func testDMMessageNotificationWithThreadAndMention() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!test:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "Alice", + roomJoinedMembers: 2, + isRoomDirect: true, + isRoomPrivate: true, + isNoisy: true, + hasMention: true, + threadRootEventID: "thread")) + + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + XCTAssertEqual(communicationContext.displayName, L10n.commonThread) + XCTAssertEqual(communicationContext.sender.displayName, L10n.notificationSenderMentionReply("Alice")) + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNotNil(notificationContent.threadRootEventID) + XCTAssertNotNil(notificationContent.sound) + // Remember we remove the @ due to an iOS bug + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!test:matrix.orgthread") + XCTAssertEqual(notificationContent.attachments, []) + } + + func testRoomMessageNotification() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "General", + roomJoinedMembers: 5, + isRoomDirect: false, + isRoomPrivate: false, + isNoisy: false)) + + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + + XCTAssertEqual(communicationContext.displayName, "General") + XCTAssertEqual(communicationContext.sender.displayName, "Alice") + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNil(notificationContent.threadRootEventID) + XCTAssertNil(notificationContent.sound) + // Remember we remove the @ due to an iOS bug + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!testroom:matrix.org") + XCTAssertEqual(notificationContent.attachments, []) + } + + func testRoomMessageNotificationWithMention() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "General", + roomJoinedMembers: 5, + isRoomDirect: false, + isRoomPrivate: false, + isNoisy: true, + hasMention: true)) + + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + XCTAssertEqual(communicationContext.displayName, "General") + XCTAssertEqual(communicationContext.sender.displayName, L10n.notificationSenderMentionReply("Alice")) + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNil(notificationContent.threadRootEventID) + XCTAssertNotNil(notificationContent.sound) + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!testroom:matrix.org") + XCTAssertEqual(notificationContent.attachments, []) + } + + func testRoomMessageNotificationWithThread() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "General", + roomJoinedMembers: 5, + isRoomDirect: false, + isRoomPrivate: false, + isNoisy: false, + threadRootEventID: "thread123")) + + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + XCTAssertEqual(communicationContext.displayName, L10n.notificationThreadInRoom("General")) + XCTAssertEqual(communicationContext.sender.displayName, "Alice") + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNotNil(notificationContent.threadRootEventID) + XCTAssertNil(notificationContent.sound) + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!testroom:matrix.orgthread123") + XCTAssertEqual(notificationContent.attachments, []) + } + + func testRoomMessageNotificationWithThreadAndMention() async { + let notificationItem = NotificationItemProxyMock(.init(roomID: "!testroom:matrix.org", + receiverID: "@bob:matrix.org", + senderDisplayName: "Alice", + roomDisplayName: "General", + roomJoinedMembers: 5, + isRoomDirect: false, + isRoomPrivate: false, + isNoisy: true, + hasMention: true, + threadRootEventID: "thread123")) + await notificationContentBuilder.process(notificationContent: ¬ificationContent, + notificationItem: notificationItem, + mediaProvider: mediaProvider) + let communicationContext = Dynamic(notificationContent, memberName: "communicationContext") + XCTAssertEqual(communicationContext.displayName, L10n.notificationThreadInRoom("General")) + XCTAssertEqual(communicationContext.sender.displayName, L10n.notificationSenderMentionReply("Alice")) + XCTAssertEqual(notificationContent.body, "Hello world!") + XCTAssertEqual(notificationContent.categoryIdentifier, NotificationConstants.Category.message) + XCTAssertNotNil(notificationContent.threadRootEventID) + XCTAssertNotNil(notificationContent.sound) + XCTAssertEqual(notificationContent.threadIdentifier, "bob:matrix.org!testroom:matrix.orgthread123") + XCTAssertEqual(notificationContent.attachments, []) + } +} diff --git a/UnitTests/SupportingFiles/target.yml b/UnitTests/SupportingFiles/target.yml index a26efd5b7e..b6f254a306 100644 --- a/UnitTests/SupportingFiles/target.yml +++ b/UnitTests/SupportingFiles/target.yml @@ -34,6 +34,7 @@ targets: - package: MatrixRustSDK - package: AsyncAlgorithms - package: Clocks + - package: Dynamic info: path: ../SupportingFiles/Info.plist diff --git a/project.yml b/project.yml index 52809a5c63..b527e3e9cc 100644 --- a/project.yml +++ b/project.yml @@ -114,6 +114,9 @@ packages: DSWaveformImage: url: https://github.com/dmrschmidt/DSWaveformImage exactVersion: 14.1.1 + Dynamic: + url: https://github.com/mhdhejazi/Dynamic + exactVersion: 1.2 GZIP: url: https://github.com/nicklockwood/GZIP minorVersion: 1.3.2