Merge branch 'release/1.8.9/master'

This commit is contained in:
Stefan Ceriu 2022-03-28 13:45:29 +03:00
commit 751fe14ed3
28 changed files with 426 additions and 146 deletions

View file

@ -1,3 +1,20 @@
## Changes in 1.8.9 (2022-03-28)
🙌 Improvements
- Upgrade MatrixSDK version ([v0.23.1](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.23.1)).
- Update suggested room preview to behave the same way in all cases ([#5771](https://github.com/vector-im/element-ios/issues/5771))
- Add "Invite people" to the space menu in the left panel and update menu order ([#5810](https://github.com/vector-im/element-ios/issues/5810))
🐛 Bugfixes
- Sync Spaces order with web ([#5134](https://github.com/vector-im/element-ios/issues/5134))
- Fixed "Add Space" error message ([#5797](https://github.com/vector-im/element-ios/issues/5797))
- Authentication: Ensure the login button is always visible ([#5875](https://github.com/vector-im/element-ios/issues/5875))
- Room: Fix typing performance by avoiding expensive UI operations ([#5906](https://github.com/vector-im/element-ios/issues/5906))
- Push notifications: show space preview if user taps invite notification ([#5915](https://github.com/vector-im/element-ios/issues/5915))
## Changes in 1.8.8 (2022-03-22)
✨ Features

View file

@ -15,5 +15,5 @@
//
// Version
MARKETING_VERSION = 1.8.8
CURRENT_PROJECT_VERSION = 1.8.8
MARKETING_VERSION = 1.8.9
CURRENT_PROJECT_VERSION = 1.8.9

View file

@ -13,7 +13,7 @@ use_frameworks!
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI
#
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
$matrixSDKVersion = '= 0.23.0'
$matrixSDKVersion = '= 0.23.1'
# $matrixSDKVersion = :local
# $matrixSDKVersion = { :branch => 'develop'}
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }

View file

@ -56,16 +56,16 @@ PODS:
- LoggerAPI (1.9.200):
- Logging (~> 1.1)
- Logging (1.4.0)
- MatrixSDK (0.23.0):
- MatrixSDK/Core (= 0.23.0)
- MatrixSDK/Core (0.23.0):
- MatrixSDK (0.23.1):
- MatrixSDK/Core (= 0.23.1)
- MatrixSDK/Core (0.23.1):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.3.0)
- libbase58 (~> 0.1.4)
- OLMKit (~> 3.2.5)
- Realm (= 10.16.0)
- SwiftyBeaver (= 1.9.5)
- MatrixSDK/JingleCallStack (0.23.0):
- MatrixSDK/JingleCallStack (0.23.1):
- JitsiMeetSDK (= 3.10.2)
- MatrixSDK/Core
- OLMKit (3.2.5):
@ -115,8 +115,8 @@ DEPENDENCIES:
- KeychainAccess (~> 4.2.2)
- KTCenterFlowLayout (~> 1.3.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatrixSDK (= 0.23.0)
- MatrixSDK/JingleCallStack (= 0.23.0)
- MatrixSDK (= 0.23.1)
- MatrixSDK/JingleCallStack (= 0.23.1)
- OLMKit
- PostHog (~> 1.4.4)
- ReadMoreTextView (~> 3.0.1)
@ -208,7 +208,7 @@ SPEC CHECKSUMS:
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
Logging: beeb016c9c80cf77042d62e83495816847ef108b
MatrixSDK: 5934f25944388513d7a379cd5e191a231ceed45f
MatrixSDK: 54d16aa08f3043fb1bcf639ef1ac5c589100f39f
OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5
PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
@ -225,6 +225,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: 426c919fd3f444aa747155bfcc20f9092573f1aa
PODFILE CHECKSUM: 820f04e07aa252459ecfa88d04da729daca4fcbb
COCOAPODS: 1.11.3

View file

@ -36,3 +36,5 @@
"onboarding_avatar_accessibility_label" = "Profile picture";
"image_picker_action_files" = "Choose from files";
"spaces_feature_not_available" = "This feature isn't available here. For now, you can do this with %@ on your computer.";

View file

@ -70,6 +70,10 @@ public extension VectorL10n {
static var onboardingPersonalizationSkip: String {
return VectorL10n.tr("Untranslated", "onboarding_personalization_skip")
}
/// This feature isn't available here. For now, you can do this with %@ on your computer.
static func spacesFeatureNotAvailable(_ p1: String) -> String {
return VectorL10n.tr("Untranslated", "spaces_feature_not_available", p1)
}
}
// swiftlint:enable function_parameter_count identifier_name line_length type_body_length

View file

@ -108,10 +108,12 @@ NS_ASSUME_NONNULL_BEGIN
@param pushNotificationService PushNotificationService object.
@param roomId Room identifier to be navigated.
@param userId ID of sender of the notification.
*/
- (void)pushNotificationService:(PushNotificationService *)pushNotificationService
shouldNavigateToRoomWithId:(NSString *)roomId
threadId:(nullable NSString *)threadId;
threadId:(nullable NSString *)threadId
sender:(nullable NSString *)userId;
@end;

View file

@ -364,6 +364,7 @@ Matrix session observer used to detect new opened sessions.
NSString *actionIdentifier = [response actionIdentifier];
NSString *roomId = content.userInfo[@"room_id"];
NSString *threadId = content.userInfo[@"thread_id"];
NSString *userId = content.userInfo[@"user_id"];
if ([actionIdentifier isEqualToString:@"inline-reply"])
{
@ -403,7 +404,7 @@ Matrix session observer used to detect new opened sessions.
}
else if ([actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier])
{
[self notifyNavigateToRoomById:roomId threadId:threadId];
[self notifyNavigateToRoomById:roomId threadId:threadId sender:userId];
completionHandler();
}
else
@ -567,11 +568,11 @@ Matrix session observer used to detect new opened sessions.
#pragma mark - Delegate Notifiers
- (void)notifyNavigateToRoomById:(NSString *)roomId threadId:(NSString *)threadId
- (void)notifyNavigateToRoomById:(NSString *)roomId threadId:(NSString *)threadId sender:(NSString *)userId
{
if ([_delegate respondsToSelector:@selector(pushNotificationService:shouldNavigateToRoomWithId:threadId:)])
if ([_delegate respondsToSelector:@selector(pushNotificationService:shouldNavigateToRoomWithId:threadId:sender:)])
{
[_delegate pushNotificationService:self shouldNavigateToRoomWithId:roomId threadId:threadId];
[_delegate pushNotificationService:self shouldNavigateToRoomWithId:roomId threadId:threadId sender:userId];
}
}

View file

@ -1108,6 +1108,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)pushNotificationService:(PushNotificationService *)pushNotificationService
shouldNavigateToRoomWithId:(NSString *)roomId
threadId:(NSString *)threadId
sender:(NSString *)userId
{
if (roomId)
{
@ -1123,7 +1124,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
_lastNavigatedRoomIdFromPush = roomId;
[self navigateToRoomById:roomId threadId:threadId];
[self navigateToRoomById:roomId threadId:threadId sender:userId];
}
#pragma mark - Badge Count
@ -2912,7 +2913,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
#pragma mark - Matrix Rooms handling
- (void)navigateToRoomById:(NSString *)roomId threadId:(NSString *)threadId
- (void)navigateToRoomById:(NSString *)roomId threadId:(NSString *)threadId sender:(NSString *)userId
{
if (roomId.length)
{
@ -2949,7 +2950,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[self showRoom:roomId
threadId:threadId
andEventId:nil
withMatrixSession:dedicatedAccount.mxSession];
withMatrixSession:dedicatedAccount.mxSession
sender:userId];
}
else
{
@ -2967,7 +2969,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
NSString *roomId = parameters.roomId;
MXSession *mxSession = parameters.mxSession;
BOOL restoreInitialDisplay = parameters.presentationParameters.restoreInitialDisplay;
if (roomId && mxSession)
{
@ -2978,21 +2979,38 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[Analytics.shared trackViewRoom:room];
}
// Indicates that spaces are not supported
if (room.summary.roomType == MXRoomTypeSpace)
if (!room)
{
[self.spaceFeatureUnavailablePresenter presentUnavailableFeatureFrom:self.presentedViewController animated:YES];
if (completion)
{
completion();
}
MXWeakify(self);
[mxSession.matrixRestClient roomSummaryWith:roomId via:@[] success:^(MXPublicRoom *room) {
MXStrongifyAndReturnIfNil(self);
if ([room.roomTypeString isEqualToString:MXRoomTypeStringSpace])
{
SpacePreviewNavigationParameters *spacePreviewNavigationParameters = [[SpacePreviewNavigationParameters alloc] initWithPublicRoom:room mxSession:mxSession senderId:parameters.senderId presentationParameters:parameters.presentationParameters];
[self showSpacePreviewWithParameters:spacePreviewNavigationParameters];
}
else
{
[self finaliseShowRoomWithParameters:parameters completion:completion];
}
} failure:^(NSError *error) {
MXStrongifyAndReturnIfNil(self);
[self finaliseShowRoomWithParameters:parameters completion:completion];
}];
return;
}
}
[self finaliseShowRoomWithParameters:parameters completion:completion];
}
- (void)finaliseShowRoomWithParameters:(RoomNavigationParameters*)parameters completion:(void (^)(void))completion
{
NSString *roomId = parameters.roomId;
BOOL restoreInitialDisplay = parameters.presentationParameters.restoreInitialDisplay;
void (^selectRoom)(void) = ^() {
// Select room to display its details (dispatch this action in order to let TabBarController end its refresh)
@ -3021,10 +3039,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession
{
[self showRoom:roomId threadId:nil andEventId:eventId withMatrixSession:mxSession];
[self showRoom:roomId threadId:nil andEventId:eventId withMatrixSession:mxSession sender:nil];
}
- (void)showRoom:(NSString*)roomId threadId:(NSString*)threadId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession
- (void)showRoom:(NSString*)roomId threadId:(NSString*)threadId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession sender:(NSString*)userId
{
// Ask to restore initial display
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES];
@ -3038,6 +3056,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:mxSession
senderId:userId
threadParameters:threadParameters
presentationParameters:presentationParameters];
@ -3097,6 +3116,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
void(^showSpace)(void) = ^{
[self.spaceDetailPresenter presentForSpaceWithPublicRoom:parameters.publicRoom
senderId:parameters.senderId
from:presentingViewController
sourceView:sourceView
session:parameters.mxSession

View file

@ -58,6 +58,9 @@ class RoomNavigationParameters: NSObject {
/// If `true`, the room settings screen will be initially displayed. Default `false`
let showSettingsInitially: Bool
/// ID of the sender of the notification. Default `nil`
let senderId: String?
// MARK: - Setup
init(roomId: String,
@ -71,6 +74,24 @@ class RoomNavigationParameters: NSObject {
self.threadParameters = threadParameters
self.presentationParameters = presentationParameters
self.showSettingsInitially = false
self.senderId = nil
super.init()
}
init(roomId: String,
eventId: String?,
mxSession: MXSession,
senderId: String?,
threadParameters: ThreadParameters?,
presentationParameters: ScreenPresentationParameters) {
self.roomId = roomId
self.eventId = eventId
self.mxSession = mxSession
self.threadParameters = threadParameters
self.presentationParameters = presentationParameters
self.showSettingsInitially = false
self.senderId = senderId
super.init()
}
@ -86,7 +107,8 @@ class RoomNavigationParameters: NSObject {
self.presentationParameters = presentationParameters
self.showSettingsInitially = showSettingsInitially
self.threadParameters = nil
self.senderId = nil
super.init()
}
}

View file

@ -25,12 +25,28 @@ class SpacePreviewNavigationParameters: SpaceNavigationParameters {
/// The data for the room preview
let publicRoom: MXPublicRoom
/// The ID of the sender of the invite
let senderId: String?
// MARK: - Setup
init(publicRoom: MXPublicRoom,
mxSession: MXSession,
presentationParameters: ScreenPresentationParameters) {
self.publicRoom = publicRoom
self.senderId = nil
super.init(roomId: publicRoom.roomId,
mxSession: mxSession,
presentationParameters: presentationParameters)
}
init(publicRoom: MXPublicRoom,
mxSession: MXSession,
senderId: String?,
presentationParameters: ScreenPresentationParameters) {
self.publicRoom = publicRoom
self.senderId = senderId
super.init(roomId: publicRoom.roomId,
mxSession: mxSession,

View file

@ -31,8 +31,6 @@
@property (weak, nonatomic) IBOutlet UIButton *skipButton;
@property (weak, nonatomic) IBOutlet UIButton *forgotPasswordButton;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *submitButtonMinLeadingConstraint;
@property (weak, nonatomic) IBOutlet UIView *serverOptionsContainer;
@property (weak, nonatomic) IBOutlet UIButton *customServersTickButton;
@property (weak, nonatomic) IBOutlet UIView *customServersContainer;

View file

@ -1058,17 +1058,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0;
}
self.forgotPasswordButton.hidden = !showForgotPasswordButton;
// Adjust minimum leading constraint of the submit button
if (self.forgotPasswordButton.isHidden)
{
self.submitButtonMinLeadingConstraint.constant = 19;
}
else
{
CGRect frame = self.forgotPasswordButton.frame;
self.submitButtonMinLeadingConstraint.constant = frame.origin.x + frame.size.width + 10;
}
}
- (void)afterSetPinFlowCompletedWithCredentials:(MXCredentials*)credentials

View file

@ -1,9 +1,9 @@
<?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">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina5_9" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -44,7 +44,6 @@
<outlet property="softLogoutClearDataContainer" destination="vX2-5Y-rQc" id="mgK-41-cnX"/>
<outlet property="softLogoutClearDataLabel" destination="QYL-Lo-tmH" id="ks9-5X-xfs"/>
<outlet property="submitButton" destination="k3J-Eg-itz" id="fiZ-wK-6YM"/>
<outlet property="submitButtonMinLeadingConstraint" destination="bEB-EO-b14" id="Iz5-ks-nSX"/>
<outlet property="view" destination="5rn-KE-plm" id="bFJ-yJ-vc0"/>
<outlet property="welcomeImageView" destination="d8r-TX-pwX" id="vzD-zK-EeC"/>
</connections>
@ -91,7 +90,7 @@
</constraints>
</view>
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Currently we do not support authentication flows defined by this homeserver" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="54b-4O-ip9" userLabel="noFlowLabel">
<rect key="frame" x="28" y="8" width="319.33333333333331" height="33.666666666666664"/>
<rect key="frame" x="28" y="8" width="319" height="33.666666666666664"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -129,63 +128,73 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gg0-TE-OGb">
<rect key="frame" x="0.0" y="360" width="375" height="125"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" hasAttributedTitle="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AJ2-lJ-NUq">
<rect key="frame" x="19" y="33" width="122" height="30"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCForgotPasswordButton"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="1mr-dZ-KtP"/>
</constraints>
<state key="normal">
<attributedString key="attributedTitle">
<fragment content="Forgot password?">
<attributes>
<color key="NSColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<font key="NSFont" size="15" name="HelveticaNeue"/>
</attributes>
</fragment>
</attributedString>
</state>
<connections>
<action selector="onButtonPressed:" destination="-1" eventType="touchUpInside" id="UVJ-Re-xe2"/>
</connections>
</button>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wEJ-AF-rdH">
<rect key="frame" x="11" y="33" width="106" height="30"/>
<color key="backgroundColor" red="0.028153735480000001" green="0.82494870580000002" blue="0.051896891280000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCSkipButton"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="HIX-iq-vTC"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="contentEdgeInsets" minX="30" minY="0.0" maxX="30" maxY="0.0"/>
<state key="normal" title="Skip">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="onButtonPressed:" destination="-1" eventType="touchUpInside" id="iEr-Vf-f6P"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k3J-Eg-itz" userLabel="SubmitBtn">
<rect key="frame" x="258" y="33" width="106" height="30"/>
<color key="backgroundColor" red="0.028153735480000001" green="0.82494870580000002" blue="0.051896891280000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCLoginButton"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="100" id="3ST-q4-gu8"/>
<constraint firstAttribute="height" constant="30" id="rR8-KH-2z5"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="contentEdgeInsets" minX="30" minY="0.0" maxX="30" maxY="0.0"/>
<state key="normal" title="Log In">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="onButtonPressed:" destination="-1" eventType="touchUpInside" id="Ocd-Ag-6hf"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FIn-2w-e6H">
<rect key="frame" x="0.0" y="68" width="375" height="178"/>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="7OO-nL-hff">
<rect key="frame" x="11" y="33" width="353" height="65"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillProportionally" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="Oeh-7N-HNr">
<rect key="frame" x="0.0" y="0.0" width="106" height="30"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k3J-Eg-itz" userLabel="SubmitBtn">
<rect key="frame" x="0.0" y="0.0" width="106" height="30"/>
<color key="backgroundColor" red="0.028153735480000001" green="0.82494870580000002" blue="0.051896891280000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCLoginButton"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="BPY-Sb-k8F"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="100" id="L9J-9d-puh"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="contentEdgeInsets" minX="30" minY="0.0" maxX="30" maxY="0.0"/>
<state key="normal" title="Log In">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="onButtonPressed:" destination="-1" eventType="touchUpInside" id="Ocd-Ag-6hf"/>
</connections>
</button>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wEJ-AF-rdH">
<rect key="frame" x="0.0" y="0.0" width="0.0" height="30"/>
<color key="backgroundColor" red="0.028153735480000001" green="0.82494870580000002" blue="0.051896891280000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCSkipButton"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="contentEdgeInsets" minX="30" minY="0.0" maxX="30" maxY="0.0"/>
<state key="normal" title="Skip">
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="onButtonPressed:" destination="-1" eventType="touchUpInside" id="iEr-Vf-f6P"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="k3J-Eg-itz" firstAttribute="height" secondItem="wEJ-AF-rdH" secondAttribute="height" id="hhT-7b-PVV"/>
</constraints>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" hasAttributedTitle="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AJ2-lJ-NUq">
<rect key="frame" x="0.0" y="35" width="122" height="30"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCForgotPasswordButton"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="1mr-dZ-KtP"/>
</constraints>
<state key="normal">
<attributedString key="attributedTitle">
<fragment content="Forgot password?">
<attributes>
<color key="NSColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<font key="NSFont" size="15" name="HelveticaNeue"/>
</attributes>
</fragment>
</attributedString>
</state>
<connections>
<action selector="onButtonPressed:" destination="-1" eventType="touchUpInside" id="UVJ-Re-xe2"/>
</connections>
</button>
</subviews>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FIn-2w-e6H" userLabel="Server Options">
<rect key="frame" x="0.0" y="103" width="375" height="178"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" hasAttributedTitle="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6yx-o1-vbD">
<rect key="frame" x="19" y="5" width="337" height="30"/>
@ -333,8 +342,8 @@
<constraint firstAttribute="trailing" secondItem="6yx-o1-vbD" secondAttribute="trailing" constant="19" id="rWk-Mp-KPS"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vX2-5Y-rQc">
<rect key="frame" x="0.0" y="96" width="375" height="170"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vX2-5Y-rQc" userLabel="Soft Logout">
<rect key="frame" x="0.0" y="148" width="375" height="170"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QYL-Lo-tmH">
<rect key="frame" x="10" y="0.0" width="355" height="121"/>
@ -384,21 +393,16 @@ Clear it if you're finished using this device, or want to sign in to another acc
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCOptionsContainer"/>
<constraints>
<constraint firstItem="FIn-2w-e6H" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" id="3G8-Tb-KaN"/>
<constraint firstItem="wEJ-AF-rdH" firstAttribute="width" secondItem="k3J-Eg-itz" secondAttribute="width" id="7sB-YJ-eX4"/>
<constraint firstAttribute="trailing" secondItem="vX2-5Y-rQc" secondAttribute="trailing" id="DPh-Jx-WP1"/>
<constraint firstItem="FIn-2w-e6H" firstAttribute="top" secondItem="7OO-nL-hff" secondAttribute="bottom" constant="5" id="Ilt-ab-dEa"/>
<constraint firstItem="vX2-5Y-rQc" firstAttribute="top" secondItem="7OO-nL-hff" secondAttribute="bottom" constant="50" id="LTk-s1-SEs"/>
<constraint firstItem="7OO-nL-hff" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" constant="11" id="Otw-gC-R6C"/>
<constraint firstItem="vX2-5Y-rQc" firstAttribute="top" secondItem="Gg0-TE-OGb" secondAttribute="top" priority="100" id="QSG-jB-VcV"/>
<constraint firstItem="wEJ-AF-rdH" firstAttribute="centerY" secondItem="k3J-Eg-itz" secondAttribute="centerY" id="Vze-EI-oXj"/>
<constraint firstAttribute="trailing" secondItem="k3J-Eg-itz" secondAttribute="trailing" constant="11" id="ZyA-Tq-Sfq"/>
<constraint firstItem="k3J-Eg-itz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Gg0-TE-OGb" secondAttribute="leading" constant="150" id="bEB-EO-b14"/>
<constraint firstItem="vX2-5Y-rQc" firstAttribute="top" secondItem="k3J-Eg-itz" secondAttribute="bottom" constant="33" id="db7-2y-vPZ"/>
<constraint firstItem="AJ2-lJ-NUq" firstAttribute="centerY" secondItem="k3J-Eg-itz" secondAttribute="centerY" id="dcE-Vs-7Rt"/>
<constraint firstItem="7OO-nL-hff" firstAttribute="top" secondItem="Gg0-TE-OGb" secondAttribute="top" constant="33" id="e4H-ld-bD7"/>
<constraint firstAttribute="trailing" secondItem="FIn-2w-e6H" secondAttribute="trailing" id="kFj-6g-v3H"/>
<constraint firstItem="vX2-5Y-rQc" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" id="kYN-Lj-zYP"/>
<constraint firstAttribute="height" priority="700" constant="300" id="lXv-gM-CjN"/>
<constraint firstItem="k3J-Eg-itz" firstAttribute="top" secondItem="Gg0-TE-OGb" secondAttribute="top" constant="33" id="mor-t9-7Ke"/>
<constraint firstItem="FIn-2w-e6H" firstAttribute="top" secondItem="k3J-Eg-itz" secondAttribute="bottom" constant="5" id="oTS-5o-MMW"/>
<constraint firstItem="wEJ-AF-rdH" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" constant="11" id="sax-RY-aOJ"/>
<constraint firstItem="AJ2-lJ-NUq" firstAttribute="leading" secondItem="Gg0-TE-OGb" secondAttribute="leading" constant="19" id="xFm-Bs-yzw"/>
<constraint firstAttribute="trailing" secondItem="7OO-nL-hff" secondAttribute="trailing" constant="11" id="pPK-AD-wiD"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TjK-XL-dQS">

View file

@ -36,7 +36,7 @@
NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewControllerDataReadyNotification";
@interface RecentsViewController () <CreateRoomCoordinatorBridgePresenterDelegate, RoomsDirectoryCoordinatorBridgePresenterDelegate, RoomNotificationSettingsCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, ExploreRoomCoordinatorBridgePresenterDelegate>
@interface RecentsViewController () <CreateRoomCoordinatorBridgePresenterDelegate, RoomsDirectoryCoordinatorBridgePresenterDelegate, RoomNotificationSettingsCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, ExploreRoomCoordinatorBridgePresenterDelegate, SpaceChildRoomDetailBridgePresenterDelegate>
{
// Tell whether a recents refresh is pending (suspended during editing mode).
BOOL isRefreshPending;
@ -83,6 +83,8 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
@property (nonatomic, strong) RoomNotificationSettingsCoordinatorBridgePresenter *roomNotificationSettingsCoordinatorBridgePresenter;
@property (nonatomic, strong) SpaceChildRoomDetailBridgePresenter *spaceChildPresenter;
@end
@implementation RecentsViewController
@ -2170,18 +2172,13 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
[self showRoomWithRoomId:roomId inMatrixSession:matrixSession];
}
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectSuggestedRoom:(MXSpaceChildInfo *)childInfo
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectSuggestedRoom:(MXSpaceChildInfo *)childInfo from:(UIView* _Nullable)sourceView
{
Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerSpaceHierarchy;
RoomPreviewData *previewData = [[RoomPreviewData alloc] initWithSpaceChildInfo:childInfo andSession:self.mainSession];
[self startActivityIndicator];
MXWeakify(self);
[previewData peekInRoom:^(BOOL succeeded) {
MXStrongifyAndReturnIfNil(self);
[self stopActivityIndicator];
[self showRoomPreviewWithData:previewData];
}];
self.spaceChildPresenter = [[SpaceChildRoomDetailBridgePresenter alloc] initWithSession:self.mainSession childInfo:childInfo];
self.spaceChildPresenter.delegate = self;
[self.spaceChildPresenter presentFrom:self sourceView:sourceView animated:YES];
}
#pragma mark - UISearchBarDelegate
@ -2432,6 +2429,23 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
self.roomNotificationSettingsCoordinatorBridgePresenter = nil;
}
#pragma mark - SpaceChildRoomDetailBridgePresenterDelegate
- (void)spaceChildRoomDetailBridgePresenterDidCancel:(SpaceChildRoomDetailBridgePresenter *)coordinator
{
[self.spaceChildPresenter dismissWithAnimated:YES completion:^{
self.spaceChildPresenter = nil;
}];
}
- (void)spaceChildRoomDetailBridgePresenter:(SpaceChildRoomDetailBridgePresenter *)coordinator didOpenRoomWith:(NSString *)roomId
{
[self showRoomWithRoomId:roomId inMatrixSession:self.mainSession];
[self.spaceChildPresenter dismissWithAnimated:YES completion:^{
self.spaceChildPresenter = nil;
}];
}
#pragma mark - Activity Indicator
- (BOOL)providesCustomActivityIndicator {

View file

@ -605,7 +605,8 @@
if (renderedCellData.isSuggestedRoom)
{
[self.delegate recentListViewController:self
didSelectSuggestedRoom:renderedCellData.roomSummary.spaceChildInfo];
didSelectSuggestedRoom:renderedCellData.roomSummary.spaceChildInfo
from:roomCollectionViewCell];
}
else
{

View file

@ -41,8 +41,9 @@ limitations under the License.
@param recentListViewController the `MXKRecentListViewController` instance.
@param childInfo the `MXSpaceChildInfo` instance that describes the selected room.
@param sourceView the view the modal has to be presented from.
*/
-(void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectSuggestedRoom:(MXSpaceChildInfo *)childInfo;
-(void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectSuggestedRoom:(MXSpaceChildInfo *)childInfo from:(UIView* _Nullable)sourceView;
@end

View file

@ -442,7 +442,8 @@
if (recentCellData.isSuggestedRoom)
{
[_delegate recentListViewController:self
didSelectSuggestedRoom:recentCellData.roomSummary.spaceChildInfo];
didSelectSuggestedRoom:recentCellData.roomSummary.spaceChildInfo
from:selectedCell];
}
else
{

View file

@ -1043,6 +1043,10 @@
- (void)setRoomTitleViewClass:(Class)roomTitleViewClass
{
if ([self.titleView.class isEqual:roomTitleViewClass]) {
return;
}
// Sanity check: accept only MXKRoomTitleView classes or sub-classes
NSParameterAssert([roomTitleViewClass isSubclassOfClass:MXKRoomTitleView.class]);

View file

@ -162,6 +162,9 @@ static CGSize kThreadListBarButtonItemImageSize;
// A flag indicating whether a room has been left
BOOL isRoomLeft;
// The last known frame of the view used to detect whether size-related layout change is needed
CGRect lastViewBounds;
// Tell whether the room has a Jitsi call or not.
BOOL hasJitsiCall;
@ -225,7 +228,7 @@ static CGSize kThreadListBarButtonItemImageSize;
// When layout of the screen changes (e.g. height), we no longer know whether
// to autoscroll to the bottom again or not. Instead we need to capture the
// scroll state just before the layout change, and restore it after the layout.
@property (nonatomic) BOOL shouldScrollToBottomAfterLayout;
@property (nonatomic) BOOL wasScrollAtBottomBeforeLayout;
/// Handles all banners that should be displayed at the top of the timeline but that should not scroll with the timeline
@property (weak, nonatomic, nullable) IBOutlet UIStackView *topBannersStackView;
@ -694,12 +697,14 @@ static CGSize kThreadListBarButtonItemImageSize;
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
self.shouldScrollToBottomAfterLayout = self.isBubblesTableScrollViewAtTheBottom;
self.wasScrollAtBottomBeforeLayout = self.isBubblesTableScrollViewAtTheBottom;
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
BOOL didViewChangeBounds = !CGRectEqualToRect(lastViewBounds, self.view.bounds);
lastViewBounds = self.view.bounds;
UIEdgeInsets contentInset = self.bubblesTableView.contentInset;
contentInset.bottom = self.view.safeAreaInsets.bottom;
@ -763,9 +768,9 @@ static CGSize kThreadListBarButtonItemImageSize;
}
// re-scroll to the bottom, if at bottom before the most recent layout
if (self.shouldScrollToBottomAfterLayout)
if (self.wasScrollAtBottomBeforeLayout && didViewChangeBounds)
{
self.shouldScrollToBottomAfterLayout = NO;
self.wasScrollAtBottomBeforeLayout = NO;
[self scrollBubblesTableViewToBottomAnimated:NO];
}
@ -1378,6 +1383,10 @@ static CGSize kThreadListBarButtonItemImageSize;
- (void)setRoomTitleViewClass:(Class)roomTitleViewClass
{
if ([self.titleView.class isEqual:roomTitleViewClass]) {
return;
}
// Sanity check: accept only MXKRoomTitleView classes or sub-classes
NSParameterAssert([roomTitleViewClass isSubclassOfClass:MXKRoomTitleView.class]);

View file

@ -320,6 +320,36 @@ final class SideMenuCoordinator: NSObject, SideMenuCoordinatorType {
self.spaceSettingsCoordinator = coordinator
}
func showSpaceInvite(spaceId: String, session: MXSession) {
guard let space = session.spaceService.getSpace(withId: spaceId), let spaceRoom = space.room else {
MXLog.error("[SideMenuCoordinator] showSpaceInvite: failed to find space with id \(spaceId)")
return
}
spaceRoom.state { [weak self] roomState in
guard let self = self else { return }
guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else {
MXLog.error("[SpaceMembersCoordinator] spaceMemberListCoordinatorShowInvite: failed to find powerLevels for room")
return
}
let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId)
guard userPowerLevel >= powerLevels.invite else {
let alert = UIAlertController(title: VectorL10n.spacesInvitePeople, message: VectorL10n.spaceInviteNotEnoughPermission, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: VectorL10n.ok, style: .default, handler: nil))
self.sideMenuViewController.present(alert, animated: true)
return
}
let coordinator = ContactsPickerCoordinator(session: session, room: spaceRoom, initialSearchText: nil, actualParticipants: nil, invitedParticipants: nil, userParticipant: nil)
coordinator.delegate = self
coordinator.start()
self.add(childCoordinator: coordinator)
self.sideMenuViewController.present(coordinator.toPresentable(), animated: true)
}
}
private func resetExploringSpaceIfNeeded() {
if sideMenuNavigationViewController.presentedViewController == nil {
Analytics.shared.exploringSpace = nil
@ -430,13 +460,15 @@ extension SideMenuCoordinator: SpaceMenuPresenterDelegate {
}
}
case .addSpace:
AppDelegate.theDelegate().showAlert(withTitle: VectorL10n.spacesAddSpace, message: VectorL10n.spacesComingSoonDetail(AppInfo.current.displayName))
AppDelegate.theDelegate().showAlert(withTitle: VectorL10n.spacesAddSpace, message: VectorL10n.spacesFeatureNotAvailable(AppInfo.current.displayName))
case .settings:
if #available(iOS 14.0, *) {
self.showSpaceSettings(spaceId: spaceId, session: session)
} else {
AppDelegate.theDelegate().showAlert(withTitle: VectorL10n.settingsTitle, message: VectorL10n.spacesComingSoonDetail(AppInfo.current.displayName))
AppDelegate.theDelegate().showAlert(withTitle: VectorL10n.settingsTitle, message: VectorL10n.spacesFeatureNotAvailable(AppInfo.current.displayName))
}
case .invite:
self.showSpaceInvite(spaceId: spaceId, session: session)
}
}
}
@ -511,6 +543,19 @@ extension SideMenuCoordinator: CreateRoomCoordinatorDelegate {
}
}
// MARK: - ContactsPickerCoordinatorDelegate
extension SideMenuCoordinator: ContactsPickerCoordinatorDelegate {
func contactsPickerCoordinatorDidStartLoading(_ coordinator: ContactsPickerCoordinatorProtocol) {
}
func contactsPickerCoordinatorDidEndLoading(_ coordinator: ContactsPickerCoordinatorProtocol) {
}
func contactsPickerCoordinatorDidClose(_ coordinator: ContactsPickerCoordinatorProtocol) {
remove(childCoordinator: coordinator)
}
}
// MARK: - UIAdaptivePresentationControllerDelegate
extension SideMenuCoordinator: UIAdaptivePresentationControllerDelegate {

View file

@ -40,6 +40,7 @@ class SpaceDetailPresenter: NSObject {
}()
private var session: MXSession!
private var spaceId: String!
private var senderId: String?
// MARK: - Public
@ -59,15 +60,16 @@ class SpaceDetailPresenter: NSObject {
self.show(with: session)
}
@objc func present(forSpaceWithPublicRoom publicRoom: MXPublicRoom,
@objc func present(forSpaceWithPublicRoom publicRoom: MXPublicRoom, senderId: String?,
from viewController: UIViewController,
sourceView: UIView?,
session: MXSession,
animated: Bool) {
self.session = session
self.spaceId = publicRoom.roomId
self.senderId = senderId
self.viewModel = SpaceDetailViewModel(session: session, publicRoom: publicRoom)
self.viewModel = SpaceDetailViewModel(session: session, publicRoom: publicRoom, senderId: senderId)
self.viewModel.coordinatorDelegate = self
self.presentingViewController = viewController
self.sourceView = sourceView

View file

@ -26,6 +26,7 @@ class SpaceDetailViewModel: SpaceDetailViewModelType {
private let session: MXSession
private let spaceId: String
private let senderId: String?
private let publicRoom: MXPublicRoom?
private var spaceGraphObserver: Any?
@ -35,12 +36,14 @@ class SpaceDetailViewModel: SpaceDetailViewModelType {
self.session = session
self.spaceId = spaceId
self.publicRoom = nil
self.senderId = nil
}
init(session: MXSession, publicRoom: MXPublicRoom) {
init(session: MXSession, publicRoom: MXPublicRoom, senderId: String?) {
self.session = session
self.publicRoom = publicRoom
self.spaceId = publicRoom.roomId
self.senderId = senderId
}
deinit {
@ -76,14 +79,21 @@ class SpaceDetailViewModel: SpaceDetailViewModelType {
private func loadData() {
if let publicRoom = self.publicRoom {
let sender: MXUser?
if let senderId = self.senderId {
sender = session.user(withUserId: senderId)
} else {
sender = nil
}
self.update(viewState: .loaded(SpaceDetailLoadedParameters(spaceId: publicRoom.roomId,
displayName: publicRoom.displayname(),
topic: publicRoom.topic,
avatarUrl: publicRoom.avatarUrl,
joinRule: publicRoom.worldReadable ? .public : .private,
membership: .unknown,
inviterId: nil,
inviter: nil,
membership: self.senderId != nil ? .invite : .unknown,
inviterId: self.senderId,
inviter: sender,
membersCount: UInt(publicRoom.numJoinedMembers))))
} else {
guard let space = self.session.spaceService.getSpace(withId: self.spaceId), let summary = space.summary else {

View file

@ -184,7 +184,7 @@ final class SpaceListViewModel: SpaceListViewModelType {
var index = 0
for itemViewData in viewDataList {
if itemViewData.spaceId == self.selectedItemId {
newSelection = IndexPath(row: index, section: sections.count - 1)
newSelection = IndexPath(row: index, section: spacesSectionIndex)
}
index += 1
}

View file

@ -25,6 +25,7 @@ enum SpaceMenuListItemAction {
case addSpace
case settings
case leaveSpace
case invite
}
/// Style of the `SpaceMenuListViewCell`

View file

@ -27,6 +27,7 @@ class SpaceMenuPresenter: NSObject {
case addRoom
case addSpace
case settings
case invite
}
// MARK: - Properties
@ -117,6 +118,8 @@ extension SpaceMenuPresenter: SpaceMenuModelViewModelCoordinatorDelegate {
self.delegate?.spaceMenuPresenter(self, didCompleteWith: .addSpace, forSpaceWithId: self.spaceId, with: self.session)
case .settings:
self.delegate?.spaceMenuPresenter(self, didCompleteWith: .settings, forSpaceWithId: self.spaceId, with: self.session)
case .invite:
self.delegate?.spaceMenuPresenter(self, didCompleteWith: .invite, forSpaceWithId: self.spaceId, with: self.session)
default:
MXLog.error("[SpaceMenuPresenter] spaceListViewModel didSelectItem: invalid action \(action)")
}

View file

@ -25,11 +25,12 @@ class SpaceMenuViewModel: SpaceMenuViewModelType {
weak var viewDelegate: SpaceMenuViewModelViewDelegate?
private let spaceMenuItems: [SpaceMenuListItemViewData] = [
SpaceMenuListItemViewData(action: .exploreSpaceMembers, style: .normal, title: VectorL10n.roomDetailsPeople, icon: Asset.Images.spaceMenuMembers.image, value: nil),
SpaceMenuListItemViewData(action: .invite, style: .normal, title: VectorL10n.spacesInvitePeople, icon: Asset.Images.spaceInviteUser.image, value: nil),
SpaceMenuListItemViewData(action: .exploreSpaceRooms, style: .normal, title: VectorL10n.spacesExploreRooms, icon: Asset.Images.spaceMenuRooms.image, value: nil),
SpaceMenuListItemViewData(action: .exploreSpaceMembers, style: .normal, title: VectorL10n.roomDetailsPeople, icon: Asset.Images.spaceMenuMembers.image, value: nil),
SpaceMenuListItemViewData(action: .settings, style: .normal, title: VectorL10n.sideMenuActionSettings, icon: Asset.Images.sideMenuActionIconSettings.image, value: nil),
SpaceMenuListItemViewData(action: .addRoom, style: .normal, title: VectorL10n.spacesAddRoom, icon: Asset.Images.spaceMenuPlusIcon.image, value: nil),
SpaceMenuListItemViewData(action: .addSpace, style: .normal, title: VectorL10n.spacesAddSpace, icon: Asset.Images.spaceMenuPlusIcon.image, value: nil, isBeta: true),
SpaceMenuListItemViewData(action: .settings, style: .normal, title: VectorL10n.sideMenuActionSettings, icon: Asset.Images.sideMenuActionIconSettings.image, value: nil),
SpaceMenuListItemViewData(action: .leaveSpace, style: .destructive, title: VectorL10n.leave, icon: Asset.Images.spaceMenuLeave.image, value: nil)
]

View file

@ -0,0 +1,113 @@
/*
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
@objc protocol SpaceChildRoomDetailBridgePresenterDelegate {
func spaceChildRoomDetailBridgePresenter(_ coordinator: SpaceChildRoomDetailBridgePresenter, didOpenRoomWith roomId: String)
func spaceChildRoomDetailBridgePresenterDidCancel(_ coordinator: SpaceChildRoomDetailBridgePresenter)
}
/// SpaceChildRoomDetailBridgePresenter enables to start SpaceChildRoomDetailCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
/// It breaks the Coordinator abstraction and it has been introduced for Objective-C compatibility (mainly for integration in legacy view controllers). Each bridge should be removed once the underlying Coordinator has
/// been integrated by another Coordinator.
@objcMembers
final class SpaceChildRoomDetailBridgePresenter: NSObject {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private let childInfo: MXSpaceChildInfo
private var coordinator: SpaceChildRoomDetailCoordinator?
private lazy var slidingModalPresenter: SlidingModalPresenter = {
return SlidingModalPresenter()
}()
// MARK: Public
weak var delegate: SpaceChildRoomDetailBridgePresenterDelegate?
// MARK: - Setup
init(session: MXSession, childInfo: MXSpaceChildInfo) {
self.session = session
self.childInfo = childInfo
super.init()
}
// MARK: - Public
// NOTE: Default value feature is not compatible with Objective-C.
// func present(from viewController: UIViewController, animated: Bool) {
// self.present(from: viewController, animated: animated)
// }
func present(from viewController: UIViewController, sourceView: UIView?, animated: Bool) {
let coordinator = SpaceChildRoomDetailCoordinator(parameters: SpaceChildRoomDetailCoordinatorParameters(session: session, childInfo: childInfo))
coordinator.delegate = self
coordinator.start()
self.coordinator = coordinator
if UIDevice.current.isPhone || sourceView == nil {
slidingModalPresenter.present(coordinator.toSlidingPresentable(), from: viewController, animated: animated, completion: nil)
} else {
let presentable = coordinator.toPresentable()
presentable.modalPresentationStyle = .popover
if let sourceView = sourceView, let popoverPresentationController = presentable.popoverPresentationController {
popoverPresentationController.sourceView = sourceView
popoverPresentationController.sourceRect = sourceView.bounds
}
viewController.present(presentable, animated: true)
}
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let coordinator = self.coordinator else {
return
}
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
if let completion = completion {
completion()
}
}
}
}
// MARK: - SpaceChildRoomDetailCoordinatorDelegate
extension SpaceChildRoomDetailBridgePresenter: SpaceChildRoomDetailCoordinatorDelegate {
func spaceChildRoomDetailCoordinator(_ coordinator: SpaceChildRoomDetailCoordinatorType, didOpenRoomWith roomId: String) {
delegate?.spaceChildRoomDetailBridgePresenter(self, didOpenRoomWith: roomId)
}
func spaceChildRoomDetailCoordinatorDidCancel(_ coordinator: SpaceChildRoomDetailCoordinatorType) {
delegate?.spaceChildRoomDetailBridgePresenterDidCancel(self)
}
}
// MARK: - UIAdaptivePresentationControllerDelegate
extension SpaceChildRoomDetailBridgePresenter: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
delegate?.spaceChildRoomDetailBridgePresenterDidCancel(self)
}
}