mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-05 07:27:42 +02:00
Introduce CallBar view management
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
|
||||
@protocol Configurable;
|
||||
@protocol LegacyAppDelegateDelegate;
|
||||
@class CallBar;
|
||||
|
||||
#pragma mark - Notifications
|
||||
/**
|
||||
@@ -238,7 +239,7 @@ JitsiViewControllerDelegate>
|
||||
Call status window displayed when user goes back to app during a call.
|
||||
*/
|
||||
@property (nonatomic, readonly) UIWindow* callStatusBarWindow;
|
||||
@property (nonatomic, readonly) UIButton* callStatusBarButton;
|
||||
@property (nonatomic, readonly) CallBar* callBar;
|
||||
|
||||
#pragma mark - App version management
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
|
||||
|
||||
NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUniversalLinkDidChangeNotification";
|
||||
|
||||
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate, CallServiceDelegate>
|
||||
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate, CallServiceDelegate, CallBarDelegate>
|
||||
{
|
||||
/**
|
||||
Reachability observer
|
||||
@@ -3043,7 +3043,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
|
||||
MXRoom *room = [_jitsiViewController.widget.mxSession roomWithRoomId:_jitsiViewController.widget.roomId];
|
||||
NSString *btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"active_call_details", @"Vector", nil), room.summary.displayname];
|
||||
[self addCallStatusBar:btnTitle];
|
||||
[self updateCallStatusBar:btnTitle];
|
||||
|
||||
if (completion)
|
||||
{
|
||||
@@ -3186,8 +3186,13 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)addCallStatusBar:(NSString*)buttonTitle
|
||||
- (void)updateCallStatusBar:(NSString*)title
|
||||
{
|
||||
if (_callBar)
|
||||
{
|
||||
_callBar.title = title;
|
||||
return;
|
||||
}
|
||||
// Add a call status bar
|
||||
CGSize topBarSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width, [self calculateCallStatusBarHeight]);
|
||||
|
||||
@@ -3195,42 +3200,20 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
_callStatusBarWindow.windowLevel = UIWindowLevelStatusBar;
|
||||
|
||||
// Create statusBarButton
|
||||
_callStatusBarButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_callStatusBarButton.frame = CGRectMake(0, 0, topBarSize.width, topBarSize.height);
|
||||
|
||||
[_callStatusBarButton setTitle:buttonTitle forState:UIControlStateNormal];
|
||||
[_callStatusBarButton setTitle:buttonTitle forState:UIControlStateHighlighted];
|
||||
|
||||
_callStatusBarButton.titleLabel.textColor = ThemeService.shared.theme.backgroundColor;
|
||||
|
||||
_callStatusBarButton.titleLabel.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium];
|
||||
|
||||
[_callStatusBarButton setBackgroundColor:ThemeService.shared.theme.tintColor];
|
||||
[_callStatusBarButton addTarget:self action:@selector(onCallStatusBarButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
_callBar = [CallBar instantiate];
|
||||
_callBar.frame = CGRectMake(0, 0, topBarSize.width, topBarSize.height);
|
||||
_callBar.title = title;
|
||||
_callBar.backgroundColor = ThemeService.shared.theme.tintColor;
|
||||
_callBar.delegate = self;
|
||||
|
||||
// Place button into the new window
|
||||
[_callStatusBarButton setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_callStatusBarWindow addSubview:_callStatusBarButton];
|
||||
|
||||
// Force callStatusBarButton to fill the window (to handle auto-layout in case of screen rotation)
|
||||
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:_callStatusBarButton
|
||||
attribute:NSLayoutAttributeWidth
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:_callStatusBarWindow
|
||||
attribute:NSLayoutAttributeWidth
|
||||
multiplier:1.0
|
||||
constant:0];
|
||||
|
||||
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:_callStatusBarButton
|
||||
attribute:NSLayoutAttributeHeight
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:_callStatusBarWindow
|
||||
attribute:NSLayoutAttributeHeight
|
||||
multiplier:1.0
|
||||
constant:0];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint]];
|
||||
[_callBar setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_callStatusBarWindow addSubview:_callBar];
|
||||
|
||||
// Force callBar to fill the window (to handle auto-layout in case of screen rotation)
|
||||
[_callBar.widthAnchor constraintEqualToAnchor:_callStatusBarWindow.widthAnchor].active = YES;
|
||||
[_callBar.heightAnchor constraintEqualToAnchor:_callStatusBarWindow.heightAnchor].active = YES;
|
||||
|
||||
_callStatusBarWindow.hidden = NO;
|
||||
[self statusBarDidChangeFrame];
|
||||
|
||||
@@ -3251,26 +3234,14 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
|
||||
// Hide & destroy it
|
||||
_callStatusBarWindow.hidden = YES;
|
||||
[_callStatusBarButton removeFromSuperview];
|
||||
_callStatusBarButton = nil;
|
||||
[_callBar removeFromSuperview];
|
||||
_callBar = nil;
|
||||
_callStatusBarWindow = nil;
|
||||
|
||||
[self statusBarDidChangeFrame];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onCallStatusBarButtonPressed
|
||||
{
|
||||
if ([_callService callStatusBarButtonTapped])
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (_jitsiViewController)
|
||||
{
|
||||
[self presentJitsiViewController:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)statusBarDidChangeFrame
|
||||
{
|
||||
UIApplication *app = [UIApplication sharedApplication];
|
||||
@@ -3307,20 +3278,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
}
|
||||
}
|
||||
|
||||
UIEdgeInsets callBarButtonContentEdgeInsets = UIEdgeInsetsZero;
|
||||
|
||||
if (@available(iOS 11.0, *))
|
||||
{
|
||||
callBarButtonContentEdgeInsets = UIApplication.sharedApplication.keyWindow.safeAreaInsets;
|
||||
// should override top inset
|
||||
callBarButtonContentEdgeInsets.top = callStatusBarHeight - CALL_STATUS_BAR_HEIGHT;
|
||||
// should ignore bottom inset
|
||||
callBarButtonContentEdgeInsets.bottom = 0.0;
|
||||
// should keep left, and right insets as original
|
||||
}
|
||||
|
||||
_callStatusBarButton.contentEdgeInsets = callBarButtonContentEdgeInsets;
|
||||
|
||||
// Apply the vertical offset due to call status bar
|
||||
rootControllerFrame.origin.y = callStatusBarHeight;
|
||||
rootControllerFrame.size.height -= callStatusBarHeight;
|
||||
@@ -4490,10 +4447,43 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
}
|
||||
}
|
||||
|
||||
- (void)callService:(CallService *)service presentCallBarFor:(CallViewController *)viewController completion:(void (^)(void))completion
|
||||
- (void)callService:(CallService *)service presentCallBarFor:(CallViewController *)activeCallViewController numberOfPausedCalls:(NSUInteger)numberOfPausedCalls completion:(void (^)(void))completion
|
||||
{
|
||||
NSString *btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"active_call_details", @"Vector", nil), viewController.callerNameLabel.text];
|
||||
[self addCallStatusBar:btnTitle];
|
||||
NSString *btnTitle;
|
||||
|
||||
if (activeCallViewController)
|
||||
{
|
||||
// TODO: Add timer for active call duration
|
||||
if (numberOfPausedCalls == 0)
|
||||
{
|
||||
// only one active
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_single_active", @"Vector", nil), activeCallViewController.callStatusLabel.text];
|
||||
}
|
||||
else if (numberOfPausedCalls == 1)
|
||||
{
|
||||
// one active and one paused
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_active_and_single_paused", @"Vector", nil), activeCallViewController.callStatusLabel.text];
|
||||
}
|
||||
else
|
||||
{
|
||||
// one active and multiple paused
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_active_and_multiple_paused", @"Vector", nil), activeCallViewController.callStatusLabel.text, @(numberOfPausedCalls)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no active calls
|
||||
if (numberOfPausedCalls == 1)
|
||||
{
|
||||
btnTitle = NSLocalizedStringFromTable(@"callbar_only_single_paused", @"Vector", nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_multiple_paused", @"Vector", nil), @(numberOfPausedCalls)];
|
||||
}
|
||||
}
|
||||
|
||||
[self updateCallStatusBar:btnTitle];
|
||||
|
||||
if (completion)
|
||||
{
|
||||
@@ -4501,7 +4491,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
}
|
||||
}
|
||||
|
||||
- (void)callService:(CallService *)service dismissCallBarFor:(CallViewController *)viewController completion:(void (^)(void))completion
|
||||
- (void)callService:(CallService *)service dismissCallBar:(void (^)(void))completion
|
||||
{
|
||||
[self removeCallStatusBar];
|
||||
|
||||
@@ -4511,4 +4501,18 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - CallBarDelegate
|
||||
|
||||
- (void)callBarDidTapReturnButton:(CallBar *)callBar
|
||||
{
|
||||
if ([_callService callStatusBarButtonTapped])
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (_jitsiViewController)
|
||||
{
|
||||
[self presentJitsiViewController:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// Copyright 2020 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Reusable
|
||||
|
||||
@objc protocol CallBarDelegate: class {
|
||||
func callBarDidTapReturnButton(_ callBar: CallBar)
|
||||
}
|
||||
|
||||
@objcMembers
|
||||
class CallBar: UIView, NibLoadable {
|
||||
|
||||
@IBOutlet private weak var callIcon: UIImageView! {
|
||||
didSet {
|
||||
callIcon.image = Asset.Images.voiceCallHangonIcon.image.vc_tintedImage(usingColor: .white)
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var titleLabel: UILabel!
|
||||
@IBOutlet private weak var returnButton: UIButton!
|
||||
|
||||
weak var delegate: CallBarDelegate?
|
||||
|
||||
static func instantiate() -> CallBar {
|
||||
return CallBar.loadFromNib()
|
||||
}
|
||||
|
||||
var title: String? {
|
||||
get {
|
||||
return titleLabel.text
|
||||
} set {
|
||||
titleLabel.text = newValue
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction private func returnButtonTapped(_ sender: UIButton) {
|
||||
delegate?.callBarDidTapReturnButton(self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17126"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CallBar" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eee-sW-qFO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="voice_call_hangon_icon" translatesAutoresizingMaskIntoConstraints="NO" id="cuO-6F-uXq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="44" height="44"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="cuO-6F-uXq" secondAttribute="height" multiplier="1:1" id="CgQ-jX-f2t"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="249" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4TV-K4-7lO">
|
||||
<rect key="frame" x="44" y="8" width="303" height="28"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UUZ-sl-L6q">
|
||||
<rect key="frame" x="355" y="0.0" width="59" height="44"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<inset key="contentEdgeInsets" minX="8" minY="8" maxX="8" maxY="8"/>
|
||||
<state key="normal" title="Return"/>
|
||||
<connections>
|
||||
<action selector="returnButtonTapped:" destination="iN0-l3-epB" eventType="touchUpInside" id="VJx-cV-NtX"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="cuO-6F-uXq" firstAttribute="leading" secondItem="eee-sW-qFO" secondAttribute="leading" id="1Md-B3-CA1"/>
|
||||
<constraint firstAttribute="bottom" secondItem="cuO-6F-uXq" secondAttribute="bottom" id="Fe6-FC-Lkh"/>
|
||||
<constraint firstItem="UUZ-sl-L6q" firstAttribute="top" secondItem="eee-sW-qFO" secondAttribute="top" id="HSs-7b-rXw"/>
|
||||
<constraint firstAttribute="bottom" secondItem="UUZ-sl-L6q" secondAttribute="bottom" id="MgQ-Px-CRu"/>
|
||||
<constraint firstItem="4TV-K4-7lO" firstAttribute="leading" secondItem="cuO-6F-uXq" secondAttribute="trailing" id="Pfy-hd-a8d"/>
|
||||
<constraint firstAttribute="trailing" secondItem="UUZ-sl-L6q" secondAttribute="trailing" id="aqk-h6-34r"/>
|
||||
<constraint firstAttribute="bottom" secondItem="4TV-K4-7lO" secondAttribute="bottom" constant="8" id="cij-lT-Nw6"/>
|
||||
<constraint firstAttribute="height" constant="44" id="g8Q-T8-geN"/>
|
||||
<constraint firstItem="4TV-K4-7lO" firstAttribute="top" secondItem="eee-sW-qFO" secondAttribute="top" constant="8" id="lfW-G9-DaP"/>
|
||||
<constraint firstItem="UUZ-sl-L6q" firstAttribute="leading" secondItem="4TV-K4-7lO" secondAttribute="trailing" constant="8" id="niz-VT-cYY"/>
|
||||
<constraint firstItem="cuO-6F-uXq" firstAttribute="top" secondItem="eee-sW-qFO" secondAttribute="top" id="v7k-1F-UR7"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" red="0.011764705882352941" green="0.70196078431372544" blue="0.50588235294117645" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="eee-sW-qFO" secondAttribute="trailing" id="8uk-4g-uhK"/>
|
||||
<constraint firstAttribute="bottom" secondItem="eee-sW-qFO" secondAttribute="bottom" id="dPh-ko-WYf"/>
|
||||
<constraint firstItem="eee-sW-qFO" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="tfp-6O-DDi"/>
|
||||
</constraints>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="callIcon" destination="cuO-6F-uXq" id="A3y-xa-XHu"/>
|
||||
<outlet property="returnButton" destination="UUZ-sl-L6q" id="baV-ub-2f1"/>
|
||||
<outlet property="titleLabel" destination="4TV-K4-7lO" id="ZkY-wt-1OH"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="137.68115942028987" y="-187.5"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="voice_call_hangon_icon" width="24" height="24"/>
|
||||
</resources>
|
||||
</document>
|
||||
Reference in New Issue
Block a user