mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Rageshake Service (#70)
This commit is contained in:
@@ -8,15 +8,19 @@
|
|||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C070FD43DC6BF4E50217965A /* LocalizationTests.swift */; };
|
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C070FD43DC6BF4E50217965A /* LocalizationTests.swift */; };
|
||||||
|
00AC53151BA23A90FAAE9FBF /* BugReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D607F47FDEF16CC63684BE0 /* BugReport.swift */; };
|
||||||
|
00F3059B1E0CFCA019710C3E /* BugReportModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B516212D9FE785DDD5E490D1 /* BugReportModels.swift */; };
|
||||||
01CB8ACFA5E143E89C168CA8 /* TimelineItemContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43AF03660F5FD4FFFA7F1CE /* TimelineItemContextMenu.swift */; };
|
01CB8ACFA5E143E89C168CA8 /* TimelineItemContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43AF03660F5FD4FFFA7F1CE /* TimelineItemContextMenu.swift */; };
|
||||||
01F4A40C1EDCEC8DC4EC9CFA /* WeakDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 109C0201D8CB3F947340DC80 /* WeakDictionary.swift */; };
|
01F4A40C1EDCEC8DC4EC9CFA /* WeakDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 109C0201D8CB3F947340DC80 /* WeakDictionary.swift */; };
|
||||||
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */; };
|
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */; };
|
||||||
03B8FEA668A5B76A93113BB1 /* MemberDetailProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C2ABC1A9B62BDB3D216E7FD /* MemberDetailProviderManager.swift */; };
|
03B8FEA668A5B76A93113BB1 /* MemberDetailProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C2ABC1A9B62BDB3D216E7FD /* MemberDetailProviderManager.swift */; };
|
||||||
03CB204C52F18E24A5C3D219 /* UITestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967873B9E11828B67F64C89A /* UITestsAppCoordinator.swift */; };
|
03CB204C52F18E24A5C3D219 /* UITestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967873B9E11828B67F64C89A /* UITestsAppCoordinator.swift */; };
|
||||||
|
05776B005C57E92582F0CF08 /* BuildSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F87116470221880017CF522 /* BuildSettings.swift */; };
|
||||||
059173B3C77056C406906B6D /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = D4DA544B2520BFA65D6DB4BB /* target.yml */; };
|
059173B3C77056C406906B6D /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = D4DA544B2520BFA65D6DB4BB /* target.yml */; };
|
||||||
0602FA07557F580086782A9E /* UserIndicatorPresentationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FA072E995316CD18BC29313 /* UserIndicatorPresentationContext.swift */; };
|
0602FA07557F580086782A9E /* UserIndicatorPresentationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FA072E995316CD18BC29313 /* UserIndicatorPresentationContext.swift */; };
|
||||||
066A1E9B94723EE9F3038044 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EBB5D698CE9A25BB553A2D /* Strings.swift */; };
|
066A1E9B94723EE9F3038044 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EBB5D698CE9A25BB553A2D /* Strings.swift */; };
|
||||||
072BA9DBA932374CCA300125 /* MessageComposerTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6C10032A77AE7DC5AA4C50 /* MessageComposerTextField.swift */; };
|
072BA9DBA932374CCA300125 /* MessageComposerTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6C10032A77AE7DC5AA4C50 /* MessageComposerTextField.swift */; };
|
||||||
|
0B1F80C2BF7D223159FBA82C /* ImageAnonymizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6045E825AE900A92D61FEFF0 /* ImageAnonymizerTests.swift */; };
|
||||||
0E8C480700870BB34A2A360F /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 78A5A8DE1E2B09C978C7F3B0 /* KeychainAccess */; };
|
0E8C480700870BB34A2A360F /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 78A5A8DE1E2B09C978C7F3B0 /* KeychainAccess */; };
|
||||||
0EA6537A07E2DC882AEA5962 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 187853A7E643995EE49FAD43 /* Localizable.stringsdict */; };
|
0EA6537A07E2DC882AEA5962 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 187853A7E643995EE49FAD43 /* Localizable.stringsdict */; };
|
||||||
0EE5EBA18BA1FE10254BB489 /* UIFont+AttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */; };
|
0EE5EBA18BA1FE10254BB489 /* UIFont+AttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */; };
|
||||||
@@ -25,21 +29,27 @@
|
|||||||
1281625B25371BE53D36CB3A /* SeparatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */; };
|
1281625B25371BE53D36CB3A /* SeparatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */; };
|
||||||
12F70C493FB69F4D7E9A37EA /* NavigationRouterStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29EBCBFEC6FD0941749404D /* NavigationRouterStore.swift */; };
|
12F70C493FB69F4D7E9A37EA /* NavigationRouterStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29EBCBFEC6FD0941749404D /* NavigationRouterStore.swift */; };
|
||||||
13C77FDF17C4C6627CFFC205 /* RoomTimelineItemFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */; };
|
13C77FDF17C4C6627CFFC205 /* RoomTimelineItemFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */; };
|
||||||
|
149D1942DC005D0485FB8D93 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */; };
|
||||||
15D1F9C415D9C921643BA82E /* UserIndicatorRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61B73D5E21F524A9BE44448D /* UserIndicatorRequest.swift */; };
|
15D1F9C415D9C921643BA82E /* UserIndicatorRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61B73D5E21F524A9BE44448D /* UserIndicatorRequest.swift */; };
|
||||||
|
172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */; };
|
||||||
17CC4FB64F3A670F43ECBE5F /* UITestsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCA431E6EDD71F7067B5F9E7 /* UITestsRootView.swift */; };
|
17CC4FB64F3A670F43ECBE5F /* UITestsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCA431E6EDD71F7067B5F9E7 /* UITestsRootView.swift */; };
|
||||||
|
187E18F21EF4DA244E436E58 /* BugReportViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28959C7DB36C7688A01D4045 /* BugReportViewModelProtocol.swift */; };
|
||||||
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; };
|
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; };
|
||||||
1999ECC6777752A2616775CF /* MemberDetailsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */; };
|
1999ECC6777752A2616775CF /* MemberDetailsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */; };
|
||||||
1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; };
|
1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; };
|
||||||
1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; };
|
1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; };
|
||||||
1F3232BD368DF430AB433907 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 531CE4334AC5CA8DFF6AEB84 /* DTCoreText */; };
|
1F3232BD368DF430AB433907 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 531CE4334AC5CA8DFF6AEB84 /* DTCoreText */; };
|
||||||
|
206F0DBAB6AF042CA1FF2C0D /* SettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D487C1185D658F8B15B8F55 /* SettingsViewModelTests.swift */; };
|
||||||
224A55EEAEECF5336B14A4A5 /* EmoteRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE2DF459F1737A594667CC46 /* EmoteRoomMessage.swift */; };
|
224A55EEAEECF5336B14A4A5 /* EmoteRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE2DF459F1737A594667CC46 /* EmoteRoomMessage.swift */; };
|
||||||
22DADD537401E79D66132134 /* NavigationRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4173A48FD8542CD4AD3645C /* NavigationRouter.swift */; };
|
22DADD537401E79D66132134 /* NavigationRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4173A48FD8542CD4AD3645C /* NavigationRouter.swift */; };
|
||||||
24906A1E82D0046655958536 /* MessageComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CF12478983A5EB390FB26 /* MessageComposer.swift */; };
|
24906A1E82D0046655958536 /* MessageComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CF12478983A5EB390FB26 /* MessageComposer.swift */; };
|
||||||
24BDDD09A90B8BFE3793F3AA /* ClientProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6033779EB37259F27F938937 /* ClientProxyProtocol.swift */; };
|
24BDDD09A90B8BFE3793F3AA /* ClientProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6033779EB37259F27F938937 /* ClientProxyProtocol.swift */; };
|
||||||
277D2531C70F207A2F9F5906 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */; };
|
277D2531C70F207A2F9F5906 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */; };
|
||||||
2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = F75DF9500D69A3AAF8339E69 /* Untranslated.stringsdict */; };
|
2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = F75DF9500D69A3AAF8339E69 /* Untranslated.stringsdict */; };
|
||||||
|
28410F3DE89C2C44E4F75C92 /* MockBugReportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E7BF8F7BB1021F889C6483 /* MockBugReportService.swift */; };
|
||||||
297CD0A27C87B0C50FF192EE /* RoomTimelineViewFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */; };
|
297CD0A27C87B0C50FF192EE /* RoomTimelineViewFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */; };
|
||||||
29AEE68A604940180AB9EBFF /* MockRoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDAC8895AB2B77B47703AE /* MockRoomSummary.swift */; };
|
29AEE68A604940180AB9EBFF /* MockRoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDAC8895AB2B77B47703AE /* MockRoomSummary.swift */; };
|
||||||
|
29EE1791E0AFA1ABB7F23D2F /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 67E7A6F388D3BF85767609D9 /* Sentry */; };
|
||||||
2BA59D0AEFB4B82A2EC2A326 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = A981A4CA233FB5C13B9CA690 /* SwiftyBeaver */; };
|
2BA59D0AEFB4B82A2EC2A326 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = A981A4CA233FB5C13B9CA690 /* SwiftyBeaver */; };
|
||||||
2BAA5B222856068158D0B3C6 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = B1E8B697DF78FE7F61FC6CA4 /* MatrixRustSDK */; };
|
2BAA5B222856068158D0B3C6 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = B1E8B697DF78FE7F61FC6CA4 /* MatrixRustSDK */; };
|
||||||
2C0CE61E5DC177938618E0B1 /* RootRouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90733775209F4D4D366A268F /* RootRouterType.swift */; };
|
2C0CE61E5DC177938618E0B1 /* RootRouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90733775209F4D4D366A268F /* RootRouterType.swift */; };
|
||||||
@@ -53,19 +63,26 @@
|
|||||||
33912D1B9264D897033E0681 /* LoginScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0779B2CC9A687CBB82A5B920 /* LoginScreenViewModelProtocol.swift */; };
|
33912D1B9264D897033E0681 /* LoginScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0779B2CC9A687CBB82A5B920 /* LoginScreenViewModelProtocol.swift */; };
|
||||||
33B4E59D408AE6E02323EE41 /* NoticeRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDA364DFFC3AC71C4771251 /* NoticeRoomMessage.swift */; };
|
33B4E59D408AE6E02323EE41 /* NoticeRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDA364DFFC3AC71C4771251 /* NoticeRoomMessage.swift */; };
|
||||||
344AF4CBB6D8786214878642 /* NavigationRouterStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9D5F812E5AD6DC786DBC9B /* NavigationRouterStoreProtocol.swift */; };
|
344AF4CBB6D8786214878642 /* NavigationRouterStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9D5F812E5AD6DC786DBC9B /* NavigationRouterStoreProtocol.swift */; };
|
||||||
|
34966D4C1C2C6D37FE3F7F50 /* SettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DD2D50A7EAA4FC78417730E /* SettingsCoordinator.swift */; };
|
||||||
352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */; };
|
352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */; };
|
||||||
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
||||||
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */; };
|
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */; };
|
||||||
3772354754450F2B54107E17 /* TemplateSimpleScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4EDB32B97910AAAFE632B2 /* TemplateSimpleScreenViewModelProtocol.swift */; };
|
3772354754450F2B54107E17 /* TemplateSimpleScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4EDB32B97910AAAFE632B2 /* TemplateSimpleScreenViewModelProtocol.swift */; };
|
||||||
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */; };
|
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */; };
|
||||||
39AE84C8E5F2FE9D2DC7775C /* EventBasedTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56008790A9C4479A6B31FDF4 /* EventBasedTimelineView.swift */; };
|
39AE84C8E5F2FE9D2DC7775C /* EventBasedTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56008790A9C4479A6B31FDF4 /* EventBasedTimelineView.swift */; };
|
||||||
|
3B770CB4DED51CC362C66D47 /* SettingsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4990FDBDA96B88E214F92F48 /* SettingsModels.swift */; };
|
||||||
|
3C549A0BF39F8A854D45D9FD /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 7731767AE437BA3BD2CC14A8 /* Sentry */; };
|
||||||
3D325A1147F6281C57BFCDF6 /* EventBrief.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4411C0DA0087A1CB143E96FA /* EventBrief.swift */; };
|
3D325A1147F6281C57BFCDF6 /* EventBrief.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4411C0DA0087A1CB143E96FA /* EventBrief.swift */; };
|
||||||
|
3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DC38E64A5ED3FDB201029A /* BugReportService.swift */; };
|
||||||
3ED2725734568F6B8CC87544 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */; };
|
3ED2725734568F6B8CC87544 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */; };
|
||||||
418B4AEFD03DC7A6D2C9D5C8 /* EventBriefFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36322DD0D4E29D31B0945ADC /* EventBriefFactory.swift */; };
|
418B4AEFD03DC7A6D2C9D5C8 /* EventBriefFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36322DD0D4E29D31B0945ADC /* EventBriefFactory.swift */; };
|
||||||
|
438FB9BC535BC95948AA5F34 /* SettingsViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2F9D5C39A4494D19F33E38 /* SettingsViewModelProtocol.swift */; };
|
||||||
462813B93C39DF93B1249403 /* RoundedToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFABDF2E19D349DAAAC18C65 /* RoundedToastView.swift */; };
|
462813B93C39DF93B1249403 /* RoundedToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFABDF2E19D349DAAAC18C65 /* RoundedToastView.swift */; };
|
||||||
46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */; };
|
46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */; };
|
||||||
4669804D0369FBED4E8625D1 /* ToastViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4470B8CB654B097D807AA713 /* ToastViewPresenter.swift */; };
|
4669804D0369FBED4E8625D1 /* ToastViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4470B8CB654B097D807AA713 /* ToastViewPresenter.swift */; };
|
||||||
|
490E606044B18985055FF690 /* SettingsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E29F98CF0E960689A410E3 /* SettingsUITests.swift */; };
|
||||||
49F2E7DD8CAACE09CEECE3E6 /* SeparatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */; };
|
49F2E7DD8CAACE09CEECE3E6 /* SeparatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */; };
|
||||||
|
4A2E0DBB63919AC8309B6D40 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A191D3FDB995309C7E2DE7D /* SettingsViewModel.swift */; };
|
||||||
4B8A2C45FF906ADBB1F5C3B4 /* UserIndicatorQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04E1273CC3BC3E471AF87BE5 /* UserIndicatorQueueTests.swift */; };
|
4B8A2C45FF906ADBB1F5C3B4 /* UserIndicatorQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04E1273CC3BC3E471AF87BE5 /* UserIndicatorQueueTests.swift */; };
|
||||||
4D23C56053013437C35E511E /* ActivityIndicatorPresenterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C2318DF4C0E601EEE31F84 /* ActivityIndicatorPresenterType.swift */; };
|
4D23C56053013437C35E511E /* ActivityIndicatorPresenterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C2318DF4C0E601EEE31F84 /* ActivityIndicatorPresenterType.swift */; };
|
||||||
4D970CB606276717B43E2332 /* TimelineItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804F9B0FABE093C7284CD09B /* TimelineItemList.swift */; };
|
4D970CB606276717B43E2332 /* TimelineItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804F9B0FABE093C7284CD09B /* TimelineItemList.swift */; };
|
||||||
@@ -75,6 +92,7 @@
|
|||||||
500CB65ED116B81DA52FDAEE /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874A1842477895F199567BD7 /* TimelineView.swift */; };
|
500CB65ED116B81DA52FDAEE /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874A1842477895F199567BD7 /* TimelineView.swift */; };
|
||||||
50391038BC50C8ED9A4D88A0 /* WeakDictionaryReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64B23371BC8BF6164D9F6A05 /* WeakDictionaryReference.swift */; };
|
50391038BC50C8ED9A4D88A0 /* WeakDictionaryReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64B23371BC8BF6164D9F6A05 /* WeakDictionaryReference.swift */; };
|
||||||
51DB67C5B5BC68B0A6FF54D4 /* MockRoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBDC1D28EFB7789EB467E0 /* MockRoomProxy.swift */; };
|
51DB67C5B5BC68B0A6FF54D4 /* MockRoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBDC1D28EFB7789EB467E0 /* MockRoomProxy.swift */; };
|
||||||
|
524C9C31EF8D58C2249F8A10 /* sample_screenshot.png in Resources */ = {isa = PBXBuildFile; fileRef = 9414DCADBDF9D6C4B806F61E /* sample_screenshot.png */; };
|
||||||
53B9C2240C2F5533246EE230 /* RectangleToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6235E1CE00A6D989D7DB6D47 /* RectangleToastView.swift */; };
|
53B9C2240C2F5533246EE230 /* RectangleToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6235E1CE00A6D989D7DB6D47 /* RectangleToastView.swift */; };
|
||||||
56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F5530B2212862FA4BEFF2D /* HomeScreenViewModelProtocol.swift */; };
|
56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F5530B2212862FA4BEFF2D /* HomeScreenViewModelProtocol.swift */; };
|
||||||
59C41313AED7566C3AC51163 /* RoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */; };
|
59C41313AED7566C3AC51163 /* RoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */; };
|
||||||
@@ -91,10 +109,13 @@
|
|||||||
6832733838C57A7D3FE8FEB5 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 04C28663564E008DB32B5972 /* Introspect */; };
|
6832733838C57A7D3FE8FEB5 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 04C28663564E008DB32B5972 /* Introspect */; };
|
||||||
68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */; };
|
68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */; };
|
||||||
6A367F3D7A437A79B7D9A31C /* FullscreenLoadingViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4112D04077F6709C5CA0A13E /* FullscreenLoadingViewPresenter.swift */; };
|
6A367F3D7A437A79B7D9A31C /* FullscreenLoadingViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4112D04077F6709C5CA0A13E /* FullscreenLoadingViewPresenter.swift */; };
|
||||||
|
6C72F66DA26A0956E9A9077A /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BEB3259B2208E5AE5BB3F65 /* Settings.swift */; };
|
||||||
|
6EA61FCA55D950BDE326A1A7 /* ImageAnonymizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */; };
|
||||||
6F2AB43A1EFAD8A97AF41A15 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 5986E300FC849DEAB2EE7AEB /* Introspect */; };
|
6F2AB43A1EFAD8A97AF41A15 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 5986E300FC849DEAB2EE7AEB /* Introspect */; };
|
||||||
7002C55A4C917F3715765127 /* MediaProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C888BCD78E2A55DCE364F160 /* MediaProviderProtocol.swift */; };
|
7002C55A4C917F3715765127 /* MediaProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C888BCD78E2A55DCE364F160 /* MediaProviderProtocol.swift */; };
|
||||||
7405B4824D45BA7C3D943E76 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D0CBC76C80E04345E11F2DB /* Application.swift */; };
|
7405B4824D45BA7C3D943E76 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D0CBC76C80E04345E11F2DB /* Application.swift */; };
|
||||||
7434A7F02D587A920B376A9A /* LoginScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */; };
|
7434A7F02D587A920B376A9A /* LoginScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */; };
|
||||||
|
7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */; };
|
||||||
77D7DAA41AAB36800C1F2E2D /* RoomTimelineProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */; };
|
77D7DAA41AAB36800C1F2E2D /* RoomTimelineProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */; };
|
||||||
77E192BA943B90F9F310CA23 /* WeakDictionaryKeyReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFCC48E7F701B6C24484593 /* WeakDictionaryKeyReference.swift */; };
|
77E192BA943B90F9F310CA23 /* WeakDictionaryKeyReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFCC48E7F701B6C24484593 /* WeakDictionaryKeyReference.swift */; };
|
||||||
78B71D53C1FC55FB7A9B75F0 /* RoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24B0C97D2F560BCB72BE73B1 /* RoomTimelineController.swift */; };
|
78B71D53C1FC55FB7A9B75F0 /* RoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24B0C97D2F560BCB72BE73B1 /* RoomTimelineController.swift */; };
|
||||||
@@ -108,8 +129,10 @@
|
|||||||
7DE5EB4CB2401C672257283C /* WeakKeyDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12969CEC0051BC750DA5068 /* WeakKeyDictionary.swift */; };
|
7DE5EB4CB2401C672257283C /* WeakKeyDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12969CEC0051BC750DA5068 /* WeakKeyDictionary.swift */; };
|
||||||
7E1EDBA3934E6C29E5BD045B /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77DD2DA5DC8654F2A80FF1D /* Bundle.swift */; };
|
7E1EDBA3934E6C29E5BD045B /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77DD2DA5DC8654F2A80FF1D /* Bundle.swift */; };
|
||||||
7F19E97E7985F518C9018B83 /* RootRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF47564C584F614B7287F3EB /* RootRouter.swift */; };
|
7F19E97E7985F518C9018B83 /* RootRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF47564C584F614B7287F3EB /* RootRouter.swift */; };
|
||||||
|
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */; };
|
||||||
7FA4227B2BAAA71560252866 /* UserIndicatorDismissal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D1532B5D9FB0C8461A1453 /* UserIndicatorDismissal.swift */; };
|
7FA4227B2BAAA71560252866 /* UserIndicatorDismissal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D1532B5D9FB0C8461A1453 /* UserIndicatorDismissal.swift */; };
|
||||||
80E04BE80A89A78FBB4863BB /* UserIndicatorViewPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193FB285430D3956B6E61E4D /* UserIndicatorViewPresentable.swift */; };
|
80E04BE80A89A78FBB4863BB /* UserIndicatorViewPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193FB285430D3956B6E61E4D /* UserIndicatorViewPresentable.swift */; };
|
||||||
|
86C2E93920FD15AD17E193A9 /* BugReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E532D95330139D118A9BF88 /* BugReportViewModel.swift */; };
|
||||||
8775F46AE3234A5A5688C19D /* UserIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FAAA4A76CE4A1F3014D9 /* UserIndicator.swift */; };
|
8775F46AE3234A5A5688C19D /* UserIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FAAA4A76CE4A1F3014D9 /* UserIndicator.swift */; };
|
||||||
8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BC7CA1BC1041E93077BBA1 /* HomeScreenModels.swift */; };
|
8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BC7CA1BC1041E93077BBA1 /* HomeScreenModels.swift */; };
|
||||||
8AB8ED1051216546CB35FA0E /* UserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5E9C044BEB7C70B1378E91 /* UserSession.swift */; };
|
8AB8ED1051216546CB35FA0E /* UserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5E9C044BEB7C70B1378E91 /* UserSession.swift */; };
|
||||||
@@ -132,6 +155,9 @@
|
|||||||
9D2E03DB175A6AB14589076D /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 0DD568A494247444A4B56031 /* Kingfisher */; };
|
9D2E03DB175A6AB14589076D /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 0DD568A494247444A4B56031 /* Kingfisher */; };
|
||||||
9DC5FB22B8F86C3B51E907C1 /* HomeScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D6E4C37E9F0E53D3DF951AC /* HomeScreenUITests.swift */; };
|
9DC5FB22B8F86C3B51E907C1 /* HomeScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D6E4C37E9F0E53D3DF951AC /* HomeScreenUITests.swift */; };
|
||||||
A0A0D2A9564BDA3FDE2E360F /* FormattedBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */; };
|
A0A0D2A9564BDA3FDE2E360F /* FormattedBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */; };
|
||||||
|
A32517FB1CA0BBCE2BC75249 /* BugReportCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6C07DA7D3FF193F7419F55 /* BugReportCoordinator.swift */; };
|
||||||
|
A4E885358D7DD5A072A06824 /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 1BCD21310B997A6837B854D6 /* GZIP */; };
|
||||||
|
A5C8F013ED9FB8AA6FEE18A7 /* InfoPlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A901D95158B02CA96C79C7F /* InfoPlist.swift */; };
|
||||||
A5EC21A071F58FC1229C20D0 /* MemberDetailsProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09747989908EC5E4AA29F844 /* MemberDetailsProviderProtocol.swift */; };
|
A5EC21A071F58FC1229C20D0 /* MemberDetailsProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09747989908EC5E4AA29F844 /* MemberDetailsProviderProtocol.swift */; };
|
||||||
A636D4900E0D98ED91536482 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF3EDF23226895776553F04A /* AppCoordinator.swift */; };
|
A636D4900E0D98ED91536482 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF3EDF23226895776553F04A /* AppCoordinator.swift */; };
|
||||||
A69B7B421C28C6CDEBBD0613 /* AuthenticationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AD575D36B9F6D1D543305D1 /* AuthenticationCoordinator.swift */; };
|
A69B7B421C28C6CDEBBD0613 /* AuthenticationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AD575D36B9F6D1D543305D1 /* AuthenticationCoordinator.swift */; };
|
||||||
@@ -140,13 +166,15 @@
|
|||||||
A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; };
|
A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; };
|
||||||
A941EAD7F407F2ED6DA54A31 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA97D630B74B0616C1468CBD /* LoginScreen.swift */; };
|
A941EAD7F407F2ED6DA54A31 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA97D630B74B0616C1468CBD /* LoginScreen.swift */; };
|
||||||
AB34401E4E1CAD5D2EC3072B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9760103CF316DF68698BCFE6 /* LaunchScreen.storyboard */; };
|
AB34401E4E1CAD5D2EC3072B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9760103CF316DF68698BCFE6 /* LaunchScreen.storyboard */; };
|
||||||
B0887A7B5AFEC88981626389 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64839516BD56D1C81D84C5E0 /* MXLog.swift */; };
|
|
||||||
B0EDAF55877DE19B67837C22 /* TemplateSimpleScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C29670CEC77346F31EE94C /* TemplateSimpleScreenModels.swift */; };
|
B0EDAF55877DE19B67837C22 /* TemplateSimpleScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C29670CEC77346F31EE94C /* TemplateSimpleScreenModels.swift */; };
|
||||||
B245583C63F8F90357B87FAE /* SwiftState in Frameworks */ = {isa = PBXBuildFile; productRef = 3853B78FB8531B83936C5DA6 /* SwiftState */; };
|
B245583C63F8F90357B87FAE /* SwiftState in Frameworks */ = {isa = PBXBuildFile; productRef = 3853B78FB8531B83936C5DA6 /* SwiftState */; };
|
||||||
B3FDB1D9CF40777695DBBD1D /* AppCoordinatorStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A9AB74614131D6706894E0C /* AppCoordinatorStateMachine.swift */; };
|
B3FDB1D9CF40777695DBBD1D /* AppCoordinatorStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A9AB74614131D6706894E0C /* AppCoordinatorStateMachine.swift */; };
|
||||||
B4AAB3257A83B73F53FB2689 /* StateStoreViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3DFE5B444F131648066F05 /* StateStoreViewModel.swift */; };
|
B4AAB3257A83B73F53FB2689 /* StateStoreViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3DFE5B444F131648066F05 /* StateStoreViewModel.swift */; };
|
||||||
|
B6DA66EFC13A90846B625836 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 91DE43B8815918E590912DDA /* InfoPlist.strings */; };
|
||||||
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */; };
|
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */; };
|
||||||
B80C4FABB5529DF12436FFDA /* AppIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 16DC8C5B2991724903F1FA6A /* AppIcon.pdf */; };
|
B80C4FABB5529DF12436FFDA /* AppIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 16DC8C5B2991724903F1FA6A /* AppIcon.pdf */; };
|
||||||
|
B94368839BDB69172E28E245 /* MXLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 111B698739E3410E2CDB7144 /* MXLog.swift */; };
|
||||||
|
BCC3EDB7AD0902797CB4BBC2 /* MXLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = EF188681D6B6068CFAEAFC3F /* MXLogger.m */; };
|
||||||
BE3237142FA6E1A13C0E7D11 /* RoomSummaryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21ECC295F4DE8DAA86D62AC /* RoomSummaryProtocol.swift */; };
|
BE3237142FA6E1A13C0E7D11 /* RoomSummaryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21ECC295F4DE8DAA86D62AC /* RoomSummaryProtocol.swift */; };
|
||||||
BEEC06EFD30BFCA02F0FD559 /* UserIndicatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D8EA85D4F10D7445BB6368A /* UserIndicatorTests.swift */; };
|
BEEC06EFD30BFCA02F0FD559 /* UserIndicatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D8EA85D4F10D7445BB6368A /* UserIndicatorTests.swift */; };
|
||||||
BF35062D06888FA80BD139FF /* Presentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB7F9D6FC121204D59E18DF /* Presentable.swift */; };
|
BF35062D06888FA80BD139FF /* Presentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB7F9D6FC121204D59E18DF /* Presentable.swift */; };
|
||||||
@@ -154,14 +182,18 @@
|
|||||||
C1156BBE4F977AEEE1E80C48 /* TemplateSimpleScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2869CFFF6CD2A642AB4B743 /* TemplateSimpleScreenCoordinator.swift */; };
|
C1156BBE4F977AEEE1E80C48 /* TemplateSimpleScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2869CFFF6CD2A642AB4B743 /* TemplateSimpleScreenCoordinator.swift */; };
|
||||||
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */; };
|
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */; };
|
||||||
C55A44C99F64A479ABA85B46 /* RoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */; };
|
C55A44C99F64A479ABA85B46 /* RoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */; };
|
||||||
|
C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */; };
|
||||||
|
CB137BFB3E083C33E398A6CB /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 997C7385E1A07E061D7E2100 /* GZIP */; };
|
||||||
CB326BAB54E9B68658909E36 /* Benchmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EAD710A2C16EFF7C3EA16F /* Benchmark.swift */; };
|
CB326BAB54E9B68658909E36 /* Benchmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EAD710A2C16EFF7C3EA16F /* Benchmark.swift */; };
|
||||||
CB498F4E27AA0545DCEF0F6F /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 50009897F60FAE7D63EF5E5B /* Kingfisher */; };
|
CB498F4E27AA0545DCEF0F6F /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 50009897F60FAE7D63EF5E5B /* Kingfisher */; };
|
||||||
|
CC736DA1AA8F8B9FD8785009 /* ScreenshotDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C4AF6E3885730CD560311C /* ScreenshotDetector.swift */; };
|
||||||
CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; };
|
CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; };
|
||||||
CF82143AA4A4F7BD11D22946 /* RoomTimelineViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACB6C5E4950B6C9842F35A38 /* RoomTimelineViewProvider.swift */; };
|
CF82143AA4A4F7BD11D22946 /* RoomTimelineViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACB6C5E4950B6C9842F35A38 /* RoomTimelineViewProvider.swift */; };
|
||||||
D013E70C8E28E43497820444 /* TextRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4110685D9CA159F3FD2D6BA1 /* TextRoomMessage.swift */; };
|
D013E70C8E28E43497820444 /* TextRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4110685D9CA159F3FD2D6BA1 /* TextRoomMessage.swift */; };
|
||||||
D0619D2E6B9C511190FBEB95 /* RoomMessageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607974D08BD2AF83725D817A /* RoomMessageProtocol.swift */; };
|
D0619D2E6B9C511190FBEB95 /* RoomMessageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607974D08BD2AF83725D817A /* RoomMessageProtocol.swift */; };
|
||||||
D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A45283CF1DB96E583BECA6 /* ImageRoomTimelineView.swift */; };
|
D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A45283CF1DB96E583BECA6 /* ImageRoomTimelineView.swift */; };
|
||||||
D826154612415D2A3BB6EBF3 /* ListTableViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E854E7CF531DAC5CBEBDC75 /* ListTableViewAdapter.swift */; };
|
D826154612415D2A3BB6EBF3 /* ListTableViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E854E7CF531DAC5CBEBDC75 /* ListTableViewAdapter.swift */; };
|
||||||
|
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */; };
|
||||||
D94F664677C380A3CAB8D7F6 /* ActivityIndicatorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68706A66BBA04268F7747A2F /* ActivityIndicatorPresenter.swift */; };
|
D94F664677C380A3CAB8D7F6 /* ActivityIndicatorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68706A66BBA04268F7747A2F /* ActivityIndicatorPresenter.swift */; };
|
||||||
DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CC95CD75B688E946438165 /* Coordinator.swift */; };
|
DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CC95CD75B688E946438165 /* Coordinator.swift */; };
|
||||||
DDB80FD2753FEAAE43CC2AAE /* ImageRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A63815AD6A5C306453342F2 /* ImageRoomTimelineItem.swift */; };
|
DDB80FD2753FEAAE43CC2AAE /* ImageRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A63815AD6A5C306453342F2 /* ImageRoomTimelineItem.swift */; };
|
||||||
@@ -170,6 +202,7 @@
|
|||||||
E81EEC1675F2371D12A880A3 /* MockRoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61ADFB893DEF81E58DF3FAB9 /* MockRoomTimelineController.swift */; };
|
E81EEC1675F2371D12A880A3 /* MockRoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61ADFB893DEF81E58DF3FAB9 /* MockRoomTimelineController.swift */; };
|
||||||
E9CEAF2C38E4E00459B811D9 /* LoginScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2082B5226B2A3A4D0798B6 /* LoginScreenModels.swift */; };
|
E9CEAF2C38E4E00459B811D9 /* LoginScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2082B5226B2A3A4D0798B6 /* LoginScreenModels.swift */; };
|
||||||
EA1E7949533E19C6D862680A /* MediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885D8C42DD17625B5261BEFF /* MediaProvider.swift */; };
|
EA1E7949533E19C6D862680A /* MediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885D8C42DD17625B5261BEFF /* MediaProvider.swift */; };
|
||||||
|
EA31DD9043B91ECB8E45A9A6 /* ScreenshotDetectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03C9D319676F3C0DC6B0203 /* ScreenshotDetectorTests.swift */; };
|
||||||
ED4F663C783E9A8C0E80B983 /* TemplateSimpleScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47543EB19F3DCF308751F53C /* TemplateSimpleScreenViewModel.swift */; };
|
ED4F663C783E9A8C0E80B983 /* TemplateSimpleScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47543EB19F3DCF308751F53C /* TemplateSimpleScreenViewModel.swift */; };
|
||||||
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */; };
|
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */; };
|
||||||
F03E16ED043C62FED5A07AE0 /* MatrixEntitityRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B81C8227BBEA95CCE86037 /* MatrixEntitityRegex.swift */; };
|
F03E16ED043C62FED5A07AE0 /* MatrixEntitityRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B81C8227BBEA95CCE86037 /* MatrixEntitityRegex.swift */; };
|
||||||
@@ -211,7 +244,9 @@
|
|||||||
08F64963396A6A23538EFCEC /* is */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = is; path = is.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
08F64963396A6A23538EFCEC /* is */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = is; path = is.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
0950733DD4BA83EEE752E259 /* PlaceholderAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderAvatarImage.swift; sourceTree = "<group>"; };
|
0950733DD4BA83EEE752E259 /* PlaceholderAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderAvatarImage.swift; sourceTree = "<group>"; };
|
||||||
095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProviderProtocol.swift; sourceTree = "<group>"; };
|
095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProviderProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementToggleStyle.swift; sourceTree = "<group>"; };
|
||||||
09747989908EC5E4AA29F844 /* MemberDetailsProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDetailsProviderProtocol.swift; sourceTree = "<group>"; };
|
09747989908EC5E4AA29F844 /* MemberDetailsProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDetailsProviderProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
0A191D3FDB995309C7E2DE7D /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
|
||||||
0AB7A0C06CB527A1095DEB33 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = da; path = da.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
0AB7A0C06CB527A1095DEB33 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = da; path = da.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
0AD575D36B9F6D1D543305D1 /* AuthenticationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationCoordinator.swift; sourceTree = "<group>"; };
|
0AD575D36B9F6D1D543305D1 /* AuthenticationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationCoordinator.swift; sourceTree = "<group>"; };
|
||||||
0C13A92C1E9C79F055B8133D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ar; path = ar.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
0C13A92C1E9C79F055B8133D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ar; path = ar.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
@@ -222,9 +257,12 @@
|
|||||||
105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactory.swift; sourceTree = "<group>"; };
|
105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactory.swift; sourceTree = "<group>"; };
|
||||||
105D16E7DB0CCE9526612BDD /* bn-IN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "bn-IN"; path = "bn-IN.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
105D16E7DB0CCE9526612BDD /* bn-IN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "bn-IN"; path = "bn-IN.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
109C0201D8CB3F947340DC80 /* WeakDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionary.swift; sourceTree = "<group>"; };
|
109C0201D8CB3F947340DC80 /* WeakDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionary.swift; sourceTree = "<group>"; };
|
||||||
|
111B698739E3410E2CDB7144 /* MXLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = "<group>"; };
|
||||||
113356152C099951A6D17D85 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
|
113356152C099951A6D17D85 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
1215A4FC53D2319E81AE8970 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
|
1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
|
||||||
124D85E85505B6B81845235F /* fy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fy; path = fy.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
124D85E85505B6B81845235F /* fy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fy; path = fy.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
|
12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageAnonymizer.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>"; };
|
||||||
16DC8C5B2991724903F1FA6A /* AppIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = AppIcon.pdf; sourceTree = "<group>"; };
|
16DC8C5B2991724903F1FA6A /* AppIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = AppIcon.pdf; sourceTree = "<group>"; };
|
||||||
184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -245,10 +283,12 @@
|
|||||||
24F5530B2212862FA4BEFF2D /* HomeScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
24F5530B2212862FA4BEFF2D /* HomeScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
2583416C8974272ADBADDBE1 /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-TW"; path = "zh-TW.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
2583416C8974272ADBADDBE1 /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-TW"; path = "zh-TW.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||||
26C4D226FCD20BAC53F1E092 /* ml */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ml; path = ml.lproj/Localizable.strings; sourceTree = "<group>"; };
|
26C4D226FCD20BAC53F1E092 /* ml */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ml; path = ml.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
28959C7DB36C7688A01D4045 /* BugReportViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
28EA8BE9EEDBD17555141C7E /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = el; path = el.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
28EA8BE9EEDBD17555141C7E /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = el; path = el.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
|
29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummary.swift; sourceTree = "<group>"; };
|
||||||
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
||||||
2AE83A3DD63BCFBB956FE5CB /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
2AE83A3DD63BCFBB956FE5CB /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
|
2BEB3259B2208E5AE5BB3F65 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
|
||||||
2CF9FE7E0CF9F40D1509E63A /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = bg; path = bg.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
2CF9FE7E0CF9F40D1509E63A /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = bg; path = bg.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModel.swift; sourceTree = "<group>"; };
|
31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
33E49C5C6F802B4D94CA78D1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
|
33E49C5C6F802B4D94CA78D1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
@@ -261,8 +301,12 @@
|
|||||||
3ACBDC1D28EFB7789EB467E0 /* MockRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomProxy.swift; sourceTree = "<group>"; };
|
3ACBDC1D28EFB7789EB467E0 /* MockRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomProxy.swift; sourceTree = "<group>"; };
|
||||||
3B5B535DA49C54523FF7A412 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nn; path = nn.lproj/Localizable.strings; sourceTree = "<group>"; };
|
3B5B535DA49C54523FF7A412 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nn; path = nn.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
3CDF9E55650D6035D6536538 /* nb-NO */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "nb-NO"; path = "nb-NO.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
3CDF9E55650D6035D6536538 /* nb-NO */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "nb-NO"; path = "nb-NO.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||||
|
3D487C1185D658F8B15B8F55 /* SettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
3D4DD336905C72F95EAF34B7 /* ElementX-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ElementX-Bridging-Header.h"; sourceTree = "<group>"; };
|
3D4DD336905C72F95EAF34B7 /* ElementX-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ElementX-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = "<group>"; };
|
||||||
|
3DD2D50A7EAA4FC78417730E /* SettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCoordinator.swift; sourceTree = "<group>"; };
|
||||||
3DD6E7C1D8B53F47789778CD /* fr-CA */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-CA"; path = "fr-CA.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
3DD6E7C1D8B53F47789778CD /* fr-CA */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "fr-CA"; path = "fr-CA.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
|
3F87116470221880017CF522 /* BuildSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildSettings.swift; sourceTree = "<group>"; };
|
||||||
3FAA6438B00FDB130F404E31 /* UserIndicatorStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorStore.swift; sourceTree = "<group>"; };
|
3FAA6438B00FDB130F404E31 /* UserIndicatorStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorStore.swift; sourceTree = "<group>"; };
|
||||||
3FEE631F3A4AFDC6652DD9DA /* RoomTimelineViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewFactory.swift; sourceTree = "<group>"; };
|
3FEE631F3A4AFDC6652DD9DA /* RoomTimelineViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewFactory.swift; sourceTree = "<group>"; };
|
||||||
4110685D9CA159F3FD2D6BA1 /* TextRoomMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomMessage.swift; sourceTree = "<group>"; };
|
4110685D9CA159F3FD2D6BA1 /* TextRoomMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomMessage.swift; sourceTree = "<group>"; };
|
||||||
@@ -281,6 +325,7 @@
|
|||||||
48971F1FFD7FC5C466889FC7 /* SplashViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SplashViewController.xib; sourceTree = "<group>"; };
|
48971F1FFD7FC5C466889FC7 /* SplashViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SplashViewController.xib; sourceTree = "<group>"; };
|
||||||
48CE6BF18E542B32FA52CE06 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fa; path = fa.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
48CE6BF18E542B32FA52CE06 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fa; path = fa.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
49193CB0C248D621A96FB2AA /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
|
49193CB0C248D621A96FB2AA /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
4990FDBDA96B88E214F92F48 /* SettingsModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModels.swift; sourceTree = "<group>"; };
|
||||||
49D2C8E66E83EA578A7F318A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
49D2C8E66E83EA578A7F318A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||||
49EAD710A2C16EFF7C3EA16F /* Benchmark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Benchmark.swift; sourceTree = "<group>"; };
|
49EAD710A2C16EFF7C3EA16F /* Benchmark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Benchmark.swift; sourceTree = "<group>"; };
|
||||||
4B40B7F6FCCE2D8C242492D9 /* ga */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ga; path = ga.lproj/Localizable.strings; sourceTree = "<group>"; };
|
4B40B7F6FCCE2D8C242492D9 /* ga */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ga; path = ga.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
@@ -303,8 +348,10 @@
|
|||||||
56008790A9C4479A6B31FDF4 /* EventBasedTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBasedTimelineView.swift; sourceTree = "<group>"; };
|
56008790A9C4479A6B31FDF4 /* EventBasedTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBasedTimelineView.swift; sourceTree = "<group>"; };
|
||||||
56F01DD1BBD4450E18115916 /* LabelledActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelledActivityIndicatorView.swift; sourceTree = "<group>"; };
|
56F01DD1BBD4450E18115916 /* LabelledActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelledActivityIndicatorView.swift; sourceTree = "<group>"; };
|
||||||
5773C86AF04AEF26515AD00C /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
5773C86AF04AEF26515AD00C /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
5872785B9C7934940146BFBA /* MXLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXLogger.h; sourceTree = "<group>"; };
|
||||||
5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenViewModelTests.swift; sourceTree = "<group>"; };
|
5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
5A9AB74614131D6706894E0C /* AppCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinatorStateMachine.swift; sourceTree = "<group>"; };
|
5A9AB74614131D6706894E0C /* AppCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinatorStateMachine.swift; sourceTree = "<group>"; };
|
||||||
|
5B2F9D5C39A4494D19F33E38 /* SettingsViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
5B9D5F812E5AD6DC786DBC9B /* NavigationRouterStoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouterStoreProtocol.swift; sourceTree = "<group>"; };
|
5B9D5F812E5AD6DC786DBC9B /* NavigationRouterStoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouterStoreProtocol.swift; sourceTree = "<group>"; };
|
||||||
5CB7F9D6FC121204D59E18DF /* Presentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Presentable.swift; sourceTree = "<group>"; };
|
5CB7F9D6FC121204D59E18DF /* Presentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Presentable.swift; sourceTree = "<group>"; };
|
||||||
5D26A086A8278D39B5756D6F /* project.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = project.yml; sourceTree = "<group>"; };
|
5D26A086A8278D39B5756D6F /* project.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = project.yml; sourceTree = "<group>"; };
|
||||||
@@ -314,6 +361,7 @@
|
|||||||
5F77E8010D41AA3F5F9A1FCA /* NavigationModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModule.swift; sourceTree = "<group>"; };
|
5F77E8010D41AA3F5F9A1FCA /* NavigationModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModule.swift; sourceTree = "<group>"; };
|
||||||
5FF214969B25BFCBF87B908B /* bn-BD */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "bn-BD"; path = "bn-BD.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
5FF214969B25BFCBF87B908B /* bn-BD */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "bn-BD"; path = "bn-BD.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||||
6033779EB37259F27F938937 /* ClientProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxyProtocol.swift; sourceTree = "<group>"; };
|
6033779EB37259F27F938937 /* ClientProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
6045E825AE900A92D61FEFF0 /* ImageAnonymizerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageAnonymizerTests.swift; sourceTree = "<group>"; };
|
||||||
607974D08BD2AF83725D817A /* RoomMessageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageProtocol.swift; sourceTree = "<group>"; };
|
607974D08BD2AF83725D817A /* RoomMessageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageProtocol.swift; sourceTree = "<group>"; };
|
||||||
616197D81103330BF2ADD559 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = gl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
616197D81103330BF2ADD559 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = gl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
61ADFB893DEF81E58DF3FAB9 /* MockRoomTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineController.swift; sourceTree = "<group>"; };
|
61ADFB893DEF81E58DF3FAB9 /* MockRoomTimelineController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineController.swift; sourceTree = "<group>"; };
|
||||||
@@ -322,7 +370,6 @@
|
|||||||
6235E1CE00A6D989D7DB6D47 /* RectangleToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RectangleToastView.swift; sourceTree = "<group>"; };
|
6235E1CE00A6D989D7DB6D47 /* RectangleToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RectangleToastView.swift; sourceTree = "<group>"; };
|
||||||
624244C398804ADC885239AA /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
|
624244C398804ADC885239AA /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineView.swift; sourceTree = "<group>"; };
|
6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
64839516BD56D1C81D84C5E0 /* MXLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXLog.swift; sourceTree = "<group>"; };
|
|
||||||
64B23371BC8BF6164D9F6A05 /* WeakDictionaryReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionaryReference.swift; sourceTree = "<group>"; };
|
64B23371BC8BF6164D9F6A05 /* WeakDictionaryReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionaryReference.swift; sourceTree = "<group>"; };
|
||||||
653610CB5F9776EAAAB98155 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
653610CB5F9776EAAAB98155 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
6654859746B0BE9611459391 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = cs; path = cs.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
6654859746B0BE9611459391 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = cs; path = cs.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
@@ -331,6 +378,8 @@
|
|||||||
68706A66BBA04268F7747A2F /* ActivityIndicatorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorPresenter.swift; sourceTree = "<group>"; };
|
68706A66BBA04268F7747A2F /* ActivityIndicatorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorPresenter.swift; sourceTree = "<group>"; };
|
||||||
6920A4869821BF72FFC58842 /* MockMediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaProvider.swift; sourceTree = "<group>"; };
|
6920A4869821BF72FFC58842 /* MockMediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaProvider.swift; sourceTree = "<group>"; };
|
||||||
6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDetailsProvider.swift; sourceTree = "<group>"; };
|
6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDetailsProvider.swift; sourceTree = "<group>"; };
|
||||||
|
6A901D95158B02CA96C79C7F /* InfoPlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPlist.swift; sourceTree = "<group>"; };
|
||||||
|
6D607F47FDEF16CC63684BE0 /* BugReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReport.swift; sourceTree = "<group>"; };
|
||||||
6DB53055CB130F0651C70763 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
|
6DB53055CB130F0651C70763 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
6E5E9C044BEB7C70B1378E91 /* UserSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSession.swift; sourceTree = "<group>"; };
|
6E5E9C044BEB7C70B1378E91 /* UserSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSession.swift; sourceTree = "<group>"; };
|
||||||
6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BindableState.swift; sourceTree = "<group>"; };
|
6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BindableState.swift; sourceTree = "<group>"; };
|
||||||
@@ -343,6 +392,7 @@
|
|||||||
72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilderProtocol.swift; sourceTree = "<group>"; };
|
72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilderProtocol.swift; sourceTree = "<group>"; };
|
||||||
752DEC02D93AFF46BC13313A /* NavigationRouterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouterType.swift; sourceTree = "<group>"; };
|
752DEC02D93AFF46BC13313A /* NavigationRouterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouterType.swift; sourceTree = "<group>"; };
|
||||||
799A3A11C434296ED28F87C8 /* iw */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = iw; path = iw.lproj/Localizable.strings; sourceTree = "<group>"; };
|
799A3A11C434296ED28F87C8 /* iw */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = iw; path = iw.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
7B04BD3874D736127A8156B8 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
7B04BD3874D736127A8156B8 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
7BDF6A69C2BB99535193E554 /* si */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = si; path = si.lproj/Localizable.strings; sourceTree = "<group>"; };
|
7BDF6A69C2BB99535193E554 /* si */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = si; path = si.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
7D0CBC76C80E04345E11F2DB /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
7D0CBC76C80E04345E11F2DB /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||||
@@ -350,6 +400,7 @@
|
|||||||
7DA80FADE73CDF01E96F5B8E /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = sq.lproj/Localizable.strings; sourceTree = "<group>"; };
|
7DA80FADE73CDF01E96F5B8E /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = sq.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
7DDBF99755A9008CF8C8499E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
7DDBF99755A9008CF8C8499E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||||
7E154FEA1E6FE964D3DF7859 /* fy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fy; path = fy.lproj/Localizable.strings; sourceTree = "<group>"; };
|
7E154FEA1E6FE964D3DF7859 /* fy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fy; path = fy.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
7E532D95330139D118A9BF88 /* BugReportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportViewModel.swift; sourceTree = "<group>"; };
|
||||||
7FFCC48E7F701B6C24484593 /* WeakDictionaryKeyReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionaryKeyReference.swift; sourceTree = "<group>"; };
|
7FFCC48E7F701B6C24484593 /* WeakDictionaryKeyReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionaryKeyReference.swift; sourceTree = "<group>"; };
|
||||||
804F9B0FABE093C7284CD09B /* TimelineItemList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemList.swift; sourceTree = "<group>"; };
|
804F9B0FABE093C7284CD09B /* TimelineItemList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemList.swift; sourceTree = "<group>"; };
|
||||||
8140010A796DB2C7977B6643 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
8140010A796DB2C7977B6643 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
@@ -375,6 +426,7 @@
|
|||||||
938BD1FCD9E6FF3FCFA7AB4C /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-CN"; path = "zh-CN.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
938BD1FCD9E6FF3FCFA7AB4C /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-CN"; path = "zh-CN.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||||
93B21E72926FACB13A186689 /* ml */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ml; path = ml.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
93B21E72926FACB13A186689 /* ml */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ml; path = ml.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelTests.swift; sourceTree = "<group>"; };
|
93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
|
9414DCADBDF9D6C4B806F61E /* sample_screenshot.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sample_screenshot.png; sourceTree = "<group>"; };
|
||||||
956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = "<group>"; };
|
956BDA4AE16429AD015661A8 /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = "<group>"; };
|
||||||
95CC95CD75B688E946438165 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
|
95CC95CD75B688E946438165 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
|
||||||
967873B9E11828B67F64C89A /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; };
|
967873B9E11828B67F64C89A /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; };
|
||||||
@@ -383,6 +435,7 @@
|
|||||||
97F893DBB5F88D746C6DCDE5 /* ku */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ku; path = ku.lproj/Localizable.strings; sourceTree = "<group>"; };
|
97F893DBB5F88D746C6DCDE5 /* ku */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ku; path = ku.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
997783054A2E95F9E624217E /* kaa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kaa; path = kaa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
997783054A2E95F9E624217E /* kaa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kaa; path = kaa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
99DE232F24EAD72A3DF7EF1A /* kab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = kab; path = kab.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
99DE232F24EAD72A3DF7EF1A /* kab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = kab; path = kab.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
|
9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportServiceProtocol.swift; sourceTree = "<group>"; };
|
||||||
9C5E81214D27A6B898FC397D /* ElementX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ElementX.entitlements; sourceTree = "<group>"; };
|
9C5E81214D27A6B898FC397D /* ElementX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ElementX.entitlements; sourceTree = "<group>"; };
|
||||||
9CE3C90E487B255B735D73C8 /* RoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModel.swift; sourceTree = "<group>"; };
|
9CE3C90E487B255B735D73C8 /* RoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -401,6 +454,7 @@
|
|||||||
ACA11F7F50A4A3887A18CA5A /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
|
ACA11F7F50A4A3887A18CA5A /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
ACB6C5E4950B6C9842F35A38 /* RoomTimelineViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewProvider.swift; sourceTree = "<group>"; };
|
ACB6C5E4950B6C9842F35A38 /* RoomTimelineViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewProvider.swift; sourceTree = "<group>"; };
|
||||||
AD378D580A41E42560C60E9C /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
AD378D580A41E42560C60E9C /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
AD6C07DA7D3FF193F7419F55 /* BugReportCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportCoordinator.swift; sourceTree = "<group>"; };
|
||||||
ADCB8A232D3A8FB3E16A7303 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
ADCB8A232D3A8FB3E16A7303 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
AE225C66978648AA4AF37B45 /* te */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = te; path = te.lproj/Localizable.strings; sourceTree = "<group>"; };
|
AE225C66978648AA4AF37B45 /* te */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = te; path = te.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
AE5DDBEBBA17973ED4638823 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
AE5DDBEBBA17973ED4638823 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
@@ -414,6 +468,7 @@
|
|||||||
B1D1532B5D9FB0C8461A1453 /* UserIndicatorDismissal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorDismissal.swift; sourceTree = "<group>"; };
|
B1D1532B5D9FB0C8461A1453 /* UserIndicatorDismissal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorDismissal.swift; sourceTree = "<group>"; };
|
||||||
B4173A48FD8542CD4AD3645C /* NavigationRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouter.swift; sourceTree = "<group>"; };
|
B4173A48FD8542CD4AD3645C /* NavigationRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouter.swift; sourceTree = "<group>"; };
|
||||||
B43AF03660F5FD4FFFA7F1CE /* TimelineItemContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemContextMenu.swift; sourceTree = "<group>"; };
|
B43AF03660F5FD4FFFA7F1CE /* TimelineItemContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemContextMenu.swift; sourceTree = "<group>"; };
|
||||||
|
B516212D9FE785DDD5E490D1 /* BugReportModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportModels.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>"; };
|
||||||
B64F3A3D0DF86ED5A241AB05 /* ActivityIndicatorView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ActivityIndicatorView.xib; sourceTree = "<group>"; };
|
B64F3A3D0DF86ED5A241AB05 /* ActivityIndicatorView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ActivityIndicatorView.xib; sourceTree = "<group>"; };
|
||||||
B695D0D12086158BAD1D9859 /* UserIndicatorPresenterSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorPresenterSpy.swift; sourceTree = "<group>"; };
|
B695D0D12086158BAD1D9859 /* UserIndicatorPresenterSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorPresenterSpy.swift; sourceTree = "<group>"; };
|
||||||
@@ -434,6 +489,7 @@
|
|||||||
C21ECC295F4DE8DAA86D62AC /* RoomSummaryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProtocol.swift; sourceTree = "<group>"; };
|
C21ECC295F4DE8DAA86D62AC /* RoomSummaryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProtocol.swift; sourceTree = "<group>"; };
|
||||||
C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenModels.swift; sourceTree = "<group>"; };
|
C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenModels.swift; sourceTree = "<group>"; };
|
||||||
C485C186CEC78443DA96BDC8 /* TemplateSimpleScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateSimpleScreenViewModelTests.swift; sourceTree = "<group>"; };
|
C485C186CEC78443DA96BDC8 /* TemplateSimpleScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateSimpleScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
|
C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportUITests.swift; sourceTree = "<group>"; };
|
||||||
C88508B6F7974CFABEC4B261 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
|
C88508B6F7974CFABEC4B261 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
C888BCD78E2A55DCE364F160 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; };
|
C888BCD78E2A55DCE364F160 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; };
|
||||||
C91A6BC1A54CDB598EE2A81B /* UserIndicatorQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorQueue.swift; sourceTree = "<group>"; };
|
C91A6BC1A54CDB598EE2A81B /* UserIndicatorQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorQueue.swift; sourceTree = "<group>"; };
|
||||||
@@ -457,6 +513,7 @@
|
|||||||
D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenCoordinator.swift; sourceTree = "<group>"; };
|
D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
D67CBAFA48ED0B6FCE74F88F /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
|
D67CBAFA48ED0B6FCE74F88F /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
D6D094C15E8DB424F1C6FC94 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
D6D094C15E8DB424F1C6FC94 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
D6DC38E64A5ED3FDB201029A /* BugReportService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportService.swift; sourceTree = "<group>"; };
|
||||||
D77DD2DA5DC8654F2A80FF1D /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; };
|
D77DD2DA5DC8654F2A80FF1D /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; };
|
||||||
DBFEAC3AC691CBB84983E275 /* ElementXTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementXTests.swift; sourceTree = "<group>"; };
|
DBFEAC3AC691CBB84983E275 /* ElementXTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementXTests.swift; sourceTree = "<group>"; };
|
||||||
DD73FAAA4A76CE4A1F3014D9 /* UserIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicator.swift; sourceTree = "<group>"; };
|
DD73FAAA4A76CE4A1F3014D9 /* UserIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicator.swift; sourceTree = "<group>"; };
|
||||||
@@ -465,6 +522,7 @@
|
|||||||
E157152B11E347F735C3FD6E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = tr; path = tr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
E157152B11E347F735C3FD6E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = tr; path = tr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
E18CF12478983A5EB390FB26 /* MessageComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageComposer.swift; sourceTree = "<group>"; };
|
E18CF12478983A5EB390FB26 /* MessageComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageComposer.swift; sourceTree = "<group>"; };
|
||||||
E2869CFFF6CD2A642AB4B743 /* TemplateSimpleScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateSimpleScreenCoordinator.swift; sourceTree = "<group>"; };
|
E2869CFFF6CD2A642AB4B743 /* TemplateSimpleScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateSimpleScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
E3E29F98CF0E960689A410E3 /* SettingsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsUITests.swift; sourceTree = "<group>"; };
|
||||||
E45C57120F28F8D619150219 /* sr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sr; path = sr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
E45C57120F28F8D619150219 /* sr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sr; path = sr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = "<group>"; };
|
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = "<group>"; };
|
||||||
E579A0DA01F488C97B771EF6 /* lv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lv; path = lv.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
E579A0DA01F488C97B771EF6 /* lv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lv; path = lv.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
@@ -477,11 +535,16 @@
|
|||||||
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>"; };
|
||||||
EE8BCD14EFED23459A43FDFF /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
EE8BCD14EFED23459A43FDFF /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewFactoryProtocol.swift; sourceTree = "<group>"; };
|
EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewFactoryProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
EF188681D6B6068CFAEAFC3F /* MXLogger.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXLogger.m; sourceTree = "<group>"; };
|
||||||
EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportServiceTests.swift; sourceTree = "<group>"; };
|
||||||
F012CB5EE3F2B67359F6CC52 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
|
F012CB5EE3F2B67359F6CC52 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
|
||||||
|
F03C9D319676F3C0DC6B0203 /* ScreenshotDetectorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotDetectorTests.swift; sourceTree = "<group>"; };
|
||||||
|
F0E7BF8F7BB1021F889C6483 /* MockBugReportService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBugReportService.swift; sourceTree = "<group>"; };
|
||||||
F23BA6D4842D53C5AC9B7584 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nn; path = nn.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
F23BA6D4842D53C5AC9B7584 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nn; path = nn.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||||
F3BC93D4555571E8B4BC47F9 /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = "<group>"; };
|
F3BC93D4555571E8B4BC47F9 /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = "<group>"; };
|
||||||
F506C6ADB1E1DA6638078E11 /* UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
F506C6ADB1E1DA6638078E11 /* UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
F5C4AF6E3885730CD560311C /* ScreenshotDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotDetector.swift; sourceTree = "<group>"; };
|
||||||
F6A8C632CEF4600107792899 /* TextRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItem.swift; sourceTree = "<group>"; };
|
F6A8C632CEF4600107792899 /* TextRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = "<group>"; };
|
F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = "<group>"; };
|
||||||
F77C060C2ACC4CB7336A29E7 /* EmoteRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItem.swift; sourceTree = "<group>"; };
|
F77C060C2ACC4CB7336A29E7 /* EmoteRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
@@ -505,6 +568,8 @@
|
|||||||
6832733838C57A7D3FE8FEB5 /* Introspect in Frameworks */,
|
6832733838C57A7D3FE8FEB5 /* Introspect in Frameworks */,
|
||||||
2BA59D0AEFB4B82A2EC2A326 /* SwiftyBeaver in Frameworks */,
|
2BA59D0AEFB4B82A2EC2A326 /* SwiftyBeaver in Frameworks */,
|
||||||
B245583C63F8F90357B87FAE /* SwiftState in Frameworks */,
|
B245583C63F8F90357B87FAE /* SwiftState in Frameworks */,
|
||||||
|
A4E885358D7DD5A072A06824 /* GZIP in Frameworks */,
|
||||||
|
29EE1791E0AFA1ABB7F23D2F /* Sentry in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -519,6 +584,8 @@
|
|||||||
6F2AB43A1EFAD8A97AF41A15 /* Introspect in Frameworks */,
|
6F2AB43A1EFAD8A97AF41A15 /* Introspect in Frameworks */,
|
||||||
93BA4A81B6D893271101F9F0 /* SwiftyBeaver in Frameworks */,
|
93BA4A81B6D893271101F9F0 /* SwiftyBeaver in Frameworks */,
|
||||||
9AC5F8142413862A9E3A2D98 /* SwiftState in Frameworks */,
|
9AC5F8142413862A9E3A2D98 /* SwiftState in Frameworks */,
|
||||||
|
CB137BFB3E083C33E398A6CB /* GZIP in Frameworks */,
|
||||||
|
3C549A0BF39F8A854D45D9FD /* Sentry in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -538,14 +605,26 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
10578D9852BA78D309A1CBDF /* ViewModel */,
|
10578D9852BA78D309A1CBDF /* ViewModel */,
|
||||||
|
328DD5DA1281F758B72006C7 /* Views */,
|
||||||
);
|
);
|
||||||
path = SwiftUI;
|
path = SwiftUI;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
06501F0E978B2D5C92771DC7 /* Logging */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
111B698739E3410E2CDB7144 /* MXLog.swift */,
|
||||||
|
5872785B9C7934940146BFBA /* MXLogger.h */,
|
||||||
|
EF188681D6B6068CFAEAFC3F /* MXLogger.m */,
|
||||||
|
);
|
||||||
|
path = Logging;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
0787F81684E503024BD0C051 /* Services */ = {
|
0787F81684E503024BD0C051 /* Services */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
AAFDD509929A0CCF8BCE51EB /* Authentication */,
|
AAFDD509929A0CCF8BCE51EB /* Authentication */,
|
||||||
|
0ED3F5C21537519389C07644 /* BugReport */,
|
||||||
8039515BAA53B7C3275AC64A /* Client */,
|
8039515BAA53B7C3275AC64A /* Client */,
|
||||||
79E560F5113ED25D172E550C /* Media */,
|
79E560F5113ED25D172E550C /* Media */,
|
||||||
40E6246F03D1FE377BC5D963 /* Room */,
|
40E6246F03D1FE377BC5D963 /* Room */,
|
||||||
@@ -567,6 +646,17 @@
|
|||||||
path = SupportingFiles;
|
path = SupportingFiles;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0ED3F5C21537519389C07644 /* BugReport */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D6DC38E64A5ED3FDB201029A /* BugReportService.swift */,
|
||||||
|
9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */,
|
||||||
|
F0E7BF8F7BB1021F889C6483 /* MockBugReportService.swift */,
|
||||||
|
F5C4AF6E3885730CD560311C /* ScreenshotDetector.swift */,
|
||||||
|
);
|
||||||
|
path = BugReport;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
10578D9852BA78D309A1CBDF /* ViewModel */ = {
|
10578D9852BA78D309A1CBDF /* ViewModel */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -595,10 +685,19 @@
|
|||||||
path = Resources;
|
path = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
328DD5DA1281F758B72006C7 /* Views */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */,
|
||||||
|
);
|
||||||
|
path = Views;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
337015ADFBA3AB96660DB3A6 /* Generated */ = {
|
337015ADFBA3AB96660DB3A6 /* Generated */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
71D52BAA5BADB06E5E8C295D /* Assets.swift */,
|
71D52BAA5BADB06E5E8C295D /* Assets.swift */,
|
||||||
|
6A901D95158B02CA96C79C7F /* InfoPlist.swift */,
|
||||||
47EBB5D698CE9A25BB553A2D /* Strings.swift */,
|
47EBB5D698CE9A25BB553A2D /* Strings.swift */,
|
||||||
1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */,
|
1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */,
|
||||||
);
|
);
|
||||||
@@ -623,6 +722,18 @@
|
|||||||
path = View;
|
path = View;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4009BE2E791C16AC6EE39A7E /* BugReport */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
AD6C07DA7D3FF193F7419F55 /* BugReportCoordinator.swift */,
|
||||||
|
B516212D9FE785DDD5E490D1 /* BugReportModels.swift */,
|
||||||
|
7E532D95330139D118A9BF88 /* BugReportViewModel.swift */,
|
||||||
|
28959C7DB36C7688A01D4045 /* BugReportViewModelProtocol.swift */,
|
||||||
|
58F951CB7BD7F96C37BE5CAD /* View */,
|
||||||
|
);
|
||||||
|
path = BugReport;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
405B00F139AEE3994601B36A = {
|
405B00F139AEE3994601B36A = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -650,6 +761,14 @@
|
|||||||
path = Room;
|
path = Room;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4541090DFE1A5499BD67BD14 /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
2BEB3259B2208E5AE5BB3F65 /* Settings.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
4658A940E89BC42EE3346A97 /* Messages */ = {
|
4658A940E89BC42EE3346A97 /* Messages */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -704,6 +823,14 @@
|
|||||||
path = Scripts;
|
path = Scripts;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
58F951CB7BD7F96C37BE5CAD /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6D607F47FDEF16CC63684BE0 /* BugReport.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
5958CAF6E56422496E0063AF /* LoginScreen */ = {
|
5958CAF6E56422496E0063AF /* LoginScreen */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -738,6 +865,18 @@
|
|||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
70B74A432C241E56A7ACE610 /* Settings */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3DD2D50A7EAA4FC78417730E /* SettingsCoordinator.swift */,
|
||||||
|
4990FDBDA96B88E214F92F48 /* SettingsModels.swift */,
|
||||||
|
0A191D3FDB995309C7E2DE7D /* SettingsViewModel.swift */,
|
||||||
|
5B2F9D5C39A4494D19F33E38 /* SettingsViewModelProtocol.swift */,
|
||||||
|
4541090DFE1A5499BD67BD14 /* View */,
|
||||||
|
);
|
||||||
|
path = Settings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
70DABA39C844CA931B829395 /* RoomSummary */ = {
|
70DABA39C844CA931B829395 /* RoomSummary */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -763,11 +902,17 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */,
|
AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */,
|
||||||
|
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
|
||||||
|
7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */,
|
||||||
DBFEAC3AC691CBB84983E275 /* ElementXTests.swift */,
|
DBFEAC3AC691CBB84983E275 /* ElementXTests.swift */,
|
||||||
505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */,
|
505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */,
|
||||||
|
6045E825AE900A92D61FEFF0 /* ImageAnonymizerTests.swift */,
|
||||||
C070FD43DC6BF4E50217965A /* LocalizationTests.swift */,
|
C070FD43DC6BF4E50217965A /* LocalizationTests.swift */,
|
||||||
|
3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */,
|
||||||
5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */,
|
5A43964330459965AF048A8C /* LoginScreenViewModelTests.swift */,
|
||||||
93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */,
|
93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */,
|
||||||
|
F03C9D319676F3C0DC6B0203 /* ScreenshotDetectorTests.swift */,
|
||||||
|
3D487C1185D658F8B15B8F55 /* SettingsViewModelTests.swift */,
|
||||||
AF552BB969DC98A4BB8CF8D5 /* UserIndicators */,
|
AF552BB969DC98A4BB8CF8D5 /* UserIndicators */,
|
||||||
);
|
);
|
||||||
path = Sources;
|
path = Sources;
|
||||||
@@ -875,9 +1020,11 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
7D0CBC76C80E04345E11F2DB /* Application.swift */,
|
7D0CBC76C80E04345E11F2DB /* Application.swift */,
|
||||||
|
C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */,
|
||||||
4D6E4C37E9F0E53D3DF951AC /* HomeScreenUITests.swift */,
|
4D6E4C37E9F0E53D3DF951AC /* HomeScreenUITests.swift */,
|
||||||
1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */,
|
1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */,
|
||||||
086B997409328F091EBA43CE /* RoomScreenUITests.swift */,
|
086B997409328F091EBA43CE /* RoomScreenUITests.swift */,
|
||||||
|
E3E29F98CF0E960689A410E3 /* SettingsUITests.swift */,
|
||||||
);
|
);
|
||||||
path = Sources;
|
path = Sources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -930,6 +1077,7 @@
|
|||||||
A0C06C0F6A8621B22BFAEB56 /* Localizations */ = {
|
A0C06C0F6A8621B22BFAEB56 /* Localizations */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
91DE43B8815918E590912DDA /* InfoPlist.strings */,
|
||||||
7109E709A7738E6BCC4553E6 /* Localizable.strings */,
|
7109E709A7738E6BCC4553E6 /* Localizable.strings */,
|
||||||
187853A7E643995EE49FAD43 /* Localizable.stringsdict */,
|
187853A7E643995EE49FAD43 /* Localizable.stringsdict */,
|
||||||
D2F7194F440375338F8E2487 /* Untranslated.strings */,
|
D2F7194F440375338F8E2487 /* Untranslated.strings */,
|
||||||
@@ -941,6 +1089,7 @@
|
|||||||
A4852B57D55D71EEBFCD931D /* UnitTests */ = {
|
A4852B57D55D71EEBFCD931D /* UnitTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E600AACDF87CDBCE32683236 /* Resources */,
|
||||||
73CD9796729EB702B4DFA88C /* Sources */,
|
73CD9796729EB702B4DFA88C /* Sources */,
|
||||||
24FD174C31912A5FACFEAFB5 /* SupportingFiles */,
|
24FD174C31912A5FACFEAFB5 /* SupportingFiles */,
|
||||||
);
|
);
|
||||||
@@ -1009,9 +1158,10 @@
|
|||||||
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */,
|
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */,
|
||||||
D77DD2DA5DC8654F2A80FF1D /* Bundle.swift */,
|
D77DD2DA5DC8654F2A80FF1D /* Bundle.swift */,
|
||||||
95CC95CD75B688E946438165 /* Coordinator.swift */,
|
95CC95CD75B688E946438165 /* Coordinator.swift */,
|
||||||
|
12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */,
|
||||||
F7B81C8227BBEA95CCE86037 /* MatrixEntitityRegex.swift */,
|
F7B81C8227BBEA95CCE86037 /* MatrixEntitityRegex.swift */,
|
||||||
64839516BD56D1C81D84C5E0 /* MXLog.swift */,
|
|
||||||
8F9A844EB44B6AD7CA18FD96 /* HTMLParsing */,
|
8F9A844EB44B6AD7CA18FD96 /* HTMLParsing */,
|
||||||
|
06501F0E978B2D5C92771DC7 /* Logging */,
|
||||||
FE50232944F9E67ADD7A2D21 /* Routers */,
|
FE50232944F9E67ADD7A2D21 /* Routers */,
|
||||||
052CC920F473C10B509F9FC1 /* SwiftUI */,
|
052CC920F473C10B509F9FC1 /* SwiftUI */,
|
||||||
F8474EB69289112888B65518 /* UserIndicators */,
|
F8474EB69289112888B65518 /* UserIndicators */,
|
||||||
@@ -1032,20 +1182,31 @@
|
|||||||
E59565F441830B19DBAE567C /* Screens */ = {
|
E59565F441830B19DBAE567C /* Screens */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4009BE2E791C16AC6EE39A7E /* BugReport */,
|
||||||
B53CA9BECD3F97805E1432D0 /* HomeScreen */,
|
B53CA9BECD3F97805E1432D0 /* HomeScreen */,
|
||||||
5958CAF6E56422496E0063AF /* LoginScreen */,
|
5958CAF6E56422496E0063AF /* LoginScreen */,
|
||||||
679E9837ECA8D6776079D16E /* RoomScreen */,
|
679E9837ECA8D6776079D16E /* RoomScreen */,
|
||||||
|
70B74A432C241E56A7ACE610 /* Settings */,
|
||||||
02175C9269C4632DB6D12C25 /* Splash */,
|
02175C9269C4632DB6D12C25 /* Splash */,
|
||||||
);
|
);
|
||||||
path = Screens;
|
path = Screens;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E600AACDF87CDBCE32683236 /* Resources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9414DCADBDF9D6C4B806F61E /* sample_screenshot.png */,
|
||||||
|
);
|
||||||
|
path = Resources;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E68740F873AB18A5C26844EA /* Sources */ = {
|
E68740F873AB18A5C26844EA /* Sources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CF3EDF23226895776553F04A /* AppCoordinator.swift */,
|
CF3EDF23226895776553F04A /* AppCoordinator.swift */,
|
||||||
5A9AB74614131D6706894E0C /* AppCoordinatorStateMachine.swift */,
|
5A9AB74614131D6706894E0C /* AppCoordinatorStateMachine.swift */,
|
||||||
EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */,
|
EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */,
|
||||||
|
3F87116470221880017CF522 /* BuildSettings.swift */,
|
||||||
967873B9E11828B67F64C89A /* UITestsAppCoordinator.swift */,
|
967873B9E11828B67F64C89A /* UITestsAppCoordinator.swift */,
|
||||||
CCA431E6EDD71F7067B5F9E7 /* UITestsRootView.swift */,
|
CCA431E6EDD71F7067B5F9E7 /* UITestsRootView.swift */,
|
||||||
0787F81684E503024BD0C051 /* Services */,
|
0787F81684E503024BD0C051 /* Services */,
|
||||||
@@ -1134,6 +1295,8 @@
|
|||||||
04C28663564E008DB32B5972 /* Introspect */,
|
04C28663564E008DB32B5972 /* Introspect */,
|
||||||
A981A4CA233FB5C13B9CA690 /* SwiftyBeaver */,
|
A981A4CA233FB5C13B9CA690 /* SwiftyBeaver */,
|
||||||
3853B78FB8531B83936C5DA6 /* SwiftState */,
|
3853B78FB8531B83936C5DA6 /* SwiftState */,
|
||||||
|
1BCD21310B997A6837B854D6 /* GZIP */,
|
||||||
|
67E7A6F388D3BF85767609D9 /* Sentry */,
|
||||||
);
|
);
|
||||||
productName = UITests;
|
productName = UITests;
|
||||||
productReference = F506C6ADB1E1DA6638078E11 /* UITests.xctest */;
|
productReference = F506C6ADB1E1DA6638078E11 /* UITests.xctest */;
|
||||||
@@ -1179,6 +1342,8 @@
|
|||||||
5986E300FC849DEAB2EE7AEB /* Introspect */,
|
5986E300FC849DEAB2EE7AEB /* Introspect */,
|
||||||
FD43A50D9B75C9D6D30F006B /* SwiftyBeaver */,
|
FD43A50D9B75C9D6D30F006B /* SwiftyBeaver */,
|
||||||
9573B94B1C86C6DF751AF3FD /* SwiftState */,
|
9573B94B1C86C6DF751AF3FD /* SwiftState */,
|
||||||
|
997C7385E1A07E061D7E2100 /* GZIP */,
|
||||||
|
7731767AE437BA3BD2CC14A8 /* Sentry */,
|
||||||
);
|
);
|
||||||
productName = ElementX;
|
productName = ElementX;
|
||||||
productReference = 4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */;
|
productReference = 4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */;
|
||||||
@@ -1283,10 +1448,12 @@
|
|||||||
mainGroup = 405B00F139AEE3994601B36A;
|
mainGroup = 405B00F139AEE3994601B36A;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */,
|
C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */,
|
||||||
|
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */,
|
||||||
A24ABD6F9CEE4D0749A6173E /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
|
A24ABD6F9CEE4D0749A6173E /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
|
||||||
61916C63E3F5BD900F08DA0C /* XCRemoteSwiftPackageReference "KeychainAccess" */,
|
61916C63E3F5BD900F08DA0C /* XCRemoteSwiftPackageReference "KeychainAccess" */,
|
||||||
D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||||
4FCDA8D25C7415C8FB33490D /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */,
|
4FCDA8D25C7415C8FB33490D /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */,
|
||||||
|
D94BF33F492E2443005F809A /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
|
||||||
6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */,
|
6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */,
|
||||||
25B4484A6A20B9F1705DEEDA /* XCRemoteSwiftPackageReference "SwiftyBeaver" */,
|
25B4484A6A20B9F1705DEEDA /* XCRemoteSwiftPackageReference "SwiftyBeaver" */,
|
||||||
);
|
);
|
||||||
@@ -1308,6 +1475,7 @@
|
|||||||
30122AB3484AC6C3A7F6A717 /* ActivityIndicatorView.xib in Resources */,
|
30122AB3484AC6C3A7F6A717 /* ActivityIndicatorView.xib in Resources */,
|
||||||
B80C4FABB5529DF12436FFDA /* AppIcon.pdf in Resources */,
|
B80C4FABB5529DF12436FFDA /* AppIcon.pdf in Resources */,
|
||||||
992F5E750F5030C4BA2D0D03 /* Assets.xcassets in Resources */,
|
992F5E750F5030C4BA2D0D03 /* Assets.xcassets in Resources */,
|
||||||
|
B6DA66EFC13A90846B625836 /* InfoPlist.strings in Resources */,
|
||||||
AB34401E4E1CAD5D2EC3072B /* LaunchScreen.storyboard in Resources */,
|
AB34401E4E1CAD5D2EC3072B /* LaunchScreen.storyboard in Resources */,
|
||||||
5F5488FBC9CFEB6F433D74A4 /* Localizable.strings in Resources */,
|
5F5488FBC9CFEB6F433D74A4 /* Localizable.strings in Resources */,
|
||||||
0EA6537A07E2DC882AEA5962 /* Localizable.stringsdict in Resources */,
|
0EA6537A07E2DC882AEA5962 /* Localizable.stringsdict in Resources */,
|
||||||
@@ -1330,6 +1498,7 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
524C9C31EF8D58C2249F8A10 /* sample_screenshot.png in Resources */,
|
||||||
35E975CFDA60E05362A7CF79 /* target.yml in Resources */,
|
35E975CFDA60E05362A7CF79 /* target.yml in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -1381,11 +1550,17 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
90DF83A6A347F7EE7EDE89EE /* AttributedStringBuilderTests.swift in Sources */,
|
90DF83A6A347F7EE7EDE89EE /* AttributedStringBuilderTests.swift in Sources */,
|
||||||
|
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
|
||||||
|
C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */,
|
||||||
9C45CE85325CD591DADBC4CA /* ElementXTests.swift in Sources */,
|
9C45CE85325CD591DADBC4CA /* ElementXTests.swift in Sources */,
|
||||||
F6F49E37272AD7397CD29A01 /* HomeScreenViewModelTests.swift in Sources */,
|
F6F49E37272AD7397CD29A01 /* HomeScreenViewModelTests.swift in Sources */,
|
||||||
|
0B1F80C2BF7D223159FBA82C /* ImageAnonymizerTests.swift in Sources */,
|
||||||
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */,
|
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */,
|
||||||
|
149D1942DC005D0485FB8D93 /* LoggingTests.swift in Sources */,
|
||||||
7434A7F02D587A920B376A9A /* LoginScreenViewModelTests.swift in Sources */,
|
7434A7F02D587A920B376A9A /* LoginScreenViewModelTests.swift in Sources */,
|
||||||
46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */,
|
46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */,
|
||||||
|
EA31DD9043B91ECB8E45A9A6 /* ScreenshotDetectorTests.swift in Sources */,
|
||||||
|
206F0DBAB6AF042CA1FF2C0D /* SettingsViewModelTests.swift in Sources */,
|
||||||
7B3D3AFD511D496DED18910B /* TemplateSimpleScreenViewModelTests.swift in Sources */,
|
7B3D3AFD511D496DED18910B /* TemplateSimpleScreenViewModelTests.swift in Sources */,
|
||||||
1151DCC5EC2C6585826545EC /* UserIndicatorPresenterSpy.swift in Sources */,
|
1151DCC5EC2C6585826545EC /* UserIndicatorPresenterSpy.swift in Sources */,
|
||||||
4B8A2C45FF906ADBB1F5C3B4 /* UserIndicatorQueueTests.swift in Sources */,
|
4B8A2C45FF906ADBB1F5C3B4 /* UserIndicatorQueueTests.swift in Sources */,
|
||||||
@@ -1410,12 +1585,21 @@
|
|||||||
CB326BAB54E9B68658909E36 /* Benchmark.swift in Sources */,
|
CB326BAB54E9B68658909E36 /* Benchmark.swift in Sources */,
|
||||||
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */,
|
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */,
|
||||||
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */,
|
B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */,
|
||||||
|
00AC53151BA23A90FAAE9FBF /* BugReport.swift in Sources */,
|
||||||
|
A32517FB1CA0BBCE2BC75249 /* BugReportCoordinator.swift in Sources */,
|
||||||
|
00F3059B1E0CFCA019710C3E /* BugReportModels.swift in Sources */,
|
||||||
|
3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */,
|
||||||
|
172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */,
|
||||||
|
86C2E93920FD15AD17E193A9 /* BugReportViewModel.swift in Sources */,
|
||||||
|
187E18F21EF4DA244E436E58 /* BugReportViewModelProtocol.swift in Sources */,
|
||||||
|
05776B005C57E92582F0CF08 /* BuildSettings.swift in Sources */,
|
||||||
7E1EDBA3934E6C29E5BD045B /* Bundle.swift in Sources */,
|
7E1EDBA3934E6C29E5BD045B /* Bundle.swift in Sources */,
|
||||||
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */,
|
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */,
|
||||||
24BDDD09A90B8BFE3793F3AA /* ClientProxyProtocol.swift in Sources */,
|
24BDDD09A90B8BFE3793F3AA /* ClientProxyProtocol.swift in Sources */,
|
||||||
DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */,
|
DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */,
|
||||||
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */,
|
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */,
|
||||||
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */,
|
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */,
|
||||||
|
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */,
|
||||||
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */,
|
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */,
|
||||||
224A55EEAEECF5336B14A4A5 /* EmoteRoomMessage.swift in Sources */,
|
224A55EEAEECF5336B14A4A5 /* EmoteRoomMessage.swift in Sources */,
|
||||||
6647430A45B4A8E692909A8F /* EmoteRoomTimelineItem.swift in Sources */,
|
6647430A45B4A8E692909A8F /* EmoteRoomTimelineItem.swift in Sources */,
|
||||||
@@ -1432,9 +1616,11 @@
|
|||||||
8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */,
|
8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */,
|
||||||
DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */,
|
DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */,
|
||||||
56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */,
|
56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */,
|
||||||
|
6EA61FCA55D950BDE326A1A7 /* ImageAnonymizer.swift in Sources */,
|
||||||
2E59008365E01F0AFB3A6B24 /* ImageRoomMessage.swift in Sources */,
|
2E59008365E01F0AFB3A6B24 /* ImageRoomMessage.swift in Sources */,
|
||||||
DDB80FD2753FEAAE43CC2AAE /* ImageRoomTimelineItem.swift in Sources */,
|
DDB80FD2753FEAAE43CC2AAE /* ImageRoomTimelineItem.swift in Sources */,
|
||||||
D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */,
|
D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */,
|
||||||
|
A5C8F013ED9FB8AA6FEE18A7 /* InfoPlist.swift in Sources */,
|
||||||
2D8A687149E46B8C8B989561 /* KeychainController.swift in Sources */,
|
2D8A687149E46B8C8B989561 /* KeychainController.swift in Sources */,
|
||||||
277D2531C70F207A2F9F5906 /* KeychainControllerProtocol.swift in Sources */,
|
277D2531C70F207A2F9F5906 /* KeychainControllerProtocol.swift in Sources */,
|
||||||
9C9E48A627C7C166084E3F5B /* LabelledActivityIndicatorView.swift in Sources */,
|
9C9E48A627C7C166084E3F5B /* LabelledActivityIndicatorView.swift in Sources */,
|
||||||
@@ -1444,7 +1630,8 @@
|
|||||||
E9CEAF2C38E4E00459B811D9 /* LoginScreenModels.swift in Sources */,
|
E9CEAF2C38E4E00459B811D9 /* LoginScreenModels.swift in Sources */,
|
||||||
7C9121245B11CA48307CB462 /* LoginScreenViewModel.swift in Sources */,
|
7C9121245B11CA48307CB462 /* LoginScreenViewModel.swift in Sources */,
|
||||||
33912D1B9264D897033E0681 /* LoginScreenViewModelProtocol.swift in Sources */,
|
33912D1B9264D897033E0681 /* LoginScreenViewModelProtocol.swift in Sources */,
|
||||||
B0887A7B5AFEC88981626389 /* MXLog.swift in Sources */,
|
B94368839BDB69172E28E245 /* MXLog.swift in Sources */,
|
||||||
|
BCC3EDB7AD0902797CB4BBC2 /* MXLogger.m in Sources */,
|
||||||
F03E16ED043C62FED5A07AE0 /* MatrixEntitityRegex.swift in Sources */,
|
F03E16ED043C62FED5A07AE0 /* MatrixEntitityRegex.swift in Sources */,
|
||||||
EA1E7949533E19C6D862680A /* MediaProvider.swift in Sources */,
|
EA1E7949533E19C6D862680A /* MediaProvider.swift in Sources */,
|
||||||
7002C55A4C917F3715765127 /* MediaProviderProtocol.swift in Sources */,
|
7002C55A4C917F3715765127 /* MediaProviderProtocol.swift in Sources */,
|
||||||
@@ -1454,6 +1641,7 @@
|
|||||||
A5EC21A071F58FC1229C20D0 /* MemberDetailsProviderProtocol.swift in Sources */,
|
A5EC21A071F58FC1229C20D0 /* MemberDetailsProviderProtocol.swift in Sources */,
|
||||||
24906A1E82D0046655958536 /* MessageComposer.swift in Sources */,
|
24906A1E82D0046655958536 /* MessageComposer.swift in Sources */,
|
||||||
072BA9DBA932374CCA300125 /* MessageComposerTextField.swift in Sources */,
|
072BA9DBA932374CCA300125 /* MessageComposerTextField.swift in Sources */,
|
||||||
|
28410F3DE89C2C44E4F75C92 /* MockBugReportService.swift in Sources */,
|
||||||
67E391A2E00709FB41903B36 /* MockMediaProvider.swift in Sources */,
|
67E391A2E00709FB41903B36 /* MockMediaProvider.swift in Sources */,
|
||||||
51DB67C5B5BC68B0A6FF54D4 /* MockRoomProxy.swift in Sources */,
|
51DB67C5B5BC68B0A6FF54D4 /* MockRoomProxy.swift in Sources */,
|
||||||
29AEE68A604940180AB9EBFF /* MockRoomSummary.swift in Sources */,
|
29AEE68A604940180AB9EBFF /* MockRoomSummary.swift in Sources */,
|
||||||
@@ -1494,8 +1682,14 @@
|
|||||||
7F19E97E7985F518C9018B83 /* RootRouter.swift in Sources */,
|
7F19E97E7985F518C9018B83 /* RootRouter.swift in Sources */,
|
||||||
2C0CE61E5DC177938618E0B1 /* RootRouterType.swift in Sources */,
|
2C0CE61E5DC177938618E0B1 /* RootRouterType.swift in Sources */,
|
||||||
462813B93C39DF93B1249403 /* RoundedToastView.swift in Sources */,
|
462813B93C39DF93B1249403 /* RoundedToastView.swift in Sources */,
|
||||||
|
CC736DA1AA8F8B9FD8785009 /* ScreenshotDetector.swift in Sources */,
|
||||||
1281625B25371BE53D36CB3A /* SeparatorRoomTimelineItem.swift in Sources */,
|
1281625B25371BE53D36CB3A /* SeparatorRoomTimelineItem.swift in Sources */,
|
||||||
49F2E7DD8CAACE09CEECE3E6 /* SeparatorRoomTimelineView.swift in Sources */,
|
49F2E7DD8CAACE09CEECE3E6 /* SeparatorRoomTimelineView.swift in Sources */,
|
||||||
|
6C72F66DA26A0956E9A9077A /* Settings.swift in Sources */,
|
||||||
|
34966D4C1C2C6D37FE3F7F50 /* SettingsCoordinator.swift in Sources */,
|
||||||
|
3B770CB4DED51CC362C66D47 /* SettingsModels.swift in Sources */,
|
||||||
|
4A2E0DBB63919AC8309B6D40 /* SettingsViewModel.swift in Sources */,
|
||||||
|
438FB9BC535BC95948AA5F34 /* SettingsViewModelProtocol.swift in Sources */,
|
||||||
FCB640C576292BEAF7FA3B2E /* SplashViewController.swift in Sources */,
|
FCB640C576292BEAF7FA3B2E /* SplashViewController.swift in Sources */,
|
||||||
B4AAB3257A83B73F53FB2689 /* StateStoreViewModel.swift in Sources */,
|
B4AAB3257A83B73F53FB2689 /* StateStoreViewModel.swift in Sources */,
|
||||||
A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */,
|
A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */,
|
||||||
@@ -1538,9 +1732,11 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
7405B4824D45BA7C3D943E76 /* Application.swift in Sources */,
|
7405B4824D45BA7C3D943E76 /* Application.swift in Sources */,
|
||||||
|
7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */,
|
||||||
9DC5FB22B8F86C3B51E907C1 /* HomeScreenUITests.swift in Sources */,
|
9DC5FB22B8F86C3B51E907C1 /* HomeScreenUITests.swift in Sources */,
|
||||||
5C8AFBF168A41E20835F3B86 /* LoginScreenUITests.swift in Sources */,
|
5C8AFBF168A41E20835F3B86 /* LoginScreenUITests.swift in Sources */,
|
||||||
2F1CF90A3460C153154427F0 /* RoomScreenUITests.swift in Sources */,
|
2F1CF90A3460C153154427F0 /* RoomScreenUITests.swift in Sources */,
|
||||||
|
490E606044B18985055FF690 /* SettingsUITests.swift in Sources */,
|
||||||
2E68C57E7D644E94778743D5 /* TemplateSimpleScreenUITests.swift in Sources */,
|
2E68C57E7D644E94778743D5 /* TemplateSimpleScreenUITests.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -1697,6 +1893,14 @@
|
|||||||
name = Localizable.strings;
|
name = Localizable.strings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
91DE43B8815918E590912DDA /* InfoPlist.strings */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
1215A4FC53D2319E81AE8970 /* en */,
|
||||||
|
);
|
||||||
|
name = InfoPlist.strings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9760103CF316DF68698BCFE6 /* LaunchScreen.storyboard */ = {
|
9760103CF316DF68698BCFE6 /* LaunchScreen.storyboard */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -2043,6 +2247,14 @@
|
|||||||
minimumVersion = 6.0.0;
|
minimumVersion = 6.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/nicklockwood/GZIP";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 1.3.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
A24ABD6F9CEE4D0749A6173E /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = {
|
A24ABD6F9CEE4D0749A6173E /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git";
|
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git";
|
||||||
@@ -2067,6 +2279,14 @@
|
|||||||
minimumVersion = 7.2.0;
|
minimumVersion = 7.2.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
D94BF33F492E2443005F809A /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/getsentry/sentry-cocoa.git";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 7.15.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
@@ -2085,6 +2305,11 @@
|
|||||||
package = D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
package = D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||||
productName = Kingfisher;
|
productName = Kingfisher;
|
||||||
};
|
};
|
||||||
|
1BCD21310B997A6837B854D6 /* GZIP */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */;
|
||||||
|
productName = GZIP;
|
||||||
|
};
|
||||||
36B7FC232711031AA2B0D188 /* DTCoreText */ = {
|
36B7FC232711031AA2B0D188 /* DTCoreText */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */;
|
package = C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */;
|
||||||
@@ -2110,6 +2335,16 @@
|
|||||||
package = A24ABD6F9CEE4D0749A6173E /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */;
|
package = A24ABD6F9CEE4D0749A6173E /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */;
|
||||||
productName = Introspect;
|
productName = Introspect;
|
||||||
};
|
};
|
||||||
|
67E7A6F388D3BF85767609D9 /* Sentry */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = D94BF33F492E2443005F809A /* XCRemoteSwiftPackageReference "sentry-cocoa" */;
|
||||||
|
productName = Sentry;
|
||||||
|
};
|
||||||
|
7731767AE437BA3BD2CC14A8 /* Sentry */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = D94BF33F492E2443005F809A /* XCRemoteSwiftPackageReference "sentry-cocoa" */;
|
||||||
|
productName = Sentry;
|
||||||
|
};
|
||||||
78A5A8DE1E2B09C978C7F3B0 /* KeychainAccess */ = {
|
78A5A8DE1E2B09C978C7F3B0 /* KeychainAccess */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 61916C63E3F5BD900F08DA0C /* XCRemoteSwiftPackageReference "KeychainAccess" */;
|
package = 61916C63E3F5BD900F08DA0C /* XCRemoteSwiftPackageReference "KeychainAccess" */;
|
||||||
@@ -2120,6 +2355,11 @@
|
|||||||
package = 6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */;
|
package = 6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */;
|
||||||
productName = SwiftState;
|
productName = SwiftState;
|
||||||
};
|
};
|
||||||
|
997C7385E1A07E061D7E2100 /* GZIP */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */;
|
||||||
|
productName = GZIP;
|
||||||
|
};
|
||||||
A678E40E917620059695F067 /* MatrixRustSDK */ = {
|
A678E40E917620059695F067 /* MatrixRustSDK */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 4FCDA8D25C7415C8FB33490D /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */;
|
package = 4FCDA8D25C7415C8FB33490D /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */;
|
||||||
|
|||||||
@@ -18,6 +18,15 @@
|
|||||||
"version" : "1.7.18"
|
"version" : "1.7.18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gzip",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/nicklockwood/GZIP",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c45c8526dad61240a79aaff5b1cf6e082d2b90b2",
|
||||||
|
"version" : "1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "keychainaccess",
|
"identity" : "keychainaccess",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
@@ -45,6 +54,15 @@
|
|||||||
"revision" : "43c88a4b0912a1589c2a28cc9bb2df45c70cdcad"
|
"revision" : "43c88a4b0912a1589c2a28cc9bb2df45c70cdcad"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "sentry-cocoa",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/getsentry/sentry-cocoa.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "afa4cd596e5cf97a797fb9b5c3afeea4add2c7a3",
|
||||||
|
"version" : "7.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swiftstate",
|
"identity" : "swiftstate",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "url_preview_close_dark.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"preserves-vector-representation" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< /ExtGState << /E1 << /ca 0.800000 >> >> >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
/E1 gs
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||||
|
0.223529 0.250980 0.286275 scn
|
||||||
|
24.000000 12.000000 m
|
||||||
|
24.000000 5.372583 18.627417 0.000000 12.000000 0.000000 c
|
||||||
|
5.372583 0.000000 0.000000 5.372583 0.000000 12.000000 c
|
||||||
|
0.000000 18.627417 5.372583 24.000000 12.000000 24.000000 c
|
||||||
|
18.627417 24.000000 24.000000 18.627417 24.000000 12.000000 c
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 7.999756 5.805014 cm
|
||||||
|
0.662745 0.698039 0.737255 scn
|
||||||
|
0.707107 10.902368 m
|
||||||
|
0.316583 11.292892 -0.316582 11.292892 -0.707107 10.902368 c
|
||||||
|
-1.097631 10.511844 -1.097631 9.878678 -0.707107 9.488154 c
|
||||||
|
0.707107 10.902368 l
|
||||||
|
h
|
||||||
|
7.292891 1.488155 m
|
||||||
|
7.683415 1.097631 8.316580 1.097631 8.707105 1.488155 c
|
||||||
|
9.097629 1.878679 9.097629 2.511844 8.707105 2.902369 c
|
||||||
|
7.292891 1.488155 l
|
||||||
|
h
|
||||||
|
-0.707107 9.488154 m
|
||||||
|
7.292891 1.488155 l
|
||||||
|
8.707105 2.902369 l
|
||||||
|
0.707107 10.902368 l
|
||||||
|
-0.707107 9.488154 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
-1.000000 -0.000000 -0.000000 1.000000 16.000488 5.805014 cm
|
||||||
|
0.662745 0.698039 0.737255 scn
|
||||||
|
0.707107 10.902368 m
|
||||||
|
0.316582 11.292892 -0.316583 11.292892 -0.707107 10.902368 c
|
||||||
|
-1.097631 10.511844 -1.097631 9.878678 -0.707107 9.488154 c
|
||||||
|
0.707107 10.902368 l
|
||||||
|
h
|
||||||
|
7.292893 1.488155 m
|
||||||
|
7.683417 1.097631 8.316583 1.097631 8.707107 1.488155 c
|
||||||
|
9.097631 1.878679 9.097631 2.511845 8.707107 2.902369 c
|
||||||
|
7.292893 1.488155 l
|
||||||
|
h
|
||||||
|
-0.707107 9.488154 m
|
||||||
|
7.292893 1.488155 l
|
||||||
|
8.707107 2.902369 l
|
||||||
|
0.707107 10.902368 l
|
||||||
|
-0.707107 9.488154 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1439
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Type /Catalog
|
||||||
|
/Pages 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000074 00000 n
|
||||||
|
0000001569 00000 n
|
||||||
|
0000001592 00000 n
|
||||||
|
0000001765 00000 n
|
||||||
|
0000001839 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1898
|
||||||
|
%%EOF
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"NSPhotoLibraryUsageDescription" = "The photo library is used to send photos and videos.";
|
||||||
@@ -1 +1,3 @@
|
|||||||
"untranslated" = "Untranslated";
|
"untranslated" = "Untranslated";
|
||||||
|
"screenshot_detected_title" = "You took a screenshot";
|
||||||
|
"screenshot_detected_message" = "Would you like to submit a bug report?";
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
|
|||||||
private var userSession: UserSession!
|
private var userSession: UserSession!
|
||||||
|
|
||||||
private let memberDetailProviderManager: MemberDetailProviderManager
|
private let memberDetailProviderManager: MemberDetailProviderManager
|
||||||
|
|
||||||
|
private let bugReportService: BugReportServiceProtocol
|
||||||
|
private let screenshotDetector: ScreenshotDetector
|
||||||
|
|
||||||
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
|
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
|
||||||
private var loadingIndicator: UserIndicator?
|
private var loadingIndicator: UserIndicator?
|
||||||
private var errorIndicator: UserIndicator?
|
private var errorIndicator: UserIndicator?
|
||||||
@@ -34,7 +37,14 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
stateMachine = AppCoordinatorStateMachine()
|
stateMachine = AppCoordinatorStateMachine()
|
||||||
|
|
||||||
|
do {
|
||||||
|
bugReportService = try BugReportService(withBaseUrlString: BuildSettings.bugReportServiceBaseUrlString,
|
||||||
|
sentryEndpoint: BuildSettings.bugReportSentryEndpoint)
|
||||||
|
} catch {
|
||||||
|
fatalError(error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
splashViewController = SplashViewController()
|
splashViewController = SplashViewController()
|
||||||
mainNavigationController = UINavigationController(rootViewController: splashViewController)
|
mainNavigationController = UINavigationController(rootViewController: splashViewController)
|
||||||
window = UIWindow(frame: UIScreen.main.bounds)
|
window = UIWindow(frame: UIScreen.main.bounds)
|
||||||
@@ -53,12 +63,20 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
|
|||||||
keychainController = KeychainController(identifier: bundleIdentifier)
|
keychainController = KeychainController(identifier: bundleIdentifier)
|
||||||
authenticationCoordinator = AuthenticationCoordinator(keychainController: keychainController,
|
authenticationCoordinator = AuthenticationCoordinator(keychainController: keychainController,
|
||||||
navigationRouter: navigationRouter)
|
navigationRouter: navigationRouter)
|
||||||
|
|
||||||
|
screenshotDetector = ScreenshotDetector()
|
||||||
|
screenshotDetector.callback = processScreenshotDetection
|
||||||
|
|
||||||
authenticationCoordinator.delegate = self
|
authenticationCoordinator.delegate = self
|
||||||
|
|
||||||
setupStateMachine()
|
setupStateMachine()
|
||||||
|
|
||||||
let loggerConfiguration = MXLogConfiguration()
|
let loggerConfiguration = MXLogConfiguration()
|
||||||
loggerConfiguration.logLevel = .verbose
|
loggerConfiguration.logLevel = .verbose
|
||||||
|
// Redirect NSLogs to files only if we are not debugging
|
||||||
|
if isatty(STDERR_FILENO) == 0 {
|
||||||
|
loggerConfiguration.redirectLogsToFiles = true
|
||||||
|
}
|
||||||
MXLog.configure(loggerConfiguration)
|
MXLog.configure(loggerConfiguration)
|
||||||
|
|
||||||
// Benchmark.trackingEnabled = true
|
// Benchmark.trackingEnabled = true
|
||||||
@@ -117,6 +135,10 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
|
|||||||
self.tearDownUserSession()
|
self.tearDownUserSession()
|
||||||
case (.signingOut, .failedSigningOut, _):
|
case (.signingOut, .failedSigningOut, _):
|
||||||
self.showLogoutErrorToast()
|
self.showLogoutErrorToast()
|
||||||
|
case (.homeScreen, .showSettingsScreen, .settingsScreen):
|
||||||
|
self.presentSettingsScreen()
|
||||||
|
case (.settingsScreen, .dismissedSettingsScreen, .homeScreen):
|
||||||
|
self.tearDownDismissedSettingsScreen()
|
||||||
default:
|
default:
|
||||||
fatalError("Unknown transition: \(context)")
|
fatalError("Unknown transition: \(context)")
|
||||||
}
|
}
|
||||||
@@ -162,13 +184,33 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
|
|||||||
switch action {
|
switch action {
|
||||||
case .logout:
|
case .logout:
|
||||||
self.stateMachine.processEvent(.attemptSignOut)
|
self.stateMachine.processEvent(.attemptSignOut)
|
||||||
case .selectRoom(let roomIdentifier):
|
case .presentRoom(let roomIdentifier):
|
||||||
self.stateMachine.processEvent(.showRoomScreen(roomId: roomIdentifier))
|
self.stateMachine.processEvent(.showRoomScreen(roomId: roomIdentifier))
|
||||||
|
case .presentSettings:
|
||||||
|
self.stateMachine.processEvent(.showSettingsScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add(childCoordinator: coordinator)
|
add(childCoordinator: coordinator)
|
||||||
navigationRouter.setRootModule(coordinator)
|
navigationRouter.setRootModule(coordinator)
|
||||||
|
|
||||||
|
if bugReportService.crashedLastRun {
|
||||||
|
showCrashPopup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentSettingsScreen() {
|
||||||
|
let parameters = SettingsCoordinatorParameters(navigationRouter: navigationRouter,
|
||||||
|
bugReportService: bugReportService)
|
||||||
|
let coordinator = SettingsCoordinator(parameters: parameters)
|
||||||
|
|
||||||
|
add(childCoordinator: coordinator)
|
||||||
|
coordinator.start()
|
||||||
|
navigationRouter.push(coordinator) { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.stateMachine.processEvent(.dismissedSettingsScreen)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentRoomWithIdentifier(_ roomIdentifier: String) {
|
private func presentRoomWithIdentifier(_ roomIdentifier: String) {
|
||||||
@@ -206,6 +248,14 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
|
|||||||
|
|
||||||
remove(childCoordinator: coordinator)
|
remove(childCoordinator: coordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func tearDownDismissedSettingsScreen() {
|
||||||
|
guard let coordinator = childCoordinators.last as? SettingsCoordinator else {
|
||||||
|
fatalError("Invalid coordinator hierarchy: \(childCoordinators)")
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(childCoordinator: coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
private func showLoadingIndicator() {
|
private func showLoadingIndicator() {
|
||||||
loadingIndicator = indicatorPresenter.present(.loading(label: "Loading", isInteractionBlocking: true))
|
loadingIndicator = indicatorPresenter.present(.loading(label: "Loading", isInteractionBlocking: true))
|
||||||
@@ -216,10 +266,70 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func showLoginErrorToast() {
|
private func showLoginErrorToast() {
|
||||||
errorIndicator = indicatorPresenter.present(.success(label: "Failed logging in"))
|
errorIndicator = indicatorPresenter.present(.error(label: "Failed logging in"))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showLogoutErrorToast() {
|
private func showLogoutErrorToast() {
|
||||||
errorIndicator = indicatorPresenter.present(.success(label: "Failed logging out"))
|
errorIndicator = indicatorPresenter.present(.success(label: "Failed logging out"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func showCrashPopup() {
|
||||||
|
let alert = UIAlertController(title: nil,
|
||||||
|
message: ElementL10n.sendBugReportAppCrashed,
|
||||||
|
preferredStyle: .alert)
|
||||||
|
|
||||||
|
alert.addAction(UIAlertAction(title: ElementL10n.no, style: .cancel))
|
||||||
|
alert.addAction(UIAlertAction(title: ElementL10n.yes, style: .default) { [weak self] _ in
|
||||||
|
self?.presentBugReportScreen()
|
||||||
|
})
|
||||||
|
|
||||||
|
navigationRouter.present(alert, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func processScreenshotDetection(image: UIImage?, error: Error?) {
|
||||||
|
MXLog.debug("[AppCoordinator] processScreenshotDetection: \(String(describing: image)), error: \(String(describing: error))")
|
||||||
|
|
||||||
|
let alert = UIAlertController(title: ElementL10n.screenshotDetectedTitle,
|
||||||
|
message: ElementL10n.screenshotDetectedMessage,
|
||||||
|
preferredStyle: .alert)
|
||||||
|
|
||||||
|
alert.addAction(UIAlertAction(title: ElementL10n.no, style: .cancel))
|
||||||
|
alert.addAction(UIAlertAction(title: ElementL10n.yes, style: .default) { [weak self] _ in
|
||||||
|
self?.presentBugReportScreen(for: image)
|
||||||
|
})
|
||||||
|
|
||||||
|
navigationRouter.present(alert, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentBugReportScreen(for image: UIImage? = nil) {
|
||||||
|
let parameters = BugReportCoordinatorParameters(bugReportService: bugReportService,
|
||||||
|
screenshot: image)
|
||||||
|
let coordinator = BugReportCoordinator(parameters: parameters)
|
||||||
|
coordinator.completion = { [weak self, weak coordinator] in
|
||||||
|
guard let self = self, let coordinator = coordinator else { return }
|
||||||
|
self.navigationRouter.dismissModule(animated: true)
|
||||||
|
self.remove(childCoordinator: coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(childCoordinator: coordinator)
|
||||||
|
coordinator.start()
|
||||||
|
let navController = UINavigationController(rootViewController: coordinator.toPresentable())
|
||||||
|
navController.navigationBar.topItem?.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel,
|
||||||
|
target: self,
|
||||||
|
action: #selector(dismissBugReportScreen))
|
||||||
|
navController.isModalInPresentation = true
|
||||||
|
navigationRouter.present(navController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
private func dismissBugReportScreen() {
|
||||||
|
MXLog.debug("[AppCoorrdinator] dismissBugReportScreen")
|
||||||
|
|
||||||
|
guard let bugReportCoordinator = childCoordinators.first(where: { $0 is BugReportCoordinator }) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationRouter.dismissModule()
|
||||||
|
remove(childCoordinator: bugReportCoordinator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ class AppCoordinatorStateMachine {
|
|||||||
case signedIn
|
case signedIn
|
||||||
/// Showing the home screen
|
/// Showing the home screen
|
||||||
case homeScreen
|
case homeScreen
|
||||||
|
/// Showing the settings screen
|
||||||
|
case settingsScreen
|
||||||
/// Showing a particular room's timeline
|
/// Showing a particular room's timeline
|
||||||
/// - Parameter roomId: that room's identifier
|
/// - Parameter roomId: that room's identifier
|
||||||
case roomScreen(roomId: String)
|
case roomScreen(roomId: String)
|
||||||
@@ -52,6 +54,10 @@ class AppCoordinatorStateMachine {
|
|||||||
case showRoomScreen(roomId: String)
|
case showRoomScreen(roomId: String)
|
||||||
/// The room screen has been dismissed
|
/// The room screen has been dismissed
|
||||||
case dismissedRoomScreen
|
case dismissedRoomScreen
|
||||||
|
/// The settings screen has been dismissed
|
||||||
|
case dismissedSettingsScreen
|
||||||
|
/// Request settings screen presentation
|
||||||
|
case showSettingsScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
private let stateMachine: StateMachine<State, Event>
|
private let stateMachine: StateMachine<State, Event>
|
||||||
@@ -71,6 +77,8 @@ class AppCoordinatorStateMachine {
|
|||||||
|
|
||||||
machine.addRoutes(event: .succeededSigningOut, transitions: [ .signingOut => .signedOut ])
|
machine.addRoutes(event: .succeededSigningOut, transitions: [ .signingOut => .signedOut ])
|
||||||
machine.addRoutes(event: .failedSigningOut, transitions: [ .signingOut => .homeScreen ])
|
machine.addRoutes(event: .failedSigningOut, transitions: [ .signingOut => .homeScreen ])
|
||||||
|
machine.addRoutes(event: .showSettingsScreen, transitions: [ .homeScreen => .settingsScreen ])
|
||||||
|
machine.addRoutes(event: .dismissedSettingsScreen, transitions: [ .settingsScreen => .homeScreen ])
|
||||||
|
|
||||||
// Transitions with associated values need to be handled through `addRouteMapping`
|
// Transitions with associated values need to be handled through `addRouteMapping`
|
||||||
machine.addRouteMapping { event, fromState, _ in
|
machine.addRouteMapping { event, fromState, _ in
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// BuildSettings.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Ismail on 2.06.2022.
|
||||||
|
// Copyright © 2022 Element. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class BuildSettings {
|
||||||
|
|
||||||
|
// MARK: - Bug report
|
||||||
|
static let bugReportServiceBaseUrlString = "https://riot.im/bugreports"
|
||||||
|
static let bugReportSentryEndpoint = "https://f39ac49e97714316965b777d9f3d6cd8@sentry.tools.element.io/44"
|
||||||
|
// Use the name allocated by the bug report server
|
||||||
|
static let bugReportApplicationId = "riot-ios"
|
||||||
|
static let bugReportUISIId = "element-auto-uisi"
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ internal enum Asset {
|
|||||||
}
|
}
|
||||||
internal enum Images {
|
internal enum Images {
|
||||||
internal static let appLogo = ImageAsset(name: "Images/app-logo")
|
internal static let appLogo = ImageAsset(name: "Images/app-logo")
|
||||||
|
internal static let closeCircle = ImageAsset(name: "Images/close_circle")
|
||||||
internal static let timelineComposerSendMessage = ImageAsset(name: "Images/timelineComposerSendMessage")
|
internal static let timelineComposerSendMessage = ImageAsset(name: "Images/timelineComposerSendMessage")
|
||||||
internal static let timelineScrollToBottom = ImageAsset(name: "Images/timelineScrollToBottom")
|
internal static let timelineScrollToBottom = ImageAsset(name: "Images/timelineScrollToBottom")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// swiftlint:disable all
|
||||||
|
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
// swiftlint:disable superfluous_disable_command
|
||||||
|
// swiftlint:disable file_length
|
||||||
|
|
||||||
|
// MARK: - Plist Files
|
||||||
|
|
||||||
|
// swiftlint:disable identifier_name line_length type_body_length
|
||||||
|
internal enum ElementInfoPlist {
|
||||||
|
private static let _document = PlistDocument(path: "Info.plist")
|
||||||
|
|
||||||
|
internal static let cfBundleDevelopmentRegion: String = _document["CFBundleDevelopmentRegion"]
|
||||||
|
internal static let cfBundleExecutable: String = _document["CFBundleExecutable"]
|
||||||
|
internal static let cfBundleIdentifier: String = _document["CFBundleIdentifier"]
|
||||||
|
internal static let cfBundleInfoDictionaryVersion: String = _document["CFBundleInfoDictionaryVersion"]
|
||||||
|
internal static let cfBundleName: String = _document["CFBundleName"]
|
||||||
|
internal static let cfBundlePackageType: String = _document["CFBundlePackageType"]
|
||||||
|
internal static let cfBundleShortVersionString: String = _document["CFBundleShortVersionString"]
|
||||||
|
internal static let cfBundleVersion: String = _document["CFBundleVersion"]
|
||||||
|
internal static let uiLaunchStoryboardName: String = _document["UILaunchStoryboardName"]
|
||||||
|
internal static let uiSupportedInterfaceOrientations: [String] = _document["UISupportedInterfaceOrientations"]
|
||||||
|
}
|
||||||
|
// swiftlint:enable identifier_name line_length type_body_length
|
||||||
|
|
||||||
|
// MARK: - Implementation Details
|
||||||
|
|
||||||
|
private func arrayFromPlist<T>(at path: String) -> [T] {
|
||||||
|
guard let url = BundleToken.bundle.url(forResource: path, withExtension: nil),
|
||||||
|
let data = NSArray(contentsOf: url) as? [T] else {
|
||||||
|
fatalError("Unable to load PLIST at path: \(path)")
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PlistDocument {
|
||||||
|
let data: [String: Any]
|
||||||
|
|
||||||
|
init(path: String) {
|
||||||
|
guard let url = BundleToken.bundle.url(forResource: path, withExtension: nil),
|
||||||
|
let data = NSDictionary(contentsOf: url) as? [String: Any] else {
|
||||||
|
fatalError("Unable to load PLIST at path: \(path)")
|
||||||
|
}
|
||||||
|
self.data = data
|
||||||
|
}
|
||||||
|
|
||||||
|
subscript<T>(key: String) -> T {
|
||||||
|
guard let result = data[key] as? T else {
|
||||||
|
fatalError("Property '\(key)' is not of type \(T.self)")
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable convenience_type
|
||||||
|
private final class BundleToken {
|
||||||
|
static let bundle: Bundle = {
|
||||||
|
#if SWIFT_PACKAGE
|
||||||
|
return Bundle.module
|
||||||
|
#else
|
||||||
|
return Bundle(for: BundleToken.self)
|
||||||
|
#endif
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
// swiftlint:enable convenience_type
|
||||||
@@ -10,6 +10,10 @@ import Foundation
|
|||||||
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
|
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
|
||||||
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
|
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
|
||||||
extension ElementL10n {
|
extension ElementL10n {
|
||||||
|
/// Would you like to submit a bug report?
|
||||||
|
public static let screenshotDetectedMessage = ElementL10n.tr("Untranslated", "screenshot_detected_message")
|
||||||
|
/// You took a screenshot
|
||||||
|
public static let screenshotDetectedTitle = ElementL10n.tr("Untranslated", "screenshot_detected_title")
|
||||||
/// Untranslated
|
/// Untranslated
|
||||||
public static let untranslated = ElementL10n.tr("Untranslated", "untranslated")
|
public static let untranslated = ElementL10n.tr("Untranslated", "untranslated")
|
||||||
/// Plural format key: "%#@VARIABLE@"
|
/// Plural format key: "%#@VARIABLE@"
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// UIImage+.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Ismail on 20.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Vision
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
enum ImageAnonymizerError: Error {
|
||||||
|
case noCgImageBased
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ImageAnonymizer {
|
||||||
|
|
||||||
|
private static var allowedTextItems: [String] = [
|
||||||
|
"#",
|
||||||
|
"@",
|
||||||
|
"%",
|
||||||
|
"&",
|
||||||
|
"+",
|
||||||
|
"-",
|
||||||
|
"_",
|
||||||
|
"\"",
|
||||||
|
"?",
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
|
||||||
|
static func anonymizedImage(from image: UIImage,
|
||||||
|
confidenceLevel: Float = 0.5,
|
||||||
|
fillColor: UIColor = .red) async throws -> UIImage {
|
||||||
|
guard let cgImage = image.cgImage else {
|
||||||
|
throw ImageAnonymizerError.noCgImageBased
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a handler with cgImage
|
||||||
|
let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
|
||||||
|
var observations: [VNDetectedObjectObservation] = []
|
||||||
|
|
||||||
|
// create a text request
|
||||||
|
let textRequest = VNRecognizeTextRequest { request, error in
|
||||||
|
guard let results = request.results as? [VNRecognizedTextObservation],
|
||||||
|
error == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
observations.append(contentsOf: results)
|
||||||
|
}
|
||||||
|
textRequest.recognitionLevel = .accurate
|
||||||
|
textRequest.revision = VNRecognizeTextRequestRevision2
|
||||||
|
|
||||||
|
// create a face request
|
||||||
|
let faceRequest = VNDetectFaceRectanglesRequest { request, error in
|
||||||
|
guard let results = request.results as? [VNFaceObservation],
|
||||||
|
error == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
observations.append(contentsOf: results)
|
||||||
|
}
|
||||||
|
// revision3 doesn't work!
|
||||||
|
faceRequest.revision = VNDetectFaceRectanglesRequestRevision2
|
||||||
|
|
||||||
|
// perform requests
|
||||||
|
try handler.perform([
|
||||||
|
textRequest,
|
||||||
|
faceRequest
|
||||||
|
])
|
||||||
|
|
||||||
|
return render(image: image,
|
||||||
|
confidenceLevel: confidenceLevel,
|
||||||
|
fillColor: fillColor,
|
||||||
|
observations: observations)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func render(image: UIImage,
|
||||||
|
confidenceLevel: Float,
|
||||||
|
fillColor: UIColor,
|
||||||
|
observations: [VNDetectedObjectObservation]) -> UIImage {
|
||||||
|
let size = image.size
|
||||||
|
let result = UIGraphicsImageRenderer(size: size).image { rendererContext in
|
||||||
|
// first draw self
|
||||||
|
image.draw(in: CGRect(origin: .zero, size: size))
|
||||||
|
// set fill color
|
||||||
|
fillColor.setFill()
|
||||||
|
for observation in observations {
|
||||||
|
guard observation.confidence >= confidenceLevel else {
|
||||||
|
// ensure observation's confidence level
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if let textObservation = observation as? VNRecognizedTextObservation,
|
||||||
|
let text = textObservation.topCandidates(1).first?.string {
|
||||||
|
if Double(text) != nil || Self.allowedTextItems.contains(text) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let box = observation.boundingBox
|
||||||
|
// boc is normalized (and in starts from the lower left corner)
|
||||||
|
// convert it to a rect in the image
|
||||||
|
let rect = CGRect(x: box.minX * size.width,
|
||||||
|
y: size.height - box.maxY * size.height,
|
||||||
|
width: box.width * size.width,
|
||||||
|
height: box.height * size.height)
|
||||||
|
rendererContext.fill(rect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -136,14 +136,14 @@ private var logger: SwiftyBeaver.Type = {
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
fileprivate static func configureLogger(_ logger: SwiftyBeaver.Type, withConfiguration configuration: MXLogConfiguration) {
|
fileprivate static func configureLogger(_ logger: SwiftyBeaver.Type, withConfiguration configuration: MXLogConfiguration) {
|
||||||
// if let subLogName = configuration.subLogName {
|
if let subLogName = configuration.subLogName {
|
||||||
// MXLogger.setSubLogName(subLogName)
|
MXLogger.setSubLogName(subLogName)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// MXLogger.redirectNSLog(toFiles: configuration.redirectLogsToFiles,
|
MXLogger.redirectNSLog(toFiles: configuration.redirectLogsToFiles,
|
||||||
// numberOfFiles: configuration.maxLogFilesCount,
|
numberOfFiles: configuration.maxLogFilesCount,
|
||||||
// sizeLimit: configuration.logFilesSizeLimit)
|
sizeLimit: configuration.logFilesSizeLimit)
|
||||||
//
|
|
||||||
guard configuration.logLevel != .none else {
|
guard configuration.logLevel != .none else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 OpenMarket Ltd
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C
|
||||||
|
|
||||||
|
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/Foundation.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
The `MXLogger` tool redirects NSLog output into a fixed pool of files.
|
||||||
|
Another log file is used every time [MXLogger redirectNSLogToFiles:YES]
|
||||||
|
is called. The pool contains 3 files.
|
||||||
|
|
||||||
|
`MXLogger` can track and log uncatched exceptions or crashes.
|
||||||
|
*/
|
||||||
|
@interface MXLogger : NSObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
Redirect NSLog output to MXLogger files.
|
||||||
|
|
||||||
|
It is advised to condition this redirection in '#if (!isatty(STDERR_FILENO))' block to enable
|
||||||
|
it only when the device is not attached to the debugger.
|
||||||
|
|
||||||
|
@param redirectNSLogToFiles YES to enable the redirection.
|
||||||
|
*/
|
||||||
|
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Redirect NSLog output to MXLogger files.
|
||||||
|
|
||||||
|
It is advised to condition this redirection in '#if (!isatty(STDERR_FILENO))' block to enable
|
||||||
|
it only when the device is not attached to the debugger.
|
||||||
|
|
||||||
|
@param redirectNSLogToFiles YES to enable the redirection.
|
||||||
|
@param numberOfFiles number of files to keep (default is 10).
|
||||||
|
*/
|
||||||
|
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Redirect NSLog output to MXLogger files.
|
||||||
|
|
||||||
|
@param redirectNSLogToFiles YES to enable the redirection.
|
||||||
|
@param numberOfFiles number of files to keep (default is 10).
|
||||||
|
@param sizeLimit size limit of log files in bytes. 0 means no limitation, the default value for other methods
|
||||||
|
*/
|
||||||
|
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles sizeLimit:(NSUInteger)sizeLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Delete all log files.
|
||||||
|
*/
|
||||||
|
+ (void)deleteLogFiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the list of all log files.
|
||||||
|
|
||||||
|
@return files of
|
||||||
|
*/
|
||||||
|
+ (NSArray<NSString*>*)logFiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Make `MXLogger` catch and log unmanaged exceptions or application crashes.
|
||||||
|
|
||||||
|
When such error happens, `MXLogger` stores the application stack trace into a file
|
||||||
|
just before the application leaves. The path of this file is provided by [MXLogger crashLog].
|
||||||
|
|
||||||
|
@param logCrashes YES to enable the catch.
|
||||||
|
*/
|
||||||
|
+ (void)logCrashes:(BOOL)logCrashes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the app build version.
|
||||||
|
It will be reported in crash report.
|
||||||
|
*/
|
||||||
|
+ (void)setBuildVersion:(NSString*)buildVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set a sub name for namespacing log files.
|
||||||
|
|
||||||
|
A sub name must be set when running from an app extension because extensions can
|
||||||
|
run in parallel to the app.
|
||||||
|
It must be called before `redirectNSLogToFiles`.
|
||||||
|
|
||||||
|
@param subLogName the subname for log files. Files will be named as 'console-[subLogName].log'
|
||||||
|
Default is nil.
|
||||||
|
*/
|
||||||
|
+ (void)setSubLogName:(NSString*)subLogName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
If any, get the file containing the last application crash log.
|
||||||
|
|
||||||
|
Only one crash log is stored at a time. The best moment for the app to handle it is the
|
||||||
|
at its next startup.
|
||||||
|
|
||||||
|
@return the crash log file. nil if there is none.
|
||||||
|
*/
|
||||||
|
+ (NSString*)crashLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Delete the crash log file.
|
||||||
|
*/
|
||||||
|
+ (void)deleteCrashLog;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,392 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 OpenMarket Ltd
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C
|
||||||
|
|
||||||
|
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 "MXLogger.h"
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
// stderr so it can be restored
|
||||||
|
int stderrSave = 0;
|
||||||
|
|
||||||
|
static NSString *buildVersion;
|
||||||
|
static NSString *subLogName;
|
||||||
|
|
||||||
|
#define MXLOGGER_CRASH_LOG @"crash.log"
|
||||||
|
|
||||||
|
@implementation MXLogger
|
||||||
|
|
||||||
|
#pragma mark - NSLog redirection
|
||||||
|
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles
|
||||||
|
{
|
||||||
|
[self redirectNSLogToFiles:redirectNSLogToFiles numberOfFiles:10];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles
|
||||||
|
{
|
||||||
|
[self redirectNSLogToFiles:redirectNSLogToFiles numberOfFiles:numberOfFiles sizeLimit:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles sizeLimit:(NSUInteger)sizeLimit
|
||||||
|
{
|
||||||
|
if (redirectNSLogToFiles)
|
||||||
|
{
|
||||||
|
NSMutableString *log = [NSMutableString string];
|
||||||
|
|
||||||
|
// Default subname
|
||||||
|
if (!subLogName)
|
||||||
|
{
|
||||||
|
subLogName = @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set log location
|
||||||
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||||
|
|
||||||
|
// Do a circular buffer based on X files
|
||||||
|
for (NSInteger index = numberOfFiles - 2; index >= 0; index--)
|
||||||
|
{
|
||||||
|
NSString *nsLogPathOlder;
|
||||||
|
NSString *nsLogPathCurrent;
|
||||||
|
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
nsLogPathOlder = [NSString stringWithFormat:@"console%@.1.log", subLogName];
|
||||||
|
nsLogPathCurrent = [NSString stringWithFormat:@"console%@.log", subLogName];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nsLogPathOlder = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index + 1];
|
||||||
|
nsLogPathCurrent = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index];
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLogPathOlder = [logsFolderPath stringByAppendingPathComponent:nsLogPathOlder];
|
||||||
|
nsLogPathCurrent = [logsFolderPath stringByAppendingPathComponent:nsLogPathCurrent];
|
||||||
|
|
||||||
|
if ([fileManager fileExistsAtPath:nsLogPathCurrent])
|
||||||
|
{
|
||||||
|
if ([fileManager fileExistsAtPath:nsLogPathOlder])
|
||||||
|
{
|
||||||
|
// Temp log
|
||||||
|
[log appendFormat:@"[MXLogger] redirectNSLogToFiles: removeItemAtPath: %@\n", nsLogPathOlder];
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
[fileManager removeItemAtPath:nsLogPathOlder error:&error];
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
[log appendFormat:@"[MXLogger] ERROR: removeItemAtPath: %@. Error: %@\n", nsLogPathOlder, error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temp log
|
||||||
|
[log appendFormat:@"[MXLogger] redirectNSLogToFiles: moveItemAtPath: %@ toPath: %@\n", nsLogPathCurrent, nsLogPathOlder];
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
[fileManager moveItemAtPath:nsLogPathCurrent toPath:nsLogPathOlder error:&error];
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
[log appendFormat:@"[MXLogger] ERROR: moveItemAtPath: %@ toPath: %@. Error: %@\n", nsLogPathCurrent, nsLogPathOlder, error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save stderr so it can be restored.
|
||||||
|
stderrSave = dup(STDERR_FILENO);
|
||||||
|
|
||||||
|
NSString *nsLogPath = [logsFolderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"console%@.log", subLogName]];
|
||||||
|
freopen([nsLogPath fileSystemRepresentation], "w+", stderr);
|
||||||
|
|
||||||
|
// MXLogDebug(@"[MXLogger] redirectNSLogToFiles: YES");
|
||||||
|
if (log.length)
|
||||||
|
{
|
||||||
|
// We can now log into files
|
||||||
|
// MXLogDebug(@"%@", log);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self removeExtraFilesFromCount:numberOfFiles];
|
||||||
|
|
||||||
|
if (sizeLimit > 0)
|
||||||
|
{
|
||||||
|
[self removeFilesAfterSizeLimit:sizeLimit];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (stderrSave)
|
||||||
|
{
|
||||||
|
// Flush before restoring stderr
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
// Now restore stderr, so new output goes to console.
|
||||||
|
dup2(stderrSave, STDERR_FILENO);
|
||||||
|
close(stderrSave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)deleteLogFiles
|
||||||
|
{
|
||||||
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
for (NSString *logFile in [self logFiles])
|
||||||
|
{
|
||||||
|
[fileManager removeItemAtPath:logFile error:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSString*>*)logFiles
|
||||||
|
{
|
||||||
|
NSMutableArray *logFiles = [NSMutableArray array];
|
||||||
|
|
||||||
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||||
|
|
||||||
|
NSDirectoryEnumerator *dirEnum = [fileManager enumeratorAtPath:logsFolderPath];
|
||||||
|
|
||||||
|
// Find all *.log files
|
||||||
|
NSString *file = nil;
|
||||||
|
while ((file = [dirEnum nextObject]))
|
||||||
|
{
|
||||||
|
if ([[file lastPathComponent] hasPrefix:@"console"])
|
||||||
|
{
|
||||||
|
NSString *logPath = [logsFolderPath stringByAppendingPathComponent:file];
|
||||||
|
[logFiles addObject:logPath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MXLogDebug(@"[MXLogger] logFiles: %@", logFiles);
|
||||||
|
|
||||||
|
return logFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Exceptions and crashes
|
||||||
|
// Exceptions uncaught by try catch block are handled here
|
||||||
|
static void handleUncaughtException(NSException *exception)
|
||||||
|
{
|
||||||
|
[MXLogger logCrashes:NO];
|
||||||
|
|
||||||
|
// Extract running app information
|
||||||
|
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
|
||||||
|
NSString* appVersion;
|
||||||
|
NSString* app, *appId;
|
||||||
|
|
||||||
|
app = infoDict[@"CFBundleExecutable"];
|
||||||
|
appId = infoDict[@"CFBundleIdentifier"];
|
||||||
|
|
||||||
|
if ([infoDict objectForKey:@"CFBundleVersion"])
|
||||||
|
{
|
||||||
|
appVersion = [NSString stringWithFormat:@"%@ (r%@)", [infoDict objectForKey:@"CFBundleShortVersionString"], [infoDict objectForKey:@"CFBundleVersion"]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appVersion = [infoDict objectForKey:@"CFBundleShortVersionString"];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the crash log
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
NSString *model = [[UIDevice currentDevice] model];
|
||||||
|
NSString *version = [[UIDevice currentDevice] systemVersion];
|
||||||
|
#elif TARGET_OS_OSX
|
||||||
|
NSString *model = @"Mac";
|
||||||
|
NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString];
|
||||||
|
#endif
|
||||||
|
NSArray *backtrace = [exception callStackSymbols];
|
||||||
|
NSString *description = [NSString stringWithFormat:@"%.0f - %@\n%@\nApplication: %@ (%@)\nApplication version: %@\nMatrix SDK version: %@\nBuild: %@\n%@ %@\n\nMain thread: %@\n%@\n",
|
||||||
|
[[NSDate date] timeIntervalSince1970],
|
||||||
|
[NSDate date],
|
||||||
|
exception.description,
|
||||||
|
app, appId,
|
||||||
|
appVersion,
|
||||||
|
@"",
|
||||||
|
buildVersion,
|
||||||
|
model, version,
|
||||||
|
[NSThread isMainThread] ? @"YES" : @"NO",
|
||||||
|
backtrace];
|
||||||
|
|
||||||
|
// Write to the crash log file
|
||||||
|
[MXLogger deleteCrashLog];
|
||||||
|
NSString *crashLog = crashLogPath();
|
||||||
|
[description writeToFile:crashLog
|
||||||
|
atomically:NO
|
||||||
|
encoding:NSStringEncodingConversionAllowLossy
|
||||||
|
error:nil];
|
||||||
|
|
||||||
|
NSLog(@"[MXLogger] handleUncaughtException:\n%@", description);
|
||||||
|
// MXLogError(@"[MXLogger] handleUncaughtException:\n%@", description);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signals emitted by the app are handled here
|
||||||
|
static void handleSignal(int signalValue)
|
||||||
|
{
|
||||||
|
// Throw a custom Objective-C exception
|
||||||
|
// The Objective-C runtime will then be able to build a readable call stack in handleUncaughtException
|
||||||
|
[NSException raise:@"Signal detected" format:@"Signal detected: %d", signalValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logCrashes:(BOOL)logCrashes
|
||||||
|
{
|
||||||
|
if (logCrashes)
|
||||||
|
{
|
||||||
|
// Handle not managed exceptions by ourselves
|
||||||
|
NSSetUncaughtExceptionHandler(&handleUncaughtException);
|
||||||
|
|
||||||
|
// Register signal event (seg fault & cie)
|
||||||
|
signal(SIGABRT, handleSignal);
|
||||||
|
signal(SIGILL, handleSignal);
|
||||||
|
signal(SIGSEGV, handleSignal);
|
||||||
|
signal(SIGFPE, handleSignal);
|
||||||
|
signal(SIGBUS, handleSignal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Disable crash handling
|
||||||
|
NSSetUncaughtExceptionHandler(NULL);
|
||||||
|
signal(SIGABRT, SIG_DFL);
|
||||||
|
signal(SIGILL, SIG_DFL);
|
||||||
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
signal(SIGFPE, SIG_DFL);
|
||||||
|
signal(SIGBUS, SIG_DFL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setBuildVersion:(NSString *)theBuildVersion
|
||||||
|
{
|
||||||
|
buildVersion = theBuildVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setSubLogName:(NSString *)theSubLogName
|
||||||
|
{
|
||||||
|
subLogName = [NSString stringWithFormat:@"-%@", theSubLogName];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the path of the crash log file
|
||||||
|
static NSString* crashLogPath(void)
|
||||||
|
{
|
||||||
|
return [[MXLogger logsFolderPath] stringByAppendingPathComponent:MXLOGGER_CRASH_LOG];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString*)crashLog
|
||||||
|
{
|
||||||
|
NSString *exceptionLog;
|
||||||
|
|
||||||
|
NSString *crashLog = crashLogPath();
|
||||||
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
if([fileManager fileExistsAtPath:crashLog])
|
||||||
|
{
|
||||||
|
exceptionLog = crashLog;
|
||||||
|
}
|
||||||
|
return exceptionLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)deleteCrashLog
|
||||||
|
{
|
||||||
|
NSString *crashLog = crashLogPath();
|
||||||
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
if([fileManager fileExistsAtPath:crashLog])
|
||||||
|
{
|
||||||
|
[fileManager removeItemAtPath:crashLog error:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The folder where logs are stored
|
||||||
|
+ (NSString*)logsFolderPath
|
||||||
|
{
|
||||||
|
NSString *logsFolderPath = nil;
|
||||||
|
|
||||||
|
// NSURL *sharedContainerURL = [[NSFileManager defaultManager] applicationGroupContainerURL];
|
||||||
|
// if (sharedContainerURL)
|
||||||
|
// {
|
||||||
|
// logsFolderPath = [sharedContainerURL path];
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
NSArray<NSURL *> *paths = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
|
||||||
|
logsFolderPath = paths[0].path;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return logsFolderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If [self redirectNSLogToFiles: numberOfFiles:] is called with a lower numberOfFiles we need to do some cleanup
|
||||||
|
+ (void)removeExtraFilesFromCount:(NSUInteger)count
|
||||||
|
{
|
||||||
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||||
|
|
||||||
|
NSUInteger index = count;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
NSString *fileName = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index];
|
||||||
|
NSString *logFile = [logsFolderPath stringByAppendingPathComponent:fileName];
|
||||||
|
|
||||||
|
if ([fileManager fileExistsAtPath:logFile])
|
||||||
|
{
|
||||||
|
[fileManager removeItemAtPath:logFile error:nil];
|
||||||
|
// MXLogDebug(@"[MXLogger] removeExtraFilesFromCount: %@. removeItemAtPath: %@\n", @(count), logFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)removeFilesAfterSizeLimit:(NSUInteger)sizeLimit
|
||||||
|
{
|
||||||
|
NSUInteger logSize = 0;
|
||||||
|
BOOL removeFiles = NO;
|
||||||
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
|
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||||
|
|
||||||
|
// Start from console.1.log. Do not consider console.log. It should be almost empty
|
||||||
|
NSUInteger index = 0;
|
||||||
|
while (++index)
|
||||||
|
{
|
||||||
|
NSString *fileName = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index];
|
||||||
|
NSString *logFile = [logsFolderPath stringByAppendingPathComponent:fileName];
|
||||||
|
|
||||||
|
if ([fileManager fileExistsAtPath:logFile])
|
||||||
|
{
|
||||||
|
logSize += [fileManager attributesOfItemAtPath:logFile error:nil].fileSize;
|
||||||
|
|
||||||
|
if (logSize >= sizeLimit)
|
||||||
|
{
|
||||||
|
removeFiles = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeFiles)
|
||||||
|
{
|
||||||
|
// MXLogDebug(@"[MXLogger] removeFilesAfterSizeLimit: Remove files from index %@ because logs are too large (%@ for a limit of %@)\n",
|
||||||
|
// @(index),
|
||||||
|
// [NSByteCountFormatter stringFromByteCount:logSize countStyle:NSByteCountFormatterCountStyleBinary],
|
||||||
|
// [NSByteCountFormatter stringFromByteCount:sizeLimit countStyle:NSByteCountFormatterCountStyleBinary]);
|
||||||
|
[self removeExtraFilesFromCount:index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// MXLogDebug(@"[MXLogger] removeFilesAfterSizeLimit: No need: %@ for a limit of %@\n",
|
||||||
|
// [NSByteCountFormatter stringFromByteCount:logSize countStyle:NSByteCountFormatterCountStyleBinary],
|
||||||
|
// [NSByteCountFormatter stringFromByteCount:sizeLimit countStyle:NSByteCountFormatterCountStyleBinary]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// ElementToggleStyle.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Ismail on 2.06.2022.
|
||||||
|
// Copyright © 2022 Element. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// A toggle style that uses a button, with a checked/unchecked image like a checkbox.
|
||||||
|
struct ElementToggleStyle: ToggleStyle {
|
||||||
|
|
||||||
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
|
Button { configuration.isOn.toggle() } label: {
|
||||||
|
Image(systemName: configuration.isOn ? "checkmark.square.fill" : "square")
|
||||||
|
.font(.title3.weight(.regular))
|
||||||
|
.imageScale(.large)
|
||||||
|
.foregroundColor(Color(uiColor: Asset.Colors.elementGreen.color))
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,6 +103,9 @@ class RoundedToastView: UIView {
|
|||||||
case .success:
|
case .success:
|
||||||
imageView.image = UIImage(systemName: "checkmark.circle")
|
imageView.image = UIImage(systemName: "checkmark.circle")
|
||||||
return imageView
|
return imageView
|
||||||
|
case .error:
|
||||||
|
imageView.image = UIImage(systemName: "x.circle")
|
||||||
|
return imageView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ struct ToastViewState {
|
|||||||
enum Style {
|
enum Style {
|
||||||
case loading
|
case loading
|
||||||
case success
|
case success
|
||||||
|
case error
|
||||||
}
|
}
|
||||||
|
|
||||||
let style: Style
|
let style: Style
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import UIKit
|
|||||||
enum UserIndicatorType {
|
enum UserIndicatorType {
|
||||||
case loading(label: String, isInteractionBlocking: Bool)
|
case loading(label: String, isInteractionBlocking: Bool)
|
||||||
case success(label: String)
|
case success(label: String)
|
||||||
|
case error(label: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A presenter which can handle `UserIndicatorType` by creating the underlying `UserIndicator`
|
/// A presenter which can handle `UserIndicatorType` by creating the underlying `UserIndicator`
|
||||||
@@ -72,6 +73,8 @@ class UserIndicatorTypePresenter: UserIndicatorTypePresenterProtocol {
|
|||||||
}
|
}
|
||||||
case .success(let label):
|
case .success(let label):
|
||||||
return successRequest(label: label)
|
return successRequest(label: label)
|
||||||
|
case .error(let label):
|
||||||
|
return errorRequest(label: label)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,4 +116,18 @@ class UserIndicatorTypePresenter: UserIndicatorTypePresenterProtocol {
|
|||||||
dismissal: .timeout(1.5)
|
dismissal: .timeout(1.5)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func errorRequest(label: String) -> UserIndicatorRequest {
|
||||||
|
let presenter = ToastViewPresenter(
|
||||||
|
viewState: .init(
|
||||||
|
style: .error,
|
||||||
|
label: label
|
||||||
|
),
|
||||||
|
presentationContext: presentationContext
|
||||||
|
)
|
||||||
|
return UserIndicatorRequest(
|
||||||
|
presenter: presenter,
|
||||||
|
dismissal: .timeout(1.5)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 SwiftUI
|
||||||
|
|
||||||
|
struct BugReportCoordinatorParameters {
|
||||||
|
let bugReportService: BugReportServiceProtocol
|
||||||
|
let screenshot: UIImage?
|
||||||
|
}
|
||||||
|
|
||||||
|
final class BugReportCoordinator: Coordinator, Presentable {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private let parameters: BugReportCoordinatorParameters
|
||||||
|
private let bugReportHostingController: UIViewController
|
||||||
|
private var bugReportViewModel: BugReportViewModelProtocol
|
||||||
|
|
||||||
|
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
|
||||||
|
private var loadingIndicator: UserIndicator?
|
||||||
|
private var errorIndicator: UserIndicator?
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
// Must be used only internally
|
||||||
|
var childCoordinators: [Coordinator] = []
|
||||||
|
var completion: (() -> Void)?
|
||||||
|
|
||||||
|
// MARK: - Setup
|
||||||
|
|
||||||
|
init(parameters: BugReportCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
|
||||||
|
let viewModel = BugReportViewModel(bugReportService: parameters.bugReportService,
|
||||||
|
screenshot: parameters.screenshot)
|
||||||
|
let view = BugReport(context: viewModel.context)
|
||||||
|
bugReportViewModel = viewModel
|
||||||
|
bugReportHostingController = UIHostingController(rootView: view)
|
||||||
|
|
||||||
|
indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: bugReportHostingController)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
MXLog.debug("[BugReportCoordinator] did start.")
|
||||||
|
bugReportViewModel.callback = { [weak self] result in
|
||||||
|
guard let self = self else { return }
|
||||||
|
MXLog.debug("[BugReportCoordinator] BugReportViewModel did complete with result: \(result).")
|
||||||
|
switch result {
|
||||||
|
case .submitStarted:
|
||||||
|
self.startLoading()
|
||||||
|
case .submitFinished:
|
||||||
|
self.stopLoading()
|
||||||
|
self.showSuccess(label: ElementL10n.done)
|
||||||
|
case .submitFailed(let error):
|
||||||
|
self.stopLoading()
|
||||||
|
self.showError(label: error.localizedDescription)
|
||||||
|
case .cancel:
|
||||||
|
self.completion?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> UIViewController {
|
||||||
|
bugReportHostingController
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
/// Show an activity indicator whilst loading.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - label: The label to show on the indicator.
|
||||||
|
/// - isInteractionBlocking: Whether the indicator should block any user interaction.
|
||||||
|
private func startLoading(label: String = ElementL10n.loading, isInteractionBlocking: Bool = true) {
|
||||||
|
loadingIndicator = indicatorPresenter.present(.loading(label: label,
|
||||||
|
isInteractionBlocking: isInteractionBlocking))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hide the currently displayed activity indicator.
|
||||||
|
private func stopLoading() {
|
||||||
|
loadingIndicator = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show success indicator
|
||||||
|
private func showSuccess(label: String) {
|
||||||
|
errorIndicator = indicatorPresenter.present(.success(label: label))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show error indicator
|
||||||
|
private func showError(label: String) {
|
||||||
|
errorIndicator = indicatorPresenter.present(.error(label: label))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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
|
||||||
|
|
||||||
|
// MARK: - Coordinator
|
||||||
|
|
||||||
|
// MARK: View model
|
||||||
|
|
||||||
|
enum BugReportViewModelAction {
|
||||||
|
case submitStarted
|
||||||
|
case submitFinished
|
||||||
|
case submitFailed(error: Error)
|
||||||
|
case cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: View
|
||||||
|
|
||||||
|
struct BugReportViewState: BindableState {
|
||||||
|
var screenshot: UIImage?
|
||||||
|
var bindings: BugReportViewStateBindings
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BugReportViewStateBindings {
|
||||||
|
var reportText: String
|
||||||
|
var sendingLogsEnabled: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BugReportViewAction {
|
||||||
|
case submit
|
||||||
|
case cancel
|
||||||
|
case toggleSendLogs
|
||||||
|
case removeScreenshot
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 SwiftUI
|
||||||
|
|
||||||
|
@available(iOS 14, *)
|
||||||
|
typealias BugReportViewModelType = StateStoreViewModel<BugReportViewState,
|
||||||
|
BugReportViewAction>
|
||||||
|
@available(iOS 14, *)
|
||||||
|
class BugReportViewModel: BugReportViewModelType, BugReportViewModelProtocol {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
let bugReportService: BugReportServiceProtocol
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
func submitBugReport() async {
|
||||||
|
callback?(.submitStarted)
|
||||||
|
do {
|
||||||
|
var files: [URL] = []
|
||||||
|
if let screenshot = state.screenshot {
|
||||||
|
let anonymized = try await ImageAnonymizer.anonymizedImage(from: screenshot)
|
||||||
|
let tmpUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("screenshot").appendingPathExtension("png")
|
||||||
|
// remove old screenshot if exists
|
||||||
|
if FileManager.default.fileExists(atPath: tmpUrl.path) {
|
||||||
|
try FileManager.default.removeItem(at: tmpUrl)
|
||||||
|
}
|
||||||
|
try anonymized.dataForPNGRepresentation().write(to: tmpUrl)
|
||||||
|
files.append(tmpUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = try await bugReportService.submitBugReport(text: context.reportText,
|
||||||
|
includeLogs: context.sendingLogsEnabled,
|
||||||
|
includeCrashLog: true,
|
||||||
|
githubLabels: [],
|
||||||
|
files: files)
|
||||||
|
MXLog.info("[BugReportViewModel] submitBugReport succeeded, result: \(result.reportUrl)")
|
||||||
|
callback?(.submitFinished)
|
||||||
|
} catch let error {
|
||||||
|
MXLog.error("[BugReportViewModel] submitBugReport failed: \(error)")
|
||||||
|
callback?(.submitFailed(error: error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
var callback: ((BugReportViewModelAction) -> Void)?
|
||||||
|
|
||||||
|
// MARK: - Setup
|
||||||
|
|
||||||
|
init(bugReportService: BugReportServiceProtocol,
|
||||||
|
screenshot: UIImage?) {
|
||||||
|
self.bugReportService = bugReportService
|
||||||
|
let bindings = BugReportViewStateBindings(reportText: "", sendingLogsEnabled: true)
|
||||||
|
super.init(initialViewState: BugReportViewState(screenshot: screenshot,
|
||||||
|
bindings: bindings))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
override func process(viewAction: BugReportViewAction) async {
|
||||||
|
switch viewAction {
|
||||||
|
case .submit:
|
||||||
|
await submitBugReport()
|
||||||
|
case .cancel:
|
||||||
|
callback?(.cancel)
|
||||||
|
case .toggleSendLogs:
|
||||||
|
context.sendingLogsEnabled.toggle()
|
||||||
|
case .removeScreenshot:
|
||||||
|
state.screenshot = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
protocol BugReportViewModelProtocol {
|
||||||
|
|
||||||
|
var callback: ((BugReportViewModelAction) -> Void)? { get set }
|
||||||
|
@available(iOS 14, *)
|
||||||
|
var context: BugReportViewModelType.Context { get }
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 SwiftUI
|
||||||
|
|
||||||
|
struct BugReport: View {
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||||
|
|
||||||
|
private var horizontalPadding: CGFloat {
|
||||||
|
horizontalSizeClass == .regular ? 50 : 16
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
@ObservedObject var context: BugReportViewModel.Context
|
||||||
|
|
||||||
|
// MARK: Views
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
VStack {
|
||||||
|
ScrollView {
|
||||||
|
mainContent
|
||||||
|
.padding(.top, 50)
|
||||||
|
.padding(.horizontal, horizontalPadding)
|
||||||
|
}
|
||||||
|
.introspectScrollView { scrollView in
|
||||||
|
scrollView.keyboardDismissMode = .onDrag
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons
|
||||||
|
.padding(.horizontal, horizontalPadding)
|
||||||
|
.padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 16)
|
||||||
|
}
|
||||||
|
.navigationTitle(ElementL10n.titleActivityBugReport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The main content of the view to be shown in a scroll view.
|
||||||
|
var mainContent: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
|
Text(ElementL10n.sendBugReportDescription)
|
||||||
|
.accessibilityIdentifier("reportBugDescription")
|
||||||
|
ZStack(alignment: .topLeading) {
|
||||||
|
RoundedRectangle(cornerRadius: 8, style: .continuous)
|
||||||
|
.fill(Color(UIColor.secondarySystemBackground))
|
||||||
|
|
||||||
|
if context.reportText.isEmpty {
|
||||||
|
Text(ElementL10n.sendBugReportPlaceholder)
|
||||||
|
.foregroundColor(Color(UIColor.placeholderText))
|
||||||
|
.padding(.horizontal, 8)
|
||||||
|
.padding(.vertical, 12)
|
||||||
|
}
|
||||||
|
TextEditor(text: $context.reportText)
|
||||||
|
.padding(4)
|
||||||
|
.background(Color.clear)
|
||||||
|
.cornerRadius(8)
|
||||||
|
.accessibilityIdentifier("reportTextView")
|
||||||
|
.introspectTextView { textView in
|
||||||
|
textView.backgroundColor = .clear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.frame(height: 300)
|
||||||
|
.font(.body)
|
||||||
|
Text(ElementL10n.sendBugReportLogsDescription)
|
||||||
|
.accessibilityIdentifier("sendLogsDescription")
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Toggle(ElementL10n.sendBugReportIncludeLogs, isOn: $context.sendingLogsEnabled)
|
||||||
|
.toggleStyle(ElementToggleStyle())
|
||||||
|
.accessibilityIdentifier("sendLogsToggle")
|
||||||
|
Text(ElementL10n.sendBugReportIncludeLogs).accessibilityIdentifier("sendLogsText")
|
||||||
|
}
|
||||||
|
.onTapGesture {
|
||||||
|
context.send(viewAction: .toggleSendLogs)
|
||||||
|
}
|
||||||
|
screenshot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The action buttons shown at the bottom of the view.
|
||||||
|
var buttons: some View {
|
||||||
|
VStack {
|
||||||
|
Button { context.send(viewAction: .submit) } label: {
|
||||||
|
Text(ElementL10n.actionSend)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical, 16)
|
||||||
|
.disabled(context.reportText.count < 5)
|
||||||
|
.accessibilityIdentifier("sendButton")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
var screenshot: some View {
|
||||||
|
if let screenshot = context.viewState.screenshot {
|
||||||
|
ZStack(alignment: .topTrailing) {
|
||||||
|
Image(uiImage: screenshot)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 100)
|
||||||
|
.accessibilityIdentifier("screenshotImage")
|
||||||
|
Button { context.send(viewAction: .removeScreenshot) } label: {
|
||||||
|
Image(uiImage: Asset.Images.closeCircle.image)
|
||||||
|
}
|
||||||
|
.offset(x: 10, y: -10)
|
||||||
|
.accessibilityIdentifier("removeScreenshotButton")
|
||||||
|
}
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
|
struct BugReport_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
Group {
|
||||||
|
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: Asset.Images.appLogo.image)
|
||||||
|
BugReport(context: viewModel.context)
|
||||||
|
.previewInterfaceOrientation(.portrait)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,8 @@ struct HomeScreenCoordinatorParameters {
|
|||||||
|
|
||||||
enum HomeScreenCoordinatorAction {
|
enum HomeScreenCoordinatorAction {
|
||||||
case logout
|
case logout
|
||||||
case selectRoom(roomIdentifier: String)
|
case presentRoom(roomIdentifier: String)
|
||||||
|
case presentSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
final class HomeScreenCoordinator: Coordinator, Presentable {
|
final class HomeScreenCoordinator: Coordinator, Presentable {
|
||||||
@@ -65,7 +66,9 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
|
|||||||
case .logout:
|
case .logout:
|
||||||
self.callback?(.logout)
|
self.callback?(.logout)
|
||||||
case .selectRoom(let roomIdentifier):
|
case .selectRoom(let roomIdentifier):
|
||||||
self.callback?(.selectRoom(roomIdentifier: roomIdentifier))
|
self.callback?(.presentRoom(roomIdentifier: roomIdentifier))
|
||||||
|
case .tapUserAvatar:
|
||||||
|
self.callback?(.presentSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ import UIKit
|
|||||||
enum HomeScreenViewModelAction {
|
enum HomeScreenViewModelAction {
|
||||||
case logout
|
case logout
|
||||||
case selectRoom(roomIdentifier: String)
|
case selectRoom(roomIdentifier: String)
|
||||||
|
case tapUserAvatar
|
||||||
}
|
}
|
||||||
|
|
||||||
enum HomeScreenViewAction {
|
enum HomeScreenViewAction {
|
||||||
case logout
|
case logout
|
||||||
case loadRoomData(roomIdentifier: String)
|
case loadRoomData(roomIdentifier: String)
|
||||||
case selectRoom(roomIdentifier: String)
|
case selectRoom(roomIdentifier: String)
|
||||||
|
case tapUserAvatar
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HomeScreenViewState: BindableState {
|
struct HomeScreenViewState: BindableState {
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
loadRoomDataForIdentifier(roomIdentifier)
|
loadRoomDataForIdentifier(roomIdentifier)
|
||||||
case .selectRoom(let roomIdentifier):
|
case .selectRoom(let roomIdentifier):
|
||||||
callback?(.selectRoom(roomIdentifier: roomIdentifier))
|
callback?(.selectRoom(roomIdentifier: roomIdentifier))
|
||||||
|
case .tapUserAvatar:
|
||||||
|
callback?(.tapUserAvatar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,11 +75,13 @@ struct HomeScreen: View {
|
|||||||
HStack {
|
HStack {
|
||||||
ZStack {
|
ZStack {
|
||||||
if let avatar = context.viewState.userAvatar {
|
if let avatar = context.viewState.userAvatar {
|
||||||
Image(uiImage: avatar)
|
Button { context.send(viewAction: .tapUserAvatar) } label: {
|
||||||
.resizable()
|
Image(uiImage: avatar)
|
||||||
.scaledToFill()
|
.resizable()
|
||||||
.frame(width: 40, height: 40, alignment: .center)
|
.scaledToFill()
|
||||||
.mask(Circle())
|
.frame(width: 40, height: 40, alignment: .center)
|
||||||
|
.mask(Circle())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
@@ -89,9 +91,12 @@ struct HomeScreen: View {
|
|||||||
|
|
||||||
ZStack {
|
ZStack {
|
||||||
if let displayName = context.viewState.userDisplayName {
|
if let displayName = context.viewState.userDisplayName {
|
||||||
Text("Hello, \(displayName)!")
|
Button { context.send(viewAction: .tapUserAvatar) } label: {
|
||||||
.font(.subheadline)
|
Text("Hello, \(displayName)!")
|
||||||
.fontWeight(.bold)
|
.font(.subheadline)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.foregroundColor(.black)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 SwiftUI
|
||||||
|
|
||||||
|
struct SettingsCoordinatorParameters {
|
||||||
|
let navigationRouter: NavigationRouterType
|
||||||
|
let bugReportService: BugReportServiceProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
final class SettingsCoordinator: Coordinator, Presentable {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private let parameters: SettingsCoordinatorParameters
|
||||||
|
private let settingsHostingController: UIViewController
|
||||||
|
private var settingsViewModel: SettingsViewModelProtocol
|
||||||
|
|
||||||
|
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
|
||||||
|
private var loadingIndicator: UserIndicator?
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
// Must be used only internally
|
||||||
|
var childCoordinators: [Coordinator] = []
|
||||||
|
|
||||||
|
// MARK: - Setup
|
||||||
|
|
||||||
|
init(parameters: SettingsCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
|
||||||
|
let viewModel = SettingsViewModel()
|
||||||
|
let view = Settings(context: viewModel.context)
|
||||||
|
settingsViewModel = viewModel
|
||||||
|
settingsHostingController = UIHostingController(rootView: view)
|
||||||
|
|
||||||
|
indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: settingsHostingController)
|
||||||
|
|
||||||
|
settingsViewModel.callback = { [weak self] result in
|
||||||
|
guard let self = self else { return }
|
||||||
|
MXLog.debug("[SettingsCoordinator] SettingsViewModel did complete with result: \(result).")
|
||||||
|
switch result {
|
||||||
|
case .reportBug:
|
||||||
|
self.presentBugReportScreen()
|
||||||
|
case .crash:
|
||||||
|
self.parameters.bugReportService.crash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> UIViewController {
|
||||||
|
settingsHostingController
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
/// Show an activity indicator whilst loading.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - label: The label to show on the indicator.
|
||||||
|
/// - isInteractionBlocking: Whether the indicator should block any user interaction.
|
||||||
|
private func startLoading(label: String = ElementL10n.loading, isInteractionBlocking: Bool = true) {
|
||||||
|
loadingIndicator = indicatorPresenter.present(.loading(label: label, isInteractionBlocking: isInteractionBlocking))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hide the currently displayed activity indicator.
|
||||||
|
private func stopLoading() {
|
||||||
|
loadingIndicator = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentBugReportScreen() {
|
||||||
|
let params = BugReportCoordinatorParameters(bugReportService: parameters.bugReportService,
|
||||||
|
screenshot: nil)
|
||||||
|
let coordinator = BugReportCoordinator(parameters: params)
|
||||||
|
coordinator.completion = { [weak self, weak coordinator] in
|
||||||
|
guard let self = self, let coordinator = coordinator else { return }
|
||||||
|
self.parameters.navigationRouter.popModule(animated: true)
|
||||||
|
self.remove(childCoordinator: coordinator)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(childCoordinator: coordinator)
|
||||||
|
coordinator.start()
|
||||||
|
self.parameters.navigationRouter.push(coordinator, animated: true) { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.remove(childCoordinator: coordinator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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
|
||||||
|
|
||||||
|
// MARK: - Coordinator
|
||||||
|
|
||||||
|
// MARK: View model
|
||||||
|
|
||||||
|
enum SettingsViewModelAction {
|
||||||
|
case reportBug
|
||||||
|
case crash
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: View
|
||||||
|
|
||||||
|
struct SettingsViewState: BindableState {
|
||||||
|
var crashButtonVisible: Bool
|
||||||
|
var bindings: SettingsViewStateBindings
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SettingsViewStateBindings {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SettingsViewAction {
|
||||||
|
case reportBug
|
||||||
|
case crash
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 SwiftUI
|
||||||
|
|
||||||
|
@available(iOS 14, *)
|
||||||
|
typealias SettingsViewModelType = StateStoreViewModel<SettingsViewState,
|
||||||
|
SettingsViewAction>
|
||||||
|
@available(iOS 14, *)
|
||||||
|
class SettingsViewModel: SettingsViewModelType, SettingsViewModelProtocol {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
var callback: ((SettingsViewModelAction) -> Void)?
|
||||||
|
|
||||||
|
// MARK: - Setup
|
||||||
|
|
||||||
|
init() {
|
||||||
|
let bindings = SettingsViewStateBindings()
|
||||||
|
super.init(initialViewState: .init(crashButtonVisible: true, bindings: bindings))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Public
|
||||||
|
|
||||||
|
override func process(viewAction: SettingsViewAction) async {
|
||||||
|
switch viewAction {
|
||||||
|
case .reportBug:
|
||||||
|
callback?(.reportBug)
|
||||||
|
case .crash:
|
||||||
|
callback?(.crash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
protocol SettingsViewModelProtocol {
|
||||||
|
|
||||||
|
var callback: ((SettingsViewModelAction) -> Void)? { get set }
|
||||||
|
@available(iOS 14, *)
|
||||||
|
var context: SettingsViewModelType.Context { get }
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 SwiftUI
|
||||||
|
|
||||||
|
struct Settings: View {
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
@ObservedObject var context: SettingsViewModel.Context
|
||||||
|
|
||||||
|
// MARK: Views
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Form {
|
||||||
|
Button { context.send(viewAction: .reportBug) } label: {
|
||||||
|
Text(ElementL10n.sendBugReport)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical, 16)
|
||||||
|
.accessibilityIdentifier("reportBugButton")
|
||||||
|
|
||||||
|
if context.viewState.crashButtonVisible {
|
||||||
|
Button { context.send(viewAction: .crash) } label: {
|
||||||
|
Text("Crash the app")
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical, 16)
|
||||||
|
.accessibilityIdentifier("crashButton")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle(ElementL10n.settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
|
struct Settings_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
Group {
|
||||||
|
let viewModel = SettingsViewModel()
|
||||||
|
Settings(context: viewModel.context)
|
||||||
|
.previewInterfaceOrientation(.portrait)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
//
|
||||||
|
// BugReportService.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Ismail on 16.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MatrixRustSDK
|
||||||
|
import UIKit
|
||||||
|
import GZIP
|
||||||
|
import Sentry
|
||||||
|
|
||||||
|
enum BugReportServiceError: Error {
|
||||||
|
case invalidBaseUrlString
|
||||||
|
case invalidSentryEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
class BugReportService: BugReportServiceProtocol {
|
||||||
|
private let baseURL: URL
|
||||||
|
private let sentryEndpoint: String
|
||||||
|
private let applicationId: String
|
||||||
|
private let session: URLSession
|
||||||
|
|
||||||
|
init(withBaseUrlString baseUrlString: String,
|
||||||
|
sentryEndpoint: String,
|
||||||
|
applicationId: String = BuildSettings.bugReportApplicationId,
|
||||||
|
session: URLSession = .shared) throws {
|
||||||
|
guard let url = URL(string: baseUrlString) else {
|
||||||
|
throw BugReportServiceError.invalidBaseUrlString
|
||||||
|
}
|
||||||
|
guard !sentryEndpoint.isEmpty else {
|
||||||
|
throw BugReportServiceError.invalidSentryEndpoint
|
||||||
|
}
|
||||||
|
self.baseURL = url
|
||||||
|
self.sentryEndpoint = sentryEndpoint
|
||||||
|
self.applicationId = applicationId
|
||||||
|
self.session = session
|
||||||
|
|
||||||
|
// enable SentrySDK
|
||||||
|
SentrySDK.start { options in
|
||||||
|
options.dsn = sentryEndpoint
|
||||||
|
#if DEBUG
|
||||||
|
options.debug = true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
|
||||||
|
// We recommend adjusting this value in production.
|
||||||
|
options.tracesSampleRate = 1.0
|
||||||
|
|
||||||
|
options.beforeSend = { event in
|
||||||
|
MXLog.error("Sentry detected crash: \(event)")
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
options.onCrashedLastRun = { event in
|
||||||
|
MXLog.debug("Sentry detected application was crashed: \(event)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// also enable logging crashes, to send them with bug reports
|
||||||
|
MXLogger.logCrashes(true)
|
||||||
|
// set build version for logger
|
||||||
|
MXLogger.setBuildVersion(ElementInfoPlist.cfBundleShortVersionString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - BugReportServiceProtocol
|
||||||
|
|
||||||
|
var crashedLastRun: Bool {
|
||||||
|
return SentrySDK.crashedLastRun
|
||||||
|
}
|
||||||
|
|
||||||
|
func crash() {
|
||||||
|
SentrySDK.crash()
|
||||||
|
}
|
||||||
|
|
||||||
|
func submitBugReport(text: String,
|
||||||
|
includeLogs: Bool,
|
||||||
|
includeCrashLog: Bool,
|
||||||
|
githubLabels: [String],
|
||||||
|
files: [URL]) async throws -> SubmitBugReportResponse {
|
||||||
|
MXLog.debug("[BugReportService] submitBugReport")
|
||||||
|
|
||||||
|
var params = [
|
||||||
|
MultipartFormData(key: "text", type: .text(value: text))
|
||||||
|
]
|
||||||
|
params.append(contentsOf: defaultParams)
|
||||||
|
for label in githubLabels {
|
||||||
|
params.append(MultipartFormData(key: "label", type: .text(value: label)))
|
||||||
|
}
|
||||||
|
let zippedFiles = try await zipFiles(includeLogs: includeLogs,
|
||||||
|
includeCrashLog: includeCrashLog)
|
||||||
|
// log or compressed-log
|
||||||
|
if !zippedFiles.isEmpty {
|
||||||
|
for url in zippedFiles {
|
||||||
|
params.append(MultipartFormData(key: "compressed-log", type: .file(url: url)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for url in files {
|
||||||
|
params.append(MultipartFormData(key: "file", type: .file(url: url)))
|
||||||
|
}
|
||||||
|
|
||||||
|
let boundary = "Boundary-\(UUID().uuidString)"
|
||||||
|
var body = Data()
|
||||||
|
for param in params {
|
||||||
|
body.appendString(string: "--\(boundary)\r\n")
|
||||||
|
body.appendString(string: "Content-Disposition:form-data; name=\"\(param.key)\"")
|
||||||
|
switch param.type {
|
||||||
|
case .text(let value):
|
||||||
|
body.appendString(string: "\r\n\r\n\(value)\r\n")
|
||||||
|
case .file(let url):
|
||||||
|
body.appendString(string: "; filename=\"\(url.lastPathComponent)\"\r\n")
|
||||||
|
body.appendString(string: "Content-Type: \"content-type header\"\r\n\r\n")
|
||||||
|
body.append(try Data(contentsOf: url))
|
||||||
|
body.appendString(string: "\r\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body.appendString(string: "--\(boundary)--\r\n")
|
||||||
|
|
||||||
|
var request = URLRequest(url: baseURL.appendingPathComponent("submit"))
|
||||||
|
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
request.httpBody = body as Data
|
||||||
|
|
||||||
|
let (data, _) = try await session.data(for: request)
|
||||||
|
|
||||||
|
// Parse the JSON data
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
|
let result = try decoder.decode(SubmitBugReportResponse.self, from: data)
|
||||||
|
|
||||||
|
if !result.reportUrl.isEmpty {
|
||||||
|
MXLogger.deleteCrashLog()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private var defaultParams: [MultipartFormData] {
|
||||||
|
[
|
||||||
|
MultipartFormData(key: "user_agent", type: .text(value: "iOS")),
|
||||||
|
MultipartFormData(key: "app", type: .text(value: applicationId)),
|
||||||
|
MultipartFormData(key: "version", type: .text(value: version)),
|
||||||
|
MultipartFormData(key: "os", type: .text(value: os)),
|
||||||
|
MultipartFormData(key: "client", type: .text(value: "Element-X"))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
private var os: String {
|
||||||
|
"\(UIDevice.current.systemName) \(UIDevice.current.systemVersion)"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var version: String {
|
||||||
|
ElementInfoPlist.cfBundleShortVersionString
|
||||||
|
}
|
||||||
|
|
||||||
|
private func zipFiles(includeLogs: Bool,
|
||||||
|
includeCrashLog: Bool) async throws -> [URL] {
|
||||||
|
MXLog.debug("[BugReportService] zipFiles: includeLogs: \(includeLogs), includeCrashLog: \(includeCrashLog)")
|
||||||
|
|
||||||
|
var filesToCompress: [URL] = []
|
||||||
|
if includeLogs, let logFiles = MXLogger.logFiles() {
|
||||||
|
let urls = logFiles.compactMap { URL(fileURLWithPath: $0) }
|
||||||
|
filesToCompress.append(contentsOf: urls)
|
||||||
|
}
|
||||||
|
if includeCrashLog, let crashLogFile = MXLogger.crashLog() {
|
||||||
|
filesToCompress.append(URL(fileURLWithPath: crashLogFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalSize: Int = 0
|
||||||
|
var totalZippedSize: Int = 0
|
||||||
|
var zippedFiles: [URL] = []
|
||||||
|
|
||||||
|
for url in filesToCompress {
|
||||||
|
let zippedFileURL = URL(fileURLWithPath: NSTemporaryDirectory())
|
||||||
|
.appendingPathComponent(url.lastPathComponent)
|
||||||
|
|
||||||
|
// remove old zipped file if exists
|
||||||
|
try? FileManager.default.removeItem(at: zippedFileURL)
|
||||||
|
|
||||||
|
let rawData = try Data(contentsOf: url)
|
||||||
|
if rawData.isEmpty {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guard let zippedData = (rawData as NSData).gzipped() else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
totalSize += rawData.count
|
||||||
|
totalZippedSize += zippedData.count
|
||||||
|
|
||||||
|
try zippedData.write(to: zippedFileURL)
|
||||||
|
|
||||||
|
zippedFiles.append(zippedFileURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
MXLog.debug("[BugReportService] zipFiles: totalSize: \(totalSize), totalZippedSize: \(totalZippedSize)")
|
||||||
|
|
||||||
|
return zippedFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension Data {
|
||||||
|
mutating func appendString(string: String, encoding: String.Encoding = .utf8) {
|
||||||
|
if let data = string.data(using: encoding) {
|
||||||
|
append(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct MultipartFormData {
|
||||||
|
let key: String
|
||||||
|
let type: MultipartFormDataType
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum MultipartFormDataType {
|
||||||
|
case text(value: String)
|
||||||
|
case file(url: URL)
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// BugReportServiceProtocol.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Ismail on 16.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
struct SubmitBugReportResponse: Decodable {
|
||||||
|
var reportUrl: String
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol BugReportServiceProtocol {
|
||||||
|
|
||||||
|
var crashedLastRun: Bool { get }
|
||||||
|
|
||||||
|
func crash()
|
||||||
|
|
||||||
|
func submitBugReport(text: String,
|
||||||
|
includeLogs: Bool,
|
||||||
|
includeCrashLog: Bool,
|
||||||
|
githubLabels: [String],
|
||||||
|
files: [URL]) async throws -> SubmitBugReportResponse
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// MockBugReportService.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Ismail on 16.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class MockBugReportService: BugReportServiceProtocol {
|
||||||
|
|
||||||
|
func submitBugReport(text: String,
|
||||||
|
includeLogs: Bool,
|
||||||
|
includeCrashLog: Bool,
|
||||||
|
githubLabels: [String],
|
||||||
|
files: [URL]) async throws -> SubmitBugReportResponse {
|
||||||
|
return SubmitBugReportResponse(reportUrl: "https://www.example/com/123")
|
||||||
|
}
|
||||||
|
|
||||||
|
var crashedLastRun: Bool = false
|
||||||
|
|
||||||
|
func crash() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// ScreenshotObserver.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Ismail on 31.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Photos
|
||||||
|
|
||||||
|
enum ScreenshotDetectorError: String, Error {
|
||||||
|
case loadFailed
|
||||||
|
case notAuthorized
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class ScreenshotDetector {
|
||||||
|
|
||||||
|
var callback: (@MainActor (UIImage?, Error?) -> Void)?
|
||||||
|
|
||||||
|
/// Flag to whether ask for photos authorization by default if needed.
|
||||||
|
var autoRequestPHAuthorization = true
|
||||||
|
|
||||||
|
init() {
|
||||||
|
startObservingScreenshots()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func startObservingScreenshots() {
|
||||||
|
NotificationCenter.default.addObserver(self,
|
||||||
|
selector: #selector(userDidTakeScreenshot),
|
||||||
|
name: UIApplication.userDidTakeScreenshotNotification,
|
||||||
|
object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func userDidTakeScreenshot() {
|
||||||
|
let authStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
|
||||||
|
if authStatus == .authorized {
|
||||||
|
findScreenshot()
|
||||||
|
} else if authStatus == .notDetermined && autoRequestPHAuthorization {
|
||||||
|
Task {
|
||||||
|
self.handleAuthStatus(await PHPhotoLibrary.requestAuthorization(for: .readWrite))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail(withError: ScreenshotDetectorError.notAuthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleAuthStatus(_ status: PHAuthorizationStatus) {
|
||||||
|
if status == .authorized {
|
||||||
|
findScreenshot()
|
||||||
|
} else {
|
||||||
|
fail(withError: ScreenshotDetectorError.notAuthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func findScreenshot() {
|
||||||
|
if let asset = PHAsset.fetchLastScreenshot() {
|
||||||
|
let imageManager = PHImageManager()
|
||||||
|
imageManager.requestImage(for: asset,
|
||||||
|
targetSize: PHImageManagerMaximumSize,
|
||||||
|
contentMode: .default,
|
||||||
|
options: PHImageRequestOptions.highQualitySyncLocal) { [weak self] image, _ in
|
||||||
|
guard let image = image else {
|
||||||
|
self?.fail(withError: ScreenshotDetectorError.loadFailed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self?.succeed(withImage: image)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail(withError: ScreenshotDetectorError.loadFailed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func succeed(withImage image: UIImage) {
|
||||||
|
callback?(image, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fail(withError error: Error) {
|
||||||
|
callback?(nil, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension PHAsset {
|
||||||
|
|
||||||
|
static func fetchLastScreenshot() -> PHAsset? {
|
||||||
|
let options = PHFetchOptions()
|
||||||
|
|
||||||
|
options.fetchLimit = 1
|
||||||
|
options.includeAssetSourceTypes = [.typeUserLibrary]
|
||||||
|
options.wantsIncrementalChangeDetails = false
|
||||||
|
options.predicate = NSPredicate(format: "(mediaSubtype & %d) != 0", PHAssetMediaSubtype.photoScreenshot.rawValue)
|
||||||
|
options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
|
||||||
|
|
||||||
|
return PHAsset.fetchAssets(with: .image, options: options).firstObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension PHImageRequestOptions {
|
||||||
|
|
||||||
|
static var highQualitySyncLocal: PHImageRequestOptions {
|
||||||
|
let options = PHImageRequestOptions()
|
||||||
|
options.deliveryMode = .highQualityFormat
|
||||||
|
options.isNetworkAccessAllowed = false
|
||||||
|
options.isSynchronous = true
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,9 +37,14 @@ class UITestsAppCoordinator: Coordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func mockScreens() -> [MockScreen] {
|
private func mockScreens() -> [MockScreen] {
|
||||||
[MockScreen(id: "Login screen", coordinator: LoginScreenCoordinator(parameters: .init())),
|
[
|
||||||
MockScreen(id: "Simple Screen - Regular", coordinator: TemplateSimpleScreenCoordinator(parameters: .init(promptType: .regular))),
|
MockScreen(id: "Login screen", coordinator: LoginScreenCoordinator(parameters: .init())),
|
||||||
MockScreen(id: "Simple Screen - Upgrade", coordinator: TemplateSimpleScreenCoordinator(parameters: .init(promptType: .upgrade)))]
|
MockScreen(id: "Simple Screen - Regular", coordinator: TemplateSimpleScreenCoordinator(parameters: .init(promptType: .regular))),
|
||||||
|
MockScreen(id: "Simple Screen - Upgrade", coordinator: TemplateSimpleScreenCoordinator(parameters: .init(promptType: .upgrade))),
|
||||||
|
MockScreen(id: "Settings screen", coordinator: SettingsCoordinator(parameters: .init(navigationRouter: NavigationRouter(navigationController: UINavigationController()), bugReportService: MockBugReportService()))),
|
||||||
|
MockScreen(id: "Bug report screen", coordinator: BugReportCoordinator(parameters: .init(bugReportService: MockBugReportService(), screenshot: nil))),
|
||||||
|
MockScreen(id: "Bug report screen with screenshot", coordinator: BugReportCoordinator(parameters: .init(bugReportService: MockBugReportService(), screenshot: Asset.Images.appLogo.image)))
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
//
|
//
|
||||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||||
//
|
//
|
||||||
|
#import "MXLogger.h"
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ targets:
|
|||||||
- package: Introspect
|
- package: Introspect
|
||||||
- package: SwiftyBeaver
|
- package: SwiftyBeaver
|
||||||
- package: SwiftState
|
- package: SwiftState
|
||||||
|
- package: GZIP
|
||||||
|
- package: Sentry
|
||||||
|
|
||||||
sources:
|
sources:
|
||||||
- path: ../Sources
|
- path: ../Sources
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ struct TemplateSimpleScreen: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
VStack {
|
VStack {
|
||||||
ScrollView(showsIndicators: false) {
|
ScrollView {
|
||||||
mainContent
|
mainContent
|
||||||
.padding(.top, 50)
|
.padding(.top, 50)
|
||||||
.padding(.horizontal, horizontalPadding)
|
.padding(.horizontal, horizontalPadding)
|
||||||
|
|||||||
@@ -24,3 +24,10 @@ strings:
|
|||||||
params:
|
params:
|
||||||
enumName: ElementL10n
|
enumName: ElementL10n
|
||||||
publicAccess: true
|
publicAccess: true
|
||||||
|
plist:
|
||||||
|
inputs: SupportingFiles/Info.plist
|
||||||
|
outputs:
|
||||||
|
templateName: runtime-swift5
|
||||||
|
output: InfoPlist.swift
|
||||||
|
params:
|
||||||
|
enumName: ElementInfoPlist
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 XCTest
|
||||||
|
import ElementX
|
||||||
|
|
||||||
|
class BugReportUITests: XCTestCase {
|
||||||
|
|
||||||
|
func testInitialStateComponents() {
|
||||||
|
let app = Application.launch()
|
||||||
|
app.goToScreenWithIdentifier("Bug report screen")
|
||||||
|
|
||||||
|
XCTAssert(app.navigationBars["Bug report"].exists)
|
||||||
|
XCTAssert(app.staticTexts["reportBugDescription"].exists)
|
||||||
|
XCTAssert(app.staticTexts["sendLogsDescription"].exists)
|
||||||
|
XCTAssert(app.textViews["reportTextView"].exists)
|
||||||
|
let sendingLogsToggle = app.switches["sendLogsToggle"]
|
||||||
|
XCTAssert(sendingLogsToggle.exists)
|
||||||
|
XCTAssert(sendingLogsToggle.isOn)
|
||||||
|
XCTAssert(app.staticTexts["sendLogsText"].exists)
|
||||||
|
let sendButton = app.buttons["sendButton"]
|
||||||
|
XCTAssert(sendButton.exists)
|
||||||
|
XCTAssertFalse(sendButton.isEnabled)
|
||||||
|
XCTAssertFalse(app.images["screenshotImage"].exists)
|
||||||
|
XCTAssertFalse(app.buttons["removeScreenshotButton"].exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testToggleSendingLogs() {
|
||||||
|
let app = Application.launch()
|
||||||
|
app.goToScreenWithIdentifier("Bug report screen")
|
||||||
|
|
||||||
|
app.switches["sendLogsToggle"].tap()
|
||||||
|
|
||||||
|
let sendingLogsToggle = app.switches["sendLogsToggle"]
|
||||||
|
XCTAssert(sendingLogsToggle.exists)
|
||||||
|
XCTAssertFalse(sendingLogsToggle.isOn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReportText() {
|
||||||
|
let app = Application.launch()
|
||||||
|
app.goToScreenWithIdentifier("Bug report screen")
|
||||||
|
|
||||||
|
// type 4 chars
|
||||||
|
app.textViews["reportTextView"].tap()
|
||||||
|
app.textViews["reportTextView"].typeText("Test")
|
||||||
|
XCTAssertFalse(app.buttons["sendButton"].isEnabled)
|
||||||
|
|
||||||
|
// type one more char and see the button enabled
|
||||||
|
app.textViews["reportTextView"].tap()
|
||||||
|
app.textViews["reportTextView"].typeText("-")
|
||||||
|
XCTAssert(app.buttons["sendButton"].isEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInitialStateComponentsWithScreenshot() {
|
||||||
|
let app = Application.launch()
|
||||||
|
app.goToScreenWithIdentifier("Bug report screen with screenshot")
|
||||||
|
|
||||||
|
XCTAssert(app.navigationBars["Bug report"].exists)
|
||||||
|
XCTAssert(app.staticTexts["reportBugDescription"].exists)
|
||||||
|
XCTAssert(app.staticTexts["sendLogsDescription"].exists)
|
||||||
|
|
||||||
|
XCTAssert(app.textViews["reportTextView"].exists)
|
||||||
|
let sendingLogsToggle = app.switches["sendLogsToggle"]
|
||||||
|
XCTAssert(sendingLogsToggle.exists)
|
||||||
|
XCTAssert(sendingLogsToggle.isOn)
|
||||||
|
XCTAssert(app.staticTexts["sendLogsText"].exists)
|
||||||
|
let sendButton = app.buttons["sendButton"]
|
||||||
|
XCTAssert(sendButton.exists)
|
||||||
|
XCTAssertFalse(sendButton.isEnabled)
|
||||||
|
XCTAssert(app.images["screenshotImage"].exists)
|
||||||
|
XCTAssert(app.buttons["removeScreenshotButton"].exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension XCUIElement {
|
||||||
|
var isOn: Bool {
|
||||||
|
(value as? String) == "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 XCTest
|
||||||
|
import ElementX
|
||||||
|
|
||||||
|
class SettingsUITests: XCTestCase {
|
||||||
|
|
||||||
|
func testInitialStateComponents() {
|
||||||
|
let app = Application.launch()
|
||||||
|
app.goToScreenWithIdentifier("Settings screen")
|
||||||
|
|
||||||
|
XCTAssert(app.navigationBars["Settings"].exists)
|
||||||
|
XCTAssert(app.buttons["reportBugButton"].exists)
|
||||||
|
XCTAssert(app.buttons["crashButton"].exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,6 +21,10 @@ targets:
|
|||||||
linkType: static
|
linkType: static
|
||||||
- package: SwiftState
|
- package: SwiftState
|
||||||
linkType: static
|
linkType: static
|
||||||
|
- package: GZIP
|
||||||
|
linkType: static
|
||||||
|
- package: Sentry
|
||||||
|
linkType: static
|
||||||
|
|
||||||
info:
|
info:
|
||||||
path: ../SupportingFiles/Info.plist
|
path: ../SupportingFiles/Info.plist
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 191 KiB |
@@ -0,0 +1,90 @@
|
|||||||
|
//
|
||||||
|
// BugReportServiceTests.swift
|
||||||
|
// UnitTests
|
||||||
|
//
|
||||||
|
// Created by Ismail on 31.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
@testable import ElementX
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class BugReportServiceTests: XCTestCase {
|
||||||
|
|
||||||
|
let bugReportService = MockBugReportService()
|
||||||
|
|
||||||
|
func testInitialStateWithMockService() {
|
||||||
|
XCTAssertFalse(bugReportService.crashedLastRun)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSubmitBugReportWithMockService() async throws {
|
||||||
|
let result = try await bugReportService.submitBugReport(text: "i cannot send message",
|
||||||
|
includeLogs: true,
|
||||||
|
includeCrashLog: true,
|
||||||
|
githubLabels: [],
|
||||||
|
files: [])
|
||||||
|
XCTAssertFalse(result.reportUrl.isEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInitialStateWithRealService() throws {
|
||||||
|
let service = try BugReportService(withBaseUrlString: "https://www.example.com",
|
||||||
|
sentryEndpoint: "mock_sentry_dsn",
|
||||||
|
applicationId: "mock_app_id",
|
||||||
|
session: .mock)
|
||||||
|
XCTAssertFalse(service.crashedLastRun)
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor func testSubmitBugReportWithRealService() async throws {
|
||||||
|
let service = try BugReportService(withBaseUrlString: "https://www.example.com",
|
||||||
|
sentryEndpoint: "mock_sentry_dsn",
|
||||||
|
applicationId: "mock_app_id",
|
||||||
|
session: .mock)
|
||||||
|
|
||||||
|
let result = try await service.submitBugReport(text: "i cannot send message",
|
||||||
|
includeLogs: true,
|
||||||
|
includeCrashLog: true,
|
||||||
|
githubLabels: [],
|
||||||
|
files: [])
|
||||||
|
|
||||||
|
XCTAssertEqual(result.reportUrl, "https://example.com/123")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MockURLProtocol: URLProtocol {
|
||||||
|
|
||||||
|
override func startLoading() {
|
||||||
|
let response = "{\"report_url\":\"https://example.com/123\"}"
|
||||||
|
if let data = response.data(using: .utf8) {
|
||||||
|
let urlResponse = URLResponse()
|
||||||
|
client?.urlProtocol(self, didReceive: urlResponse, cacheStoragePolicy: .allowedInMemoryOnly)
|
||||||
|
client?.urlProtocol(self, didLoad: data)
|
||||||
|
client?.urlProtocolDidFinishLoading(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func stopLoading() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
override class func canInit(with request: URLRequest) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension URLSession {
|
||||||
|
|
||||||
|
static var mock: URLSession {
|
||||||
|
let configuration = URLSessionConfiguration.default
|
||||||
|
configuration.protocolClasses = [MockURLProtocol.self] + (configuration.protocolClasses ?? [])
|
||||||
|
let result = URLSession(configuration: configuration)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 XCTest
|
||||||
|
|
||||||
|
@testable import ElementX
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class BugReportViewModelTests: XCTestCase {
|
||||||
|
|
||||||
|
func testInitialState() {
|
||||||
|
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: nil)
|
||||||
|
let context = viewModel.context
|
||||||
|
|
||||||
|
XCTAssertEqual(context.reportText, "")
|
||||||
|
XCTAssertNil(context.viewState.screenshot)
|
||||||
|
XCTAssertTrue(context.sendingLogsEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testToggleSendingLogs() async throws {
|
||||||
|
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: nil)
|
||||||
|
let context = viewModel.context
|
||||||
|
|
||||||
|
context.send(viewAction: .toggleSendLogs)
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssertFalse(context.sendingLogsEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testClearScreenshot() async throws {
|
||||||
|
let viewModel = BugReportViewModel(bugReportService: MockBugReportService(), screenshot: UIImage.actions)
|
||||||
|
let context = viewModel.context
|
||||||
|
|
||||||
|
context.send(viewAction: .removeScreenshot)
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssertNil(context.viewState.screenshot)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,11 +19,65 @@ import XCTest
|
|||||||
@testable import ElementX
|
@testable import ElementX
|
||||||
|
|
||||||
class HomeScreenViewModelTests: XCTestCase {
|
class HomeScreenViewModelTests: XCTestCase {
|
||||||
override func setUpWithError() throws {
|
|
||||||
|
|
||||||
|
var viewModel: HomeScreenViewModelProtocol!
|
||||||
|
var context: HomeScreenViewModelType.Context!
|
||||||
|
|
||||||
|
@MainActor override func setUpWithError() throws {
|
||||||
|
viewModel = HomeScreenViewModel(attributedStringBuilder: AttributedStringBuilder())
|
||||||
|
context = viewModel.context
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInitialState() {
|
@MainActor func testLogout() async throws {
|
||||||
|
var correctResult = false
|
||||||
|
viewModel.callback = { result in
|
||||||
|
switch result {
|
||||||
|
case .logout:
|
||||||
|
correctResult = true
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.send(viewAction: .logout)
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssert(correctResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainActor func testSelectRoom() async throws {
|
||||||
|
let mockRoomId = "mock_room_id"
|
||||||
|
var correctResult = false
|
||||||
|
var selectedRoomId = ""
|
||||||
|
viewModel.callback = { result in
|
||||||
|
switch result {
|
||||||
|
case .selectRoom(let roomId):
|
||||||
|
correctResult = true
|
||||||
|
selectedRoomId = roomId
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.send(viewAction: .selectRoom(roomIdentifier: mockRoomId))
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssert(correctResult)
|
||||||
|
XCTAssertEqual(mockRoomId, selectedRoomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor func testTapUserAvatar() async throws {
|
||||||
|
var correctResult = false
|
||||||
|
viewModel.callback = { result in
|
||||||
|
switch result {
|
||||||
|
case .tapUserAvatar:
|
||||||
|
correctResult = true
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.send(viewAction: .tapUserAvatar)
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssert(correctResult)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// ImageExtensionTests.swift
|
||||||
|
// UnitTests
|
||||||
|
//
|
||||||
|
// Created by Ismail on 31.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import ElementX
|
||||||
|
|
||||||
|
enum ImageAnonymizerTestsError: String, Error {
|
||||||
|
case screenshotNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImageAnonymizerTests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDownWithError() throws {
|
||||||
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
func sampleScreenshot() throws -> UIImage {
|
||||||
|
let bundle = Bundle(for: self.classForCoder)
|
||||||
|
guard let path = bundle.path(forResource: "sample_screenshot", ofType: "png"),
|
||||||
|
let image = UIImage(contentsOfFile: path) else {
|
||||||
|
throw ImageAnonymizerTestsError.screenshotNotFound
|
||||||
|
}
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
|
||||||
|
func testImageAnonymizationConfidenceLevel() async throws {
|
||||||
|
let image = try sampleScreenshot()
|
||||||
|
|
||||||
|
let anonymized5 = try await ImageAnonymizer.anonymizedImage(from: image)
|
||||||
|
let anonymized1 = try await ImageAnonymizer.anonymizedImage(from: image, confidenceLevel: 0.1)
|
||||||
|
|
||||||
|
// comparing colors is a complicated process, just compare images for now
|
||||||
|
XCTAssertNotEqual(image, anonymized5)
|
||||||
|
XCTAssertNotEqual(anonymized1, anonymized5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testImageAnonymizationFillColor() async throws {
|
||||||
|
let image = try sampleScreenshot()
|
||||||
|
|
||||||
|
let anonymizedRed = try await ImageAnonymizer.anonymizedImage(from: image)
|
||||||
|
let anonymizedBlue = try await ImageAnonymizer.anonymizedImage(from: image, fillColor: .blue)
|
||||||
|
|
||||||
|
// comparing colors is a complicated process, just compare images for now
|
||||||
|
XCTAssertNotEqual(image, anonymizedRed)
|
||||||
|
XCTAssertNotEqual(anonymizedBlue, anonymizedRed)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
//
|
||||||
|
// LoggingTests.swift
|
||||||
|
// UnitTests
|
||||||
|
//
|
||||||
|
// Created by Ismail on 31.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import ElementX
|
||||||
|
|
||||||
|
class LoggingTests: XCTestCase {
|
||||||
|
|
||||||
|
private enum Constants {
|
||||||
|
static let genericFailure = "Test failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDownWithError() throws {
|
||||||
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFileLogging() throws {
|
||||||
|
MXLogger.deleteLogFiles()
|
||||||
|
guard let logFiles = MXLogger.logFiles() else {
|
||||||
|
XCTFail(Constants.genericFailure)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
XCTAssertTrue(logFiles.isEmpty)
|
||||||
|
|
||||||
|
let log = UUID().uuidString
|
||||||
|
|
||||||
|
let configuration = MXLogConfiguration()
|
||||||
|
configuration.redirectLogsToFiles = true
|
||||||
|
MXLog.configure(configuration)
|
||||||
|
MXLog.debug(log)
|
||||||
|
guard let logFile = MXLogger.logFiles().first else {
|
||||||
|
XCTFail(Constants.genericFailure)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = try String(contentsOfFile: logFile)
|
||||||
|
XCTAssert(content.contains(log))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLogLevels() throws {
|
||||||
|
MXLogger.deleteLogFiles()
|
||||||
|
guard let logFiles = MXLogger.logFiles() else {
|
||||||
|
XCTFail(Constants.genericFailure)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
XCTAssert(logFiles.isEmpty)
|
||||||
|
|
||||||
|
let log = UUID().uuidString
|
||||||
|
|
||||||
|
let configuration = MXLogConfiguration()
|
||||||
|
configuration.logLevel = .error
|
||||||
|
configuration.redirectLogsToFiles = true
|
||||||
|
MXLog.configure(configuration)
|
||||||
|
MXLog.debug(log)
|
||||||
|
guard let logFile = MXLogger.logFiles().first else {
|
||||||
|
XCTFail(Constants.genericFailure)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = try String(contentsOfFile: logFile)
|
||||||
|
XCTAssertFalse(content.contains(log))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSubLogName() {
|
||||||
|
MXLogger.deleteLogFiles()
|
||||||
|
guard let logFiles = MXLogger.logFiles() else {
|
||||||
|
XCTFail(Constants.genericFailure)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
XCTAssert(logFiles.isEmpty)
|
||||||
|
|
||||||
|
let subLogName = "nse"
|
||||||
|
|
||||||
|
let configuration = MXLogConfiguration()
|
||||||
|
configuration.subLogName = subLogName
|
||||||
|
configuration.redirectLogsToFiles = true
|
||||||
|
MXLog.configure(configuration)
|
||||||
|
MXLog.debug(UUID().uuidString)
|
||||||
|
guard let logFile = MXLogger.logFiles().first else {
|
||||||
|
XCTFail(Constants.genericFailure)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertTrue(logFile.contains(subLogName))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
//
|
||||||
|
// ScreenshotDetectorTests.swift
|
||||||
|
// UnitTests
|
||||||
|
//
|
||||||
|
// Created by Ismail on 31.05.2022.
|
||||||
|
// Copyright © 2022 element.io. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
@testable import ElementX
|
||||||
|
import XCTest
|
||||||
|
import Photos
|
||||||
|
|
||||||
|
class ScreenshotDetectorTests: XCTestCase {
|
||||||
|
|
||||||
|
@MainActor func testDetection() async {
|
||||||
|
async { expectation in
|
||||||
|
let detector = ScreenshotDetector()
|
||||||
|
// disable auto request authorization
|
||||||
|
detector.autoRequestPHAuthorization = false
|
||||||
|
detector.callback = { image, error in
|
||||||
|
|
||||||
|
if PHPhotoLibrary.authorizationStatus(for: .readWrite) == .authorized {
|
||||||
|
// if Photos already authorized on the simulator
|
||||||
|
|
||||||
|
// we should get an image
|
||||||
|
XCTAssertNotNil(image)
|
||||||
|
|
||||||
|
// we should not get an error
|
||||||
|
XCTAssertNil(error)
|
||||||
|
} else {
|
||||||
|
// otherwise we should not get an image
|
||||||
|
XCTAssertNil(image)
|
||||||
|
|
||||||
|
// and get an error
|
||||||
|
guard let error = error else {
|
||||||
|
XCTFail("Should get an error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch error {
|
||||||
|
case ScreenshotDetectorError.notAuthorized:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
XCTFail("Unknown error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expectation.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: UIApplication.userDidTakeScreenshotNotification, object: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func async(_ timeout: TimeInterval = 0.5, _ block: @escaping (XCTestExpectation) -> Void) {
|
||||||
|
let waiter = XCTWaiter()
|
||||||
|
let expectation = XCTestExpectation(description: "Async operation expectation")
|
||||||
|
block(expectation)
|
||||||
|
waiter.wait(for: [expectation], timeout: timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 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 XCTest
|
||||||
|
|
||||||
|
@testable import ElementX
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class SettingsViewModelTests: XCTestCase {
|
||||||
|
|
||||||
|
var viewModel: SettingsViewModelProtocol!
|
||||||
|
var context: SettingsViewModelType.Context!
|
||||||
|
|
||||||
|
@MainActor override func setUpWithError() throws {
|
||||||
|
viewModel = SettingsViewModel()
|
||||||
|
context = viewModel.context
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInitialState() {
|
||||||
|
XCTAssert(context.viewState.crashButtonVisible)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReportBug() async throws {
|
||||||
|
var correctResult = false
|
||||||
|
viewModel.callback = { result in
|
||||||
|
correctResult = result == .reportBug
|
||||||
|
}
|
||||||
|
|
||||||
|
context.send(viewAction: .reportBug)
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssert(correctResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCrash() async throws {
|
||||||
|
var correctResult = false
|
||||||
|
viewModel.callback = { result in
|
||||||
|
correctResult = result == .crash
|
||||||
|
}
|
||||||
|
|
||||||
|
context.send(viewAction: .crash)
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssert(correctResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,3 +22,4 @@ targets:
|
|||||||
- path: ../Sources
|
- path: ../Sources
|
||||||
- path: ../SupportingFiles
|
- path: ../SupportingFiles
|
||||||
- path: ../../Tools/Scripts/Templates/SimpleScreenExample/Tests/Unit
|
- path: ../../Tools/Scripts/Templates/SimpleScreenExample/Tests/Unit
|
||||||
|
- path: ../Resources
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Implement rageshake service.
|
||||||
@@ -51,3 +51,9 @@ packages:
|
|||||||
SwiftState:
|
SwiftState:
|
||||||
url: https://github.com/ReactKit/SwiftState
|
url: https://github.com/ReactKit/SwiftState
|
||||||
majorVersion: 6.0.0
|
majorVersion: 6.0.0
|
||||||
|
GZIP:
|
||||||
|
url: https://github.com/nicklockwood/GZIP
|
||||||
|
majorVersion: 1.3.0
|
||||||
|
Sentry:
|
||||||
|
url: https://github.com/getsentry/sentry-cocoa.git
|
||||||
|
majorVersion: 7.15.0
|
||||||
|
|||||||
Reference in New Issue
Block a user