diff --git a/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/Contents.json new file mode 100644 index 000000000..6bb7945f7 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "space_private_icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "space_private_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "space_private_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon.png b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon.png new file mode 100644 index 000000000..10bc95ab8 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon.png differ diff --git a/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon@2x.png b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon@2x.png new file mode 100644 index 000000000..cae6344e1 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon@3x.png b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon@3x.png new file mode 100644 index 000000000..eaf48592a Binary files /dev/null and b/Riot/Assets/Images.xcassets/Spaces/space_private_icon.imageset/space_private_icon@3x.png differ diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 63b974866..bad6db43d 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1730,6 +1730,7 @@ Tap the + to start adding people."; "spaces_coming_soon_detail" = "This feature hasn’t been implemented here, but it’s on the way. For now, you can do that with Element on your computer."; "space_participants_action_remove" = "Remove from this space"; "space_participants_action_ban" = "Ban from this space"; +"space_home_show_all_rooms" = "Show all rooms"; "space_private_join_rule" = "Private space"; "space_public_join_rule" = "Public space"; diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index c681c2fbe..83b830e6c 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -195,6 +195,7 @@ internal enum Asset { internal static let spaceMenuLeave = ImageAsset(name: "space_menu_leave") internal static let spaceMenuMembers = ImageAsset(name: "space_menu_members") internal static let spaceMenuRooms = ImageAsset(name: "space_menu_rooms") + internal static let spacePrivateIcon = ImageAsset(name: "space_private_icon") internal static let spaceRoomIcon = ImageAsset(name: "space_room_icon") internal static let spaceTypeIcon = ImageAsset(name: "space_type_icon") internal static let spaceUserIcon = ImageAsset(name: "space_user_icon") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index f23c03d2a..db36f708a 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -4903,6 +4903,10 @@ public class VectorL10n: NSObject { public static var spaceFeatureUnavailableTitle: String { return VectorL10n.tr("Vector", "space_feature_unavailable_title") } + /// Show all rooms + public static var spaceHomeShowAllRooms: String { + return VectorL10n.tr("Vector", "space_home_show_all_rooms") + } /// Ban from this space public static var spaceParticipantsActionBan: String { return VectorL10n.tr("Vector", "space_participants_action_ban") diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index e73396ac5..9942f883f 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -1177,7 +1177,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou } #pragma mark - MXKDataSourceDelegate - + - (void)dataSource:(MXKDataSource*)dataSource didCellChange:(id)changes { // Refresh is disabled during drag&drop animation diff --git a/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarTextView.swift b/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarTextView.swift index ad769b52e..729b3c2e7 100644 --- a/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarTextView.swift +++ b/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarTextView.swift @@ -16,8 +16,14 @@ import GrowingTextView +@objc protocol RoomInputToolbarTextViewDelegate: AnyObject { + func textView(_ textView: RoomInputToolbarTextView, didReceivePasteForMediaFromSender sender: Any?) +} + class RoomInputToolbarTextView: GrowingTextView { + @objc weak var toolbarDelegate: RoomInputToolbarTextViewDelegate? + override var keyCommands: [UIKeyCommand]? { return [UIKeyCommand(input: "\r", modifierFlags: [], action: #selector(keyCommandSelector(_:)))] } @@ -28,5 +34,19 @@ class RoomInputToolbarTextView: GrowingTextView { } delegate.onTouchUp(inside: delegate.rightInputToolbarButton) - } + } + + /// Overrides paste to handle images pasted from Safari, passing them up to the input toolbar. + /// This is required as the pasteboard contains both the image and the image's URL, with the + /// default implementation choosing to paste the URL and completely ignore the image data. + override func paste(_ sender: Any?) { + let pasteboard = MXKPasteboardManager.shared.pasteboard + let types = pasteboard.types.map { UTI(rawValue: $0) } + + if types.contains(where: { $0.conforms(to: .image) }) { + toolbarDelegate?.textView(self, didReceivePasteForMediaFromSender: sender) + } else { + super.paste(sender) + } + } } diff --git a/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarView.m b/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarView.m index a8c9f57e7..8cc889940 100644 --- a/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarView.m +++ b/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarView.m @@ -38,7 +38,7 @@ const NSTimeInterval kActionMenuContentAlphaAnimationDuration = .2; const NSTimeInterval kActionMenuComposerHeightAnimationDuration = .3; const CGFloat kComposerContainerTrailingPadding = 12; -@interface RoomInputToolbarView() +@interface RoomInputToolbarView() { // The intermediate action sheet UIAlertController *actionSheet; @@ -83,6 +83,8 @@ const CGFloat kComposerContainerTrailingPadding = 12; self.isEncryptionEnabled = _isEncryptionEnabled; [self updateUIWithTextMessage:nil animated:NO]; + + self.textView.toolbarDelegate = self; } - (void)setVoiceMessageToolbarView:(UIView *)voiceMessageToolbarView @@ -382,6 +384,16 @@ const CGFloat kComposerContainerTrailingPadding = 12; [super onTouchUpInside:button]; } +- (BOOL)becomeFirstResponder +{ + return [self.textView becomeFirstResponder]; +} + +- (void)dismissKeyboard +{ + [self.textView resignFirstResponder]; +} + - (void)destroy { if (actionSheet) @@ -455,6 +467,11 @@ const CGFloat kComposerContainerTrailingPadding = 12; [super paste:sender]; } +- (void)textView:(GrowingTextView *)textView didReceivePasteForMediaFromSender:(id)sender +{ + [self paste:sender]; +} + #pragma mark - Private - (void)updateUIWithTextMessage:(NSString *)textMessage animated:(BOOL)animated diff --git a/Riot/Modules/Spaces/SpaceDetail/SpaceDetailViewController.swift b/Riot/Modules/Spaces/SpaceDetail/SpaceDetailViewController.swift index 95f7e7b19..bca282949 100644 --- a/Riot/Modules/Spaces/SpaceDetail/SpaceDetailViewController.swift +++ b/Riot/Modules/Spaces/SpaceDetail/SpaceDetailViewController.swift @@ -231,6 +231,9 @@ class SpaceDetailViewController: UIViewController { let membersString = membersCount == 1 ? VectorL10n.roomTitleOneMember : VectorL10n.roomTitleMembers("\(membersCount)") self.spaceTypeLabel.text = "\(joinRuleString) · \(membersString)" + let joinRuleIcon = parameters.joinRule == .public ? Asset.Images.spaceTypeIcon : Asset.Images.spacePrivateIcon + self.spaceTypeIconView.image = joinRuleIcon.image + self.inviterIdLabel.text = parameters.inviterId if let inviterId = parameters.inviterId { self.inviterTitleLabel.text = "\(parameters.inviter?.displayname ?? inviterId) invited you" diff --git a/Riot/Modules/Spaces/SpaceList/SpaceListViewCell.swift b/Riot/Modules/Spaces/SpaceList/SpaceListViewCell.swift index d0ea314dd..eaf3a5e09 100644 --- a/Riot/Modules/Spaces/SpaceList/SpaceListViewCell.swift +++ b/Riot/Modules/Spaces/SpaceList/SpaceListViewCell.swift @@ -58,7 +58,7 @@ final class SpaceListViewCell: UITableViewCell, Themable, NibReusable { func fill(with viewData: SpaceListItemViewData) { self.avatarView.fill(with: viewData.avatarViewData) self.titleLabel.text = viewData.title - self.moreButton.isHidden = viewData.spaceId == SpaceListViewModel.Constants.homeSpaceId || viewData.isInvite + self.moreButton.isHidden = viewData.isInvite if viewData.isInvite { self.isBadgeAlert = true self.badgeLabel.isHidden = false diff --git a/Riot/Modules/Spaces/SpaceList/SpaceListViewModel.swift b/Riot/Modules/Spaces/SpaceList/SpaceListViewModel.swift index ed11d2df9..3f9924531 100644 --- a/Riot/Modules/Spaces/SpaceList/SpaceListViewModel.swift +++ b/Riot/Modules/Spaces/SpaceList/SpaceListViewModel.swift @@ -91,7 +91,8 @@ final class SpaceListViewModel: SpaceListViewModelType { case .moreAction(at: let indexPath, from: let sourceView): let section = self.sections[indexPath.section] switch section { - case .home: break + case .home: + self.coordinatorDelegate?.spaceListViewModel(self, didPressMoreForSpaceWithId: Constants.homeSpaceId, from: sourceView) case .spaces(let viewDataList): let spaceViewData = viewDataList[indexPath.row] self.coordinatorDelegate?.spaceListViewModel(self, didPressMoreForSpaceWithId: spaceViewData.spaceId, from: sourceView) diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuCell.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuCell.swift new file mode 100644 index 000000000..d7a3d1fe0 --- /dev/null +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuCell.swift @@ -0,0 +1,21 @@ +// +// 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 + +protocol SpaceMenuCell: Themable { + func update(with viewData: SpaceMenuListItemViewData) +} diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListItemViewData.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListItemViewData.swift index 6b7a67fa5..6f8b7378f 100644 --- a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListItemViewData.swift +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListItemViewData.swift @@ -16,16 +16,45 @@ import Foundation +/// Possible action related to a `SpaceMenuListViewCell` view data +enum SpaceMenuListItemAction { + case showAllRoomsInHomeSpace + case exploreSpaceMembers + case exploreSpaceRooms + case leaveSpace +} + /// Style of the `SpaceMenuListViewCell` enum SpaceMenuListItemStyle { case normal + case toggle case destructive } +/// `SpaceMenuListItemViewDataDelegate` allows the table view cell to update its view accordingly with it's related data change +protocol SpaceMenuListItemViewDataDelegate: AnyObject { + func spaceMenuItemValueDidChange(_ item: SpaceMenuListItemViewData) +} + /// `SpaceMenuListViewCell` view data -struct SpaceMenuListItemViewData { - let actionId: String +class SpaceMenuListItemViewData { + let action: SpaceMenuListItemAction let style: SpaceMenuListItemStyle let title: String? let icon: UIImage? + /// Any value related to the type of data (e.g. `Bool` for `boolean` style, `nil` for `normal` and `destructive` style) + var value: Any? { + didSet { + delegate?.spaceMenuItemValueDidChange(self) + } + } + weak var delegate: SpaceMenuListItemViewDataDelegate? + + init(action: SpaceMenuListItemAction, style: SpaceMenuListItemStyle, title: String?, icon: UIImage?, value: Any?) { + self.action = action + self.style = style + self.title = title + self.icon = icon + self.value = value + } } diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListViewCell.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListViewCell.swift index 952d89d4d..bc8243a9a 100644 --- a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListViewCell.swift +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuListViewCell.swift @@ -17,7 +17,7 @@ import Foundation import Reusable -class SpaceMenuListViewCell: UITableViewCell, Themable, NibReusable { +class SpaceMenuListViewCell: UITableViewCell, SpaceMenuCell, NibReusable { // MARK: - Properties @@ -49,7 +49,7 @@ class SpaceMenuListViewCell: UITableViewCell, Themable, NibReusable { // MARK: - Public - func fill(with viewData: SpaceMenuListItemViewData) { + func update(with viewData: SpaceMenuListItemViewData) { self.iconView.image = viewData.icon self.titleLabel.text = viewData.title diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuPresenter.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuPresenter.swift index 697c65b43..1949e03fd 100644 --- a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuPresenter.swift +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuPresenter.swift @@ -101,16 +101,15 @@ extension SpaceMenuPresenter: SpaceMenuModelViewModelCoordinatorDelegate { self.dismiss(animated: true, completion: nil) } - func spaceMenuViewModel(_ viewModel: SpaceMenuViewModelType, didSelectItemWithId itemId: String) { - let actionId = SpaceMenuViewModel.ActionId(rawValue: itemId) - switch actionId { - case .leave: break - case .members: + func spaceMenuViewModel(_ viewModel: SpaceMenuViewModelType, didSelectItemWith action: SpaceMenuListItemAction) { + switch action { + case .leaveSpace: break + case .exploreSpaceMembers: self.delegate?.spaceMenuPresenter(self, didCompleteWith: .exploreMembers, forSpaceWithId: self.spaceId, with: self.session) - case .rooms: + case .exploreSpaceRooms: self.delegate?.spaceMenuPresenter(self, didCompleteWith: .exploreRooms, forSpaceWithId: self.spaceId, with: self.session) default: - MXLog.error("[SpaceMenuPresenter] spaceListViewModel didSelectItemWithId: invalid itemId \(itemId)") + MXLog.error("[SpaceMenuPresenter] spaceListViewModel didSelectItem: invalid action \(action)") } } } diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuSwitchViewCell.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuSwitchViewCell.swift new file mode 100644 index 000000000..2d50e9df1 --- /dev/null +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuSwitchViewCell.swift @@ -0,0 +1,73 @@ +// +// 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 Reusable + +class SpaceMenuSwitchViewCell: UITableViewCell, SpaceMenuCell, NibReusable { + + // MARK: - Properties + + @IBOutlet private weak var titleLabel: UILabel! + @IBOutlet private weak var selectionView: UIView! + @IBOutlet private weak var switchView: UISwitch! + + // MARK: - Private + + private var theme: Theme? + + // MARK: - Life cycle + + override func awakeFromNib() { + super.awakeFromNib() + + self.selectionStyle = .none + self.selectionView.layer.cornerRadius = 8.0 + self.selectionView.layer.masksToBounds = true + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + UIView.animate(withDuration: animated ? 0.3 : 0.0) { + self.selectionView.alpha = selected ? 1.0 : 0.0 + } + } + + // MARK: - Public + + func update(with viewData: SpaceMenuListItemViewData) { + self.titleLabel.text = viewData.title + self.switchView.isOn = (viewData.value as? Bool) ?? false + + viewData.delegate = self + } + + func update(theme: Theme) { + self.theme = theme + self.backgroundColor = theme.colors.background + self.titleLabel.textColor = theme.colors.primaryContent + self.titleLabel.font = theme.fonts.body + self.selectionView.backgroundColor = theme.colors.separator + } +} + +// MARK: - SpaceMenuListItemViewDataDelegate +extension SpaceMenuSwitchViewCell: SpaceMenuListItemViewDataDelegate { + func spaceMenuItemValueDidChange(_ item: SpaceMenuListItemViewData) { + self.switchView.setOn((item.value as? Bool) ?? false, animated: true) + } +} diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuSwitchViewCell.xib b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuSwitchViewCell.xib new file mode 100644 index 000000000..f652ee4b7 --- /dev/null +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuSwitchViewCell.xib @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewController.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewController.swift index 8f9710e56..7b9bebea4 100644 --- a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewController.swift +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewController.swift @@ -114,6 +114,17 @@ class SpaceMenuViewController: UIViewController { } private func setupViews() { + setupTableView() + + if self.spaceId == SpaceListViewModel.Constants.homeSpaceId { + let avatarViewData = AvatarViewData(matrixItemId: self.spaceId, displayName: nil, avatarUrl: nil, mediaManager: session.mediaManager, fallbackImage: .image(Asset.Images.spaceHomeIcon.image, .center)) + self.avatarView.fill(with: avatarViewData) + self.titleLabel.text = VectorL10n.titleHome + self.subtitleLabel.text = VectorL10n.settingsTitle + + return + } + guard let space = self.session.spaceService.getSpace(withId: self.spaceId), let summary = space.summary else { MXLog.error("[SpaceMenuViewController] setupViews: no space found") return @@ -130,7 +141,6 @@ class SpaceMenuViewController: UIViewController { self.closeButton.layer.masksToBounds = true self.closeButton.layer.cornerRadius = self.closeButton.bounds.height / 2 - setupTableView() } private func setupTableView() { @@ -139,6 +149,7 @@ class SpaceMenuViewController: UIViewController { self.tableView.estimatedRowHeight = Constants.estimatedRowHeight self.tableView.allowsSelection = true self.tableView.register(cellType: SpaceMenuListViewCell.self) + self.tableView.register(cellType: SpaceMenuSwitchViewCell.self) self.tableView.tableFooterView = UIView() } @@ -235,12 +246,15 @@ extension SpaceMenuViewController: UITableViewDataSource { } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(for: indexPath, cellType: SpaceMenuListViewCell.self) - let viewData = viewModel.menuItems[indexPath.row] - cell.update(theme: self.theme) - cell.fill(with: viewData) + let cell = viewData.style == .toggle ? tableView.dequeueReusableCell(for: indexPath, cellType: SpaceMenuSwitchViewCell.self) : + tableView.dequeueReusableCell(for: indexPath, cellType: SpaceMenuListViewCell.self) + + if let cell = cell as? SpaceMenuCell { + cell.update(theme: self.theme) + cell.update(with: viewData) + } return cell } diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModel.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModel.swift index be6ad2514..39e38934d 100644 --- a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModel.swift +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModel.swift @@ -19,25 +19,19 @@ import Foundation /// View model used by `SpaceMenuViewController` class SpaceMenuViewModel: SpaceMenuViewModelType { - // MARK: - Enum - - enum ActionId: String { - case members = "members" - case rooms = "rooms" - case leave = "leave" - } - // MARK: - Properties weak var coordinatorDelegate: SpaceMenuModelViewModelCoordinatorDelegate? weak var viewDelegate: SpaceMenuViewModelViewDelegate? - var menuItems: [SpaceMenuListItemViewData] = [ - SpaceMenuListItemViewData(actionId: ActionId.members.rawValue, style: .normal, title: VectorL10n.roomDetailsPeople, icon: UIImage(named: "space_menu_members")), - SpaceMenuListItemViewData(actionId: ActionId.rooms.rawValue, style: .normal, title: VectorL10n.spacesExploreRooms, icon: UIImage(named: "space_menu_rooms")), - SpaceMenuListItemViewData(actionId: ActionId.leave.rawValue, style: .destructive, title: VectorL10n.leave, icon: UIImage(named: "space_menu_leave")) + private let spaceMenuItems: [SpaceMenuListItemViewData] = [ + SpaceMenuListItemViewData(action: .exploreSpaceMembers, style: .normal, title: VectorL10n.roomDetailsPeople, icon: Asset.Images.spaceMenuMembers.image, value: nil), + SpaceMenuListItemViewData(action: .exploreSpaceRooms, style: .normal, title: VectorL10n.spacesExploreRooms, icon: Asset.Images.spaceMenuRooms.image, value: nil), + SpaceMenuListItemViewData(action: .leaveSpace, style: .destructive, title: VectorL10n.leave, icon: Asset.Images.spaceMenuLeave.image, value: nil) ] + var menuItems: [SpaceMenuListItemViewData] = [] + private let session: MXSession private let spaceId: String @@ -46,6 +40,14 @@ class SpaceMenuViewModel: SpaceMenuViewModelType { init(session: MXSession, spaceId: String) { self.session = session self.spaceId = spaceId + + if spaceId != SpaceListViewModel.Constants.homeSpaceId { + self.menuItems = spaceMenuItems + } else { + self.menuItems = [ + SpaceMenuListItemViewData(action: .showAllRoomsInHomeSpace, style: .toggle, title: VectorL10n.spaceHomeShowAllRooms, icon: nil, value: MXKAppSettings.standard().showAllRoomsInHomeSpace) + ] + } } // MARK: - Public @@ -55,7 +57,7 @@ class SpaceMenuViewModel: SpaceMenuViewModelType { case .dismiss: self.coordinatorDelegate?.spaceMenuViewModelDidDismiss(self) case .selectRow(at: let indexPath): - self.processAction(with: menuItems[indexPath.row].actionId) + self.processAction(with: menuItems[indexPath.row].action, at: indexPath) case .leaveSpaceAndKeepRooms: self.leaveSpaceAndKeepRooms() case .leaveSpaceAndLeaveRooms: @@ -65,13 +67,16 @@ class SpaceMenuViewModel: SpaceMenuViewModelType { // MARK: - Private - private func processAction(with actionStringId: String) { - let actionId = ActionId(rawValue: actionStringId) - switch actionId { - case .leave: + private func processAction(with action: SpaceMenuListItemAction, at indexPath: IndexPath) { + switch action { + case .showAllRoomsInHomeSpace: + MXKAppSettings.standard().showAllRoomsInHomeSpace = !MXKAppSettings.standard().showAllRoomsInHomeSpace + self.menuItems[indexPath.row].value = MXKAppSettings.standard().showAllRoomsInHomeSpace + self.viewDelegate?.spaceMenuViewModel(self, didUpdateViewState: .deselect) + case .leaveSpace: self.leaveSpace() default: - self.coordinatorDelegate?.spaceMenuViewModel(self, didSelectItemWithId: actionStringId) + self.coordinatorDelegate?.spaceMenuViewModel(self, didSelectItemWith: action) } } diff --git a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModelType.swift b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModelType.swift index edaef39b3..7f9511f7b 100644 --- a/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModelType.swift +++ b/Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModelType.swift @@ -22,7 +22,7 @@ protocol SpaceMenuViewModelViewDelegate: AnyObject { protocol SpaceMenuModelViewModelCoordinatorDelegate: AnyObject { func spaceMenuViewModelDidDismiss(_ viewModel: SpaceMenuViewModelType) - func spaceMenuViewModel(_ viewModel: SpaceMenuViewModelType, didSelectItemWithId itemId: String) + func spaceMenuViewModel(_ viewModel: SpaceMenuViewModelType, didSelectItemWith action: SpaceMenuListItemAction) } /// Protocol describing the view model used by `SpaceMenuViewController` diff --git a/changelog.d/2076.bugfix b/changelog.d/2076.bugfix new file mode 100644 index 000000000..e85ae76ce --- /dev/null +++ b/changelog.d/2076.bugfix @@ -0,0 +1 @@ +Message Composer: Pasting images from Safari now pastes the image and not its URL. \ No newline at end of file diff --git a/changelog.d/4570.feature b/changelog.d/4570.feature new file mode 100644 index 000000000..e1a38944f --- /dev/null +++ b/changelog.d/4570.feature @@ -0,0 +1 @@ +M10.4.1 Home space data filtering \ No newline at end of file diff --git a/changelog.d/4886.bugfix b/changelog.d/4886.bugfix new file mode 100644 index 000000000..ad58b6c36 --- /dev/null +++ b/changelog.d/4886.bugfix @@ -0,0 +1 @@ +Fixed private space invite should use lock icon instead of planet \ No newline at end of file