diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 79afba68fd..95670ac009 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -56,6 +56,8 @@ 165A883C29998EC779465068 /* SoftLogoutViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC38904A9663F7FAFD47457 /* SoftLogoutViewModelProtocol.swift */; }; 1702981A8085BE4FB0EC001B /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33116993D54FADC0C721C1F /* Application.swift */; }; 172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */; }; + 1833A04F2953249E009AA2AE /* ReadMarkerRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1833A04E2953249E009AA2AE /* ReadMarkerRoomTimelineView.swift */; }; + 1833A051295324B8009AA2AE /* ReadMarkerRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1833A050295324B8009AA2AE /* ReadMarkerRoomTimelineItem.swift */; }; 187E18F21EF4DA244E436E58 /* BugReportViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28959C7DB36C7688A01D4045 /* BugReportViewModelProtocol.swift */; }; 191161FE9E0DA89704301F37 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; }; 1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; }; @@ -564,7 +566,6 @@ 1215A4FC53D2319E81AE8970 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; 124D85E85505B6B81845235F /* fy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fy; path = fy.lproj/Localizable.stringsdict; sourceTree = ""; }; - 12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageAnonymizer.swift; sourceTree = ""; }; 130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = ""; }; 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; 1423AB065857FA546444DB15 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = ""; }; @@ -574,6 +575,8 @@ 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalyticsClient.swift; sourceTree = ""; }; 1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationTests.swift; sourceTree = ""; }; 179423E34EE846E048E49CBF /* MediaSourceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaSourceProxy.swift; sourceTree = ""; }; + 1833A04E2953249E009AA2AE /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = ""; }; + 1833A050295324B8009AA2AE /* ReadMarkerRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineItem.swift; sourceTree = ""; }; 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = ""; }; 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxy.swift; sourceTree = ""; }; 18FE0CDF1FFA92EA7EE17B0B /* RoomTimelineControllerFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerFactoryProtocol.swift; sourceTree = ""; }; @@ -792,7 +795,7 @@ 8D6094DEAAEB388E1AE118C6 /* MockRoomTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineProvider.swift; sourceTree = ""; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = ""; }; - 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = ""; }; + 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = ""; }; 8ED2D2F6A137A95EA50413BE /* UserNotificationControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationControllerProtocol.swift; sourceTree = ""; }; 8F7D42E66E939B709C1EC390 /* MockRoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomSummaryProvider.swift; sourceTree = ""; }; 8FC26871038FB0E4AAE22605 /* apple_emojis_data.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = apple_emojis_data.json; sourceTree = ""; }; @@ -1002,7 +1005,7 @@ EBE5502760CF6CA2D7201883 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ja; path = ja.lproj/Localizable.stringsdict; sourceTree = ""; }; ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = ""; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = ""; }; - ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = ""; }; + ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = ""; }; EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = ""; }; EDB6E40BAD4504D899FAAC9A /* TemplateViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateViewModel.swift; sourceTree = ""; }; EE8BCD14EFED23459A43FDFF /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; @@ -1724,6 +1727,7 @@ A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */, F6A8C632CEF4600107792899 /* TextRoomTimelineItem.swift */, A4B5B19A10D3F7C2BC5315DF /* VideoRoomTimelineItem.swift */, + 1833A050295324B8009AA2AE /* ReadMarkerRoomTimelineItem.swift */, ); path = Items; sourceTree = ""; @@ -1802,6 +1806,18 @@ path = View; sourceTree = ""; }; + 7B29CA1D663299262BEADF24 /* RoomDetails */ = { + isa = PBXGroup; + children = ( + 813B198AE8833FD12E5A9C78 /* RoomDetailsCoordinator.swift */, + DEC031D32CED2CBE122E5038 /* RoomDetailsModels.swift */, + 91FB6F5ECCF51ECE98ACFEEC /* RoomDetailsViewModel.swift */, + 87B3A76EA6AB67910C11330F /* RoomDetailsViewModelProtocol.swift */, + 9A67E5629C207A43043FAF20 /* View */, + ); + path = RoomDetails; + sourceTree = ""; + }; 7DBC911559934065993A5FF4 /* NotificationManager */ = { isa = PBXGroup; children = ( @@ -1815,18 +1831,6 @@ path = NotificationManager; sourceTree = ""; }; - 7B29CA1D663299262BEADF24 /* RoomDetails */ = { - isa = PBXGroup; - children = ( - 813B198AE8833FD12E5A9C78 /* RoomDetailsCoordinator.swift */, - DEC031D32CED2CBE122E5038 /* RoomDetailsModels.swift */, - 91FB6F5ECCF51ECE98ACFEEC /* RoomDetailsViewModel.swift */, - 87B3A76EA6AB67910C11330F /* RoomDetailsViewModelProtocol.swift */, - 9A67E5629C207A43043FAF20 /* View */, - ); - path = RoomDetails; - sourceTree = ""; - }; 8039515BAA53B7C3275AC64A /* Client */ = { isa = PBXGroup; children = ( @@ -2134,6 +2138,7 @@ 0950733DD4BA83EEE752E259 /* PlaceholderAvatarImage.swift */, C8F2A7A4E3F5060F52ACFFB0 /* RedactedRoomTimelineView.swift */, 6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */, + 1833A04E2953249E009AA2AE /* ReadMarkerRoomTimelineView.swift */, F9E785D5137510481733A3E8 /* TextRoomTimelineView.swift */, 1941C8817E6B6971BA4415F5 /* VideoRoomTimelineView.swift */, ); @@ -2295,7 +2300,6 @@ 4009BE2E791C16AC6EE39A7E /* BugReport */, F5A65D1D3B83593598DC278D /* EmojiPickerScreen */, B442FCF47E0A6F28D7D50A4D /* FilePreview */, - FC26FB522EDED4965C5325F0 /* Folder */, B53CA9BECD3F97805E1432D0 /* HomeScreen */, 3F38EAC92E2281990E65DAF2 /* OnboardingScreen */, A448A3A8F764174C60CD0CA1 /* Other */, @@ -2379,13 +2383,6 @@ path = EmojiPickerScreen; sourceTree = ""; }; - FC26FB522EDED4965C5325F0 /* Folder */ = { - isa = PBXGroup; - children = ( - ); - path = Folder; - sourceTree = ""; - }; FCDF06BDB123505F0334B4F9 /* Timeline */ = { isa = PBXGroup; children = ( @@ -2934,6 +2931,7 @@ 38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */, B6DF6B6FA8734B70F9BF261E /* BlurHashDecode.swift in Sources */, A32517FB1CA0BBCE2BC75249 /* BugReportCoordinator.swift in Sources */, + 1833A04F2953249E009AA2AE /* ReadMarkerRoomTimelineView.swift in Sources */, 00F3059B1E0CFCA019710C3E /* BugReportModels.swift in Sources */, 3588F34D05B4D731A73214C6 /* BugReportScreen.swift in Sources */, 3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */, @@ -3142,6 +3140,7 @@ 43FD77998F33C32718C51450 /* TemplateCoordinator.swift in Sources */, 63C9AF0FB8278AF1C0388A0C /* TemplateModels.swift in Sources */, 1555A7643D85187D4851040C /* TemplateScreen.swift in Sources */, + 1833A051295324B8009AA2AE /* ReadMarkerRoomTimelineItem.swift in Sources */, 75EA4ABBFAA810AFF289D6F4 /* TemplateViewModel.swift in Sources */, 5F1FDE49DFD0C680386E48F9 /* TemplateViewModelProtocol.swift in Sources */, D85D4FA590305180B4A41795 /* Tests.swift in Sources */, @@ -3884,7 +3883,7 @@ repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = "1.0.22-alpha"; + version = "1.0.23-alpha"; }; }; 96495DD8554E2F39D3954354 /* XCRemoteSwiftPackageReference "posthog-ios" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f1ddcafd17..f06c4e3f3e 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -86,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-rust-components-swift", "state" : { - "revision" : "65d6f8a51367d5c411c1fec39402907f588fcd67", - "version" : "1.0.22-alpha" + "revision" : "f0144bd5faec80c8dbafac7686249893cff2de52", + "version" : "1.0.23-alpha" } }, { diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/ReadMarkerRoomTimelineView.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/ReadMarkerRoomTimelineView.swift new file mode 100644 index 0000000000..a80b5ea12e --- /dev/null +++ b/ElementX/Sources/Screens/RoomScreen/View/Timeline/ReadMarkerRoomTimelineView.swift @@ -0,0 +1,39 @@ +// +// Copyright 2022 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 SwiftUI + +struct ReadMarkerRoomTimelineView: View { + let timelineItem: ReadMarkerRoomTimelineItem + + var body: some View { + VStack { + Spacer(minLength: 4.0) + Divider() + .id(timelineItem.id) + .frame(maxWidth: .infinity) + .overlay(Color.element.accent) + } + } +} + +struct ReadMarkerRoomTimelineView_Previews: PreviewProvider { + static var previews: some View { + let item = ReadMarkerRoomTimelineItem(id: UUID().uuidString) + ReadMarkerRoomTimelineView(timelineItem: item) + } +} diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/SeparatorRoomTimelineView.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/SeparatorRoomTimelineView.swift index f4c42ae67b..869a9d82c8 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Timeline/SeparatorRoomTimelineView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Timeline/SeparatorRoomTimelineView.swift @@ -25,7 +25,7 @@ struct SeparatorRoomTimelineView: View { .font(.element.footnote) .foregroundColor(.element.secondaryContent) .id(timelineItem.id) - .padding(.vertical, 8) + .padding(.vertical, 24) .frame(maxWidth: .infinity) } } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift index 46a8f119ca..17e6d45a74 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift @@ -235,6 +235,22 @@ class RoomTimelineController: RoomTimelineControllerProtocol { case .event(let eventItem): newTimelineItems.append(timelineItemFactory.buildTimelineItemFor(eventItemProxy: eventItem, inGroupState: inGroupState)) + case .virtual(let virtualItem): + switch virtualItem { + case .dayDivider(let year, let month, let day): + // These components will be replaced by a timestamp in upcoming releases + let dateComponents = DateComponents(calendar: .current, year: Int(year), month: Int(month), day: Int(day)) + if let dateString = dateComponents.date?.formatted(date: .complete, time: .omitted) { + newTimelineItems.append(SeparatorRoomTimelineItem(id: UUID().uuidString, text: dateString)) + } else { + MXLog.error("Failed formatting separator date") + } + case .readMarker: + // Don't show the read marker if it's the last item in the timeline + if index != timelineProvider.itemsPublisher.value.indices.last { + newTimelineItems.append(ReadMarkerRoomTimelineItem(id: UUID().uuidString)) + } + } default: break } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/ReadMarkerRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/ReadMarkerRoomTimelineItem.swift new file mode 100644 index 0000000000..4226caea40 --- /dev/null +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/ReadMarkerRoomTimelineItem.swift @@ -0,0 +1,21 @@ +// +// Copyright 2022 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +struct ReadMarkerRoomTimelineItem: DecorationTimelineItemProtocol, Identifiable, Hashable { + let id: String +} diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift index b889d1fc86..6d47628d97 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift @@ -17,6 +17,7 @@ import Foundation struct RoomTimelineViewFactory: RoomTimelineViewFactoryProtocol { + // swiftlint:disable:next cyclomatic_complexity func buildTimelineViewFor(timelineItem: RoomTimelineItemProtocol) -> RoomTimelineViewProvider { switch timelineItem { case let item as TextRoomTimelineItem: @@ -37,6 +38,8 @@ struct RoomTimelineViewFactory: RoomTimelineViewFactoryProtocol { return .redacted(item) case let item as EncryptedRoomTimelineItem: return .encrypted(item) + case let item as ReadMarkerRoomTimelineItem: + return .readMarker(item) default: fatalError("Unknown timeline item") } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift index aac1cee6a8..c7831cb7b6 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift @@ -27,6 +27,7 @@ enum RoomTimelineViewProvider: Identifiable, Hashable { case notice(NoticeRoomTimelineItem) case redacted(RedactedRoomTimelineItem) case encrypted(EncryptedRoomTimelineItem) + case readMarker(ReadMarkerRoomTimelineItem) case backPaginationIndicator(Bool) var id: String { @@ -49,6 +50,8 @@ enum RoomTimelineViewProvider: Identifiable, Hashable { return item.id case .encrypted(let item): return item.id + case .readMarker(let item): + return item.id case .backPaginationIndicator: return "BackpaginationLoadingIndicator" } @@ -76,6 +79,8 @@ extension RoomTimelineViewProvider: View { RedactedRoomTimelineView(timelineItem: item) case .encrypted(let item): EncryptedRoomTimelineView(timelineItem: item) + case .readMarker(let item): + ReadMarkerRoomTimelineView(timelineItem: item) case .backPaginationIndicator(let isBackPaginating): ProgressView() .frame(maxWidth: .infinity) diff --git a/changelog.d/pr-383.feature b/changelog.d/pr-383.feature new file mode 100644 index 0000000000..722f9adbe2 --- /dev/null +++ b/changelog.d/pr-383.feature @@ -0,0 +1 @@ +Added timeline day separators and read markers \ No newline at end of file diff --git a/project.yml b/project.yml index 5a4a64e10d..a6ec0f7103 100644 --- a/project.yml +++ b/project.yml @@ -40,7 +40,7 @@ include: packages: MatrixRustSDK: url: https://github.com/matrix-org/matrix-rust-components-swift - exactVersion: 1.0.22-alpha + exactVersion: 1.0.23-alpha # path: ../matrix-rust-sdk DesignKit: path: ./