Implement FAB journeys & rough edge warnings element-ios#5226

- List of Space members with search
- Invite interactions
- Join room from list
- Implement add room button, with rough edge warning.
This commit is contained in:
Gil Eluard 2021-12-10 09:59:10 +01:00
parent 60f071ee9b
commit cf453feb02
27 changed files with 335 additions and 32 deletions

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "space_add_room.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "space_add_room@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "space_add_room@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,26 @@
{
"images" : [
{
"filename" : "space_invite_user.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "space_invite_user@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "space_invite_user@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -268,6 +268,7 @@ Tap the + to start adding people.";
"room_participants_remove_third_party_invite_prompt_msg" = "Are you sure you want to revoke this invite?";
"room_participants_invite_prompt_title" = "Confirmation";
"room_participants_invite_prompt_msg" = "Are you sure you want to invite %@ to this chat?";
"room_participants_invite_prompt_to_msg" = "Are you sure you want to invite %@ to %@?";
"room_participants_filter_room_members" = "Filter room members";
"room_participants_filter_room_members_for_dm" = "Filter members";
"room_participants_invite_another_user" = "Search / invite by User ID, Name or email";
@ -1744,6 +1745,8 @@ Tap the + to start adding people.";
"space_private_join_rule" = "Private space";
"space_public_join_rule" = "Public space";
"spaces_invite_people" = "Invite people";
"spaces_add_room" = "Add room";
// Mark: Avatar

View file

@ -195,7 +195,9 @@ internal enum Asset {
internal static let sideMenuNotifIcon = ImageAsset(name: "side_menu_notif_icon")
internal static let featureUnavaibleArtwork = ImageAsset(name: "feature_unavaible_artwork")
internal static let featureUnavaibleArtworkDark = ImageAsset(name: "feature_unavaible_artwork_dark")
internal static let spaceAddRoom = ImageAsset(name: "space_add_room")
internal static let spaceHomeIcon = ImageAsset(name: "space_home_icon")
internal static let spaceInviteUser = ImageAsset(name: "space_invite_user")
internal static let spaceMenuClose = ImageAsset(name: "space_menu_close")
internal static let spaceMenuLeave = ImageAsset(name: "space_menu_leave")
internal static let spaceMenuMembers = ImageAsset(name: "space_menu_members")

View file

@ -3327,6 +3327,10 @@ public class VectorL10n: NSObject {
public static var roomParticipantsInvitePromptTitle: String {
return VectorL10n.tr("Vector", "room_participants_invite_prompt_title")
}
/// Are you sure you want to invite %@ to %@?
public static func roomParticipantsInvitePromptToMsg(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "room_participants_invite_prompt_to_msg", p1, p2)
}
/// INVITED
public static var roomParticipantsInvitedSection: String {
return VectorL10n.tr("Vector", "room_participants_invited_section")
@ -4987,6 +4991,10 @@ public class VectorL10n: NSObject {
public static var spaceTag: String {
return VectorL10n.tr("Vector", "space_tag")
}
/// Add room
public static var spacesAddRoom: String {
return VectorL10n.tr("Vector", "spaces_add_room")
}
/// Adding rooms coming soon
public static var spacesAddRoomsComingSoonTitle: String {
return VectorL10n.tr("Vector", "spaces_add_rooms_coming_soon_title")
@ -5015,6 +5023,10 @@ public class VectorL10n: NSObject {
public static var spacesHomeSpaceTitle: String {
return VectorL10n.tr("Vector", "spaces_home_space_title")
}
/// Invite people
public static var spacesInvitePeople: String {
return VectorL10n.tr("Vector", "spaces_invite_people")
}
/// Invites coming soon
public static var spacesInvitesComingSoonTitle: String {
return VectorL10n.tr("Vector", "spaces_invites_coming_soon_title")

View file

@ -66,8 +66,9 @@
// This will be used by the shared RecentsDataSource instance for sanity checks (see UITableViewDataSource methods).
self.recentsTableView.tag = RecentsDataSourceModePeople;
UIImage *fabImage = self.dataSource.currentSpace == nil ? [UIImage imageNamed:@"people_floating_action"] : [UIImage imageNamed:@"add_member_floating_action"];
// Add the (+) button programmatically
plusButtonImageView = [self vc_addFABWithImage:[UIImage imageNamed:@"people_floating_action"]
plusButtonImageView = [self vc_addFABWithImage:fabImage
target:self
action:@selector(onPlusButtonPressed)];
}

View file

@ -42,7 +42,7 @@
'RoomParticipantsViewController' instance is used to edit members of the room defined by the property 'mxRoom'.
When this property is nil, the view controller is empty.
*/
@interface RoomParticipantsViewController : MXKViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UIGestureRecognizerDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate>
@interface RoomParticipantsViewController : MXKViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UIGestureRecognizerDelegate, MXKRoomMemberDetailsViewControllerDelegate>
{
@protected
/**
@ -91,6 +91,7 @@
@property (nonatomic) BOOL showCancelBarButtonItem;
@property (nonatomic) BOOL showParticipantCustomAccessoryView;
@property (nonatomic) BOOL showInviteUserFab;
/**
The delegate for the view controller.

View file

@ -86,6 +86,7 @@
self.enableBarTintColorStatusChange = NO;
self.rageShakeManager = [RageShakeManager sharedManager];
self.showParticipantCustomAccessoryView = YES;
self.showInviteUserFab = YES;
}
- (void)viewDidLoad
@ -141,11 +142,13 @@
[self.tableView registerClass:ContactTableViewCell.class forCellReuseIdentifier:@"ParticipantTableViewCellId"];
// Add invite members button programmatically
[self vc_addFABWithImage:[UIImage imageNamed:@"add_member_floating_action"]
target:self
action:@selector(onAddParticipantButtonPressed)];
if (_showInviteUserFab)
{
// Add invite members button programmatically
[self vc_addFABWithImage:[UIImage imageNamed:@"add_member_floating_action"]
target:self
action:@selector(onAddParticipantButtonPressed)];
}
// Observe user interface theme change.
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {

View file

@ -200,7 +200,8 @@ extension ContactsPickerViewModel: ContactsTableViewControllerDelegate {
return
}
let message = VectorL10n.roomParticipantsInvitePromptMsg(contact.displayName)
let roomName = room.displayName ?? VectorL10n.spaceTag
let message = VectorL10n.roomParticipantsInvitePromptToMsg(contact.displayName, roomName)
coordinatorDelegate?.contactsPickerViewModel(self, display: message, title: VectorL10n.roomParticipantsInvitePromptTitle, actions: [
UIAlertAction(title: MatrixKitL10n.cancel, style: .cancel, handler: nil),

View file

@ -0,0 +1,88 @@
//
// Copyright 2020 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 UIKit
import Reusable
@objc
protocol AddItemHeaderViewDelegate: AnyObject {
func addItemHeaderView(_ headerView: AddItemHeaderView, didTapButton button: UIButton)
}
@objcMembers
final class AddItemHeaderView: UIView, NibLoadable, Themable {
// MARK: - Constants
private enum Constants {
static let buttonHighlightedAlpha: CGFloat = 0.2
}
// MARK: - Properties
@IBOutlet private weak var button: UIButton!
@IBOutlet private weak var iconBackgroundView: UIView!
@IBOutlet private weak var iconView: UIImageView!
@IBOutlet private weak var titleLabel: UILabel!
weak var delegate: AddItemHeaderViewDelegate?
private var title: String? {
didSet {
titleLabel.text = title
}
}
private var icon: UIImage? {
didSet {
iconView.image = icon
}
}
// MARK: - Setup
static func instantiate(title: String?, icon: UIImage?) -> AddItemHeaderView {
let view = AddItemHeaderView.loadFromNib()
view.icon = icon
view.title = title
view.update(theme: ThemeService.shared().theme)
return view
}
// MARK: - Life cycle
override func awakeFromNib() {
super.awakeFromNib()
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
iconBackgroundView.layer.masksToBounds = true
iconBackgroundView.layer.cornerRadius = iconBackgroundView.bounds.width / 2
}
// MARK: - Public
func update(theme: Theme) {
iconBackgroundView.layer.backgroundColor = theme.colors.quinaryContent.cgColor
iconView.tintColor = theme.colors.secondaryContent
titleLabel.textColor = theme.colors.primaryContent
titleLabel.font = theme.fonts.headline
}
// MARK: - Action
@objc private func buttonAction(_ sender: UIButton) {
delegate?.addItemHeaderView(self, didTapButton: button)
}
}

View file

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="cxh-dz-aGG" customClass="AddItemHeaderView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="77"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="K8C-8y-oEb">
<rect key="frame" x="0.0" y="0.0" width="414" height="77"/>
<constraints>
<constraint firstAttribute="height" constant="77" id="JuE-b9-RNu"/>
</constraints>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="disabled">
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
</state>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5Ob-zl-Yhb">
<rect key="frame" x="13" y="17.5" width="42" height="42"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Kik-Yj-tb0">
<rect key="frame" x="0.0" y="0.0" width="42" height="42"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Kik-Yj-tb0" firstAttribute="leading" secondItem="5Ob-zl-Yhb" secondAttribute="leading" id="8x3-3e-gtx"/>
<constraint firstAttribute="trailing" secondItem="Kik-Yj-tb0" secondAttribute="trailing" id="AJT-WT-ytj"/>
<constraint firstAttribute="bottom" secondItem="Kik-Yj-tb0" secondAttribute="bottom" id="ELg-cy-SKj"/>
<constraint firstAttribute="height" constant="42" id="cY8-gc-vLW"/>
<constraint firstAttribute="width" constant="42" id="fJr-GR-ahN"/>
<constraint firstItem="Kik-Yj-tb0" firstAttribute="top" secondItem="5Ob-zl-Yhb" secondAttribute="top" id="m8Y-Fu-iJd"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mfm-61-xzF">
<rect key="frame" x="69" y="28" width="331" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="Ehk-Sf-ESZ"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="5Ob-zl-Yhb" firstAttribute="centerY" secondItem="cxh-dz-aGG" secondAttribute="centerY" id="7fq-2U-Q7B"/>
<constraint firstItem="Mfm-61-xzF" firstAttribute="centerY" secondItem="cxh-dz-aGG" secondAttribute="centerY" id="8Th-Y1-glF"/>
<constraint firstItem="5Ob-zl-Yhb" firstAttribute="leading" secondItem="cxh-dz-aGG" secondAttribute="leading" constant="13" id="Ec0-ux-5ZW"/>
<constraint firstItem="Ehk-Sf-ESZ" firstAttribute="trailing" secondItem="Mfm-61-xzF" secondAttribute="trailing" constant="14" id="HCD-YR-0ip"/>
<constraint firstItem="K8C-8y-oEb" firstAttribute="top" secondItem="cxh-dz-aGG" secondAttribute="top" id="dLb-B4-eBJ"/>
<constraint firstAttribute="trailing" secondItem="K8C-8y-oEb" secondAttribute="trailing" id="nXF-QG-u1t"/>
<constraint firstItem="K8C-8y-oEb" firstAttribute="leading" secondItem="cxh-dz-aGG" secondAttribute="leading" id="rZm-C4-mTe"/>
<constraint firstAttribute="bottom" secondItem="K8C-8y-oEb" secondAttribute="bottom" id="tDj-72-Eek"/>
<constraint firstItem="Mfm-61-xzF" firstAttribute="leading" secondItem="5Ob-zl-Yhb" secondAttribute="trailing" constant="14" id="wWl-9y-vew"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="button" destination="K8C-8y-oEb" id="xU3-t7-lLR"/>
<outlet property="iconBackgroundView" destination="5Ob-zl-Yhb" id="O8Y-re-hFp"/>
<outlet property="iconView" destination="Kik-Yj-tb0" id="lE3-da-2mt"/>
<outlet property="titleLabel" destination="Mfm-61-xzF" id="27Q-vu-oPf"/>
</connections>
<point key="canvasLocation" x="114.49275362318842" y="-639.50892857142856"/>
</view>
</objects>
</document>

View file

@ -70,4 +70,8 @@ extension SpaceMemberListCoordinator: SpaceMemberListViewModelCoordinatorDelegat
func spaceMemberListViewModelDidCancel(_ viewModel: SpaceMemberListViewModelType) {
self.delegate?.spaceMemberListCoordinatorDidCancel(self)
}
func spaceMemberListViewModelShowInvite(_ viewModel: SpaceMemberListViewModelType) {
self.delegate?.spaceMemberListCoordinatorShowInvite(self)
}
}

View file

@ -21,6 +21,7 @@ import Foundation
protocol SpaceMemberListCoordinatorDelegate: AnyObject {
func spaceMemberListCoordinator(_ coordinator: SpaceMemberListCoordinatorType, didSelect member: MXRoomMember, from sourceView: UIView?)
func spaceMemberListCoordinatorDidCancel(_ coordinator: SpaceMemberListCoordinatorType)
func spaceMemberListCoordinatorShowInvite(_ coordinator: SpaceMemberListCoordinatorType)
}
/// `SpaceMemberListCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.

View file

@ -23,4 +23,5 @@ enum SpaceMemberListViewAction {
case loadData
case complete(_ selectedMember: MXRoomMember, _ sourceView: UIView?)
case cancel
case invite
}

View file

@ -36,6 +36,7 @@ final class SpaceMemberListViewController: RoomParticipantsViewController {
private var activityPresenter: ActivityIndicatorPresenter!
private var titleView: MainTitleView!
private var emptyView: SearchEmptyView!
private let inviteHeaderView = AddItemHeaderView.instantiate(title: VectorL10n.spacesInvitePeople, icon: Asset.Images.spaceInviteUser.image)
private var emptyViewArtwork: UIImage {
return ThemeService.shared().isCurrentThemeDark() ? Asset.Images.peopleEmptyScreenArtworkDark.image : Asset.Images.peopleEmptyScreenArtwork.image
@ -47,6 +48,7 @@ final class SpaceMemberListViewController: RoomParticipantsViewController {
let viewController = SpaceMemberListViewController()
viewController.viewModel = viewModel
viewController.showParticipantCustomAccessoryView = false
viewController.showInviteUserFab = false
viewController.theme = ThemeService.shared().theme
viewController.emptyView = SearchEmptyView()
return viewController
@ -71,14 +73,21 @@ final class SpaceMemberListViewController: RoomParticipantsViewController {
self.viewModel.process(viewAction: .loadData)
self.title = ""
self.setupTableViewHeader()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return self.theme.statusBarStyle
}
// MARK: - Private
private func setupTableViewHeader() {
inviteHeaderView.delegate = self
tableView.tableHeaderView = inviteHeaderView
}
private func update(theme: Theme) {
self.theme = theme
@ -91,6 +100,8 @@ final class SpaceMemberListViewController: RoomParticipantsViewController {
theme.applyStyle(onSearchBar: self.searchBarView)
self.titleView.update(theme: theme)
self.emptyView.update(theme: theme)
self.inviteHeaderView.update(theme: theme)
}
private func registerThemeServiceDidChangeThemeNotification() {
@ -154,7 +165,7 @@ final class SpaceMemberListViewController: RoomParticipantsViewController {
// MARK: - Actions
@objc private func onAddParticipantButtonPressed() {
self.errorPresenter.presentError(from: self, title: VectorL10n.spacesInvitesComingSoonTitle, message: VectorL10n.spacesComingSoonDetail, animated: true, handler: nil)
self.viewModel.process(viewAction: .invite)
}
private func cancelButtonAction() {
@ -200,3 +211,10 @@ extension SpaceMemberListViewController: SpaceMemberListViewModelViewDelegate {
self.render(viewState: viewSate)
}
}
// MARK: - SpaceMemberListViewModelViewDelegate
extension SpaceMemberListViewController: AddItemHeaderViewDelegate {
func addItemHeaderView(_ headerView: AddItemHeaderView, didTapButton button: UIButton) {
self.viewModel.process(viewAction: .invite)
}
}

View file

@ -57,6 +57,8 @@ final class SpaceMemberListViewModel: SpaceMemberListViewModelType {
case .cancel:
self.cancelOperations()
self.coordinatorDelegate?.spaceMemberListViewModelDidCancel(self)
case .invite:
self.coordinatorDelegate?.spaceMemberListViewModelShowInvite(self)
}
}

View file

@ -25,6 +25,7 @@ protocol SpaceMemberListViewModelViewDelegate: AnyObject {
protocol SpaceMemberListViewModelCoordinatorDelegate: AnyObject {
func spaceMemberListViewModel(_ viewModel: SpaceMemberListViewModelType, didSelect member: MXRoomMember, from sourceView: UIView?)
func spaceMemberListViewModelDidCancel(_ viewModel: SpaceMemberListViewModelType)
func spaceMemberListViewModelShowInvite(_ viewModel: SpaceMemberListViewModelType)
}
/// Protocol describing the view model used by `SpaceMemberListViewController`

View file

@ -131,8 +131,34 @@ extension SpaceMembersCoordinator: SpaceMemberListCoordinatorDelegate {
func spaceMemberListCoordinatorDidCancel(_ coordinator: SpaceMemberListCoordinatorType) {
self.delegate?.spaceMembersCoordinatorDidCancel(self)
}
func spaceMemberListCoordinatorShowInvite(_ coordinator: SpaceMemberListCoordinatorType) {
guard let space = parameters.session.spaceService.getSpace(withId: parameters.spaceId), let spaceRoom = space.room else {
MXLog.error("[SpaceMembersCoordinator] spaceMemberListCoordinatorShowInvite: failed to find space with id \(parameters.spaceId)")
return
}
let coordinator = ContactsPickerCoordinator(session: parameters.session, room: spaceRoom, currentSearchText: nil, actualParticipants: nil, invitedParticipants: nil, userParticipant: nil, navigationRouter: navigationRouter)
coordinator.delegate = self
coordinator.start()
childCoordinators.append(coordinator)
}
}
// MARK: - ContactsPickerCoordinatorDelegate
extension SpaceMembersCoordinator: ContactsPickerCoordinatorDelegate {
func contactsPickerCoordinatorDidStartLoading(_ coordinator: ContactsPickerCoordinatorType) {
}
func contactsPickerCoordinatorDidEndLoading(_ coordinator: ContactsPickerCoordinatorType) {
}
func contactsPickerCoordinatorDidClose(_ coordinator: ContactsPickerCoordinatorType) {
childCoordinators.removeLast()
}
}
// MARK: - SpaceMemberDetailCoordinatorDelegate
extension SpaceMembersCoordinator: SpaceMemberDetailCoordinatorDelegate {
func spaceMemberDetailCoordinator(_ coordinator: SpaceMemberDetailCoordinatorType, showRoomWithId roomId: String) {
if !UIDevice.current.isPhone, let memberDetailCoordinator = self.memberDetailCoordinator {

View file

@ -26,24 +26,24 @@
</constraints>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GVJ-S7-stu" customClass="SpaceAvatarView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="18" y="11" width="32" height="32"/>
<rect key="frame" x="16" y="11" width="40" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" secondItem="GVJ-S7-stu" secondAttribute="height" multiplier="1:1" id="87c-7u-7ge"/>
<constraint firstAttribute="height" constant="32" id="zvP-oT-8po"/>
<constraint firstAttribute="height" constant="40" id="zvP-oT-8po"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XbP-0o-uBP">
<rect key="frame" x="66" y="7.5" width="238" height="39"/>
<rect key="frame" x="72" y="11.5" width="232" height="39"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gVa-kK-bqa">
<rect key="frame" x="0.0" y="0.0" width="198" height="17"/>
<rect key="frame" x="0.0" y="0.0" width="192" height="17"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xhg-rs-E5l">
<rect key="frame" x="202" y="0.0" width="36" height="17"/>
<rect key="frame" x="196" y="0.0" width="36" height="17"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -120,7 +120,7 @@
<constraint firstItem="4Ic-S2-Ph6" firstAttribute="leading" secondItem="YoL-49-1Hj" secondAttribute="leading" constant="11" id="BzO-a8-pjD"/>
<constraint firstAttribute="bottom" secondItem="GVJ-S7-stu" secondAttribute="bottom" constant="11" id="CCO-dh-iNA"/>
<constraint firstItem="XbP-0o-uBP" firstAttribute="centerY" secondItem="GVJ-S7-stu" secondAttribute="centerY" id="GUt-0Z-6Px"/>
<constraint firstItem="GVJ-S7-stu" firstAttribute="leading" secondItem="YoL-49-1Hj" secondAttribute="leading" constant="18" id="TmX-fw-4A1"/>
<constraint firstItem="GVJ-S7-stu" firstAttribute="leading" secondItem="YoL-49-1Hj" secondAttribute="leading" constant="16" id="TmX-fw-4A1"/>
<constraint firstAttribute="trailing" secondItem="XbP-0o-uBP" secondAttribute="trailing" constant="16" id="WHX-0h-KAF"/>
<constraint firstItem="4Ic-S2-Ph6" firstAttribute="top" secondItem="YoL-49-1Hj" secondAttribute="top" constant="1" id="ZBt-T2-SNc"/>
<constraint firstAttribute="bottom" secondItem="4Ic-S2-Ph6" secondAttribute="bottom" constant="1" id="aaA-eT-Ma1"/>

View file

@ -26,18 +26,18 @@
</constraints>
</view>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GVJ-S7-stu" customClass="RoomAvatarView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="18" y="11" width="32" height="32"/>
<rect key="frame" x="16" y="11" width="40" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" secondItem="GVJ-S7-stu" secondAttribute="height" multiplier="1:1" id="87c-7u-7ge"/>
<constraint firstAttribute="height" constant="32" id="zvP-oT-8po"/>
<constraint firstAttribute="height" constant="40" id="zvP-oT-8po"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XbP-0o-uBP">
<rect key="frame" x="66" y="7.5" width="238" height="39"/>
<rect key="frame" x="72" y="11.5" width="232" height="39"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gVa-kK-bqa">
<rect key="frame" x="0.0" y="0.0" width="198" height="17"/>
<rect key="frame" x="0.0" y="0.0" width="192" height="17"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -56,13 +56,13 @@
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Description" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cKk-HO-IfB">
<rect key="frame" x="41" y="23" width="197" height="16"/>
<rect key="frame" x="41" y="23" width="191" height="16"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xhg-rs-E5l">
<rect key="frame" x="202" y="0.0" width="36" height="17"/>
<rect key="frame" x="196" y="0.0" width="36" height="17"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -92,7 +92,7 @@
<constraint firstItem="4Ic-S2-Ph6" firstAttribute="leading" secondItem="YoL-49-1Hj" secondAttribute="leading" constant="11" id="BzO-a8-pjD"/>
<constraint firstAttribute="bottom" secondItem="GVJ-S7-stu" secondAttribute="bottom" constant="11" id="CCO-dh-iNA"/>
<constraint firstItem="XbP-0o-uBP" firstAttribute="centerY" secondItem="GVJ-S7-stu" secondAttribute="centerY" id="GUt-0Z-6Px"/>
<constraint firstItem="GVJ-S7-stu" firstAttribute="leading" secondItem="YoL-49-1Hj" secondAttribute="leading" constant="18" id="TmX-fw-4A1"/>
<constraint firstItem="GVJ-S7-stu" firstAttribute="leading" secondItem="YoL-49-1Hj" secondAttribute="leading" constant="16" id="TmX-fw-4A1"/>
<constraint firstAttribute="trailing" secondItem="XbP-0o-uBP" secondAttribute="trailing" constant="16" id="WHX-0h-KAF"/>
<constraint firstItem="4Ic-S2-Ph6" firstAttribute="top" secondItem="YoL-49-1Hj" secondAttribute="top" constant="1" id="ZBt-T2-SNc"/>
<constraint firstAttribute="bottom" secondItem="4Ic-S2-Ph6" secondAttribute="bottom" constant="1" id="aaA-eT-Ma1"/>

View file

@ -40,9 +40,9 @@ final class SpaceExploreRoomViewController: UIViewController {
private var activityPresenter: ActivityIndicatorPresenter!
private var titleView: MainTitleView!
private var emptyView: RootTabEmptyView!
private var plusButtonImageView: UIImageView!
private var hasMore: Bool = false
private let addRoomHeaderView = AddItemHeaderView.instantiate(title: VectorL10n.spacesAddRoom, icon: Asset.Images.spaceAddRoom.image)
private var itemDataList: [SpaceExploreRoomListItemViewData] = [] {
didSet {
self.tableView.reloadData()
@ -124,6 +124,8 @@ final class SpaceExploreRoomViewController: UIViewController {
self.tableView.reloadData()
self.emptyView.update(theme: theme)
theme.applyStyle(onSearchBar: self.tableSearchBar)
self.addRoomHeaderView.update(theme: theme)
}
private func registerThemeServiceDidChangeThemeNotification() {
@ -152,9 +154,9 @@ final class SpaceExploreRoomViewController: UIViewController {
self.tableView.keyboardDismissMode = .interactive
self.setupTableView()
self.emptyView.fill(with: self.emptyViewArtwork, title: VectorL10n.roomsEmptyViewTitle, informationText: VectorL10n.roomsEmptyViewInformation)
self.setupTableViewHeader()
self.plusButtonImageView = self.vc_addFAB(withImage: Asset.Images.roomsFloatingAction.image, target: self, action: #selector(addRoomAction(semder:)))
self.emptyView.fill(with: self.emptyViewArtwork, title: VectorL10n.roomsEmptyViewTitle, informationText: VectorL10n.roomsEmptyViewInformation)
self.emptyView.frame = CGRect(x: 0, y: self.tableSearchBar.frame.maxY, width: self.view.bounds.width, height: self.view.bounds.height - self.tableSearchBar.frame.maxY)
self.emptyView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
@ -162,6 +164,11 @@ final class SpaceExploreRoomViewController: UIViewController {
self.view.insertSubview(self.emptyView, at: 0)
}
private func setupTableViewHeader() {
addRoomHeaderView.delegate = self
tableView.tableHeaderView = addRoomHeaderView
}
private func setupTableView() {
self.tableView.separatorStyle = .none
self.tableView.rowHeight = UITableView.automaticDimension
@ -224,10 +231,6 @@ final class SpaceExploreRoomViewController: UIViewController {
self.viewModel.process(viewAction: .cancel)
}
@objc private func addRoomAction(semder: UIView) {
self.errorPresenter.presentError(from: self, title: VectorL10n.spacesAddRoomsComingSoonTitle, message: VectorL10n.spacesComingSoonDetail, animated: true, handler: nil)
}
// MARK: - UISearchBarDelegate
override func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
@ -286,3 +289,12 @@ extension SpaceExploreRoomViewController: SpaceExploreRoomViewModelViewDelegate
self.render(viewState: viewSate)
}
}
// MARK: - SpaceMemberListViewModelViewDelegate
extension SpaceExploreRoomViewController: AddItemHeaderViewDelegate {
func addItemHeaderView(_ headerView: AddItemHeaderView, didTapButton button: UIButton) {
self.errorPresenter.presentError(from: self, title: VectorL10n.spacesAddRoomsComingSoonTitle, message: VectorL10n.spacesComingSoonDetail, animated: true, handler: nil)
}
}