diff --git a/CHANGES.rst b/CHANGES.rst index 66cdcf3e7..c3ff551ec 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,6 +11,8 @@ Changes to be released in next version * SettingsVC: Show / hide NSFW and decrypted content options from build settings (#4290). * RoomVC: Tweaked Scroll to Bottom FAB button (#4272). * DesignKit: Introduce a new framework to manage design components. + * Add Jitsi widget remove banner for privileged users. + * Update "Jump to unread" banner to a pill style button. 🐛 Bugfix * RoomVC: Avoid navigation to integration management using integration popup with settings set to integration disabled (#4261). diff --git a/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close.png b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close.png new file mode 100644 index 000000000..35a24620d Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@2x.png b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@2x.png new file mode 100644 index 000000000..9ee4ab4f0 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@3x.png b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@3x.png new file mode 100644 index 000000000..5220dd2f9 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Close@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Contents.json new file mode 100644 index 000000000..90d19c308 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/Activities/new_close.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "Close.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Close@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Close@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Contents.json new file mode 100644 index 000000000..92d19c27b --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "Up.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Up@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Up@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up.png b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up.png new file mode 100644 index 000000000..c9556b53d Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@2x.png b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@2x.png new file mode 100644 index 000000000..f029fd55b Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@3x.png b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@3x.png new file mode 100644 index 000000000..90d3fc8ac Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Activities/room_scroll_up.imageset/Up@3x.png differ diff --git a/Riot/Assets/SharedImages.xcassets/Common/cancel.imageset/Contents.json b/Riot/Assets/SharedImages.xcassets/Common/cancel.imageset/Contents.json index 2f43e0b91..92357aede 100644 --- a/Riot/Assets/SharedImages.xcassets/Common/cancel.imageset/Contents.json +++ b/Riot/Assets/SharedImages.xcassets/Common/cancel.imageset/Contents.json @@ -1,23 +1,26 @@ { "images" : [ { - "idiom" : "universal", "filename" : "cancel.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "cancel@2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "cancel@3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 7414431dc..277d820ce 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -313,7 +313,8 @@ Tap the + to start adding people."; "room_member_power_level_short_custom" = "Custom"; // Chat -"room_jump_to_first_unread" = "Jump to first unread message"; +"room_slide_to_end_group_call" = "Slide to end the call for everyone"; +"room_jump_to_first_unread" = "Jump to unread"; "room_accessiblity_scroll_to_bottom" = "Scroll to bottom"; "room_new_message_notification" = "%d new message"; "room_new_messages_notification" = "%d new messages"; diff --git a/Riot/Categories/UIView.swift b/Riot/Categories/UIView.swift index e7ede840e..9edde2c23 100644 --- a/Riot/Categories/UIView.swift +++ b/Riot/Categories/UIView.swift @@ -64,4 +64,16 @@ extension UIView { self.accessibilityTraits.insert(.notEnabled) } } + + @objc func vc_addShadow(withColor color: UIColor, offset: CGSize, radius: CGFloat, opacity: CGFloat) { + layer.shadowColor = color.cgColor + layer.shadowOpacity = Float(opacity) + layer.shadowRadius = radius + layer.shadowOffset = offset + } + + @objc func vc_removeShadow() { + layer.shadowColor = UIColor.clear.cgColor + } + } diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index 8c6ffccdf..4565353fe 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -105,7 +105,9 @@ internal enum Asset { internal static let actionSticker = ImageAsset(name: "action_sticker") internal static let error = ImageAsset(name: "error") internal static let errorMessageTick = ImageAsset(name: "error_message_tick") + internal static let newClose = ImageAsset(name: "new_close") internal static let roomActivitiesRetry = ImageAsset(name: "room_activities_retry") + internal static let roomScrollUp = ImageAsset(name: "room_scroll_up") internal static let scrolldown = ImageAsset(name: "scrolldown") internal static let scrolldownDark = ImageAsset(name: "scrolldown_dark") internal static let sendingMessageTick = ImageAsset(name: "sending_message_tick") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index f7c0ceb66..11d0dc52d 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -2930,7 +2930,7 @@ internal enum VectorL10n { internal static var roomJoinGroupCall: String { return VectorL10n.tr("Vector", "room_join_group_call") } - /// Jump to first unread message + /// Jump to unread internal static var roomJumpToFirstUnread: String { return VectorL10n.tr("Vector", "room_jump_to_first_unread") } @@ -3390,6 +3390,10 @@ internal enum VectorL10n { internal static var roomResourceUsageLimitReachedMessageContact3: String { return VectorL10n.tr("Vector", "room_resource_usage_limit_reached_message_contact_3") } + /// Slide to end the call for everyone + internal static var roomSlideToEndGroupCall: String { + return VectorL10n.tr("Vector", "room_slide_to_end_group_call") + } /// Invite members internal static var roomTitleInviteMembers: String { return VectorL10n.tr("Vector", "room_title_invite_members") diff --git a/Riot/Managers/Call/CallPresenter.swift b/Riot/Managers/Call/CallPresenter.swift index 99e619cfe..57a60b0cb 100644 --- a/Riot/Managers/Call/CallPresenter.swift +++ b/Riot/Managers/Call/CallPresenter.swift @@ -165,7 +165,7 @@ class CallPresenter: NSObject { }) } - if let jitsiVC = jitsiVC, jitsiVC.widget.widgetId == widget.widgetId { + if let jitsiVC = jitsiVC { if jitsiVC.widget.widgetId == widget.widgetId { self.presentCallVC(jitsiVC) } else { @@ -610,7 +610,11 @@ class CallPresenter: NSObject { return } - presentCallVC(callVC) + if callVC == pipCallVC { + exitPipCallVC(callVC) + } else { + presentCallVC(callVC) + } } @objc @@ -644,7 +648,11 @@ class CallPresenter: NSObject { return } - presentCallVC(jitsiVC) + if jitsiVC == pipCallVC { + exitPipCallVC(jitsiVC) + } else { + presentCallVC(jitsiVC) + } } // MARK: - Call Screens diff --git a/Riot/Managers/Theme/Theme.swift b/Riot/Managers/Theme/Theme.swift index bb87c2965..72d2d1ab8 100644 --- a/Riot/Managers/Theme/Theme.swift +++ b/Riot/Managers/Theme/Theme.swift @@ -94,6 +94,9 @@ import DesignKit /// Color to tint the search background image var matrixSearchBackgroundImageTintColor: UIColor { get } + /// Color to use in shadows. Should be contrast to `backgroundColor`. + var shadowColor: UIColor { get } + // MARK: - Customisation methods diff --git a/Riot/Managers/Theme/ThemeService.m b/Riot/Managers/Theme/ThemeService.m index f29dbcaab..175ab5f64 100644 --- a/Riot/Managers/Theme/ThemeService.m +++ b/Riot/Managers/Theme/ThemeService.m @@ -155,6 +155,9 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan // Define the UISearchBar cancel button color [[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitleTextAttributes:@{ NSForegroundColorAttributeName : self.theme.tintColor } forState: UIControlStateNormal]; + + [[UIStackView appearanceWhenContainedInInstancesOfClasses:@[[UINavigationBar class]]] setSpacing:-7]; + [[UIStackView appearanceWhenContainedInInstancesOfClasses:@[[UINavigationBar class]]] setDistribution:UIStackViewDistributionEqualCentering]; } @end diff --git a/Riot/Managers/Theme/Themes/DarkTheme.swift b/Riot/Managers/Theme/Themes/DarkTheme.swift index df631e905..a3bc39557 100644 --- a/Riot/Managers/Theme/Themes/DarkTheme.swift +++ b/Riot/Managers/Theme/Themes/DarkTheme.swift @@ -88,6 +88,8 @@ class DarkTheme: NSObject, Theme { var matrixSearchBackgroundImageTintColor: UIColor = UIColor(rgb: 0x7E7E7E) var secondaryCircleButtonBackgroundColor: UIColor = UIColor(rgb: 0xE3E8F0) + var shadowColor: UIColor = UIColor(rgb: 0xFFFFFF) + var messageTickColor: UIColor = .white func applyStyle(onTabBar tabBar: UITabBar) { diff --git a/Riot/Managers/Theme/Themes/DefaultTheme.swift b/Riot/Managers/Theme/Themes/DefaultTheme.swift index 3014209a7..7f6ae77b1 100644 --- a/Riot/Managers/Theme/Themes/DefaultTheme.swift +++ b/Riot/Managers/Theme/Themes/DefaultTheme.swift @@ -98,6 +98,8 @@ class DefaultTheme: NSObject, Theme { var secondaryCircleButtonBackgroundColor: UIColor = UIColor(rgb: 0xE3E8F0) + var shadowColor: UIColor = UIColor(rgb: 0x000000) + func applyStyle(onTabBar tabBar: UITabBar) { tabBar.unselectedItemTintColor = self.tabBarUnselectedItemTintColor tabBar.tintColor = self.tintColor diff --git a/Riot/Modules/Call/Dialpad/DialpadViewController.swift b/Riot/Modules/Call/Dialpad/DialpadViewController.swift index 410c46dcc..23e2c21ce 100644 --- a/Riot/Modules/Call/Dialpad/DialpadViewController.swift +++ b/Riot/Modules/Call/Dialpad/DialpadViewController.swift @@ -233,10 +233,15 @@ class DialpadViewController: UIViewController { theme.applyStyle(onNavigationBar: navigationBar) } - titleLabel.textColor = theme.noticeSecondaryColor + if theme.identifier == ThemeIdentifier.light.rawValue { + titleLabel.textColor = theme.noticeSecondaryColor + closeButton.setBackgroundImage(Asset.Images.closeButton.image.vc_tintedImage(usingColor: theme.tabBarUnselectedItemTintColor), for: .normal) + } else { + titleLabel.textColor = theme.baseTextSecondaryColor + closeButton.setBackgroundImage(Asset.Images.closeButton.image.vc_tintedImage(usingColor: theme.baseTextSecondaryColor), for: .normal) + } phoneNumberTextField.textColor = theme.textPrimaryColor lineView.backgroundColor = theme.lineBreakColor - closeButton.setBackgroundImage(Asset.Images.closeButton.image.vc_tintedImage(usingColor: theme.tabBarUnselectedItemTintColor), for: .normal) updateThemesOfAllButtons(in: digitsStackView, with: theme) } diff --git a/Riot/Modules/Call/Dialpad/Views/DialpadActionButton.swift b/Riot/Modules/Call/Dialpad/Views/DialpadActionButton.swift index a14d945a5..86db7ba40 100644 --- a/Riot/Modules/Call/Dialpad/Views/DialpadActionButton.swift +++ b/Riot/Modules/Call/Dialpad/Views/DialpadActionButton.swift @@ -31,9 +31,9 @@ class DialpadActionButton: DialpadButton { switch type { case .backspace: backgroundColor = .clear - tintColor = theme.noticeSecondaryColor + tintColor = theme.colors.tertiaryContent case .call: - backgroundColor = theme.tintColor + backgroundColor = theme.colors.accent tintColor = .white } } diff --git a/Riot/Modules/Room/RoomViewController.h b/Riot/Modules/Room/RoomViewController.h index 5f1e145f6..dac5cbb05 100644 --- a/Riot/Modules/Room/RoomViewController.h +++ b/Riot/Modules/Room/RoomViewController.h @@ -47,16 +47,18 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification; // The jump to last unread banner @property (weak, nonatomic) IBOutlet UIView *jumpToLastUnreadBannerContainer; -@property (weak, nonatomic) IBOutlet NSLayoutConstraint *jumpToLastUnreadBannerContainerTopConstraint; +@property (weak, nonatomic) IBOutlet UIView *jumpToLastUnreadBanner; @property (weak, nonatomic) IBOutlet UIImageView *jumpToLastUnreadImageView; @property (weak, nonatomic) IBOutlet UIButton *jumpToLastUnreadButton; @property (weak, nonatomic) IBOutlet UILabel *jumpToLastUnreadLabel; @property (weak, nonatomic) IBOutlet UIButton *resetReadMarkerButton; -@property (weak, nonatomic) IBOutlet UIView *jumpToLastUnreadBannerSeparatorView; @property (weak, nonatomic) IBOutlet UIView *inputBackgroundView; @property (weak, nonatomic) IBOutlet UIButton *scrollToBottomButton; @property (weak, nonatomic) IBOutlet BadgeLabel *scrollToBottomBadgeLabel; +// Remove Jitsi widget container +@property (weak, nonatomic) IBOutlet UIView *removeJitsiWidgetContainer; + /** Preview data for a room invitation received by email, or a link to a room. */ diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index b43da38fd..d08af5d10 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -135,7 +135,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; @interface RoomViewController () + RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate> { // The preview header @@ -220,6 +220,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } @property (nonatomic, weak) IBOutlet UIView *overlayContainerView; +@property (nonatomic, strong) RemoveJitsiWidgetView *removeJitsiWidgetView; @property (nonatomic, strong) RoomContextualMenuViewController *roomContextualMenuViewController; @@ -387,6 +388,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; [self vc_removeBackTitle]; + [self setupRemoveJitsiWidgetRemoveView]; + // Replace the default input toolbar view. // Note: this operation will force the layout of subviews. That is why cell view classes must be registered before. [self updateRoomInputToolbarViewClassIfNeeded]; @@ -455,11 +458,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; self.activityIndicator.backgroundColor = ThemeService.shared.theme.overlayBackgroundColor; + [self.removeJitsiWidgetView updateWithTheme:ThemeService.shared.theme]; + // Prepare jump to last unread banner - self.jumpToLastUnreadBannerContainer.backgroundColor = ThemeService.shared.theme.backgroundColor; - self.jumpToLastUnreadImageView.tintColor = ThemeService.shared.theme.textPrimaryColor; + self.jumpToLastUnreadImageView.tintColor = ThemeService.shared.theme.tintColor; self.jumpToLastUnreadLabel.textColor = ThemeService.shared.theme.textPrimaryColor; - self.jumpToLastUnreadBannerSeparatorView.backgroundColor = ThemeService.shared.theme.lineBreakColor; self.previewHeaderContainer.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; @@ -473,23 +476,31 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; [self.bubblesTableView reloadData]; } - self.scrollToBottomButton.layer.shadowColor = [UIColor blackColor].CGColor; - self.scrollToBottomButton.layer.shadowOpacity = 0.2; - self.scrollToBottomButton.layer.shadowRadius = 6; - self.scrollToBottomButton.layer.shadowOffset = CGSizeMake(0, 4); + [self.scrollToBottomButton vc_addShadowWithColor:ThemeService.shared.theme.shadowColor + offset:CGSizeMake(0, 4) + radius:6 + opacity:0.2]; self.inputBackgroundView.backgroundColor = [ThemeService.shared.theme.backgroundColor colorWithAlphaComponent:0.98]; - if ([ThemeService.shared.themeId isEqualToString:@"light"]) + if (ThemeService.shared.isCurrentThemeDark) + { + [self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown_dark"] forState:UIControlStateNormal]; + + self.jumpToLastUnreadBanner.backgroundColor = ThemeService.shared.theme.colors.navigation; + [self.jumpToLastUnreadBanner vc_removeShadow]; + self.resetReadMarkerButton.tintColor = ThemeService.shared.theme.colors.quarterlyContent; + } + else { [self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown"] forState:UIControlStateNormal]; - } - else if ([ThemeService.shared.themeId isEqualToString:@"dark"] || [ThemeService.shared.themeId isEqualToString:@"black"]) - { - [self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown_dark"] forState:UIControlStateNormal]; - } - else if (@available(iOS 12.0, *) && ThemeService.shared.theme.userInterfaceStyle == UIUserInterfaceStyleDark) { - [self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown_dark"] forState:UIControlStateNormal]; + + self.jumpToLastUnreadBanner.backgroundColor = ThemeService.shared.theme.colors.background; + [self.jumpToLastUnreadBanner vc_addShadowWithColor:ThemeService.shared.theme.shadowColor + offset:CGSizeMake(0, 4) + radius:8 + opacity:0.1]; + self.resetReadMarkerButton.tintColor = ThemeService.shared.theme.colors.tertiaryContent; } self.scrollToBottomBadgeLabel.badgeColor = ThemeService.shared.theme.tintColor; @@ -518,6 +529,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; // Refresh the room title view [self refreshRoomTitle]; + // refresh remove Jitsi widget view + [self refreshRemoveJitsiWidgetView]; + // Refresh tool bar if the room data source is set. if (self.roomDataSource) { @@ -732,15 +746,12 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; self.previewHeaderContainerHeightConstraint.constant = frame.origin.y + frame.size.height; self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top; - self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant; } else { // In non expanded header mode, the navigation bar is opaque // The table view must not display behind it self.edgesForExtendedLayout = UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight; - - self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.bubblesTableView.mxk_adjustedContentInset.top; // no expanded } // stay at the bottom if already was @@ -1396,6 +1407,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; #pragma mark - Internals +- (UIBarButtonItem *)videoCallBarButtonItem +{ + UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"video_call"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(onVideoCallPressed:)]; + item.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessibility_video_call", @"Vector", nil); + + return item; +} + +- (void)setupRemoveJitsiWidgetRemoveView +{ + self.removeJitsiWidgetView = [RemoveJitsiWidgetView instantiate]; + self.removeJitsiWidgetView.delegate = self; + + [self.removeJitsiWidgetContainer vc_addSubViewMatchingParent:self.removeJitsiWidgetView]; + + self.removeJitsiWidgetContainer.hidden = YES; + + [self refreshRemoveJitsiWidgetView]; +} + - (void)forceLayoutRefresh { // Sanity check: check whether the table view data source is set. @@ -1467,70 +1501,84 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; if (self.roomDataSource.isLive) { rightBarButtonItems = [NSMutableArray new]; + BOOL hasCustomJoinButton = NO; - UIEdgeInsets itemInsets = UIEdgeInsetsMake(0, -5, 0, 5); if (self.supportCallOption) { if (self.roomDataSource.room.summary.membersCount.joined == 2 && self.roomDataSource.room.isDirect) { - UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"voice_call_hangon_icon"] style:UIBarButtonItemStylePlain target:self action:@selector(onVoiceCallPressed:)]; - item.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessibility_call", @"Vector", nil); - item.imageInsets = UIEdgeInsetsMake(0, -5, 0, 5); - item.enabled = !self.isCallActive; - [rightBarButtonItems addObject:item]; - } - - UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"video_call"] style:UIBarButtonItemStylePlain target:self action:@selector(onVideoCallPressed:)]; - item.imageInsets = rightBarButtonItems.count ? UIEdgeInsetsMake(0, 10, 0, -10) : itemInsets; - item.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessibility_video_call", @"Vector", nil); - if (self.roomDataSource.room.summary.membersCount.joined == 2 && self.roomDataSource.room.isDirect) - { - // Matrix call - item.enabled = !self.isCallActive; + // voice call button for Matrix call + UIBarButtonItem *itemVoice = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"voice_call_hangon_icon"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(onVoiceCallPressed:)]; + itemVoice.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessibility_call", @"Vector", nil); + itemVoice.enabled = !self.isCallActive; + [rightBarButtonItems addObject:itemVoice]; + + // video call button for Matrix call + UIBarButtonItem *itemVideo = [self videoCallBarButtonItem]; + itemVideo.enabled = !self.isCallActive; + [rightBarButtonItems addObject:itemVideo]; } else { - // Jitsi call + // video call button for Jitsi call if (self.isCallActive) { JitsiViewController *jitsiVC = [AppDelegate theDelegate].callPresenter.jitsiVC; if ([jitsiVC.widget.roomId isEqualToString:self.roomDataSource.roomId]) { + // show a disabled call button + UIBarButtonItem *item = [self videoCallBarButtonItem]; item.enabled = NO; + [rightBarButtonItems addObject:item]; } else { // show Join button CallTileActionButton *button = [CallTileActionButton new]; - [button setImage:[UIImage imageNamed:@"call_video_icon"] forState:UIControlStateNormal]; - [button setTitle:NSLocalizedStringFromTable(@"room_join_group_call", @"Vector", nil) forState:UIControlStateNormal]; + [button setImage:[UIImage imageNamed:@"call_video_icon"] + forState:UIControlStateNormal]; + [button setTitle:NSLocalizedStringFromTable(@"room_join_group_call", @"Vector", nil) + forState:UIControlStateNormal]; [button addTarget:self action:@selector(onVideoCallPressed:) forControlEvents:UIControlEventTouchUpInside]; button.contentEdgeInsets = UIEdgeInsetsMake(4, 12, 4, 12); - item.customView = button; - item.enabled = YES; + UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:button]; + item.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessibility_video_call", @"Vector", nil); + [rightBarButtonItems addObject:item]; + + hasCustomJoinButton = YES; } } else { + // show a video call button + // item will still be enabled, and when tapped an alert will be displayed to the user + UIBarButtonItem *item = [self videoCallBarButtonItem]; if (!self.canEditJitsiWidget) { item.image = [[UIImage imageNamed:@"video_call"] vc_withAlpha:0.3]; } - // item will still be enabled, and when tapped an alert will be displayed to the user - item.enabled = YES; + [rightBarButtonItems addObject:item]; } } - [rightBarButtonItems addObject:item]; - itemInsets = UIEdgeInsetsMake(0, 20, 0, -20); } if ([self widgetsCount:NO]) { - UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"integrations_icon"] style:UIBarButtonItemStylePlain target:self action:@selector(onIntegrationsPressed:)]; - item.imageInsets = itemInsets; + UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"integrations_icon"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(onIntegrationsPressed:)]; item.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessibility_integrations", @"Vector", nil); + if (hasCustomJoinButton) + { + item.imageInsets = UIEdgeInsetsMake(0, -5, 0, -5); + item.landscapeImagePhoneInsets = UIEdgeInsetsMake(0, -5, 0, -5); + } [rightBarButtonItems addObject:item]; } @@ -2075,7 +2123,6 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; animations:^{ self.bubblesTableViewTopConstraint.constant = 0; - self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.bubblesTableView.mxk_adjustedContentInset.top; // Force to render the view [self forceLayoutRefresh]; @@ -2194,7 +2241,6 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; animations:^{ self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.mxk_adjustedContentInset.top; - self.jumpToLastUnreadBannerContainerTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant; previewHeader.roomAvatar.alpha = 1; @@ -4431,17 +4477,20 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; - (void)listenWidgetNotifications { + MXWeakify(self); + kMXKWidgetManagerDidUpdateWidgetObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kWidgetManagerDidUpdateWidgetNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + MXStrongifyAndReturnIfNil(self); + Widget *widget = notif.object; if (widget.mxSession == self.roomDataSource.mxSession - && [widget.roomId isEqualToString:customizedRoomDataSource.roomId]) + && [widget.roomId isEqualToString:self->customizedRoomDataSource.roomId]) { - // Jitsi conference widget existence is shown in the bottom bar - // Update the bar - [self refreshActivitiesViewDisplay]; - [self refreshRoomInputToolbar]; + // Call button update [self refreshRoomTitle]; + // Remove Jitsi widget view update + [self refreshRemoveJitsiWidgetView]; } }]; } @@ -4489,8 +4538,6 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; [roomActivitiesView removeGestureRecognizer:roomActivitiesView.gestureRecognizers[0]]; } - Widget *jitsiWidget = [customizedRoomDataSource jitsiWidget]; - if ([self.roomDataSource.mxSession.syncError.errcode isEqualToString:kMXErrCodeStringResourceLimitExceeded]) { self.activitiesViewExpanded = YES; @@ -5092,6 +5139,32 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } } +- (void)refreshRemoveJitsiWidgetView +{ + if (self.roomDataSource.isLive && !self.roomDataSource.isPeeking) + { + Widget *jitsiWidget = [customizedRoomDataSource jitsiWidget]; + + if (jitsiWidget && self.canEditJitsiWidget) + { + [self.removeJitsiWidgetView reset]; + self.removeJitsiWidgetContainer.hidden = NO; + self.removeJitsiWidgetView.delegate = self; + } + else + { + self.removeJitsiWidgetContainer.hidden = YES; + self.removeJitsiWidgetView.delegate = nil; + } + } + else + { + [self.removeJitsiWidgetView reset]; + self.removeJitsiWidgetContainer.hidden = YES; + self.removeJitsiWidgetView.delegate = self; + } +} + - (void)refreshJumpToLastUnreadBannerDisplay { // This banner is only displayed when the room timeline is in live (and no peeking). @@ -6050,4 +6123,37 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; self.roomInfoCoordinatorBridgePresenter = nil; } +#pragma mark - RemoveJitsiWidgetViewDelegate + +- (void)removeJitsiWidgetViewDidCompleteSliding:(RemoveJitsiWidgetView *)view +{ + view.delegate = nil; + Widget *jitsiWidget = [customizedRoomDataSource jitsiWidget]; + + [self startActivityIndicator]; + + // close the widget + MXWeakify(self); + + [[WidgetManager sharedManager] closeWidget:jitsiWidget.widgetId + inRoom:self.roomDataSource.room + success:^{ + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + // we can wait for kWidgetManagerDidUpdateWidgetNotification, but we want to be faster + self.removeJitsiWidgetContainer.hidden = YES; + self.removeJitsiWidgetView.delegate = nil; + + // end active call if exists + if ([[AppDelegate theDelegate].callPresenter.jitsiVC.widget.widgetId isEqualToString:jitsiWidget.widgetId]) + { + [[AppDelegate theDelegate].callPresenter endActiveJitsiCall]; + } + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self showJitsiErrorAsAlert:error]; + [self stopActivityIndicator]; + }]; +} + @end diff --git a/Riot/Modules/Room/RoomViewController.xib b/Riot/Modules/Room/RoomViewController.xib index 2371d6a0e..5b1a0a909 100644 --- a/Riot/Modules/Room/RoomViewController.xib +++ b/Riot/Modules/Room/RoomViewController.xib @@ -15,15 +15,15 @@ - - - - - + + + + + @@ -55,76 +55,86 @@ - + + +