From 664abefbba87933be261ebeef54bd015113b9058 Mon Sep 17 00:00:00 2001 From: Finn Behrens Date: Fri, 6 Aug 2021 21:02:26 +0200 Subject: [PATCH] Split RecentRoomsView (macOS/iOS) --- Mio/Conversations/RecentRoomsView.swift | 71 ++++++++ Nio.xcodeproj/project.pbxproj | 26 ++- .../RecentRoomsContainerView.swift | 146 ++++++++++++++++ Nio/Conversations/RecentRoomsView.swift | 163 +----------------- Nio/NewConversation/NewConversationView.swift | 6 +- 5 files changed, 245 insertions(+), 167 deletions(-) create mode 100644 Mio/Conversations/RecentRoomsView.swift create mode 100644 Nio/Conversations/RecentRoomsContainerView.swift diff --git a/Mio/Conversations/RecentRoomsView.swift b/Mio/Conversations/RecentRoomsView.swift new file mode 100644 index 00000000..6dbef653 --- /dev/null +++ b/Mio/Conversations/RecentRoomsView.swift @@ -0,0 +1,71 @@ +// +// RecentRoomViews.swift +// RecentRoomViews +// +// Created by Finn Behrens on 06.08.21. +// Copyright © 2021 Kilian Koeltzsch. All rights reserved. +// + +import SwiftUI +import MatrixSDK + +import NioKit + +struct RecentRoomsView: View { + @EnvironmentObject var store: AccountStore + + @Binding var selectedNavigationItem: SelectedNavigationItem? + @Binding var selectedRoomId: ObjectIdentifier? + + let rooms: [NIORoom] + + private var joinedRooms: [NIORoom] { + rooms.filter {$0.room.summary.membership == .join} + } + + private var invitedRooms: [NIORoom] { + rooms.filter {$0.room.summary.membership == .invite} + } + + + var body: some View { + NavigationView { + List { + if !invitedRooms.isEmpty { + RoomsListSection( + sectionHeader: L10n.RecentRooms.PendingInvitations.header, + rooms: invitedRooms, + onLeaveAlertTitle: L10n.RecentRooms.PendingInvitations.Leave.alertTitle, + selectedRoomId: $selectedRoomId + ) + } + + RoomsListSection( + sectionHeader: invitedRooms.isEmpty ? nil : L10n.RecentRooms.Rooms.header , + rooms: joinedRooms, + onLeaveAlertTitle: L10n.RecentRooms.Leave.alertTitle, + selectedRoomId: $selectedRoomId + ) + + } + .listStyle(SidebarListStyle()) + .navigationTitle("Mio") + .frame(minWidth: Style.minSidebarWidth) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button(action: { self.selectedNavigationItem = .newConversation }) { + Label(L10n.RecentRooms.AccessibilityLabel.newConversation, + systemImage: SFSymbol.newConversation.rawValue) + } + } + } + } + } +} + +struct RecentRoomViews_Previews: PreviewProvider { + static var previews: some View { + //RecentRoomsView() + Text("TODO") + } +} diff --git a/Nio.xcodeproj/project.pbxproj b/Nio.xcodeproj/project.pbxproj index 8d974bd0..09909d37 100644 --- a/Nio.xcodeproj/project.pbxproj +++ b/Nio.xcodeproj/project.pbxproj @@ -72,6 +72,9 @@ 955A0D4726BC1E6C0027D188 /* MXRestClient+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A0D4526BC1E6C0027D188 /* MXRestClient+Async.swift */; }; 955A0D4926BC1EE80027D188 /* MXRoom+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A0D4826BC1EE80027D188 /* MXRoom+Async.swift */; }; 955A0D4A26BC1EE80027D188 /* MXRoom+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A0D4826BC1EE80027D188 /* MXRoom+Async.swift */; }; + 95AF0C0526BD9AA800AF707E /* RecentRoomsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AF0C0426BD9AA800AF707E /* RecentRoomsView.swift */; }; + 95AF0C0726BD9B4A00AF707E /* RecentRoomsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AF0C0626BD9B4A00AF707E /* RecentRoomsContainerView.swift */; }; + 95AF0C0826BD9B4A00AF707E /* RecentRoomsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AF0C0626BD9B4A00AF707E /* RecentRoomsContainerView.swift */; }; A51BF8CE254C2FE5000FB0A4 /* NioApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BF8CD254C2FE5000FB0A4 /* NioApp.swift */; }; A51F762C25D6E9950061B4A4 /* MessageTextViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51F762B25D6E9950061B4A4 /* MessageTextViewWrapper.swift */; }; A56D4FDE267E6CA300D0F1E8 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = A56D4FDD267E6CA300D0F1E8 /* SwiftyBeaver */; }; @@ -127,7 +130,6 @@ E843F30925F2781800B0F33B /* MXURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3984654423B7ECBA006C173B /* MXURL.swift */; }; E843F30A25F2781800B0F33B /* Formatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392389932388899200B2E1DF /* Formatter.swift */; }; E843F30B25F2781B00B0F33B /* RoomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C93208238553E4004449E1 /* RoomView.swift */; }; - E843F30C25F2781B00B0F33B /* RecentRoomsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C932062384BB13004449E1 /* RecentRoomsView.swift */; }; E843F30D25F2781B00B0F33B /* RoomListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3923898E2388707E00B2E1DF /* RoomListItemView.swift */; }; E843F30E25F2781F00B0F33B /* EventContextMenuModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392221AF243A6F8E004D8794 /* EventContextMenuModel.swift */; }; E843F30F25F2782000B0F33B /* ReactionPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3922219F2437285B004D8794 /* ReactionPicker.swift */; }; @@ -377,6 +379,8 @@ 955A0D4226BC1E2C0027D188 /* MXAutoDiscovery+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXAutoDiscovery+Async.swift"; sourceTree = ""; }; 955A0D4526BC1E6C0027D188 /* MXRestClient+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXRestClient+Async.swift"; sourceTree = ""; }; 955A0D4826BC1EE80027D188 /* MXRoom+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXRoom+Async.swift"; sourceTree = ""; }; + 95AF0C0426BD9AA800AF707E /* RecentRoomsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentRoomsView.swift; sourceTree = ""; }; + 95AF0C0626BD9B4A00AF707E /* RecentRoomsContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentRoomsContainerView.swift; sourceTree = ""; }; A51BF8CD254C2FE5000FB0A4 /* NioApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NioApp.swift; sourceTree = ""; }; A51F762B25D6E9950061B4A4 /* MessageTextViewWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTextViewWrapper.swift; sourceTree = ""; }; CAAF5BF72478696F006FDC33 /* UITextViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITextViewWrapper.swift; sourceTree = ""; }; @@ -639,11 +643,11 @@ children = ( 4BD3D29424951F150031846F /* Configs */, 39C931DB2384328A004449E1 /* Nio */, - 393411CF239087D2003B49B8 /* NioTests */, - CADF662E24614D2300F5063F /* NioKit */, - CADF663B24614D2300F5063F /* NioKitTests */, 4BFEFD7D246F414D00CCF4A0 /* NioShareExtension */, E843F2DB25F2748200B0F33B /* Mio */, + CADF662E24614D2300F5063F /* NioKit */, + CADF663B24614D2300F5063F /* NioKitTests */, + 393411CF239087D2003B49B8 /* NioTests */, 39C931DA2384328A004449E1 /* Products */, A58352AA25A667B300533363 /* Frameworks */, ); @@ -717,6 +721,7 @@ 39C9320A23856033004449E1 /* MessageComposerView.swift */, 39B834BF243FC42000AE1EA0 /* TypingIndicatorView.swift */, 3907AB482393FE0E00B25DE9 /* Event Views */, + 95AF0C0626BD9B4A00AF707E /* RecentRoomsContainerView.swift */, ); path = Conversations; sourceTree = ""; @@ -791,6 +796,14 @@ path = NioShareExtension; sourceTree = ""; }; + 95AF0C0326BD9A9700AF707E /* Conversations */ = { + isa = PBXGroup; + children = ( + 95AF0C0426BD9AA800AF707E /* RecentRoomsView.swift */, + ); + path = Conversations; + sourceTree = ""; + }; A58352AA25A667B300533363 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -882,6 +895,7 @@ E843F2DB25F2748200B0F33B /* Mio */ = { isa = PBXGroup; children = ( + 95AF0C0326BD9A9700AF707E /* Conversations */, E843F2E025F2748300B0F33B /* Assets.xcassets */, E843F2E525F2748300B0F33B /* Info.plist */, E843F2E625F2748300B0F33B /* Mio.entitlements */, @@ -1283,6 +1297,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 95AF0C0726BD9B4A00AF707E /* RecentRoomsContainerView.swift in Sources */, 39C9320B23856033004449E1 /* MessageComposerView.swift in Sources */, CAC46D5923A272D10079C24F /* BorderedMessageView.swift in Sources */, 39B834C0243FC42000AE1EA0 /* TypingIndicatorView.swift in Sources */, @@ -1389,9 +1404,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 95AF0C0826BD9B4A00AF707E /* RecentRoomsContainerView.swift in Sources */, E843F31E25F2782E00B0F33B /* RoomMemberEventView.swift in Sources */, - E843F30C25F2781B00B0F33B /* RecentRoomsView.swift in Sources */, E843F30E25F2781F00B0F33B /* EventContextMenuModel.swift in Sources */, + 95AF0C0526BD9AA800AF707E /* RecentRoomsView.swift in Sources */, E843F30425F2781400B0F33B /* ReverseList.swift in Sources */, E843F32825F2783900B0F33B /* String+Extensions.swift in Sources */, E843F31525F2782700B0F33B /* ReactionsListItemView.swift in Sources */, diff --git a/Nio/Conversations/RecentRoomsContainerView.swift b/Nio/Conversations/RecentRoomsContainerView.swift new file mode 100644 index 00000000..a81a6c59 --- /dev/null +++ b/Nio/Conversations/RecentRoomsContainerView.swift @@ -0,0 +1,146 @@ +// +// RecentRoomsContainerView.swift +// RecentRoomsContainerView +// +// Created by Finn Behrens on 06.08.21. +// Copyright © 2021 Kilian Koeltzsch. All rights reserved. +// + +import SwiftUI +import MatrixSDK + +import NioKit + +struct RecentRoomsContainerView: View { + @EnvironmentObject var store: AccountStore + @AppStorage("accentColor") var accentColor: Color = .purple + + @State private var selectedNavigationItem: SelectedNavigationItem? + @State private var selectedRoomId: ObjectIdentifier? + + private func autoselectFirstRoom() { + if selectedRoomId == nil { + selectedRoomId = store.rooms.first?.id + } + } + + var body: some View { + RecentRoomsView(selectedNavigationItem: $selectedNavigationItem, + selectedRoomId: $selectedRoomId, + rooms: store.rooms) + .sheet(item: $selectedNavigationItem) { + NavigationSheet(selectedItem: $0, selectedRoomId: $selectedRoomId) + // This really shouldn't be necessary. SwiftUI bug? + // 2021-03-07(hh): SwiftUI doesn't document when + // environments are preserved. Also + // different between platforms. + .environmentObject(self.store) + .accentColor(accentColor) + } + .onAppear { + self.store.startListeningForRoomEvents() + if #available(macOS 11, *) { autoselectFirstRoom() } + } + } +} + + +enum SelectedNavigationItem: Int, Identifiable { + case settings + case newConversation + + var id: Int { + return self.rawValue + } +} + +struct RoomsListSection: View { + let sectionHeader: String? + let rooms: [NIORoom] + let onLeaveAlertTitle: String + + @Binding var selectedRoomId: ObjectIdentifier? + + @State private var showConfirm: Bool = false + @State private var leaveId: Int? + + private var roomToLeave: NIORoom? { + guard + let leaveId = self.leaveId, + rooms.count > leaveId + else { return nil } + return self.rooms[leaveId] + } + + private var sectionContent: some View { + ForEach(rooms) { room in + NavigationLink(destination: RoomContainerView(room: room), tag: room.id, selection: $selectedRoomId) { + RoomListItemContainerView(room: room) + } + } + .onDelete(perform: setLeaveIndex) + } + + @ViewBuilder + private var section: some View { + if let sectionHeader = sectionHeader { + Section(header: Text(sectionHeader)) { + sectionContent + } + } else { + Section { + sectionContent + } + } + } + + var body: some View { + section + .alert(isPresented: $showConfirm) { + Alert( + title: Text(onLeaveAlertTitle), + message: Text(verbatim: L10n.RecentRooms.Leave.alertBody( + roomToLeave?.summary.displayname + ?? roomToLeave?.summary.roomId + ?? "")), + primaryButton: .destructive( + Text(verbatim: L10n.Room.Remove.action), + action: self.leaveRoom), + secondaryButton: .cancel()) + } + } + + private func setLeaveIndex(at offsets: IndexSet) { + self.showConfirm = true + for offset in offsets { + self.leaveId = offset + } + } + + private func leaveRoom() { + guard let leaveId = self.leaveId, rooms.count > leaveId else { return } + guard let mxRoom = self.roomToLeave?.room else { return } + mxRoom.mxSession?.leaveRoom(mxRoom.roomId) { _ in } + } +} + +private struct NavigationSheet: View { + var selectedItem: SelectedNavigationItem + @Binding var selectedRoomId: ObjectIdentifier? + + var body: some View { + switch selectedItem { + case .settings: + SettingsContainerView() + case .newConversation: + NewConversationContainerView(createdRoomId: $selectedRoomId) + } + } +} + + +struct RecentRoomsContainerView_Previews: PreviewProvider { + static var previews: some View { + RecentRoomsContainerView() + } +} diff --git a/Nio/Conversations/RecentRoomsView.swift b/Nio/Conversations/RecentRoomsView.swift index 141b5bdd..e08c4ab0 100644 --- a/Nio/Conversations/RecentRoomsView.swift +++ b/Nio/Conversations/RecentRoomsView.swift @@ -4,44 +4,11 @@ import Introspect import NioKit -struct RecentRoomsContainerView: View { - @EnvironmentObject var store: AccountStore - @AppStorage("accentColor") var accentColor: Color = .purple - - @State private var selectedNavigationItem: SelectedNavigationItem? - @State private var selectedRoomId: ObjectIdentifier? - - private func autoselectFirstRoom() { - if selectedRoomId == nil { - selectedRoomId = store.rooms.first?.id - } - } - - var body: some View { - RecentRoomsView(selectedNavigationItem: $selectedNavigationItem, - selectedRoomId: $selectedRoomId, - rooms: store.rooms) - .sheet(item: $selectedNavigationItem) { - NavigationSheet(selectedItem: $0, selectedRoomId: $selectedRoomId) - // This really shouldn't be necessary. SwiftUI bug? - // 2021-03-07(hh): SwiftUI doesn't document when - // environments are preserved. Also - // different between platforms. - .environmentObject(self.store) - .accentColor(accentColor) - } - .onAppear { - self.store.startListeningForRoomEvents() - if #available(macOS 11, *) { autoselectFirstRoom() } - } - } -} - struct RecentRoomsView: View { @EnvironmentObject var store: AccountStore - @Binding fileprivate var selectedNavigationItem: SelectedNavigationItem? - @Binding fileprivate var selectedRoomId: ObjectIdentifier? + @Binding var selectedNavigationItem: SelectedNavigationItem? + @Binding var selectedRoomId: ObjectIdentifier? let rooms: [NIORoom] @@ -53,41 +20,6 @@ struct RecentRoomsView: View { rooms.filter {$0.room.summary.membership == .invite} } - #if os(macOS) - var body: some View { - NavigationView { - List { - if !invitedRooms.isEmpty { - RoomsListSection( - sectionHeader: L10n.RecentRooms.PendingInvitations.header, - rooms: invitedRooms, - onLeaveAlertTitle: L10n.RecentRooms.PendingInvitations.Leave.alertTitle, - selectedRoomId: $selectedRoomId - ) - } - - RoomsListSection( - sectionHeader: invitedRooms.isEmpty ? nil : L10n.RecentRooms.Rooms.header , - rooms: joinedRooms, - onLeaveAlertTitle: L10n.RecentRooms.Leave.alertTitle, - selectedRoomId: $selectedRoomId - ) - - } - .listStyle(SidebarListStyle()) - .navigationTitle("Mio") - .frame(minWidth: Style.minSidebarWidth) - .toolbar { - ToolbarItem(placement: .cancellationAction) { - Button(action: { self.selectedNavigationItem = .newConversation }) { - Label(L10n.RecentRooms.AccessibilityLabel.newConversation, - systemImage: SFSymbol.newConversation.rawValue) - } - } - } - } - } - #else // iOS private var settingsButton: some View { Button(action: { self.selectedNavigationItem = .settings @@ -141,101 +73,10 @@ struct RecentRoomsView: View { .navigationBarItems(leading: settingsButton, trailing: newConversationButton) } } - #endif // iOS } -struct RoomsListSection: View { - let sectionHeader: String? - let rooms: [NIORoom] - let onLeaveAlertTitle: String - - @Binding var selectedRoomId: ObjectIdentifier? - - @State private var showConfirm: Bool = false - @State private var leaveId: Int? - - private var roomToLeave: NIORoom? { - guard - let leaveId = self.leaveId, - rooms.count > leaveId - else { return nil } - return self.rooms[leaveId] - } - - private var sectionContent: some View { - ForEach(rooms) { room in - NavigationLink(destination: RoomContainerView(room: room), tag: room.id, selection: $selectedRoomId) { - RoomListItemContainerView(room: room) - } - } - .onDelete(perform: setLeaveIndex) - } - @ViewBuilder - private var section: some View { - if let sectionHeader = sectionHeader { - Section(header: Text(sectionHeader)) { - sectionContent - } - } else { - Section { - sectionContent - } - } - } - var body: some View { - section - .alert(isPresented: $showConfirm) { - Alert( - title: Text(onLeaveAlertTitle), - message: Text(verbatim: L10n.RecentRooms.Leave.alertBody( - roomToLeave?.summary.displayname - ?? roomToLeave?.summary.roomId - ?? "")), - primaryButton: .destructive( - Text(verbatim: L10n.Room.Remove.action), - action: self.leaveRoom), - secondaryButton: .cancel()) - } - } - - private func setLeaveIndex(at offsets: IndexSet) { - self.showConfirm = true - for offset in offsets { - self.leaveId = offset - } - } - - private func leaveRoom() { - guard let leaveId = self.leaveId, rooms.count > leaveId else { return } - guard let mxRoom = self.roomToLeave?.room else { return } - mxRoom.mxSession?.leaveRoom(mxRoom.roomId) { _ in } - } -} - -private enum SelectedNavigationItem: Int, Identifiable { - case settings - case newConversation - - var id: Int { - return self.rawValue - } -} - -private struct NavigationSheet: View { - var selectedItem: SelectedNavigationItem - @Binding var selectedRoomId: ObjectIdentifier? - - var body: some View { - switch selectedItem { - case .settings: - SettingsContainerView() - case .newConversation: - NewConversationContainerView(createdRoomId: $selectedRoomId) - } - } -} struct RecentRoomsView_Previews: PreviewProvider { static var previews: some View { diff --git a/Nio/NewConversation/NewConversationView.swift b/Nio/NewConversation/NewConversationView.swift index 22e74e3a..ebf68e62 100644 --- a/Nio/NewConversation/NewConversationView.swift +++ b/Nio/NewConversation/NewConversationView.swift @@ -100,7 +100,11 @@ private struct NewConversationView: View { } } ToolbarItem(placement: .confirmationAction) { - Button(action: createRoom) { + Button(action: { + Task.init(priority: .userInitiated) { + createRoom() + } + }) { Text(verbatim: L10n.NewConversation.createRoom) } .disabled(users.contains("") || (roomName.isEmpty && users.count > 1))