mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-25 11:02:48 +02:00
Merge branch 'ismail/5068_design_tweaks' into ismail/5096_thread_notifications
This commit is contained in:
@@ -73,14 +73,6 @@
|
||||
return ThemeService.shared.theme.statusBarStyle;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"AttachmentsViewer"];
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[super destroy];
|
||||
|
||||
@@ -59,7 +59,7 @@ import Foundation
|
||||
case .reply:
|
||||
image = Asset.Images.roomContextMenuReply.image
|
||||
case .replyInThread:
|
||||
image = Asset.Images.roomContextMenuReplyInThread.image
|
||||
image = Asset.Images.roomContextMenuThread.image
|
||||
case .edit:
|
||||
image = Asset.Images.roomContextMenuEdit.image
|
||||
case .more:
|
||||
|
||||
@@ -564,7 +564,7 @@ const CGFloat kTypingCellHeight = 24;
|
||||
constant:leftMargin],
|
||||
topConstraint,
|
||||
[threadSummaryView.heightAnchor constraintEqualToConstant:[ThreadSummaryView contentViewHeightForThread:component.thread fitting:cellData.maxTextViewWidth]],
|
||||
[threadSummaryView.trailingAnchor constraintEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
|
||||
[threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
|
||||
]];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
/// Class to build an event menu.
|
||||
@objcMembers
|
||||
class EventMenuBuilder: NSObject {
|
||||
|
||||
private var items: [EventMenuItemType: UIAlertAction] = [:]
|
||||
|
||||
/// Returns true if no items or only one item with the type `EventMenuItemType.cancel`.
|
||||
var isEmpty: Bool {
|
||||
return items.isEmpty || (items.count == 1 && items.first?.key == .cancel)
|
||||
}
|
||||
|
||||
/// Add a menu item.
|
||||
/// - Parameters:
|
||||
/// - type: item type
|
||||
/// - action: alert action
|
||||
func addItem(withType type: EventMenuItemType,
|
||||
action: UIAlertAction) {
|
||||
items[type] = action
|
||||
}
|
||||
|
||||
/// Builds the action menu items.
|
||||
/// - Returns: alert actions. Sorted by item types.
|
||||
func build() -> [UIAlertAction] {
|
||||
items.sorted(by: { $0.key < $1.key }).map { $1 }
|
||||
}
|
||||
|
||||
/// Reset the builder. Builder will be empty after this method call.
|
||||
func reset() {
|
||||
items.removeAll()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
/// Type of an event menu item. Ordering of the cases is important. See `EventMenuBuilder`.
|
||||
@objc
|
||||
enum EventMenuItemType: Int {
|
||||
case viewInRoom
|
||||
case copy
|
||||
case retrySending
|
||||
case cancelSending
|
||||
case cancelDownloading
|
||||
case saveMedia
|
||||
case quote
|
||||
case forward
|
||||
case permalink
|
||||
case share
|
||||
case removePoll
|
||||
case endPoll
|
||||
case reactionHistory
|
||||
case viewSource
|
||||
case viewDecryptedSource
|
||||
case viewEncryption
|
||||
case report
|
||||
case remove
|
||||
case cancel
|
||||
}
|
||||
|
||||
extension EventMenuItemType: Comparable {
|
||||
|
||||
static func < (lhs: EventMenuItemType, rhs: EventMenuItemType) -> Bool {
|
||||
return lhs.rawValue < rhs.rawValue
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,8 @@ limitations under the License.
|
||||
|
||||
#import "MatrixKit.h"
|
||||
|
||||
@class AnalyticsScreenTimer;
|
||||
|
||||
/**
|
||||
This view controller displays the attachments of a room. Only one matrix session is handled by this view controller.
|
||||
*/
|
||||
@@ -23,4 +25,9 @@ limitations under the License.
|
||||
|
||||
@property (nonatomic) BOOL showCancelBarButtonItem;
|
||||
|
||||
/**
|
||||
The screen timer used for analytics if they've been enabled. The default value is nil.
|
||||
*/
|
||||
@property (nonatomic) AnalyticsScreenTimer *screenTimer;
|
||||
|
||||
@end
|
||||
|
||||
@@ -110,6 +110,14 @@
|
||||
[UIView setAnimationsEnabled:NO];
|
||||
[self roomInputToolbarView:self.inputToolbarView heightDidChanged:0 completion:nil];
|
||||
[UIView setAnimationsEnabled:YES];
|
||||
|
||||
[self.screenTimer start];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
[self.screenTimer stop];
|
||||
}
|
||||
|
||||
- (void)userInterfaceThemeDidChange
|
||||
|
||||
@@ -104,6 +104,8 @@
|
||||
|
||||
@property(nonatomic, strong) UserVerificationCoordinatorBridgePresenter *userVerificationCoordinatorBridgePresenter;
|
||||
|
||||
@property(nonatomic) AnalyticsScreenTimer *screenTimer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RoomMemberDetailsViewController
|
||||
@@ -139,6 +141,8 @@
|
||||
|
||||
// Keep visible the status bar by default.
|
||||
isStatusBarHidden = NO;
|
||||
|
||||
self.screenTimer = [[AnalyticsScreenTimer alloc] initWithScreen:AnalyticsScreenUser];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
@@ -239,9 +243,6 @@
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomMemberDetails"];
|
||||
|
||||
[self userInterfaceThemeDidChange];
|
||||
|
||||
// Hide the bottom border of the navigation bar to display the expander header
|
||||
@@ -264,6 +265,18 @@
|
||||
self.bottomImageView.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
[self.screenTimer start];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
[self.screenTimer stop];
|
||||
}
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
|
||||
{
|
||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
|
||||
@@ -92,6 +92,11 @@
|
||||
*/
|
||||
@property (nonatomic, weak) id<RoomParticipantsViewControllerDelegate> delegate;
|
||||
|
||||
/**
|
||||
The screen timer used for analytics if they've been enabled. The default value is nil.
|
||||
*/
|
||||
@property (nonatomic) AnalyticsScreenTimer *screenTimer;
|
||||
|
||||
/**
|
||||
Returns the `UINib` object initialized for a `RoomParticipantsViewController`.
|
||||
|
||||
|
||||
@@ -245,9 +245,6 @@
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomParticipants"];
|
||||
|
||||
// Refresh display
|
||||
[self refreshTableView];
|
||||
@@ -268,6 +265,8 @@
|
||||
[contactsPickerViewController destroy];
|
||||
contactsPickerViewController = nil;
|
||||
}
|
||||
|
||||
[self.screenTimer start];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
@@ -284,6 +283,12 @@
|
||||
[self searchBarCancelButtonClicked:_searchBarView];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
[self.screenTimer stop];
|
||||
}
|
||||
|
||||
- (void)withdrawViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
|
||||
{
|
||||
// Check whether the current view controller is displayed inside a segmented view controller in order to withdraw the right item
|
||||
|
||||
@@ -39,9 +39,11 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType {
|
||||
participants.enableMention = true
|
||||
participants.mxRoom = self.room
|
||||
participants.delegate = self
|
||||
participants.screenTimer = AnalyticsScreenTimer(screen: .roomMembers)
|
||||
|
||||
let files = RoomFilesViewController()
|
||||
files.finalizeInit()
|
||||
files.screenTimer = AnalyticsScreenTimer(screen: .roomUploads)
|
||||
MXKRoomDataSource.load(withRoomId: self.room.roomId, andMatrixSession: self.session) { (dataSource) in
|
||||
guard let dataSource = dataSource as? MXKRoomDataSource else { return }
|
||||
dataSource.filterMessagesWithURL = true
|
||||
@@ -52,6 +54,7 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType {
|
||||
|
||||
let settings = RoomSettingsViewController()
|
||||
settings.finalizeInit()
|
||||
settings.screenTimer = AnalyticsScreenTimer(screen: .roomSettings)
|
||||
settings.initWith(self.session, andRoomId: self.room.roomId)
|
||||
|
||||
if self.room.isDirect {
|
||||
|
||||
@@ -40,6 +40,7 @@ final class RoomInfoListViewController: UIViewController {
|
||||
private var errorPresenter: MXKErrorPresentation!
|
||||
private var activityPresenter: ActivityIndicatorPresenter!
|
||||
private var isRoomDirect: Bool = false
|
||||
private var screenTimer = AnalyticsScreenTimer(screen: .roomDetails)
|
||||
|
||||
private lazy var closeButton: CloseButton = {
|
||||
let button = CloseButton()
|
||||
@@ -128,12 +129,22 @@ final class RoomInfoListViewController: UIViewController {
|
||||
return self.theme.statusBarStyle
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
screenTimer.start()
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
mainTableView.vc_relayoutHeaderView()
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
screenTimer.stop()
|
||||
}
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
coordinator.animate(alongsideTransition: {_ in
|
||||
self.basicInfoView.updateTrimmingOnTopic()
|
||||
|
||||
@@ -257,11 +257,13 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
@property (nonatomic, strong) SpaceDetailPresenter *spaceDetailPresenter;
|
||||
|
||||
@property (nonatomic, strong) ShareManager *shareManager;
|
||||
@property (nonatomic, strong) EventMenuBuilder *eventMenuBuilder;
|
||||
|
||||
@property (nonatomic, strong) UserSuggestionCoordinatorBridge *userSuggestionCoordinator;
|
||||
@property (nonatomic, weak) IBOutlet UIView *userSuggestionContainerView;
|
||||
|
||||
@property (nonatomic, readwrite) RoomDisplayConfiguration *displayConfiguration;
|
||||
@property (nonatomic) AnalyticsScreenTimer *screenTimer;
|
||||
|
||||
@end
|
||||
|
||||
@@ -347,6 +349,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
self.enableBarTintColorStatusChange = NO;
|
||||
self.rageShakeManager = [RageShakeManager sharedManager];
|
||||
formattedBodyParser = [FormattedBodyParser new];
|
||||
self.eventMenuBuilder = [EventMenuBuilder new];
|
||||
|
||||
_showMissedDiscussionsBadge = YES;
|
||||
_scrollToBottomHidden = YES;
|
||||
@@ -360,6 +363,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
|
||||
_voiceMessageController = [[VoiceMessageController alloc] initWithThemeService:ThemeService.shared mediaServiceProvider:VoiceMessageMediaServiceProvider.sharedProvider];
|
||||
self.voiceMessageController.delegate = self;
|
||||
|
||||
self.screenTimer = [[AnalyticsScreenTimer alloc] initWithScreen:AnalyticsScreenRoom];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
@@ -592,9 +597,6 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"ChatRoom"];
|
||||
|
||||
// Refresh the room title view
|
||||
[self refreshRoomTitle];
|
||||
|
||||
@@ -635,8 +637,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
[self.roomDataSource reload];
|
||||
[LegacyAppDelegate theDelegate].lastNavigatedRoomIdFromPush = nil;
|
||||
|
||||
notificationTaskProfile = [MXSDKOptions.sharedInstance.profiler startMeasuringTaskWithName:AnalyticsNoficationsTimeToDisplayContent
|
||||
category:AnalyticsNoficationsCategory];
|
||||
notificationTaskProfile = [MXSDKOptions.sharedInstance.profiler startMeasuringTaskWithName:MXTaskProfileNameNotificationsOpenEvent];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,6 +734,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
hasJitsiCall = NO;
|
||||
[self reloadBubblesTable:YES];
|
||||
}
|
||||
|
||||
// Screen tracking
|
||||
[self.screenTimer start];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
@@ -768,6 +772,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
hasJitsiCall = YES;
|
||||
[self reloadBubblesTable:YES];
|
||||
}
|
||||
|
||||
[self.screenTimer stop];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
@@ -1554,8 +1560,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
- (BadgedBarButtonItem *)threadListBarButtonItem
|
||||
{
|
||||
UIButton *button = [UIButton new];
|
||||
UIImage *icon = [[UIImage imageNamed:@"threads_icon"] vc_resizedWith:CGSizeMake(24, 24)];
|
||||
button.contentEdgeInsets = UIEdgeInsetsMake(4, 8, 4, 8);
|
||||
[button setImage:[UIImage imageNamed:@"room_context_menu_reply_in_thread"]
|
||||
[button setImage:icon
|
||||
forState:UIControlStateNormal];
|
||||
[button addTarget:self
|
||||
action:@selector(onThreadListTapped:)
|
||||
@@ -3272,17 +3279,19 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
currentAlert = nil;
|
||||
}
|
||||
|
||||
[self.eventMenuBuilder reset];
|
||||
|
||||
MXWeakify(self);
|
||||
UIAlertController *actionsMenu = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
BOOL showThreadOption = RiotSettings.shared.enableThreads
|
||||
&& !self.roomDataSource.threadId
|
||||
&& !selectedEvent.threadId;
|
||||
&& !self.roomDataSource.threadId
|
||||
&& !selectedEvent.threadId;
|
||||
if (showThreadOption && [self canCopyEvent:selectedEvent andCell:cell])
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCopy]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeCopy
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCopy]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3294,9 +3303,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
// Add actions for a failed event
|
||||
if (selectedEvent.sentState == MXEventSentStateFailed)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n retry]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeRetrySending
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n retry]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3305,9 +3315,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
[self.roomDataSource resendEventWithEventId:selectedEvent.eventId success:nil failure:nil];
|
||||
}]];
|
||||
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionDelete]
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeRemove
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionDelete]
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3316,6 +3327,22 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}]];
|
||||
}
|
||||
|
||||
// View in room action
|
||||
if (self.roomDataSource.threadId && [selectedEvent.eventId isEqualToString:self.roomDataSource.threadId])
|
||||
{
|
||||
// if in the thread and selected event is the root event
|
||||
// add "View in room" action
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeViewInRoom
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewInRoom]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self.delegate roomViewController:self
|
||||
showRoomWithId:self.roomDataSource.roomId
|
||||
eventId:selectedEvent.eventId];
|
||||
}]];
|
||||
}
|
||||
|
||||
// Add actions for text message
|
||||
if (!attachment)
|
||||
{
|
||||
@@ -3337,9 +3364,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
selectedEvent.sentState == MXEventSentStateEncrypting ||
|
||||
selectedEvent.sentState == MXEventSentStateSending)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCancelSend]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeCancelSending
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCancelSend]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
self->currentAlert = nil;
|
||||
@@ -3352,35 +3380,12 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}]];
|
||||
}
|
||||
|
||||
if (self.roomDataSource.threadId && [selectedEvent.eventId isEqualToString:self.roomDataSource.threadId])
|
||||
{
|
||||
// if in the thread and selected event is the root event
|
||||
// add "View in room" action
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewInRoom]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self.delegate roomViewController:self
|
||||
showRoomWithId:self.roomDataSource.roomId
|
||||
eventId:selectedEvent.eventId];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (selectedEvent.sentState == MXEventSentStateSent && selectedEvent.eventType != MXEventTypePollStart)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionForward]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (!isJitsiCallEvent && selectedEvent.eventType != MXEventTypePollStart)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionQuote]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeQuote
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionQuote]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3393,11 +3398,23 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}]];
|
||||
}
|
||||
|
||||
if (selectedEvent.sentState == MXEventSentStateSent && selectedEvent.eventType != MXEventTypePollStart)
|
||||
{
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeForward
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionForward]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (!isJitsiCallEvent && BuildSettings.messageDetailsAllowShare && selectedEvent.eventType != MXEventTypePollStart)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionShare]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeShare
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionShare]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3438,9 +3455,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
attachment.type == MXKAttachmentTypeImage ||
|
||||
attachment.type == MXKAttachmentTypeVideo ||
|
||||
attachment.type == MXKAttachmentTypeVoiceMessage)) {
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionForward]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeForward
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionForward]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
|
||||
}]];
|
||||
@@ -3450,9 +3468,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
{
|
||||
if (attachment.type == MXKAttachmentTypeImage || attachment.type == MXKAttachmentTypeVideo)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionSave]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeSaveMedia
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionSave]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3487,9 +3506,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
NSString *uploadId = roomBubbleTableViewCell.bubbleData.attachment.contentURL;
|
||||
if ([MXMediaManager existingUploaderWithId:uploadId])
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCancelSend]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeCancelSending
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCancelSend]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
@@ -3521,9 +3541,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
{
|
||||
if (BuildSettings.messageDetailsAllowShare)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionShare]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeShare
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionShare]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3568,9 +3589,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
NSString *downloadId = roomBubbleTableViewCell.bubbleData.attachment.downloadId;
|
||||
if ([MXMediaManager existingDownloaderWithIdentifier:downloadId])
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCancelDownload]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeCancelDownloading
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionCancelDownload]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3586,24 +3608,92 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (BuildSettings.messageDetailsAllowPermalink)
|
||||
{
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypePermalink
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionPermalink]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
// Create a matrix.to permalink that is common to all matrix clients
|
||||
NSString *permalink = [MXTools permalinkToEvent:selectedEvent.eventId inRoom:selectedEvent.roomId];
|
||||
|
||||
if (permalink)
|
||||
{
|
||||
MXKPasteboardManager.shared.pasteboard.string = permalink;
|
||||
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
|
||||
image:[UIImage imageNamed:@"link_icon"]
|
||||
duration:2.0
|
||||
position:ToastPositionBottom
|
||||
additionalMargin:self.roomInputToolbarContainerHeightConstraint.constant];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[RoomViewController] Contextual menu permalink action failed. Permalink is nil room id/event id: %@/%@", selectedEvent.roomId, selectedEvent.eventId);
|
||||
}
|
||||
}]];
|
||||
}
|
||||
|
||||
if (BuildSettings.messageDetailsAllowViewSource)
|
||||
{
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeViewSource
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewSource]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
// Display event details
|
||||
[self showEventDetails:selectedEvent];
|
||||
}]];
|
||||
|
||||
|
||||
// Add "View Decrypted Source" for e2ee event we can decrypt
|
||||
if (selectedEvent.isEncrypted && selectedEvent.clearEvent)
|
||||
{
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeViewDecryptedSource
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewDecryptedSource]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
// Display clear event details
|
||||
[self showEventDetails:selectedEvent.clearEvent];
|
||||
}]];
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allow to redact the event that enabled encryption (m.room.encryption)
|
||||
// because it breaks everything
|
||||
if (selectedEvent.eventType != MXEventTypeRoomEncryption)
|
||||
{
|
||||
NSString *title;
|
||||
UIAlertActionStyle style;
|
||||
EventMenuItemType itemType;
|
||||
if (selectedEvent.eventType == MXEventTypePollStart)
|
||||
{
|
||||
title = [VectorL10n roomEventActionRemovePoll];
|
||||
style = UIAlertActionStyleDefault;
|
||||
itemType = EventMenuItemTypeRemovePoll;
|
||||
}
|
||||
else
|
||||
{
|
||||
title = [VectorL10n roomEventActionRedact];
|
||||
style = UIAlertActionStyleDestructive;
|
||||
itemType = EventMenuItemTypeRemove;
|
||||
}
|
||||
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:title
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:itemType
|
||||
action:[UIAlertAction actionWithTitle:title
|
||||
style:style
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3625,11 +3715,14 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}]];
|
||||
}
|
||||
|
||||
if (selectedEvent.eventType == MXEventTypePollStart && [selectedEvent.sender isEqualToString:self.mainSession.myUserId]) {
|
||||
if ([self.delegate roomViewController:self canEndPollWithEventIdentifier:selectedEvent.eventId]) {
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionEndPoll]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
if (selectedEvent.eventType == MXEventTypePollStart && [selectedEvent.sender isEqualToString:self.mainSession.myUserId])
|
||||
{
|
||||
if ([self.delegate roomViewController:self canEndPollWithEventIdentifier:selectedEvent.eventId])
|
||||
{
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeEndPoll
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionEndPoll]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self.delegate roomViewController:self endPollWithEventIdentifier:selectedEvent.eventId];
|
||||
@@ -3639,43 +3732,13 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}
|
||||
}
|
||||
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self hideContextualMenuAnimated:YES];
|
||||
}]];
|
||||
|
||||
if (BuildSettings.messageDetailsAllowPermalink)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionPermalink]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
// Create a matrix.to permalink that is common to all matrix clients
|
||||
NSString *permalink = [MXTools permalinkToEvent:selectedEvent.eventId inRoom:selectedEvent.roomId];
|
||||
|
||||
if (permalink)
|
||||
{
|
||||
MXKPasteboardManager.shared.pasteboard.string = permalink;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[RoomViewController] Contextual menu permalink action failed. Permalink is nil room id/event id: %@/%@", selectedEvent.roomId, selectedEvent.eventId);
|
||||
}
|
||||
}]];
|
||||
}
|
||||
|
||||
// Add reaction history if event contains reactions
|
||||
if (roomBubbleTableViewCell.bubbleData.reactions[selectedEvent.eventId].aggregatedReactionsWithNonZeroCount)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionReactionHistory]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeReactionHistory
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionReactionHistory]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3685,41 +3748,12 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}]];
|
||||
}
|
||||
|
||||
if (BuildSettings.messageDetailsAllowViewSource)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewSource]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
// Display event details
|
||||
[self showEventDetails:selectedEvent];
|
||||
}]];
|
||||
|
||||
|
||||
// Add "View Decrypted Source" for e2ee event we can decrypt
|
||||
if (selectedEvent.isEncrypted && selectedEvent.clearEvent)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewDecryptedSource]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
// Display clear event details
|
||||
[self showEventDetails:selectedEvent.clearEvent];
|
||||
}]];
|
||||
}
|
||||
}
|
||||
|
||||
if (![selectedEvent.sender isEqualToString:self.mainSession.myUserId] && RiotSettings.shared.roomContextualMenuShowReportContentOption)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionReport]
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeReport
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionReport]
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3809,9 +3843,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
|
||||
if (!isJitsiCallEvent && self.roomDataSource.room.summary.isEncrypted)
|
||||
{
|
||||
[actionsMenu addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewEncryption]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeViewEncryption
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionViewEncryption]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
@@ -3821,11 +3856,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}]];
|
||||
}
|
||||
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeCancel
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n cancel]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self hideContextualMenuAnimated:YES];
|
||||
}]];
|
||||
|
||||
}
|
||||
|
||||
// Do not display empty action sheet
|
||||
if (actionsMenu.actions.count > 1)
|
||||
if (!self.eventMenuBuilder.isEmpty)
|
||||
{
|
||||
UIAlertController *actionsMenu = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
// build actions and add them to the alert
|
||||
NSArray<UIAlertAction*> *actions = [self.eventMenuBuilder build];
|
||||
for (UIAlertAction *action in actions)
|
||||
{
|
||||
[actionsMenu addAction:action];
|
||||
}
|
||||
|
||||
NSInteger bubbleComponentIndex = [roomBubbleTableViewCell.bubbleData bubbleComponentIndexForEventId:selectedEvent.eventId];
|
||||
|
||||
CGRect sourceRect = [roomBubbleTableViewCell componentFrameInContentViewForIndex:bubbleComponentIndex];
|
||||
@@ -6074,10 +6127,6 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
|
||||
NSMutableArray<RoomContextualMenuItem*> *items = [NSMutableArray arrayWithCapacity:5];
|
||||
|
||||
if (!showThreadOption)
|
||||
{
|
||||
[items addObject:[self copyMenuItemWithEvent:event andCell:cell]];
|
||||
}
|
||||
[items addObject:[self replyMenuItemWithEvent:event]];
|
||||
if (showThreadOption)
|
||||
{
|
||||
@@ -6085,6 +6134,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
[items addObject:[self replyInThreadMenuItemWithEvent:event]];
|
||||
}
|
||||
[items addObject:[self editMenuItemWithEvent:event]];
|
||||
if (!showThreadOption)
|
||||
{
|
||||
[items addObject:[self copyMenuItemWithEvent:event andCell:cell]];
|
||||
}
|
||||
if (showMoreOption)
|
||||
{
|
||||
[items addObject:[self moreMenuItemWithEvent:event andCell:cell]];
|
||||
|
||||
@@ -109,9 +109,6 @@
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomFilesSearch"];
|
||||
|
||||
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
|
||||
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
@@ -111,9 +111,6 @@
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomMessagesSearch"];
|
||||
|
||||
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
|
||||
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
MXKSearchDataSource *filesSearchDataSource;
|
||||
}
|
||||
|
||||
@property (nonatomic) AnalyticsScreenTimer *screenTimer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RoomSearchViewController
|
||||
@@ -49,6 +51,8 @@
|
||||
[super finalizeInit];
|
||||
|
||||
// The navigation bar tint color and the rageShake Manager are handled by super (see SegmentedViewController).
|
||||
|
||||
self.screenTimer = [[AnalyticsScreenTimer alloc] initWithScreen:AnalyticsScreenRoomSearch];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
@@ -106,9 +110,6 @@
|
||||
[self.activityIndicator stopAnimating];
|
||||
self.activityIndicator = nil;
|
||||
}
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomsSearch"];
|
||||
|
||||
// Enable the search field by default at the screen opening
|
||||
if (self.searchBarHidden)
|
||||
@@ -124,6 +125,8 @@
|
||||
// Refresh the search results.
|
||||
// Note: We wait for 'viewDidAppear' call to consider the actual view size during this update.
|
||||
[self updateSearch];
|
||||
|
||||
[self.screenTimer start];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
@@ -138,6 +141,12 @@
|
||||
[super viewWillDisappear:animated];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
[self.screenTimer stop];
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle
|
||||
{
|
||||
return ThemeService.shared.theme.statusBarStyle;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#import "MediaPickerViewController.h"
|
||||
#import "TableViewCellWithCheckBoxes.h"
|
||||
|
||||
@class AnalyticsScreenTimer;
|
||||
|
||||
/**
|
||||
List the settings fields. Used to preselect/edit a field
|
||||
*/
|
||||
@@ -52,5 +54,10 @@ typedef enum : NSUInteger {
|
||||
*/
|
||||
@property (nonatomic) RoomSettingsViewControllerField selectedRoomSettingsField;
|
||||
|
||||
/**
|
||||
The screen timer used for analytics if they've been enabled. The default value is nil.
|
||||
*/
|
||||
@property (nonatomic) AnalyticsScreenTimer *screenTimer;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -311,9 +311,6 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomSettings"];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateRules:) name:kMXNotificationCenterDidUpdateRules object:nil];
|
||||
|
||||
@@ -334,6 +331,8 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
{
|
||||
self.selectedRoomSettingsField = _selectedRoomSettingsField;
|
||||
}
|
||||
|
||||
[self.screenTimer start];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
@@ -351,6 +350,12 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
[self.screenTimer stop];
|
||||
}
|
||||
|
||||
// Those methods are called when the viewcontroller is added or removed from a container view controller.
|
||||
- (void)willMoveToParentViewController:(nullable UIViewController *)parent
|
||||
{
|
||||
@@ -1027,27 +1032,32 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsCopyRoomUrl]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->currentAlert = nil;
|
||||
|
||||
// Create a matrix.to permalink to the room
|
||||
|
||||
NSString *permalink = [MXTools permalinkToRoom:roomAliasLabel.text];
|
||||
|
||||
if (permalink)
|
||||
{
|
||||
MXKPasteboardManager.shared.pasteboard.string = permalink;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[RoomSettingsViewController] Copy room URL failed. Room URL is nil");
|
||||
}
|
||||
}
|
||||
|
||||
}]];
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->currentAlert = nil;
|
||||
|
||||
// Create a matrix.to permalink to the room
|
||||
|
||||
NSString *permalink = [MXTools permalinkToRoom:roomAliasLabel.text];
|
||||
|
||||
if (permalink)
|
||||
{
|
||||
MXKPasteboardManager.shared.pasteboard.string = permalink;
|
||||
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
|
||||
image:[UIImage imageNamed:@"link_icon"]
|
||||
duration:2.0
|
||||
position:ToastPositionBottom
|
||||
additionalMargin:0.0];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[RoomSettingsViewController] Copy room URL failed. Room URL is nil");
|
||||
}
|
||||
}
|
||||
|
||||
}]];
|
||||
|
||||
// The user can only delete alias they has created, even if the Admin has set it as canonical.
|
||||
// So, let the server answer if it's possible to delete an alias.
|
||||
|
||||
@@ -27,7 +27,7 @@ protocol ThreadSummaryViewDelegate: AnyObject {
|
||||
class ThreadSummaryView: UIView {
|
||||
|
||||
private enum Constants {
|
||||
static let viewHeight: CGFloat = 32
|
||||
static let viewHeight: CGFloat = 40
|
||||
static let viewDefaultWidth: CGFloat = 320
|
||||
static let cornerRadius: CGFloat = 4
|
||||
static let lastMessageFont: UIFont = .systemFont(ofSize: 13)
|
||||
@@ -38,6 +38,7 @@ class ThreadSummaryView: UIView {
|
||||
@IBOutlet private weak var lastMessageAvatarView: UserAvatarView!
|
||||
@IBOutlet private weak var lastMessageContentLabel: UILabel!
|
||||
|
||||
private var theme: Theme = ThemeService.shared().theme
|
||||
private(set) var thread: MXThread!
|
||||
|
||||
private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
|
||||
@@ -74,12 +75,12 @@ class ThreadSummaryView: UIView {
|
||||
} else {
|
||||
lastMessageAvatarView.avatarImageView.image = nil
|
||||
}
|
||||
if let lastMessageText = viewModel.lastMessageText {
|
||||
let mutableAttributedString = NSMutableAttributedString(attributedString: lastMessageText)
|
||||
mutableAttributedString.setAttributes([
|
||||
if let lastMessage = viewModel.lastMessageText {
|
||||
let mutable = NSMutableAttributedString(attributedString: lastMessage)
|
||||
mutable.setAttributes([
|
||||
.font: Constants.lastMessageFont
|
||||
], range: NSRange(location: 0, length: mutableAttributedString.length))
|
||||
lastMessageContentLabel.attributedText = mutableAttributedString
|
||||
], range: NSRange(location: 0, length: mutable.length))
|
||||
lastMessageContentLabel.attributedText = mutable
|
||||
} else {
|
||||
lastMessageContentLabel.attributedText = nil
|
||||
}
|
||||
@@ -112,7 +113,9 @@ class ThreadSummaryView: UIView {
|
||||
room.state { [weak self] roomState in
|
||||
guard let self = self else { return }
|
||||
let formatterError = UnsafeMutablePointer<MXKEventFormatterError>.allocate(capacity: 1)
|
||||
let lastMessageText = eventFormatter.attributedString(from: lastMessage, with: roomState, error: formatterError)
|
||||
let lastMessageText = eventFormatter.attributedString(from: lastMessage,
|
||||
with: roomState,
|
||||
error: formatterError)
|
||||
|
||||
let viewModel = ThreadSummaryViewModel(numberOfReplies: thread.numberOfReplies,
|
||||
lastMessageSenderAvatar: avatarViewData,
|
||||
@@ -137,6 +140,8 @@ extension ThreadSummaryView: NibOwnerLoadable {}
|
||||
extension ThreadSummaryView: Themable {
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
backgroundColor = theme.colors.system
|
||||
iconView.tintColor = theme.colors.secondaryContent
|
||||
numberOfRepliesLabel.textColor = theme.colors.secondaryContent
|
||||
|
||||
@@ -18,35 +18,38 @@
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="32"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TFL-sS-eJc">
|
||||
<rect key="frame" x="8" y="4" width="398" height="24"/>
|
||||
<rect key="frame" x="8" y="4" width="398" height="32"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="room_context_menu_reply_in_thread" translatesAutoresizingMaskIntoConstraints="NO" id="vva-PV-3Ya">
|
||||
<rect key="frame" x="1" y="3" width="18" height="18"/>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="threads_icon" translatesAutoresizingMaskIntoConstraints="NO" id="vva-PV-3Ya">
|
||||
<rect key="frame" x="4" y="3" width="26" height="26"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="vva-PV-3Ya" secondAttribute="height" multiplier="1:1" id="972-WJ-2Zq"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" text="1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GcG-W8-9LR">
|
||||
<rect key="frame" x="25" y="0.0" width="6" height="24"/>
|
||||
<rect key="frame" x="34" y="0.0" width="6" height="32"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="6" id="9Nt-Rk-O81"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9wW-1f-f69" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="39" y="0.0" width="24" height="24"/>
|
||||
<rect key="frame" x="52" y="0.0" width="32" height="32"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="9wW-1f-f69" secondAttribute="height" multiplier="1:1" id="V4H-JA-w4O"/>
|
||||
</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="DVT-JI-3kw">
|
||||
<rect key="frame" x="71" y="0.0" width="319" height="24"/>
|
||||
<rect key="frame" x="92" y="0.0" width="298" height="32"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -60,14 +63,14 @@
|
||||
<constraint firstAttribute="bottom" secondItem="GcG-W8-9LR" secondAttribute="bottom" id="FI4-bk-goz"/>
|
||||
<constraint firstItem="9wW-1f-f69" firstAttribute="top" secondItem="TFL-sS-eJc" secondAttribute="top" id="GBe-gi-Iwc"/>
|
||||
<constraint firstItem="DVT-JI-3kw" firstAttribute="top" secondItem="TFL-sS-eJc" secondAttribute="top" id="MSs-PD-tov"/>
|
||||
<constraint firstItem="GcG-W8-9LR" firstAttribute="leading" secondItem="vva-PV-3Ya" secondAttribute="trailing" constant="6" id="PhI-J3-Ycb"/>
|
||||
<constraint firstItem="GcG-W8-9LR" firstAttribute="leading" secondItem="vva-PV-3Ya" secondAttribute="trailing" constant="4" id="PhI-J3-Ycb"/>
|
||||
<constraint firstItem="GcG-W8-9LR" firstAttribute="top" secondItem="TFL-sS-eJc" secondAttribute="top" id="Twp-gS-w3u"/>
|
||||
<constraint firstAttribute="bottom" secondItem="9wW-1f-f69" secondAttribute="bottom" id="VG5-XU-DAK"/>
|
||||
<constraint firstAttribute="trailing" secondItem="DVT-JI-3kw" secondAttribute="trailing" constant="8" id="bX2-Ha-8bf"/>
|
||||
<constraint firstItem="DVT-JI-3kw" firstAttribute="leading" secondItem="9wW-1f-f69" secondAttribute="trailing" constant="8" id="qGg-0A-C6M"/>
|
||||
<constraint firstItem="9wW-1f-f69" firstAttribute="leading" secondItem="GcG-W8-9LR" secondAttribute="trailing" constant="8" id="s2V-X9-cyI"/>
|
||||
<constraint firstItem="9wW-1f-f69" firstAttribute="leading" secondItem="GcG-W8-9LR" secondAttribute="trailing" constant="12" id="s2V-X9-cyI"/>
|
||||
<constraint firstAttribute="bottom" secondItem="vva-PV-3Ya" secondAttribute="bottom" constant="3" id="smY-cv-CoE"/>
|
||||
<constraint firstItem="vva-PV-3Ya" firstAttribute="leading" secondItem="TFL-sS-eJc" secondAttribute="leading" constant="1" id="vyh-e4-Vy3"/>
|
||||
<constraint firstItem="vva-PV-3Ya" firstAttribute="leading" secondItem="TFL-sS-eJc" secondAttribute="leading" constant="4" id="vyh-e4-Vy3"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
@@ -84,6 +87,6 @@
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="room_context_menu_reply_in_thread" width="18" height="18"/>
|
||||
<image name="threads_icon" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -25,11 +25,6 @@ enum ThreadRoomTitleViewMode {
|
||||
@objcMembers
|
||||
class ThreadRoomTitleView: RoomTitleView {
|
||||
|
||||
private enum Constants {
|
||||
static let titleLeadingConstraintOnPortrait: CGFloat = 6
|
||||
static let titleLeadingConstraintOnLandscape: CGFloat = 18
|
||||
}
|
||||
|
||||
var mode: ThreadRoomTitleViewMode = .allThreads {
|
||||
didSet {
|
||||
update()
|
||||
@@ -37,7 +32,6 @@ class ThreadRoomTitleView: RoomTitleView {
|
||||
}
|
||||
|
||||
@IBOutlet private weak var titleLabel: UILabel!
|
||||
@IBOutlet private weak var titleLabelLeadingConstraint: NSLayoutConstraint!
|
||||
@IBOutlet private weak var roomAvatarView: RoomAvatarView!
|
||||
@IBOutlet private weak var roomEncryptionBadgeView: UIImageView!
|
||||
@IBOutlet private weak var roomNameLabel: UILabel!
|
||||
@@ -81,7 +75,7 @@ class ThreadRoomTitleView: RoomTitleView {
|
||||
room.displayName))
|
||||
|
||||
let encrpytionBadge: UIImage?
|
||||
if let summary = room.summary, room.mxSession.crypto != nil {
|
||||
if let summary = room.summary, summary.isEncrypted, room.mxSession.crypto != nil {
|
||||
encrpytionBadge = EncryptionTrustLevelBadgeImageHelper.roomBadgeImage(for: summary.roomEncryptionTrustLevel())
|
||||
} else {
|
||||
encrpytionBadge = nil
|
||||
@@ -100,16 +94,6 @@ class ThreadRoomTitleView: RoomTitleView {
|
||||
registerThemeServiceDidChangeThemeNotification()
|
||||
}
|
||||
|
||||
override func updateLayout(for orientation: UIInterfaceOrientation) {
|
||||
super.updateLayout(for: orientation)
|
||||
|
||||
if orientation.isPortrait {
|
||||
titleLabelLeadingConstraint.constant = Constants.titleLeadingConstraintOnPortrait
|
||||
} else {
|
||||
titleLabelLeadingConstraint.constant = Constants.titleLeadingConstraintOnLandscape
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func registerThemeServiceDidChangeThemeNotification() {
|
||||
|
||||
@@ -12,61 +12,90 @@
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="ThreadRoomTitleView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="243" height="64"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="243" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ami-Cg-fcA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="243" height="64"/>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="1" translatesAutoresizingMaskIntoConstraints="NO" id="0tP-MX-JE1">
|
||||
<rect key="frame" x="6" y="0.0" width="221" height="44"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Thread" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BnG-NU-7Mg">
|
||||
<rect key="frame" x="18" y="22" width="56.5" height="20.5"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Bkf-Ia-XzU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="221" height="0.0"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" id="sTs-mz-Sem"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Thread" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="BnG-NU-7Mg">
|
||||
<rect key="frame" x="0.0" y="1" width="221" height="20.5"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FJB-2F-rrQ" customClass="RoomAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="82.5" y="24" width="16" height="16"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ABf-Vz-jLY">
|
||||
<rect key="frame" x="0.0" y="22.5" width="221" height="2"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="16" id="Fg7-y5-fEC"/>
|
||||
<constraint firstAttribute="height" constant="16" id="Qxm-RC-uC5"/>
|
||||
<constraint firstAttribute="height" constant="2" id="kec-7k-q3g"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Mli-PC-WUh">
|
||||
<rect key="frame" x="92.5" y="28" width="12" height="12"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5Ww-tc-6by">
|
||||
<rect key="frame" x="0.0" y="25.5" width="221" height="17.5"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FJB-2F-rrQ" customClass="RoomAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="1" width="16" height="16"/>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="16" id="Fg7-y5-fEC"/>
|
||||
<constraint firstAttribute="height" constant="16" id="Qxm-RC-uC5"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Mli-PC-WUh">
|
||||
<rect key="frame" x="10" y="6" width="12" height="12"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="Mli-PC-WUh" secondAttribute="height" multiplier="1:1" id="Ohw-dy-qg0"/>
|
||||
<constraint firstAttribute="width" constant="12" id="nKB-SN-cO0"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Room name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.69999999999999996" translatesAutoresizingMaskIntoConstraints="NO" id="8lk-sN-3IP">
|
||||
<rect key="frame" x="27" y="1.5" width="194" height="14.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="Mli-PC-WUh" secondAttribute="height" multiplier="1:1" id="Ohw-dy-qg0"/>
|
||||
<constraint firstAttribute="width" constant="12" id="nKB-SN-cO0"/>
|
||||
<constraint firstItem="Mli-PC-WUh" firstAttribute="bottom" secondItem="FJB-2F-rrQ" secondAttribute="bottom" constant="1" id="1SB-L0-yS4"/>
|
||||
<constraint firstItem="8lk-sN-3IP" firstAttribute="centerY" secondItem="5Ww-tc-6by" secondAttribute="centerY" id="GFB-ot-8b1"/>
|
||||
<constraint firstAttribute="trailing" secondItem="8lk-sN-3IP" secondAttribute="trailing" id="HCl-gK-Xhs"/>
|
||||
<constraint firstItem="FJB-2F-rrQ" firstAttribute="centerY" secondItem="5Ww-tc-6by" secondAttribute="centerY" id="NiB-In-y7x"/>
|
||||
<constraint firstItem="FJB-2F-rrQ" firstAttribute="leading" secondItem="5Ww-tc-6by" secondAttribute="leading" id="Smn-wx-c0n"/>
|
||||
<constraint firstItem="8lk-sN-3IP" firstAttribute="leading" secondItem="FJB-2F-rrQ" secondAttribute="trailing" constant="11" id="Y1z-dr-Y0X"/>
|
||||
<constraint firstItem="Mli-PC-WUh" firstAttribute="leading" secondItem="5Ww-tc-6by" secondAttribute="leading" constant="10" id="zH1-h4-JAC"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Room name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8lk-sN-3IP">
|
||||
<rect key="frame" x="109.5" y="24.5" width="67" height="15"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tf4-ZQ-a7v">
|
||||
<rect key="frame" x="0.0" y="44" width="221" height="0.0"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" id="Pb4-25-yBS"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Mli-PC-WUh" firstAttribute="centerX" secondItem="FJB-2F-rrQ" secondAttribute="trailing" id="BU4-yl-DrP"/>
|
||||
<constraint firstItem="BnG-NU-7Mg" firstAttribute="leading" secondItem="Ami-Cg-fcA" secondAttribute="leading" constant="18" id="ES6-mL-Y9F"/>
|
||||
<constraint firstItem="8lk-sN-3IP" firstAttribute="centerY" secondItem="Ami-Cg-fcA" secondAttribute="centerY" id="S0S-6y-Vkn"/>
|
||||
<constraint firstItem="FJB-2F-rrQ" firstAttribute="leading" secondItem="BnG-NU-7Mg" secondAttribute="trailing" constant="8" id="SQk-zN-CO6"/>
|
||||
<constraint firstItem="FJB-2F-rrQ" firstAttribute="centerY" secondItem="Ami-Cg-fcA" secondAttribute="centerY" id="nY0-2s-Wgo"/>
|
||||
<constraint firstItem="8lk-sN-3IP" firstAttribute="leading" secondItem="FJB-2F-rrQ" secondAttribute="trailing" constant="11" id="ql2-B3-82Y"/>
|
||||
<constraint firstItem="BnG-NU-7Mg" firstAttribute="centerY" secondItem="Ami-Cg-fcA" secondAttribute="centerY" id="rwC-ak-Ydb"/>
|
||||
<constraint firstItem="Mli-PC-WUh" firstAttribute="bottom" secondItem="FJB-2F-rrQ" secondAttribute="bottom" id="ulL-Xh-oCC"/>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="32" id="Ctj-V2-sxt"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="Ami-Cg-fcA" secondAttribute="trailing" id="a9m-d6-0go"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Ami-Cg-fcA" secondAttribute="bottom" id="fEm-nj-yVF"/>
|
||||
<constraint firstItem="Ami-Cg-fcA" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="h0M-ab-EGv"/>
|
||||
<constraint firstItem="Ami-Cg-fcA" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="zAN-VI-ZYk"/>
|
||||
<constraint firstItem="0tP-MX-JE1" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="30P-0k-oLG"/>
|
||||
<constraint firstItem="0tP-MX-JE1" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="6" id="Ef8-9o-qNh"/>
|
||||
<constraint firstAttribute="bottom" secondItem="0tP-MX-JE1" secondAttribute="bottom" id="EqL-Br-ple"/>
|
||||
<constraint firstAttribute="trailing" secondItem="0tP-MX-JE1" secondAttribute="trailing" constant="16" id="JQX-7q-vCS"/>
|
||||
</constraints>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
@@ -74,9 +103,8 @@
|
||||
<outlet property="roomEncryptionBadgeView" destination="Mli-PC-WUh" id="MuX-Qw-DfQ"/>
|
||||
<outlet property="roomNameLabel" destination="8lk-sN-3IP" id="wFm-R4-fBo"/>
|
||||
<outlet property="titleLabel" destination="BnG-NU-7Mg" id="gDw-Pr-oR8"/>
|
||||
<outlet property="titleLabelLeadingConstraint" destination="ES6-mL-Y9F" id="MpE-vt-KKC"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="0.7246376811594204" y="-152.00892857142856"/>
|
||||
<point key="canvasLocation" x="10.869565217391305" y="-256.47321428571428"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
|
||||
Reference in New Issue
Block a user