mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Pill View (#1797)
* provider can now check the current session * More testable code * created the test condition * it works but not always not sure why, need to dig deeper * sadly we need to use textkit 1 to solve this issue * removed developer option screen test * this experimental solution kinda works but I need a way to pill recomputation is weird * format * display improvement * better and faster solution * pilished the code * better coloring * swift format * just need to solve the caching issue * fix caching issue * tests done! * changelog * pr comments addressed * all pr comments addressed * docs * line lenght * updated tests and fixed a parsing permalink issue * MentionBuilder * pr comments * swiftformat * code blocks should not have links * Update ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Update ElementX/Sources/Services/Client/ClientProxy.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Update UnitTests/Sources/AttributedStringBuilderTests.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Update ElementX/Sources/UITests/UITestsAppCoordinator.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Update ElementX/Sources/Other/Pills/PillAttachmentViewProvider.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Update ElementX/Sources/Other/Pills/MentionBuilder.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * pr comments * swiftformat --------- Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com>
This commit is contained in:
parent
8d4c5e2885
commit
7bde419e85
@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 56;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@ -445,8 +445,10 @@
|
|||||||
8B41D0357B91CD3B6F6A3BCA /* EmoteRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */; };
|
8B41D0357B91CD3B6F6A3BCA /* EmoteRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */; };
|
||||||
8B76191B9DDD1AC90A6E3A35 /* MediaFileHandleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */; };
|
8B76191B9DDD1AC90A6E3A35 /* MediaFileHandleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */; };
|
||||||
8BC8EF6705A78946C1F22891 /* SoftLogoutScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71A7D4DDEEE5D2CA0C8D63CD /* SoftLogoutScreen.swift */; };
|
8BC8EF6705A78946C1F22891 /* SoftLogoutScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71A7D4DDEEE5D2CA0C8D63CD /* SoftLogoutScreen.swift */; };
|
||||||
|
8C050A8012E6078BEAEF5BC8 /* PillTextAttachmentData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913C8E13B8B602C7B6C0C4AE /* PillTextAttachmentData.swift */; };
|
||||||
8C1A5ECAF895D4CAF8C4D461 /* AppActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F21ED7205048668BEB44A38 /* AppActivityView.swift */; };
|
8C1A5ECAF895D4CAF8C4D461 /* AppActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F21ED7205048668BEB44A38 /* AppActivityView.swift */; };
|
||||||
8C454500B8073E1201F801A9 /* MXLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = A34A814CBD56230BC74FFCF4 /* MXLogger.swift */; };
|
8C454500B8073E1201F801A9 /* MXLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = A34A814CBD56230BC74FFCF4 /* MXLogger.swift */; };
|
||||||
|
8C706DA7EAC0974CA2F8F1CD /* MentionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15748C254911E3654C93B0ED /* MentionBuilder.swift */; };
|
||||||
8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */; };
|
8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */; };
|
||||||
8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */; };
|
8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */; };
|
||||||
8D605456793F243649EC96AA /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = CD6B0C4639E066915B5E6463 /* target.yml */; };
|
8D605456793F243649EC96AA /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = CD6B0C4639E066915B5E6463 /* target.yml */; };
|
||||||
@ -711,10 +713,10 @@
|
|||||||
D8359F67AF3A83516E9083C1 /* MockUserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4756C5A8C8649AD6C10C615 /* MockUserSession.swift */; };
|
D8359F67AF3A83516E9083C1 /* MockUserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4756C5A8C8649AD6C10C615 /* MockUserSession.swift */; };
|
||||||
D8385A51A3D0FA9283556281 /* RoundedLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */; };
|
D8385A51A3D0FA9283556281 /* RoundedLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */; };
|
||||||
D84D5BDFB1B915389AC807B4 /* CreatePollScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A328F9E556F5CFA89332017 /* CreatePollScreenViewModel.swift */; };
|
D84D5BDFB1B915389AC807B4 /* CreatePollScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A328F9E556F5CFA89332017 /* CreatePollScreenViewModel.swift */; };
|
||||||
D85D4FA590305180B4A41795 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB3073CCD77D906B330BC1D6 /* Tests.swift */; };
|
|
||||||
D871C8CF46950F959C9A62C3 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C54464351F170D570110AFCA /* WelcomeScreen.swift */; };
|
D871C8CF46950F959C9A62C3 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C54464351F170D570110AFCA /* WelcomeScreen.swift */; };
|
||||||
D876EC0FED3B6D46C806912A /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */; };
|
D876EC0FED3B6D46C806912A /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */; };
|
||||||
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */; };
|
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */; };
|
||||||
|
D9092786ACCFF72565AD7389 /* PillContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B203689DFD1431181A795F4 /* PillContext.swift */; };
|
||||||
D9473FC9B077A6EDB7A12001 /* LocationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */; };
|
D9473FC9B077A6EDB7A12001 /* LocationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */; };
|
||||||
D98B5EE8C4F5A2CE84687AE8 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
|
D98B5EE8C4F5A2CE84687AE8 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
|
||||||
D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352359663A0E52BA20761EE /* LoadableImage.swift */; };
|
D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352359663A0E52BA20761EE /* LoadableImage.swift */; };
|
||||||
@ -724,6 +726,7 @@
|
|||||||
DC68E866D6E664B0D2B06E74 /* MockImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */; };
|
DC68E866D6E664B0D2B06E74 /* MockImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */; };
|
||||||
DDB47D29C6865669288BF87C /* UIFont+AttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */; };
|
DDB47D29C6865669288BF87C /* UIFont+AttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */; };
|
||||||
DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */; };
|
DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */; };
|
||||||
|
DEF1477A76F5AAE0A2EB0F32 /* NSEMentionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3AF5A7EE5CA321724ED32CC /* NSEMentionBuilder.swift */; };
|
||||||
DF004A5B2EABBD0574D06A04 /* SplashScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 854BCEAF2A832176FAACD2CB /* SplashScreenCoordinator.swift */; };
|
DF004A5B2EABBD0574D06A04 /* SplashScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 854BCEAF2A832176FAACD2CB /* SplashScreenCoordinator.swift */; };
|
||||||
DF05F9C9D3D977EB77E13692 /* DesignKit in Frameworks */ = {isa = PBXBuildFile; productRef = A593735D882778FD2C9A185B /* DesignKit */; };
|
DF05F9C9D3D977EB77E13692 /* DesignKit in Frameworks */ = {isa = PBXBuildFile; productRef = A593735D882778FD2C9A185B /* DesignKit */; };
|
||||||
DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */; };
|
DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */; };
|
||||||
@ -830,6 +833,7 @@
|
|||||||
FCD3F2B82CAB29A07887A127 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; };
|
FCD3F2B82CAB29A07887A127 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; };
|
||||||
FCDA202B246F75BA28E10C5F /* MapTilerAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = E062C1750EFC8627DE4CAB8E /* MapTilerAuthorization.swift */; };
|
FCDA202B246F75BA28E10C5F /* MapTilerAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = E062C1750EFC8627DE4CAB8E /* MapTilerAuthorization.swift */; };
|
||||||
FD4C21F8DA1E273DE94FCD1A /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */; };
|
FD4C21F8DA1E273DE94FCD1A /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */; };
|
||||||
|
FD4DEC88210F35C35B2FB386 /* ProcessInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3A1398EFF65090FDA1CB639 /* ProcessInfo.swift */; };
|
||||||
FD762761C5D0C30E6255C3D8 /* ServerConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */; };
|
FD762761C5D0C30E6255C3D8 /* ServerConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */; };
|
||||||
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1593DD87F974F8509BB619 /* ElementAnimations.swift */; };
|
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1593DD87F974F8509BB619 /* ElementAnimations.swift */; };
|
||||||
FF34BF2AF731340AF9414A18 /* SwipeRightAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4552D3466B1453F287223ADA /* SwipeRightAction.swift */; };
|
FF34BF2AF731340AF9414A18 /* SwipeRightAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4552D3466B1453F287223ADA /* SwipeRightAction.swift */; };
|
||||||
@ -943,13 +947,14 @@
|
|||||||
127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = "<group>"; };
|
127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = "<group>"; };
|
||||||
12EDAFB64FA5F6812D54F39A /* MigrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenViewModel.swift; sourceTree = "<group>"; };
|
12EDAFB64FA5F6812D54F39A /* MigrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
12F1E7F9C2BE8BB751037826 /* WaitlistScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenCoordinator.swift; sourceTree = "<group>"; };
|
12F1E7F9C2BE8BB751037826 /* WaitlistScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
|
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
|
||||||
130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; };
|
130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; };
|
||||||
13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
1423AB065857FA546444DB15 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
1423AB065857FA546444DB15 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
||||||
142808B69851451AC32A2CEA /* RoomSummaryDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryDetails.swift; sourceTree = "<group>"; };
|
142808B69851451AC32A2CEA /* RoomSummaryDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryDetails.swift; sourceTree = "<group>"; };
|
||||||
1454CF3AABD242F55C8A2615 /* InviteUsersScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenModels.swift; sourceTree = "<group>"; };
|
1454CF3AABD242F55C8A2615 /* InviteUsersScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenModels.swift; sourceTree = "<group>"; };
|
||||||
153726EDCE1ACBB3D466A916 /* ReactionsSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsSummaryView.swift; sourceTree = "<group>"; };
|
153726EDCE1ACBB3D466A916 /* ReactionsSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsSummaryView.swift; sourceTree = "<group>"; };
|
||||||
|
15748C254911E3654C93B0ED /* MentionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionBuilder.swift; sourceTree = "<group>"; };
|
||||||
15A657D96779D1DEB8EF1327 /* CreateRoomViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModel.swift; sourceTree = "<group>"; };
|
15A657D96779D1DEB8EF1327 /* CreateRoomViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModel.swift; sourceTree = "<group>"; };
|
||||||
16037EE9E9A52AF37B7818E3 /* AnalyticsSettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenUITests.swift; sourceTree = "<group>"; };
|
16037EE9E9A52AF37B7818E3 /* AnalyticsSettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
16D09C79746BDCD9173EB3A7 /* RoomDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenModels.swift; sourceTree = "<group>"; };
|
16D09C79746BDCD9173EB3A7 /* RoomDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenModels.swift; sourceTree = "<group>"; };
|
||||||
@ -1095,7 +1100,7 @@
|
|||||||
47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = "<group>"; };
|
47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = "<group>"; };
|
471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
47873756E45B46683D97DC32 /* LegalInformationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenModels.swift; sourceTree = "<group>"; };
|
47873756E45B46683D97DC32 /* LegalInformationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenModels.swift; sourceTree = "<group>"; };
|
||||||
478BE8591BD13E908EF70C0C /* DesignKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = DesignKit; path = DesignKit; sourceTree = SOURCE_ROOT; };
|
478BE8591BD13E908EF70C0C /* DesignKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DesignKit; sourceTree = SOURCE_ROOT; };
|
||||||
4798B3B7A1E8AE3901CEE8C6 /* FramePreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramePreferenceKey.swift; sourceTree = "<group>"; };
|
4798B3B7A1E8AE3901CEE8C6 /* FramePreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramePreferenceKey.swift; sourceTree = "<group>"; };
|
||||||
47EBB5D698CE9A25BB553A2D /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
|
47EBB5D698CE9A25BB553A2D /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
|
||||||
47F29139BC2A804CE5E0757E /* MediaUploadPreviewScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenViewModel.swift; sourceTree = "<group>"; };
|
47F29139BC2A804CE5E0757E /* MediaUploadPreviewScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
@ -1109,6 +1114,7 @@
|
|||||||
4A4AD793D50748F8997E5B15 /* TimelineItemMacContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMacContextMenu.swift; sourceTree = "<group>"; };
|
4A4AD793D50748F8997E5B15 /* TimelineItemMacContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMacContextMenu.swift; sourceTree = "<group>"; };
|
||||||
4AB7D7DAAAF662DED9D02379 /* MockMediaLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaLoader.swift; sourceTree = "<group>"; };
|
4AB7D7DAAAF662DED9D02379 /* MockMediaLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaLoader.swift; sourceTree = "<group>"; };
|
||||||
4ADC55DFF46083BC957E0019 /* CreatePollScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreenModels.swift; sourceTree = "<group>"; };
|
4ADC55DFF46083BC957E0019 /* CreatePollScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreenModels.swift; sourceTree = "<group>"; };
|
||||||
|
4B203689DFD1431181A795F4 /* PillContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContext.swift; sourceTree = "<group>"; };
|
||||||
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
|
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
|
||||||
4B5046BB295AEAFA6FB81655 /* SessionVerificationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenModels.swift; sourceTree = "<group>"; };
|
4B5046BB295AEAFA6FB81655 /* SessionVerificationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenModels.swift; sourceTree = "<group>"; };
|
||||||
4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
@ -1293,7 +1299,7 @@
|
|||||||
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
|
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
|
||||||
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
|
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = "<group>"; };
|
8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = "<group>"; };
|
||||||
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; };
|
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = "<group>"; };
|
||||||
8E1BBA73B611EDEEA6E20E05 /* InvitesScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenModels.swift; sourceTree = "<group>"; };
|
8E1BBA73B611EDEEA6E20E05 /* InvitesScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenModels.swift; sourceTree = "<group>"; };
|
||||||
8EC57A32ABC80D774CC663DB /* SettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenUITests.swift; sourceTree = "<group>"; };
|
8EC57A32ABC80D774CC663DB /* SettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
8F21ED7205048668BEB44A38 /* AppActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppActivityView.swift; sourceTree = "<group>"; };
|
8F21ED7205048668BEB44A38 /* AppActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppActivityView.swift; sourceTree = "<group>"; };
|
||||||
@ -1302,6 +1308,7 @@
|
|||||||
8FC803282F9268D49F4ABF14 /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
|
8FC803282F9268D49F4ABF14 /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
|
||||||
90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItem.swift; sourceTree = "<group>"; };
|
90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
90F2F8998E5632668B0AD848 /* RoomTimelineItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemView.swift; sourceTree = "<group>"; };
|
90F2F8998E5632668B0AD848 /* RoomTimelineItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemView.swift; sourceTree = "<group>"; };
|
||||||
|
913C8E13B8B602C7B6C0C4AE /* PillTextAttachmentData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillTextAttachmentData.swift; sourceTree = "<group>"; };
|
||||||
91CF6F7D08228D16BA69B63B /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
91CF6F7D08228D16BA69B63B /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
923485F85E1D765EF9D20E88 /* UserProfileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileCell.swift; sourceTree = "<group>"; };
|
923485F85E1D765EF9D20E88 /* UserProfileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileCell.swift; sourceTree = "<group>"; };
|
||||||
92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCAuthenticationPresenter.swift; sourceTree = "<group>"; };
|
92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCAuthenticationPresenter.swift; sourceTree = "<group>"; };
|
||||||
@ -1403,12 +1410,13 @@
|
|||||||
B2E7C987AE5DC9087BB19F7D /* MediaUploadPreviewScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenModels.swift; sourceTree = "<group>"; };
|
B2E7C987AE5DC9087BB19F7D /* MediaUploadPreviewScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenModels.swift; sourceTree = "<group>"; };
|
||||||
B3005886F00029F058DB62BE /* StartChatScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenCoordinator.swift; sourceTree = "<group>"; };
|
B3005886F00029F058DB62BE /* StartChatScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
B383DCD3DCB19E00FD478A5F /* ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialog.swift; sourceTree = "<group>"; };
|
B383DCD3DCB19E00FD478A5F /* ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialog.swift; sourceTree = "<group>"; };
|
||||||
|
B3A1398EFF65090FDA1CB639 /* ProcessInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessInfo.swift; sourceTree = "<group>"; };
|
||||||
B43456E73F8A2D52B69B9FB9 /* TemplateScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModel.swift; sourceTree = "<group>"; };
|
B43456E73F8A2D52B69B9FB9 /* TemplateScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
B48B7AD4908C5C374517B892 /* MapAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MapAssets.xcassets; sourceTree = "<group>"; };
|
B48B7AD4908C5C374517B892 /* MapAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MapAssets.xcassets; sourceTree = "<group>"; };
|
||||||
B4CFE236419E830E8946639C /* Analytics+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Analytics+SwiftUI.swift"; sourceTree = "<group>"; };
|
B4CFE236419E830E8946639C /* Analytics+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Analytics+SwiftUI.swift"; sourceTree = "<group>"; };
|
||||||
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; };
|
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; };
|
||||||
B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; };
|
B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; };
|
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = "<group>"; };
|
||||||
B6311F21F911E23BE4DF51B4 /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = "<group>"; };
|
B6311F21F911E23BE4DF51B4 /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = "<group>"; };
|
B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
B697816AF93DA06EC58C5D70 /* WaitlistScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
B697816AF93DA06EC58C5D70 /* WaitlistScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
@ -1430,7 +1438,6 @@
|
|||||||
BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = "<group>"; };
|
BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = "<group>"; };
|
||||||
BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreen.swift; sourceTree = "<group>"; };
|
BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreen.swift; sourceTree = "<group>"; };
|
||||||
BB23BEAF8831DC6A57E39F52 /* CreatePollScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreenCoordinator.swift; sourceTree = "<group>"; };
|
BB23BEAF8831DC6A57E39F52 /* CreatePollScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
BB3073CCD77D906B330BC1D6 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
|
|
||||||
BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenCoordinator.swift; sourceTree = "<group>"; };
|
BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
BC8AA23D4F37CC26564F63C5 /* LayoutMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutMocks.swift; sourceTree = "<group>"; };
|
BC8AA23D4F37CC26564F63C5 /* LayoutMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutMocks.swift; sourceTree = "<group>"; };
|
||||||
BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNNotificationContent.swift; sourceTree = "<group>"; };
|
BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNNotificationContent.swift; sourceTree = "<group>"; };
|
||||||
@ -1455,6 +1462,7 @@
|
|||||||
C2E9B841EE4878283ECDB554 /* InviteUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreen.swift; sourceTree = "<group>"; };
|
C2E9B841EE4878283ECDB554 /* InviteUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreen.swift; sourceTree = "<group>"; };
|
||||||
C2F079B5DBD0D85FEA687AAE /* SDKGeneratedMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKGeneratedMocks.swift; sourceTree = "<group>"; };
|
C2F079B5DBD0D85FEA687AAE /* SDKGeneratedMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKGeneratedMocks.swift; sourceTree = "<group>"; };
|
||||||
C352359663A0E52BA20761EE /* LoadableImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableImage.swift; sourceTree = "<group>"; };
|
C352359663A0E52BA20761EE /* LoadableImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableImage.swift; sourceTree = "<group>"; };
|
||||||
|
C3AF5A7EE5CA321724ED32CC /* NSEMentionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEMentionBuilder.swift; sourceTree = "<group>"; };
|
||||||
C49C1CEBA9BCF5D2AD1884FA /* OnboardingScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenViewModel.swift; sourceTree = "<group>"; };
|
C49C1CEBA9BCF5D2AD1884FA /* OnboardingScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
C4C89820BB2B88D4EA28131C /* BugReportScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
C4C89820BB2B88D4EA28131C /* BugReportScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
C4CD503F5E0938FE53C7C6E7 /* UserDetailsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenCoordinator.swift; sourceTree = "<group>"; };
|
C4CD503F5E0938FE53C7C6E7 /* UserDetailsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
@ -1499,7 +1507,7 @@
|
|||||||
CD95B3714F806AC9CF9A557B /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; };
|
CD95B3714F806AC9CF9A557B /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; };
|
||||||
CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = "<group>"; };
|
CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = "<group>"; };
|
||||||
CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
|
CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
|
||||||
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; };
|
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
|
||||||
CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; sourceTree = "<group>"; };
|
CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; sourceTree = "<group>"; };
|
||||||
D0140615D2232612C813FD6C /* EncryptedHistoryRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineItem.swift; sourceTree = "<group>"; };
|
D0140615D2232612C813FD6C /* EncryptedHistoryRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = "<group>"; };
|
D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = "<group>"; };
|
||||||
@ -1587,7 +1595,7 @@
|
|||||||
ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModel.swift; sourceTree = "<group>"; };
|
ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; };
|
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; };
|
||||||
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
||||||
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; };
|
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = "<group>"; };
|
||||||
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
|
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; };
|
EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
||||||
@ -1601,7 +1609,7 @@
|
|||||||
F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenModels.swift; sourceTree = "<group>"; };
|
F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenModels.swift; sourceTree = "<group>"; };
|
||||||
F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = "<group>"; };
|
F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = "<group>"; };
|
||||||
F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = "<group>"; };
|
F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = "<group>"; };
|
F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = "<group>"; };
|
||||||
F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; };
|
F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; };
|
||||||
F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; };
|
F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
F36C0A6D59717193F49EA986 /* UserSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionTests.swift; sourceTree = "<group>"; };
|
F36C0A6D59717193F49EA986 /* UserSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionTests.swift; sourceTree = "<group>"; };
|
||||||
@ -2470,6 +2478,7 @@
|
|||||||
children = (
|
children = (
|
||||||
4959CECEC984B3995616F427 /* DataProtectionManager.swift */,
|
4959CECEC984B3995616F427 /* DataProtectionManager.swift */,
|
||||||
D3D455BC2423D911A62ACFB2 /* NSELogger.swift */,
|
D3D455BC2423D911A62ACFB2 /* NSELogger.swift */,
|
||||||
|
C3AF5A7EE5CA321724ED32CC /* NSEMentionBuilder.swift */,
|
||||||
E9DFC0FBA0FC6FC4DC0FC9FC /* NSESettings.swift */,
|
E9DFC0FBA0FC6FC4DC0FC9FC /* NSESettings.swift */,
|
||||||
EEAA2832D93EC7D2608703FB /* NSEUserSession.swift */,
|
EEAA2832D93EC7D2608703FB /* NSEUserSession.swift */,
|
||||||
49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */,
|
49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */,
|
||||||
@ -3200,10 +3209,13 @@
|
|||||||
9C4193C4524B35FD6B94B5A9 /* Pills */ = {
|
9C4193C4524B35FD6B94B5A9 /* Pills */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
15748C254911E3654C93B0ED /* MentionBuilder.swift */,
|
||||||
E1E0B4A34E69BD2132BEC521 /* MessageText.swift */,
|
E1E0B4A34E69BD2132BEC521 /* MessageText.swift */,
|
||||||
1B53D6C5C0D14B04D3AB3F6E /* PillAttachmentViewProvider.swift */,
|
1B53D6C5C0D14B04D3AB3F6E /* PillAttachmentViewProvider.swift */,
|
||||||
9CF1EE0AA78470C674554262 /* PillTextAttachment.swift */,
|
9CF1EE0AA78470C674554262 /* PillTextAttachment.swift */,
|
||||||
|
913C8E13B8B602C7B6C0C4AE /* PillTextAttachmentData.swift */,
|
||||||
7773CBFDBD458E0B7E270507 /* PillView.swift */,
|
7773CBFDBD458E0B7E270507 /* PillView.swift */,
|
||||||
|
4B203689DFD1431181A795F4 /* PillContext.swift */,
|
||||||
);
|
);
|
||||||
path = Pills;
|
path = Pills;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -3533,11 +3545,11 @@
|
|||||||
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */,
|
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */,
|
||||||
10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */,
|
10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */,
|
||||||
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */,
|
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */,
|
||||||
|
B3A1398EFF65090FDA1CB639 /* ProcessInfo.swift */,
|
||||||
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */,
|
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */,
|
||||||
DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */,
|
DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */,
|
||||||
4481799F455B3DA243BDA2AC /* ShareToMapsAppActivity.swift */,
|
4481799F455B3DA243BDA2AC /* ShareToMapsAppActivity.swift */,
|
||||||
B1E227F34BE43B08E098796E /* TestablePreview.swift */,
|
B1E227F34BE43B08E098796E /* TestablePreview.swift */,
|
||||||
BB3073CCD77D906B330BC1D6 /* Tests.swift */,
|
|
||||||
1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */,
|
1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */,
|
||||||
35FA991289149D31F4286747 /* UserPreference.swift */,
|
35FA991289149D31F4286747 /* UserPreference.swift */,
|
||||||
7431C962E314ADAE38B6D708 /* Analytics */,
|
7431C962E314ADAE38B6D708 /* Analytics */,
|
||||||
@ -4409,6 +4421,7 @@
|
|||||||
E2DB696117BAEABAD5718023 /* MediaSourceProxy.swift in Sources */,
|
E2DB696117BAEABAD5718023 /* MediaSourceProxy.swift in Sources */,
|
||||||
4FC085B1E5D1EB804495E2F4 /* MockMediaProvider.swift in Sources */,
|
4FC085B1E5D1EB804495E2F4 /* MockMediaProvider.swift in Sources */,
|
||||||
5455147CAC63F71E48F7D699 /* NSELogger.swift in Sources */,
|
5455147CAC63F71E48F7D699 /* NSELogger.swift in Sources */,
|
||||||
|
DEF1477A76F5AAE0A2EB0F32 /* NSEMentionBuilder.swift in Sources */,
|
||||||
E571163060CBE87D82CE24FD /* NSESettings.swift in Sources */,
|
E571163060CBE87D82CE24FD /* NSESettings.swift in Sources */,
|
||||||
30CC4F796B27BE8B1DFDBF5A /* NSEUserSession.swift in Sources */,
|
30CC4F796B27BE8B1DFDBF5A /* NSEUserSession.swift in Sources */,
|
||||||
1D5DC685CED904386C89B7DA /* NSRegularExpresion.swift in Sources */,
|
1D5DC685CED904386C89B7DA /* NSRegularExpresion.swift in Sources */,
|
||||||
@ -4776,6 +4789,7 @@
|
|||||||
A969147E0EEE0E27EE226570 /* MediaUploadPreviewScreenViewModel.swift in Sources */,
|
A969147E0EEE0E27EE226570 /* MediaUploadPreviewScreenViewModel.swift in Sources */,
|
||||||
9B872FF37DBE6BE054903831 /* MediaUploadPreviewScreenViewModelProtocol.swift in Sources */,
|
9B872FF37DBE6BE054903831 /* MediaUploadPreviewScreenViewModelProtocol.swift in Sources */,
|
||||||
8A0BD60CA4A6004DB06B5403 /* MediaUploadingPreprocessor.swift in Sources */,
|
8A0BD60CA4A6004DB06B5403 /* MediaUploadingPreprocessor.swift in Sources */,
|
||||||
|
8C706DA7EAC0974CA2F8F1CD /* MentionBuilder.swift in Sources */,
|
||||||
64AB99285DC4437C0DDE9585 /* MenuSheetLabelStyle.swift in Sources */,
|
64AB99285DC4437C0DDE9585 /* MenuSheetLabelStyle.swift in Sources */,
|
||||||
858B0A45257174AAFD448EA0 /* MessageComposer.swift in Sources */,
|
858B0A45257174AAFD448EA0 /* MessageComposer.swift in Sources */,
|
||||||
C8E0FA0FF2CD6613264FA6B9 /* MessageForwardingScreen.swift in Sources */,
|
C8E0FA0FF2CD6613264FA6B9 /* MessageForwardingScreen.swift in Sources */,
|
||||||
@ -4846,7 +4860,9 @@
|
|||||||
962A4F8AD6312804E2C6BB6E /* PhotoLibraryPicker.swift in Sources */,
|
962A4F8AD6312804E2C6BB6E /* PhotoLibraryPicker.swift in Sources */,
|
||||||
EE4E2C1922BBF5169E213555 /* PillAttachmentViewProvider.swift in Sources */,
|
EE4E2C1922BBF5169E213555 /* PillAttachmentViewProvider.swift in Sources */,
|
||||||
7708976CEE6AFB5CFAEFBA68 /* PillTextAttachment.swift in Sources */,
|
7708976CEE6AFB5CFAEFBA68 /* PillTextAttachment.swift in Sources */,
|
||||||
|
8C050A8012E6078BEAEF5BC8 /* PillTextAttachmentData.swift in Sources */,
|
||||||
7E2BB42805C59DB57E95610F /* PillView.swift in Sources */,
|
7E2BB42805C59DB57E95610F /* PillView.swift in Sources */,
|
||||||
|
D9092786ACCFF72565AD7389 /* PillContext.swift in Sources */,
|
||||||
9D79B94493FB32249F7E472F /* PlaceholderAvatarImage.swift in Sources */,
|
9D79B94493FB32249F7E472F /* PlaceholderAvatarImage.swift in Sources */,
|
||||||
1BA04D05EBC6646958B1BE60 /* PlaceholderScreenCoordinator.swift in Sources */,
|
1BA04D05EBC6646958B1BE60 /* PlaceholderScreenCoordinator.swift in Sources */,
|
||||||
16CBD087038DE3815CDA512C /* PollMock.swift in Sources */,
|
16CBD087038DE3815CDA512C /* PollMock.swift in Sources */,
|
||||||
@ -4854,6 +4870,7 @@
|
|||||||
864C0D3A4077BF433DBC691F /* PollRoomTimelineItem.swift in Sources */,
|
864C0D3A4077BF433DBC691F /* PollRoomTimelineItem.swift in Sources */,
|
||||||
153E22E8227F46545E5D681C /* PollRoomTimelineView.swift in Sources */,
|
153E22E8227F46545E5D681C /* PollRoomTimelineView.swift in Sources */,
|
||||||
DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */,
|
DF504B10A4918F971A57BEF2 /* PostHogAnalyticsClient.swift in Sources */,
|
||||||
|
FD4DEC88210F35C35B2FB386 /* ProcessInfo.swift in Sources */,
|
||||||
2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */,
|
2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */,
|
||||||
9095B9E40DB5CF8BA26CE0D8 /* ReactionsSummaryView.swift in Sources */,
|
9095B9E40DB5CF8BA26CE0D8 /* ReactionsSummaryView.swift in Sources */,
|
||||||
743790BF6A5B0577EA74AF14 /* ReadMarkerRoomTimelineItem.swift in Sources */,
|
743790BF6A5B0577EA74AF14 /* ReadMarkerRoomTimelineItem.swift in Sources */,
|
||||||
@ -5005,7 +5022,6 @@
|
|||||||
275EDE8849A2AC1D9309ED7C /* TemplateScreenViewModel.swift in Sources */,
|
275EDE8849A2AC1D9309ED7C /* TemplateScreenViewModel.swift in Sources */,
|
||||||
2C4C750D0039AFABDF24236C /* TemplateScreenViewModelProtocol.swift in Sources */,
|
2C4C750D0039AFABDF24236C /* TemplateScreenViewModelProtocol.swift in Sources */,
|
||||||
642DF13C49ED4121C148230E /* TestablePreview.swift in Sources */,
|
642DF13C49ED4121C148230E /* TestablePreview.swift in Sources */,
|
||||||
D85D4FA590305180B4A41795 /* Tests.swift in Sources */,
|
|
||||||
8317E1314C00DCCC99D30DA8 /* TextBasedRoomTimelineItem.swift in Sources */,
|
8317E1314C00DCCC99D30DA8 /* TextBasedRoomTimelineItem.swift in Sources */,
|
||||||
A2A5AB2E8B3F5CA769E531FA /* TextBasedRoomTimelineViewProtocol.swift in Sources */,
|
A2A5AB2E8B3F5CA769E531FA /* TextBasedRoomTimelineViewProtocol.swift in Sources */,
|
||||||
BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */,
|
BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */,
|
||||||
|
@ -34,7 +34,6 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
|||||||
private var userSession: UserSessionProtocol? {
|
private var userSession: UserSessionProtocol? {
|
||||||
didSet {
|
didSet {
|
||||||
userSessionObserver?.cancel()
|
userSessionObserver?.cancel()
|
||||||
|
|
||||||
if userSession != nil {
|
if userSession != nil {
|
||||||
configureNotificationManager()
|
configureNotificationManager()
|
||||||
observeUserSessionChanges()
|
observeUserSessionChanges()
|
||||||
|
@ -41,6 +41,7 @@ final class AppSettings {
|
|||||||
case hasShownWelcomeScreen
|
case hasShownWelcomeScreen
|
||||||
case swiftUITimelineEnabled
|
case swiftUITimelineEnabled
|
||||||
case voiceMessageEnabled
|
case voiceMessageEnabled
|
||||||
|
case mentionsEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
||||||
@ -248,4 +249,7 @@ final class AppSettings {
|
|||||||
|
|
||||||
@UserPreference(key: UserDefaultsKeys.voiceMessageEnabled, defaultValue: false, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.voiceMessageEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
var voiceMessageEnabled
|
var voiceMessageEnabled
|
||||||
|
|
||||||
|
@UserPreference(key: UserDefaultsKeys.mentionsEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
|
var mentionsEnabled
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,9 @@ struct Application: App {
|
|||||||
private let appCoordinator: AppCoordinatorProtocol
|
private let appCoordinator: AppCoordinatorProtocol
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
if Tests.isRunningUITests {
|
if ProcessInfo.isRunningUITests {
|
||||||
appCoordinator = UITestsAppCoordinator()
|
appCoordinator = UITestsAppCoordinator()
|
||||||
} else if Tests.isRunningUnitTests {
|
} else if ProcessInfo.isRunningUnitTests {
|
||||||
appCoordinator = UnitTestsAppCoordinator()
|
appCoordinator = UnitTestsAppCoordinator()
|
||||||
} else {
|
} else {
|
||||||
appCoordinator = AppCoordinator()
|
appCoordinator = AppCoordinator()
|
||||||
@ -59,6 +59,6 @@ struct Application: App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var shouldHideStatusBar: Bool {
|
private var shouldHideStatusBar: Bool {
|
||||||
Tests.isRunningUITests
|
ProcessInfo.isRunningUITests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
let timelineItemFactory = RoomTimelineItemFactory(userID: userID,
|
let timelineItemFactory = RoomTimelineItemFactory(userID: userID,
|
||||||
mediaProvider: userSession.mediaProvider,
|
mediaProvider: userSession.mediaProvider,
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: appSettings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: appSettings.permalinkBaseURL,
|
||||||
|
mentionBuilder: MentionBuilder(mentionsEnabled: appSettings.mentionsEnabled)),
|
||||||
stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID),
|
stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID),
|
||||||
appSettings: appSettings)
|
appSettings: appSettings)
|
||||||
|
|
||||||
|
@ -261,7 +261,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
private func presentHomeScreen() {
|
private func presentHomeScreen() {
|
||||||
let parameters = HomeScreenCoordinatorParameters(userSession: userSession,
|
let parameters = HomeScreenCoordinatorParameters(userSession: userSession,
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||||
|
mentionBuilder: MentionBuilder(mentionsEnabled: ServiceLocator.shared.settings.mentionsEnabled)),
|
||||||
bugReportService: bugReportService,
|
bugReportService: bugReportService,
|
||||||
navigationStackCoordinator: detailNavigationStackCoordinator,
|
navigationStackCoordinator: detailNavigationStackCoordinator,
|
||||||
selectedRoomPublisher: selectedRoomSubject.asCurrentValuePublisher())
|
selectedRoomPublisher: selectedRoomSubject.asCurrentValuePublisher())
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated using Sourcery 2.0.3 — https://github.com/krzysztofzablocki/Sourcery
|
// Generated using Sourcery 2.1.1 — https://github.com/krzysztofzablocki/Sourcery
|
||||||
// DO NOT EDIT
|
// DO NOT EDIT
|
||||||
|
|
||||||
// swiftlint:disable all
|
// swiftlint:disable all
|
||||||
|
@ -23,6 +23,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
private let temporaryCodeBlockMarkingColor = UIColor.cyan
|
private let temporaryCodeBlockMarkingColor = UIColor.cyan
|
||||||
private let linkColor = UIColor.blue
|
private let linkColor = UIColor.blue
|
||||||
private let permalinkBaseURL: URL
|
private let permalinkBaseURL: URL
|
||||||
|
private let mentionBuilder: MentionBuilderProtocol
|
||||||
|
|
||||||
private static var cache = LRUCache<String, AttributedString>(countLimit: 1000)
|
private static var cache = LRUCache<String, AttributedString>(countLimit: 1000)
|
||||||
|
|
||||||
@ -30,8 +31,9 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
cache.removeAllValues()
|
cache.removeAllValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(permalinkBaseURL: URL) {
|
init(permalinkBaseURL: URL, mentionBuilder: MentionBuilderProtocol) {
|
||||||
self.permalinkBaseURL = permalinkBaseURL
|
self.permalinkBaseURL = permalinkBaseURL
|
||||||
|
self.mentionBuilder = mentionBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromPlain(_ string: String?) -> AttributedString? {
|
func fromPlain(_ string: String?) -> AttributedString? {
|
||||||
@ -45,6 +47,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
|
|
||||||
let mutableAttributedString = NSMutableAttributedString(string: string)
|
let mutableAttributedString = NSMutableAttributedString(string: string)
|
||||||
addLinks(mutableAttributedString)
|
addLinks(mutableAttributedString)
|
||||||
|
detectPermalinks(mutableAttributedString)
|
||||||
removeLinkColors(mutableAttributedString)
|
removeLinkColors(mutableAttributedString)
|
||||||
|
|
||||||
let result = try? AttributedString(mutableAttributedString, including: \.elementX)
|
let result = try? AttributedString(mutableAttributedString, including: \.elementX)
|
||||||
@ -97,10 +100,10 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
|
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
|
||||||
removeDefaultForegroundColor(mutableAttributedString)
|
removeDefaultForegroundColor(mutableAttributedString)
|
||||||
addLinks(mutableAttributedString)
|
addLinks(mutableAttributedString)
|
||||||
detectPermalinks(mutableAttributedString)
|
|
||||||
removeLinkColors(mutableAttributedString)
|
|
||||||
replaceMarkedBlockquotes(mutableAttributedString)
|
replaceMarkedBlockquotes(mutableAttributedString)
|
||||||
replaceMarkedCodeBlocks(mutableAttributedString)
|
replaceMarkedCodeBlocks(mutableAttributedString)
|
||||||
|
detectPermalinks(mutableAttributedString)
|
||||||
|
removeLinkColors(mutableAttributedString)
|
||||||
removeDTCoreTextArtifacts(mutableAttributedString)
|
removeDTCoreTextArtifacts(mutableAttributedString)
|
||||||
|
|
||||||
let result = try? AttributedString(mutableAttributedString, including: \.elementX)
|
let result = try? AttributedString(mutableAttributedString, including: \.elementX)
|
||||||
@ -140,6 +143,8 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
if let value = value as? UIColor,
|
if let value = value as? UIColor,
|
||||||
value == temporaryCodeBlockMarkingColor {
|
value == temporaryCodeBlockMarkingColor {
|
||||||
attributedString.addAttribute(.backgroundColor, value: UIColor(.compound._bgCodeBlock) as Any, range: range)
|
attributedString.addAttribute(.backgroundColor, value: UIColor(.compound._bgCodeBlock) as Any, range: range)
|
||||||
|
// Codeblocks should not have links
|
||||||
|
attributedString.removeAttribute(.link, range: range)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +182,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
guard let matchRange = Range(match.range, in: string) else {
|
guard let matchRange = Range(match.range, in: string) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasLink = false
|
var hasLink = false
|
||||||
attributedString.enumerateAttribute(.link, in: match.range, options: []) { value, _, stop in
|
attributedString.enumerateAttribute(.link, in: match.range, options: []) { value, _, stop in
|
||||||
if value != nil {
|
if value != nil {
|
||||||
@ -196,7 +201,9 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
link.insert(contentsOf: "https://", at: link.startIndex)
|
link.insert(contentsOf: "https://", at: link.startIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
attributedString.addAttribute(.link, value: link as Any, range: match.range)
|
if let url = URL(string: link) {
|
||||||
|
attributedString.addAttribute(.link, value: url, range: match.range)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +213,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
if let url = value as? URL {
|
if let url = value as? URL {
|
||||||
switch PermalinkBuilder.detectPermalink(in: url, baseURL: permalinkBaseURL) {
|
switch PermalinkBuilder.detectPermalink(in: url, baseURL: permalinkBaseURL) {
|
||||||
case .userIdentifier(let identifier):
|
case .userIdentifier(let identifier):
|
||||||
attributedString.addAttributes([.MatrixUserID: identifier], range: range)
|
mentionBuilder.handleUserMention(for: attributedString, in: range, url: url, userID: identifier)
|
||||||
case .roomIdentifier(let identifier):
|
case .roomIdentifier(let identifier):
|
||||||
attributedString.addAttributes([.MatrixRoomID: identifier], range: range)
|
attributedString.addAttributes([.MatrixRoomID: identifier], range: range)
|
||||||
case .roomAlias(let alias):
|
case .roomAlias(let alias):
|
||||||
@ -280,3 +287,7 @@ extension NSAttributedString.Key {
|
|||||||
static let MatrixRoomAlias: NSAttributedString.Key = .init(rawValue: RoomAliasAttribute.name)
|
static let MatrixRoomAlias: NSAttributedString.Key = .init(rawValue: RoomAliasAttribute.name)
|
||||||
static let MatrixEventID: NSAttributedString.Key = .init(rawValue: EventIDAttribute.name)
|
static let MatrixEventID: NSAttributedString.Key = .init(rawValue: EventIDAttribute.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protocol MentionBuilderProtocol {
|
||||||
|
func handleUserMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, userID: String)
|
||||||
|
}
|
||||||
|
49
ElementX/Sources/Other/Pills/MentionBuilder.swift
Normal file
49
ElementX/Sources/Other/Pills/MentionBuilder.swift
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2023 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
struct MentionBuilder: MentionBuilderProtocol {
|
||||||
|
// Can be removed when mentions are enabled by default
|
||||||
|
let mentionsEnabled: Bool
|
||||||
|
|
||||||
|
func handleUserMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, userID: String) {
|
||||||
|
guard mentionsEnabled else {
|
||||||
|
attributedString.addAttributes([.MatrixUserID: userID], range: range)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let attributes = attributedString.attributes(at: 0, longestEffectiveRange: nil, in: range)
|
||||||
|
let font = attributes[.font] as? UIFont ?? .preferredFont(forTextStyle: .body)
|
||||||
|
let blockquote = attributes[.MatrixBlockquote]
|
||||||
|
|
||||||
|
let attachmentData = PillTextAttachmentData(type: .user(userID: userID), font: font)
|
||||||
|
guard let attachment = PillTextAttachment(attachmentData: attachmentData) else {
|
||||||
|
attributedString.addAttributes([.MatrixUserID: userID], range: range)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var attributesToAdd: [NSAttributedString.Key: Any] = [.link: url, .MatrixUserID: userID]
|
||||||
|
if let blockquote {
|
||||||
|
// mentions can be in blockquotes, so if the replaced string was in one, we keep the attribute
|
||||||
|
attributesToAdd[.MatrixBlockquote] = blockquote
|
||||||
|
}
|
||||||
|
let attachmentString = NSMutableAttributedString(attachment: attachment)
|
||||||
|
attachmentString.addAttributes(attributes, range: NSRange(location: 0, length: attachmentString.length))
|
||||||
|
attributedString.replaceCharacters(in: range, with: attachmentString)
|
||||||
|
}
|
||||||
|
}
|
@ -15,21 +15,49 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UIKit
|
|
||||||
|
|
||||||
final class MessageTextView: UITextView {
|
final class MessageTextView: UITextView {
|
||||||
|
var roomContext: RoomScreenViewModel.Context?
|
||||||
|
var updateClosure: (() -> Void)?
|
||||||
|
|
||||||
// This prevents the magnifying glass from showing up
|
// This prevents the magnifying glass from showing up
|
||||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
gestureRecognizer as? UILongPressGestureRecognizer == nil
|
gestureRecognizer as? UILongPressGestureRecognizer == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func invalidateTextAttachmentsDisplay(update: Bool) {
|
||||||
|
attributedText.enumerateAttribute(.attachment,
|
||||||
|
in: NSRange(location: 0, length: attributedText.length),
|
||||||
|
options: []) { value, range, _ in
|
||||||
|
guard value != nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.layoutManager.invalidateDisplay(forCharacterRange: range)
|
||||||
|
if update {
|
||||||
|
updateClosure?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required to setup the first rendering of the pill view
|
||||||
|
override func layoutSubviews() {
|
||||||
|
invalidateTextAttachmentsDisplay(update: false)
|
||||||
|
super.layoutSubviews()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MessageText: UIViewRepresentable {
|
struct MessageText: UIViewRepresentable {
|
||||||
@Environment(\.openURL) private var openURLAction: OpenURLAction
|
@Environment(\.openURL) private var openURLAction: OpenURLAction
|
||||||
let attributedString: AttributedString
|
@EnvironmentObject private var viewModel: RoomScreenViewModel.Context
|
||||||
|
@State var attributedString: AttributedString
|
||||||
|
|
||||||
func makeUIView(context: Context) -> MessageTextView {
|
func makeUIView(context: Context) -> MessageTextView {
|
||||||
let textView = MessageTextView()
|
// Need to use TextKit 1 for mentions
|
||||||
|
let textView = MessageTextView(usingTextLayoutManager: false)
|
||||||
|
textView.roomContext = viewModel
|
||||||
|
textView.updateClosure = {
|
||||||
|
attributedString = AttributedString(textView.attributedText)
|
||||||
|
}
|
||||||
textView.isEditable = false
|
textView.isEditable = false
|
||||||
textView.isScrollEnabled = false
|
textView.isScrollEnabled = false
|
||||||
textView.adjustsFontForContentSizeCategory = true
|
textView.adjustsFontForContentSizeCategory = true
|
||||||
@ -46,7 +74,7 @@ struct MessageText: UIViewRepresentable {
|
|||||||
textView.contentInsetAdjustmentBehavior = .never
|
textView.contentInsetAdjustmentBehavior = .never
|
||||||
textView.textContainerInset = .zero
|
textView.textContainerInset = .zero
|
||||||
textView.textContainer.lineFragmentPadding = 0
|
textView.textContainer.lineFragmentPadding = 0
|
||||||
textView.textLayoutManager?.usesFontLeading = false
|
textView.layoutManager.usesFontLeading = false
|
||||||
textView.backgroundColor = .clear
|
textView.backgroundColor = .clear
|
||||||
textView.attributedText = NSAttributedString(attributedString)
|
textView.attributedText = NSAttributedString(attributedString)
|
||||||
textView.delegate = context.coordinator
|
textView.delegate = context.coordinator
|
||||||
@ -94,9 +122,20 @@ struct MessageText_Previews: PreviewProvider, TestablePreview {
|
|||||||
container.font = UIFont.preferredFont(forTextStyle: .body)
|
container.font = UIFont.preferredFont(forTextStyle: .body)
|
||||||
return container
|
return container
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private static let attributedString = AttributedString("Hello World! Hello world! Hello world! Hello world! Hello World! Hellooooooooooooooooooooooo Woooooooooooooooooooooorld", attributes: defaultFontContainer)
|
private static let attributedString = AttributedString("Hello World! Hello world! Hello world! Hello world! Hello World! Hellooooooooooooooooooooooo Woooooooooooooooooooooorld", attributes: defaultFontContainer)
|
||||||
private static let attributedStringWithAttachment = "Hello " + AttributedString(NSAttributedString(attachment: PillTextAttachment(data: Data(), ofType: InfoPlistReader.main.pillsUTType))) + " World!"
|
|
||||||
|
private static let attributedStringWithAttachment: AttributedString = {
|
||||||
|
let testData = PillTextAttachmentData(type: .user(userID: "@alice:example.com"), font: .preferredFont(forTextStyle: .body))
|
||||||
|
guard let attachment = PillTextAttachment(attachmentData: testData) else {
|
||||||
|
return AttributedString()
|
||||||
|
}
|
||||||
|
|
||||||
|
var attributedString = "Hello test test test " + AttributedString(NSAttributedString(attachment: attachment)) + " World!"
|
||||||
|
attributedString
|
||||||
|
.mergeAttributes(defaultFontContainer)
|
||||||
|
return attributedString
|
||||||
|
}()
|
||||||
|
|
||||||
private static let htmlStringWithQuote =
|
private static let htmlStringWithQuote =
|
||||||
"""
|
"""
|
||||||
@ -106,28 +145,36 @@ struct MessageText_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
private static let htmlStringWithList = "<p>This is a list</p>\n<ul>\n<li>One</li>\n<li>Two</li>\n<li>And number 3</li>\n</ul>\n"
|
private static let htmlStringWithList = "<p>This is a list</p>\n<ul>\n<li>One</li>\n<li>Two</li>\n<li>And number 3</li>\n</ul>\n"
|
||||||
|
|
||||||
private static let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL)
|
private static let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: true))
|
||||||
|
|
||||||
|
static var attachmentPreview: some View {
|
||||||
|
MessageText(attributedString: attributedStringWithAttachment)
|
||||||
|
.border(Color.purple)
|
||||||
|
.environmentObject(RoomScreenViewModel.mock.context)
|
||||||
|
}
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
MessageText(attributedString: attributedString)
|
MessageText(attributedString: attributedString)
|
||||||
.border(Color.purple)
|
.border(Color.purple)
|
||||||
.previewDisplayName("Custom Text")
|
.previewDisplayName("Custom Text")
|
||||||
|
.environmentObject(RoomScreenViewModel.mock.context)
|
||||||
// For comparison
|
// For comparison
|
||||||
Text(attributedString)
|
Text(attributedString)
|
||||||
.border(Color.purple)
|
.border(Color.purple)
|
||||||
.previewDisplayName("SwiftUI Default Text")
|
.previewDisplayName("SwiftUI Default Text")
|
||||||
MessageText(attributedString: attributedStringWithAttachment)
|
attachmentPreview
|
||||||
.border(Color.purple)
|
|
||||||
.previewDisplayName("Custom Attachment")
|
.previewDisplayName("Custom Attachment")
|
||||||
if let attributedString = attributedStringBuilder.fromHTML(htmlStringWithQuote) {
|
if let attributedString = attributedStringBuilder.fromHTML(htmlStringWithQuote) {
|
||||||
MessageText(attributedString: attributedString)
|
MessageText(attributedString: attributedString)
|
||||||
.border(Color.purple)
|
.border(Color.purple)
|
||||||
.previewDisplayName("With block quote")
|
.previewDisplayName("With block quote")
|
||||||
|
.environmentObject(RoomScreenViewModel.mock.context)
|
||||||
}
|
}
|
||||||
if let attributedString = attributedStringBuilder.fromHTML(htmlStringWithList) {
|
if let attributedString = attributedStringBuilder.fromHTML(htmlStringWithList) {
|
||||||
MessageText(attributedString: attributedString)
|
MessageText(attributedString: attributedString)
|
||||||
.border(Color.purple)
|
.border(Color.purple)
|
||||||
.previewDisplayName("With list")
|
.previewDisplayName("With list")
|
||||||
|
.environmentObject(RoomScreenViewModel.mock.context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,21 +15,52 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import SwiftUIIntrospect
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
final class PillAttachmentViewProvider: NSTextAttachmentViewProvider {
|
final class PillAttachmentViewProvider: NSTextAttachmentViewProvider {
|
||||||
|
private weak var messageTextView: MessageTextView?
|
||||||
|
|
||||||
// MARK: - Override
|
// MARK: - Override
|
||||||
|
|
||||||
|
override init(textAttachment: NSTextAttachment, parentView: UIView?, textLayoutManager: NSTextLayoutManager?, location: NSTextLocation) {
|
||||||
|
super.init(textAttachment: textAttachment, parentView: parentView, textLayoutManager: textLayoutManager, location: location)
|
||||||
|
|
||||||
|
// Keep a reference to the parent text view for size adjustments and pills flushing.
|
||||||
|
messageTextView = parentView?.superview as? MessageTextView
|
||||||
|
tracksTextAttachmentViewBounds = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
override func loadView() {
|
override func loadView() {
|
||||||
super.loadView()
|
super.loadView()
|
||||||
|
|
||||||
guard textAttachment is PillTextAttachment else {
|
guard let textAttachmentData = (textAttachment as? PillTextAttachment)?.pillData else {
|
||||||
MXLog.failure("[PillAttachmentViewProvider]: attachment is missing or not of expected class")
|
MXLog.failure("[PillAttachmentViewProvider]: attachment is missing data or not of expected class")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let view = PillView()
|
let viewModel: PillContext
|
||||||
|
let imageProvider: ImageProviderProtocol?
|
||||||
|
if ProcessInfo.isXcodePreview || ProcessInfo.isRunningTests {
|
||||||
|
// The mock viewModel simulates the loading logic for testing purposes
|
||||||
|
viewModel = PillContext.mock(type: .loadUser)
|
||||||
|
imageProvider = MockMediaProvider()
|
||||||
|
} else if let roomContext = messageTextView?.roomContext {
|
||||||
|
viewModel = PillContext(roomContext: roomContext, data: textAttachmentData)
|
||||||
|
imageProvider = roomContext.imageProvider
|
||||||
|
} else {
|
||||||
|
MXLog.failure("[PillAttachmentViewProvider]: missing room context")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let view = PillView(imageProvider: imageProvider, viewModel: viewModel) { [weak self] in
|
||||||
|
self?.messageTextView?.invalidateTextAttachmentsDisplay(update: true)
|
||||||
|
}
|
||||||
let controller = UIHostingController(rootView: view)
|
let controller = UIHostingController(rootView: view)
|
||||||
|
controller.view.backgroundColor = .clear
|
||||||
|
// This allows the text view to handle it as a link
|
||||||
|
controller.view.isUserInteractionEnabled = false
|
||||||
self.view = controller.view
|
self.view = controller.view
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
110
ElementX/Sources/Other/Pills/PillContext.swift
Normal file
110
ElementX/Sources/Other/Pills/PillContext.swift
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2023 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class PillContext: ObservableObject {
|
||||||
|
enum PillViewState {
|
||||||
|
case loading(contentID: String)
|
||||||
|
case loaded(contentID: String, name: String, avatarURL: URL?)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published private var state: PillViewState
|
||||||
|
|
||||||
|
var url: URL? {
|
||||||
|
switch state {
|
||||||
|
case .loading:
|
||||||
|
return nil
|
||||||
|
case .loaded(_, _, let url):
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var name: String? {
|
||||||
|
switch state {
|
||||||
|
case .loading:
|
||||||
|
return nil
|
||||||
|
case .loaded(_, let name, _):
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayText: String {
|
||||||
|
switch state {
|
||||||
|
case .loaded(_, let name, _):
|
||||||
|
return name
|
||||||
|
case .loading(let contentID):
|
||||||
|
return contentID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentID: String {
|
||||||
|
switch state {
|
||||||
|
case .loaded(let contentID, _, _), .loading(let contentID):
|
||||||
|
return contentID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var cancellable: AnyCancellable?
|
||||||
|
|
||||||
|
init(roomContext: RoomScreenViewModel.Context, data: PillTextAttachmentData) {
|
||||||
|
switch data.type {
|
||||||
|
case let .user(id):
|
||||||
|
if let profile = roomContext.viewState.members[id] {
|
||||||
|
state = .loaded(contentID: id, name: profile.displayName ?? id, avatarURL: profile.avatarURL)
|
||||||
|
} else {
|
||||||
|
state = .loading(contentID: id)
|
||||||
|
cancellable = roomContext.$viewState.sink { [weak self] viewState in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let profile = viewState.members[id] {
|
||||||
|
state = .loaded(contentID: id, name: profile.displayName ?? id, avatarURL: profile.avatarURL)
|
||||||
|
cancellable = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PillContext {
|
||||||
|
enum MockType {
|
||||||
|
case loadUser
|
||||||
|
case loadedUser
|
||||||
|
}
|
||||||
|
|
||||||
|
static func mock(type: MockType) -> PillContext {
|
||||||
|
let pillType: PillType
|
||||||
|
switch type {
|
||||||
|
case .loadUser:
|
||||||
|
pillType = .user(userID: "@test:test.com")
|
||||||
|
let viewModel = PillContext(roomContext: RoomScreenViewModel.mock.context, data: PillTextAttachmentData(type: pillType, font: .preferredFont(forTextStyle: .body)))
|
||||||
|
Task {
|
||||||
|
try? await Task.sleep(for: .seconds(2))
|
||||||
|
viewModel.state = .loaded(contentID: "@test:test.com", name: "Test Longer Display Text", avatarURL: URL.documentsDirectory)
|
||||||
|
}
|
||||||
|
return viewModel
|
||||||
|
case .loadedUser:
|
||||||
|
pillType = .user(userID: "@test:test.com")
|
||||||
|
let viewModel = PillContext(roomContext: RoomScreenViewModel.mock.context, data: PillTextAttachmentData(type: pillType, font: .preferredFont(forTextStyle: .body)))
|
||||||
|
viewModel.state = .loaded(contentID: "@test:test.com", name: "Very Very Long Test Display Text", avatarURL: URL.documentsDirectory)
|
||||||
|
return viewModel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,4 +17,27 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
/// Text attachment for pills display.
|
/// Text attachment for pills display.
|
||||||
final class PillTextAttachment: NSTextAttachment { }
|
final class PillTextAttachment: NSTextAttachment {
|
||||||
|
convenience init?(attachmentData: PillTextAttachmentData) {
|
||||||
|
let encoder = JSONEncoder()
|
||||||
|
guard let encodedData = try? encoder.encode(attachmentData) else { return nil }
|
||||||
|
self.init(data: encodedData, ofType: InfoPlistReader.main.pillsUTType)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pillData: PillTextAttachmentData? {
|
||||||
|
guard let contents else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
return try? decoder.decode(PillTextAttachmentData.self, from: contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func attachmentBounds(for textContainer: NSTextContainer?, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect {
|
||||||
|
var rect = super.attachmentBounds(for: textContainer, proposedLineFragment: lineFrag, glyphPosition: position, characterIndex: charIndex)
|
||||||
|
if let font = pillData?.font {
|
||||||
|
// Align the pill text vertically with the surrounding text.
|
||||||
|
rect.origin.y = font.descender + (font.lineHeight - rect.height) / 2.0
|
||||||
|
}
|
||||||
|
return rect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
64
ElementX/Sources/Other/Pills/PillTextAttachmentData.swift
Normal file
64
ElementX/Sources/Other/Pills/PillTextAttachmentData.swift
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2023 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
enum PillType: Codable {
|
||||||
|
/// A pill that mentions a user
|
||||||
|
case user(userID: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PillTextAttachmentData {
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
/// Pill type
|
||||||
|
let type: PillType
|
||||||
|
|
||||||
|
/// Font for the display name
|
||||||
|
let font: UIFont
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PillTextAttachmentData: Codable {
|
||||||
|
// MARK: - Codable
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case type
|
||||||
|
case font
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PillTextAttachmentDataError: Error {
|
||||||
|
case noFontData
|
||||||
|
}
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
type = try container.decode(PillType.self, forKey: .type)
|
||||||
|
let fontData = try container.decode(Data.self, forKey: .font)
|
||||||
|
if let font = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIFont.self, from: fontData) {
|
||||||
|
self.font = font
|
||||||
|
} else {
|
||||||
|
throw PillTextAttachmentDataError.noFontData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encode(type, forKey: .type)
|
||||||
|
let fontData = try NSKeyedArchiver.archivedData(withRootObject: font, requiringSecureCoding: false)
|
||||||
|
try container.encode(fontData, forKey: .font)
|
||||||
|
}
|
||||||
|
}
|
@ -17,21 +17,43 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct PillView: View {
|
struct PillView: View {
|
||||||
|
let imageProvider: ImageProviderProtocol?
|
||||||
|
@ObservedObject var viewModel: PillContext
|
||||||
|
/// callback triggerd by changes in the display text
|
||||||
|
let didChangeText: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
HStack(spacing: 4) {
|
||||||
MXLog.info("TEXT ATTACHMENT TEST")
|
LoadableAvatarImage(url: viewModel.url, name: viewModel.name, contentID: viewModel.contentID, avatarSize: .custom(24), imageProvider: imageProvider)
|
||||||
} label: {
|
Text(viewModel.displayText)
|
||||||
HStack {
|
.font(.compound.bodyLGSemibold)
|
||||||
Image(asset: Asset.Images.appLogo)
|
.foregroundColor(.compound.textOnSolidPrimary)
|
||||||
.resizable()
|
.lineLimit(1)
|
||||||
.scaledToFit()
|
}
|
||||||
}
|
.padding(.horizontal, 8)
|
||||||
|
.padding(.vertical, 4)
|
||||||
|
// for now design has defined no color so we will just use gray
|
||||||
|
.background(Capsule().foregroundColor(.gray))
|
||||||
|
.frame(maxWidth: 235)
|
||||||
|
.onChange(of: viewModel.displayText) { _ in
|
||||||
|
didChangeText()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PillView_Previews: PreviewProvider, TestablePreview {
|
struct PillView_Previews: PreviewProvider, TestablePreview {
|
||||||
|
static let mockMediaProvider = MockMediaProvider()
|
||||||
|
|
||||||
|
static var loading: some View {
|
||||||
|
PillView(imageProvider: mockMediaProvider,
|
||||||
|
viewModel: PillContext.mock(type: .loadUser)) { }
|
||||||
|
}
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
PillView()
|
loading
|
||||||
|
.previewDisplayName("Loading")
|
||||||
|
PillView(imageProvider: mockMediaProvider,
|
||||||
|
viewModel: PillContext.mock(type: .loadedUser)) { }
|
||||||
|
.previewDisplayName("Loaded Long")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum Tests {
|
extension ProcessInfo {
|
||||||
/// Flag indicating whether the app is running the unit tests.
|
/// Flag indicating whether the app is running the unit tests.
|
||||||
static var isRunningUnitTests: Bool {
|
static var isRunningUnitTests: Bool {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ProcessInfo.processInfo.environment["IS_RUNNING_UNIT_TESTS"] == "1"
|
processInfo.environment["IS_RUNNING_UNIT_TESTS"] == "1"
|
||||||
#else
|
#else
|
||||||
false
|
false
|
||||||
#endif
|
#endif
|
||||||
@ -29,7 +29,7 @@ public enum Tests {
|
|||||||
/// Flag indicating whether the app is running the UI tests.
|
/// Flag indicating whether the app is running the UI tests.
|
||||||
static var isRunningUITests: Bool {
|
static var isRunningUITests: Bool {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ProcessInfo.processInfo.environment["UI_TESTS_SCREEN"] != nil
|
processInfo.environment["UI_TESTS_SCREEN"] != nil
|
||||||
#else
|
#else
|
||||||
false
|
false
|
||||||
#endif
|
#endif
|
||||||
@ -41,9 +41,9 @@ public enum Tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The identifier of the screen to be loaded when running UI tests.
|
/// The identifier of the screen to be loaded when running UI tests.
|
||||||
static var screenID: UITestsScreenIdentifier? {
|
static var testScreenID: UITestsScreenIdentifier? {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ProcessInfo.processInfo.environment["UI_TESTS_SCREEN"].flatMap(UITestsScreenIdentifier.init)
|
processInfo.environment["UI_TESTS_SCREEN"].flatMap(UITestsScreenIdentifier.init)
|
||||||
#else
|
#else
|
||||||
nil
|
nil
|
||||||
#endif
|
#endif
|
||||||
@ -55,9 +55,17 @@ public enum Tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
return ProcessInfo.processInfo.environment["UI_TESTS_DISABLE_TIMELINE_ACCESSIBILITY"] != nil
|
return processInfo.environment["UI_TESTS_DISABLE_TIMELINE_ACCESSIBILITY"] != nil
|
||||||
#else
|
#else
|
||||||
return false
|
return false
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var isXcodePreview: Bool {
|
||||||
|
#if DEBUG
|
||||||
|
processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
|
||||||
|
#else
|
||||||
|
false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
@ -23,13 +23,13 @@ public extension Animation {
|
|||||||
|
|
||||||
/// `noAnimation` if running tests, otherwise `default` animation if `UIAccessibility.isReduceMotionEnabled` is false
|
/// `noAnimation` if running tests, otherwise `default` animation if `UIAccessibility.isReduceMotionEnabled` is false
|
||||||
static var elementDefault: Animation {
|
static var elementDefault: Animation {
|
||||||
let animation: Animation = Tests.isRunningTests ? .noAnimation : .default
|
let animation: Animation = ProcessInfo.isRunningTests ? .noAnimation : .default
|
||||||
return animation.disabledIfReduceMotionEnabled()
|
return animation.disabledIfReduceMotionEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
// `noAnimation` if running tests, otherwise `self` if `UIAccessibility.isReduceMotionEnabled` is false
|
// `noAnimation` if running tests, otherwise `self` if `UIAccessibility.isReduceMotionEnabled` is false
|
||||||
func disabledDuringTests() -> Self {
|
func disabledDuringTests() -> Self {
|
||||||
let animation: Animation = Tests.isRunningTests ? .noAnimation : self
|
let animation: Animation = ProcessInfo.isRunningTests ? .noAnimation : self
|
||||||
return animation.disabledIfReduceMotionEnabled()
|
return animation.disabledIfReduceMotionEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,8 @@ extension View {
|
|||||||
struct ShimmerOverlay_Previews: PreviewProvider, TestablePreview {
|
struct ShimmerOverlay_Previews: PreviewProvider, TestablePreview {
|
||||||
static let viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: MockClientProxy(userID: ""),
|
static let viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: MockClientProxy(userID: ""),
|
||||||
mediaProvider: MockMediaProvider()),
|
mediaProvider: MockMediaProvider()),
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||||
|
mentionBuilder: MentionBuilder(mentionsEnabled: ServiceLocator.shared.settings.mentionsEnabled)),
|
||||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
@ -338,7 +338,7 @@ struct HomeScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
mediaProvider: MockMediaProvider())
|
mediaProvider: MockMediaProvider())
|
||||||
|
|
||||||
return HomeScreenViewModel(userSession: userSession,
|
return HomeScreenViewModel(userSession: userSession,
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: ServiceLocator.shared.settings.mentionsEnabled)),
|
||||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
@ -154,7 +154,7 @@ struct HomeScreenEmptyStateView_Previews: PreviewProvider, TestablePreview {
|
|||||||
mediaProvider: MockMediaProvider())
|
mediaProvider: MockMediaProvider())
|
||||||
|
|
||||||
return HomeScreenViewModel(userSession: userSession,
|
return HomeScreenViewModel(userSession: userSession,
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: ServiceLocator.shared.settings.mentionsEnabled)),
|
||||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
@ -188,7 +188,8 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
|
|||||||
mediaProvider: MockMediaProvider())
|
mediaProvider: MockMediaProvider())
|
||||||
|
|
||||||
let viewModel = HomeScreenViewModel(userSession: userSession,
|
let viewModel = HomeScreenViewModel(userSession: userSession,
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||||
|
mentionBuilder: MentionBuilder(mentionsEnabled: ServiceLocator.shared.settings.mentionsEnabled)),
|
||||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
@ -201,7 +201,7 @@ struct FormattedBodyText_Previews: PreviewProvider, TestablePreview {
|
|||||||
"<p>This is a list</p>\n<ul>\n<li>One</li>\n<li>Two</li>\n<li>And number 3</li>\n</ul>\n"
|
"<p>This is a list</p>\n<ul>\n<li>One</li>\n<li>Two</li>\n<li>And number 3</li>\n</ul>\n"
|
||||||
]
|
]
|
||||||
|
|
||||||
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL)
|
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: ServiceLocator.shared.settings.mentionsEnabled))
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(alignment: .leading, spacing: 24.0) {
|
VStack(alignment: .leading, spacing: 24.0) {
|
||||||
@ -234,6 +234,7 @@ private struct PreviewBubbleModifier: ViewModifier {
|
|||||||
.padding(timelineStyle == .bubbles ? 8 : 0)
|
.padding(timelineStyle == .bubbles ? 8 : 0)
|
||||||
.background(timelineStyle == .bubbles ? Color.compound._bgBubbleOutgoing : nil)
|
.background(timelineStyle == .bubbles ? Color.compound._bgBubbleOutgoing : nil)
|
||||||
.cornerRadius(timelineStyle == .bubbles ? 12 : 0)
|
.cornerRadius(timelineStyle == .bubbles ? 12 : 0)
|
||||||
|
.environmentObject(RoomScreenViewModel.mock.context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class TimelineTableViewController: UIViewController {
|
|||||||
|
|
||||||
// Prevents XCUITest from invoking the diffable dataSource's cellProvider
|
// Prevents XCUITest from invoking the diffable dataSource's cellProvider
|
||||||
// for each possible cell, causing layout issues
|
// for each possible cell, causing layout issues
|
||||||
tableView.accessibilityElementsHidden = Tests.shouldDisableTimelineAccessibility
|
tableView.accessibilityElementsHidden = ProcessInfo.shouldDisableTimelineAccessibility
|
||||||
|
|
||||||
scrollToBottomPublisher
|
scrollToBottomPublisher
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
|
@ -50,6 +50,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
|||||||
var readReceiptsEnabled: Bool { get set }
|
var readReceiptsEnabled: Bool { get set }
|
||||||
var swiftUITimelineEnabled: Bool { get set }
|
var swiftUITimelineEnabled: Bool { get set }
|
||||||
var voiceMessageEnabled: Bool { get set }
|
var voiceMessageEnabled: Bool { get set }
|
||||||
|
var mentionsEnabled: Bool { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppSettings: DeveloperOptionsProtocol { }
|
extension AppSettings: DeveloperOptionsProtocol { }
|
||||||
|
@ -45,6 +45,11 @@ struct DeveloperOptionsScreen: View {
|
|||||||
Text("SwiftUI Timeline")
|
Text("SwiftUI Timeline")
|
||||||
Text("Resets on reboot")
|
Text("Resets on reboot")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: $context.mentionsEnabled) {
|
||||||
|
Text("Show user mentions")
|
||||||
|
Text("Requires app reboot")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Room creation") {
|
Section("Room creation") {
|
||||||
|
@ -443,7 +443,8 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
.finish()
|
.finish()
|
||||||
let roomListService = syncService.roomListService()
|
let roomListService = syncService.roomListService()
|
||||||
|
|
||||||
let roomMessageEventStringBuilder = RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .homeDirectory))
|
let roomMessageEventStringBuilder = RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: appSettings.permalinkBaseURL,
|
||||||
|
mentionBuilder: MentionBuilder(mentionsEnabled: appSettings.mentionsEnabled)))
|
||||||
let eventStringBuilder = RoomEventStringBuilder(stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID),
|
let eventStringBuilder = RoomEventStringBuilder(stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID),
|
||||||
messageEventStringBuilder: roomMessageEventStringBuilder)
|
messageEventStringBuilder: roomMessageEventStringBuilder)
|
||||||
roomSummaryProvider = RoomSummaryProvider(roomListService: roomListService,
|
roomSummaryProvider = RoomSummaryProvider(roomListService: roomListService,
|
||||||
|
@ -97,7 +97,9 @@ enum RoomTimelineItemFixtures {
|
|||||||
isThreaded: false,
|
isThreaded: false,
|
||||||
sender: .init(id: "", displayName: "Helena"),
|
sender: .init(id: "", displayName: "Helena"),
|
||||||
content: .init(body: "",
|
content: .init(body: "",
|
||||||
formattedBody: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL).fromHTML("Hol' up <blockquote>New home office set up!</blockquote>That's amazing! Congrats 🥳")))
|
formattedBody: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||||
|
mentionBuilder: MentionBuilder(mentionsEnabled: ServiceLocator.shared.settings.mentionsEnabled))
|
||||||
|
.fromHTML("Hol' up <blockquote>New home office set up!</blockquote>That's amazing! Congrats 🥳")))
|
||||||
]
|
]
|
||||||
|
|
||||||
/// A small chunk of events, containing 2 text items.
|
/// A small chunk of events, containing 2 text items.
|
||||||
|
@ -50,7 +50,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
|
|||||||
delegate.window??.layer.speed = 0
|
delegate.window??.layer.speed = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let screenID = Tests.screenID else { fatalError("Unable to launch with unknown screen.") }
|
guard let screenID = ProcessInfo.testScreenID else { fatalError("Unable to launch with unknown screen.") }
|
||||||
|
|
||||||
let mockScreen = MockScreen(id: screenID)
|
let mockScreen = MockScreen(id: screenID)
|
||||||
navigationRootCoordinator.setRootCoordinator(mockScreen.coordinator)
|
navigationRootCoordinator.setRootCoordinator(mockScreen.coordinator)
|
||||||
@ -162,7 +162,7 @@ class MockScreen: Identifiable {
|
|||||||
let session = MockUserSession(clientProxy: MockClientProxy(userID: "@mock:matrix.org"),
|
let session = MockUserSession(clientProxy: MockClientProxy(userID: "@mock:matrix.org"),
|
||||||
mediaProvider: MockMediaProvider())
|
mediaProvider: MockMediaProvider())
|
||||||
let coordinator = HomeScreenCoordinator(parameters: .init(userSession: session,
|
let coordinator = HomeScreenCoordinator(parameters: .init(userSession: session,
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: true)),
|
||||||
bugReportService: BugReportServiceMock(),
|
bugReportService: BugReportServiceMock(),
|
||||||
navigationStackCoordinator: navigationStackCoordinator,
|
navigationStackCoordinator: navigationStackCoordinator,
|
||||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher()))
|
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher()))
|
||||||
|
@ -20,7 +20,7 @@ import UserNotifications
|
|||||||
|
|
||||||
class NotificationServiceExtension: UNNotificationServiceExtension {
|
class NotificationServiceExtension: UNNotificationServiceExtension {
|
||||||
private let settings = NSESettings()
|
private let settings = NSESettings()
|
||||||
private let notificationContentBuilder = NotificationContentBuilder(messageEventStringBuilder: RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .homeDirectory)))
|
private let notificationContentBuilder = NotificationContentBuilder(messageEventStringBuilder: RoomMessageEventStringBuilder(attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .homeDirectory, mentionBuilder: NSEMentionBuilder())))
|
||||||
private lazy var keychainController = KeychainController(service: .sessions,
|
private lazy var keychainController = KeychainController(service: .sessions,
|
||||||
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
|
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
|
||||||
private var handler: ((UNNotificationContent) -> Void)?
|
private var handler: ((UNNotificationContent) -> Void)?
|
||||||
|
23
NSE/Sources/Other/NSEMentionBuilder.swift
Normal file
23
NSE/Sources/Other/NSEMentionBuilder.swift
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2023 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct NSEMentionBuilder: MentionBuilderProtocol {
|
||||||
|
func handleUserMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, userID: String) {
|
||||||
|
attributedString.addAttributes([.MatrixUserID: userID], range: range)
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
class AttributedStringBuilderTests: XCTestCase {
|
class AttributedStringBuilderTests: XCTestCase {
|
||||||
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL)
|
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: true))
|
||||||
let maxHeaderPointSize = ceil(UIFont.preferredFont(forTextStyle: .body).pointSize * 1.2)
|
let maxHeaderPointSize = ceil(UIFont.preferredFont(forTextStyle: .body).pointSize * 1.2)
|
||||||
|
|
||||||
func testRenderHTMLStringWithHeaders() {
|
func testRenderHTMLStringWithHeaders() {
|
||||||
@ -413,6 +413,14 @@ class AttributedStringBuilderTests: XCTestCase {
|
|||||||
XCTAssertEqual(numberOfBlockquotes, 3, "Couldn't find all the blockquotes")
|
XCTAssertEqual(numberOfBlockquotes, 3, "Couldn't find all the blockquotes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testUserMentionAtachment() {
|
||||||
|
let string = "https://matrix.to/#/@test:matrix.org"
|
||||||
|
let attributedStringFromHTML = attributedStringBuilder.fromHTML(string)
|
||||||
|
XCTAssertNotNil(attributedStringFromHTML?.attachment)
|
||||||
|
let attributedStringFromPlain = attributedStringBuilder.fromPlain(string)
|
||||||
|
XCTAssert(attributedStringFromPlain?.attachment.isNil == false)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func checkLinkIn(attributedString: AttributedString?, expectedLink: String, expectedRuns: Int) {
|
private func checkLinkIn(attributedString: AttributedString?, expectedLink: String, expectedRuns: Int) {
|
||||||
|
@ -21,7 +21,7 @@ class AttributedStringTests: XCTestCase {
|
|||||||
func testReplacingFontWithPresentationIntent() {
|
func testReplacingFontWithPresentationIntent() {
|
||||||
// Given a string parsed from HTML that contains specific fixed size fonts.
|
// Given a string parsed from HTML that contains specific fixed size fonts.
|
||||||
let boldString = "Bold"
|
let boldString = "Bold"
|
||||||
guard let originalString = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL)
|
guard let originalString = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: true))
|
||||||
.fromHTML("Normal <b>\(boldString)</b> Normal.") else {
|
.fromHTML("Normal <b>\(boldString)</b> Normal.") else {
|
||||||
XCTFail("The attributed string should be built from the HTML.")
|
XCTFail("The attributed string should be built from the HTML.")
|
||||||
return
|
return
|
||||||
|
@ -31,7 +31,7 @@ class HomeScreenViewModelTests: XCTestCase {
|
|||||||
clientProxy = MockClientProxy(userID: "@mock:client.com")
|
clientProxy = MockClientProxy(userID: "@mock:client.com")
|
||||||
viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: clientProxy,
|
viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: clientProxy,
|
||||||
mediaProvider: MockMediaProvider()),
|
mediaProvider: MockMediaProvider()),
|
||||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL),
|
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder(mentionsEnabled: true)),
|
||||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
BIN
UnitTests/__Snapshots__/PreviewTests/test_formattedBodyText.1.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_formattedBodyText.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_formattedBodyText.2.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_formattedBodyText.2.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_messageText.Custom-Attachment.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_messageText.Custom-Attachment.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_messageText.With-block-quote.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_messageText.With-block-quote.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_messageText.With-list.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_messageText.With-list.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_pillView.1.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_pillView.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_pillView.Loaded-Long.png
(Stored with Git LFS)
Normal file
BIN
UnitTests/__Snapshots__/PreviewTests/test_pillView.Loaded-Long.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_pillView.Loading.png
(Stored with Git LFS)
Normal file
BIN
UnitTests/__Snapshots__/PreviewTests/test_pillView.Loading.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_roomScreen.1.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_roomScreen.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineItemBubbledStylerView.Mock-Timeline-RTL.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineItemBubbledStylerView.Mock-Timeline-RTL.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineItemBubbledStylerView.Mock-Timeline.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineItemBubbledStylerView.Mock-Timeline.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineItemPlainStylerView.1.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineItemPlainStylerView.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineView.1.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_timelineView.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UnitTests/__Snapshots__/PreviewTests/test_uITimelineView.1.png
(Stored with Git LFS)
BIN
UnitTests/__Snapshots__/PreviewTests/test_uITimelineView.1.png
(Stored with Git LFS)
Binary file not shown.
1
changelog.d/1804.feature
Normal file
1
changelog.d/1804.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
User mentions pills (behind a Feature Flag).
|
Loading…
x
Reference in New Issue
Block a user