Group call from group chat

This commit is contained in:
Christophe Deschamps 2022-06-14 11:15:28 +02:00
parent 18910129b5
commit 2f48008050
11 changed files with 106 additions and 43 deletions

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -21,7 +21,6 @@
<outlet property="ephemeralndicator" destination="LN7-ci-kNn" id="hqU-98-qkJ"/>
<outlet property="imagesCollectionView" destination="JGQ-p2-HCX" id="6dt-1f-jpa"/>
<outlet property="imagesView" destination="3qd-ys-t2L" id="f9L-FU-PMI"/>
<outlet property="infoButton" destination="Vqb-Un-4xv" id="pa1-Iz-5QQ"/>
<outlet property="landscapeView" destination="VoU-7Q-fgp" id="iRJ-sh-thF"/>
<outlet property="listSwipeGestureRecognizer" destination="dzw-n4-l9i" id="JVP-Vl-lIa"/>
<outlet property="listTapGestureRecognizer" destination="tkk-Tm-A7C" id="gqU-iJ-RGm"/>
@ -185,22 +184,6 @@
<action selector="onSelectionToggle:" destination="29" eventType="touchUpInside" id="eP5-bU-LEA"/>
</connections>
</button>
<button hidden="YES" opaque="NO" tag="10" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" reversesTitleShadowWhenHighlighted="YES" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Vqb-Un-4xv" userLabel="infoButton" customClass="UIInterfaceStyleButton">
<rect key="frame" x="248" y="0.0" width="83" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<accessibility key="accessibilityConfiguration" label="Select all"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
<state key="normal" image="chat_group_informations.png">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<state key="disabled" image="select_all_disabled.png"/>
<state key="selected" image="select_all_default.png"/>
<state key="highlighted" backgroundImage="color_E.png"/>
<connections>
<action selector="onInfoClick:" destination="-1" eventType="touchUpInside" id="VfD-K7-V15"/>
</connections>
</button>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="5" contentMode="left" fixedFrame="YES" text="addresses" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ncq-Zc-X6j" userLabel="participantsLabel">
<rect key="frame" x="75" y="36" width="160" height="25"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>

View file

@ -80,7 +80,6 @@
@property(nonatomic, strong) IBOutlet UIButton *pictureButton;
@property(weak, nonatomic) IBOutlet UIButton *callButton;
@property(weak, nonatomic) IBOutlet UIBackToCallButton *backToCallButton;
@property (weak, nonatomic) IBOutlet UIButton *infoButton;
@property (weak, nonatomic) IBOutlet UILabel *particpantsLabel;
@property NSMutableArray <NSNumber *> *qualitySettingsArray;
@property (weak, nonatomic) IBOutlet UICollectionView *imagesCollectionView;

View file

@ -196,6 +196,7 @@ static UICompositeViewDescription *compositeDescription = nil;
_vrInnerView.layer.masksToBounds = YES;
_vrWaveMaskPlayer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"color_L"]]; // rgba(1,88,7,0.2);
_showVoiceRecorderView = false;
_callButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
}
@ -638,12 +639,32 @@ static UICompositeViewDescription *compositeDescription = nil;
}];
}
- (BOOL) groupCallAvailable {
if (isOneToOne || !_backToCallButton.hidden || _tableController.tableView.isEditing)
return false;
LinphoneAccount *account = linphone_core_get_default_account(LC);
if (!account)
return false;
const LinphoneAccountParams *params = linphone_account_get_params(account);
if (!params)
return false;
return linphone_account_params_get_audio_video_conference_factory_address(params) != nil || linphone_account_params_get_conference_factory_uri(params) != nil;
}
- (void)updateSuperposedButtons {
[_backToCallButton update];
_infoButton.hidden = (isOneToOne|| !_backToCallButton.hidden || _tableController.tableView.isEditing);
_callButton.hidden = !_backToCallButton.hidden || !_infoButton.hidden || _tableController.tableView.isEditing;
_callButton.hidden = !_backToCallButton.hidden || _tableController.tableView.isEditing;
_toggleMenuButton.hidden = [self isBasicChatRoom] || _tableController.tableView.isEditing;
_tableController.editButton.hidden = _tableController.editButton.hidden || ![self isBasicChatRoom];
// Group call :
if (self.groupCallAvailable ) {
[_callButton setImage:[UIImage imageNamed:@"voip_conference_new"] forState:UIControlStateNormal];
_callButton.hidden = false;
} else {
[_callButton setImage:[UIImage imageNamed:@"call_alt_start_default"] forState:UIControlStateNormal];
}
}
- (void)updateParticipantLabel {
@ -841,7 +862,21 @@ static UICompositeViewDescription *compositeDescription = nil;
bctbx_list_t *participants = linphone_chat_room_get_participants(_chatRoom);
LinphoneParticipant *firstParticipant = participants ? (LinphoneParticipant *)participants->data : NULL;
const LinphoneAddress *addr = firstParticipant ? linphone_participant_get_address(firstParticipant) : linphone_chat_room_get_peer_address(_chatRoom);
[LinphoneManager.instance call:addr];
if (self.groupCallAvailable) {
UIConfirmationDialog *d = [UIConfirmationDialog ShowWithMessage:VoipTexts.conference_start_group_call_dialog_message
cancelMessage:nil
confirmMessage:VoipTexts.conference_start_group_call_dialog_ok_button
onCancelClick:^() {}
onConfirmationClick:^() {
[ConferenceViewModelBridge startGroupCallWithCChatRoom:_chatRoom];
}];
d.groupCallImage.hidden = NO;
[d.groupCallImage setImageNamed:@"voip_conference_new" tintColor:UIColor.whiteColor];
[d setSpecialColor];
[d setWhiteCancel];
} else
[LinphoneManager.instance call:addr];
}
- (IBAction)onListSwipe:(id)sender {
@ -1655,14 +1690,17 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self onToggleMenu:nil];
if (indexPath.row == 0) {
[self goToDeviceListView];
[self onInfoClick:nil];
}
if (indexPath.row == 1) {
[self goToDeviceListView];
}
if (indexPath.row == 2) {
[_tableController onEditClick:nil];
[self onEditionChangeClick:nil];
}
if ([ConfigManager.instance lpConfigBoolForKeyWithKey:@"ephemeral_feature" defaultValue:false] && [self canAdminEphemeral:_chatRoom]) {
if (indexPath.row == 2) {
if (indexPath.row == 3) {
EphemeralSettingsView *view = VIEW(EphemeralSettingsView);
view.room = _chatRoom;
[PhoneMainView.instance popToView:view.compositeViewDescription];
@ -1675,22 +1713,27 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [ConfigManager.instance lpConfigBoolForKeyWithKey:@"ephemeral_feature" defaultValue:false] && [self canAdminEphemeral:_chatRoom] ? 3 : 2;
return [ConfigManager.instance lpConfigBoolForKeyWithKey:@"ephemeral_feature" defaultValue:false] && [self canAdminEphemeral:_chatRoom] ? 4 : 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] init];
if (indexPath.row == 0) {
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"chat_group_informations.png"] newSize:CGSizeMake(25, 25)];
cell.textLabel.text = NSLocalizedString(@"Group infos",nil);
}
if (indexPath.row == 1) {
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"menu_security_default.png"] newSize:CGSizeMake(20, 25)];
cell.textLabel.text = NSLocalizedString(@"Conversation's devices",nil);
}
if (indexPath.row == 1) {
if (indexPath.row == 2) {
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"delete_default.png"] newSize:CGSizeMake(20, 25)];
cell.textLabel.text = NSLocalizedString(@"Delete messages",nil);
}
if ([ConfigManager.instance lpConfigBoolForKeyWithKey:@"ephemeral_feature" defaultValue:false] && [self canAdminEphemeral:_chatRoom]) {
if (indexPath.row == 2) {
if (indexPath.row == 3) {
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"ephemeral_messages_default.png"] newSize:CGSizeMake(20, 25)];
cell.textLabel.text = NSLocalizedString(@"Ephemeral messages",nil);
}

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -14,6 +14,7 @@
<outlet property="cancelButton" destination="B1K-CB-3of" id="KKi-Xc-ldA"/>
<outlet property="confirmationButton" destination="SbQ-re-fGQ" id="yiv-a9-o8E"/>
<outlet property="forwardImage" destination="1Wh-Yi-cUe" id="YQq-bt-pk1"/>
<outlet property="groupCallImage" destination="SVn-4k-9yc" id="sAP-8V-ttn"/>
<outlet property="securityImage" destination="bbo-g3-bGy" id="qZa-li-yrl"/>
<outlet property="titleLabel" destination="jLz-g1-cTe" id="qaj-OB-2r1"/>
<outlet property="view" destination="2Vb-Xy-rci" id="nNw-EJ-AY3"/>
@ -93,6 +94,10 @@
<rect key="frame" x="89" y="50" width="138" height="54"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="voip_conference_new.png" translatesAutoresizingMaskIntoConstraints="NO" id="SVn-4k-9yc">
<rect key="frame" x="89" y="50" width="138" height="54"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
</subviews>
</view>
</subviews>
@ -111,5 +116,6 @@
<image name="color_M.png" width="2" height="2"/>
<image name="forward_message_default.png" width="187" height="148"/>
<image name="security_2_indicator.png" width="27.5" height="32.5"/>
<image name="voip_conference_new.png" width="97.599998474121094" height="97.599998474121094"/>
</resources>
</document>

View file

@ -46,12 +46,14 @@ typedef void (^UIConfirmationBlock)(void);
@property(weak, nonatomic) IBOutlet UIRoundBorderedButton *cancelButton;
@property (weak, nonatomic) IBOutlet UIImageView *securityImage;
@property (weak, nonatomic) IBOutlet UIImageView *forwardImage;
@property (weak, nonatomic) IBOutlet UIImageView *groupCallImage;
@property(weak, nonatomic) IBOutlet UIRoundBorderedButton *confirmationButton;
@property (weak, nonatomic) IBOutlet UIView *authView;
@property(weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *authButton;
- (void)setSpecialColor;
-(void) setWhiteCancel;
- (IBAction)onCancelClick:(id)sender;
- (IBAction)onConfirmationClick:(id)sender;
- (IBAction)onAuthClick:(id)sender;

View file

@ -19,6 +19,7 @@
#import "UIConfirmationDialog.h"
#import "PhoneMainView.h"
#import "linphoneapp-Swift.h""
@implementation UIConfirmationDialog
+ (UIConfirmationDialog *)initDialog:(NSString *)cancel
@ -97,6 +98,12 @@
[[UIColor colorWithPatternImage:[UIImage imageNamed:@"color_A.png"]] CGColor];
}
-(void) setWhiteCancel {
[_cancelButton setBackgroundImage:nil forState:UIControlStateNormal];
[_cancelButton setBackgroundColor:UIColor.whiteColor];
[_cancelButton setTitleColor:VoipTheme.voip_dark_gray forState:UIControlStateNormal];
}
- (IBAction)onCancelClick:(id)sender {
[self.view removeFromSuperview];
[self removeFromParentViewController];

View file

@ -56,7 +56,7 @@ class ConferenceSchedulingViewModel {
let selectedAddresses = MutableLiveData<[Address]>([])
private let conferenceScheduler = try? Core.get().createConferenceScheduler()
private var conferenceScheduler: ConferenceScheduler? = nil
private var hour: Int = 0
@ -112,11 +112,7 @@ class ConferenceSchedulingViewModel {
self.conferenceCreationCompletedEvent.value = Pair(conferenceAddress.asStringUriOnly(),self.conferenceScheduler?.info?.subject)
}
)
conferenceScheduler?.addDelegate(delegate: conferenceSchedulerDelegate!)
chatRooomDelegate = ChatRoomDelegateStub(
onStateChanged : { (room: ChatRoom, state: ChatRoom.State) -> Void in
if (state == ChatRoom.State.Created) {
@ -182,8 +178,7 @@ class ConferenceSchedulingViewModel {
func gotoChatRoom() {
}
func createConference() {
if (selectedAddresses.value?.count == 0) {
@ -197,6 +192,9 @@ class ConferenceSchedulingViewModel {
Log.e("[Conference Creation] Couldn't get local address from default account!")
return
}
conferenceScheduler = try? Core.get().createConferenceScheduler()
conferenceScheduler?.addDelegate(delegate: conferenceSchedulerDelegate!)
let conferenceInfo = try Factory.Instance.createConferenceInfo()
conferenceInfo.organizer = localAddress

View file

@ -113,7 +113,9 @@ import UIKit
static let conference_first_to_join = NSLocalizedString("You're the first to join the group call",comment:"")
static let conference_incoming_title = NSLocalizedString("Incoming group call",comment:"")
static let conference_participants_title = NSLocalizedString("%d participants",comment:"")
@objc static let conference_start_group_call_dialog_message = NSLocalizedString("Do you want to start a group call?\nEveryone in this group will receive a call to join the meeting.",comment:"")
@objc static let conference_start_group_call_dialog_ok_button = NSLocalizedString("START",comment:"")
// Call Stats

View file

@ -20,12 +20,12 @@
import Foundation
import UIKit
class VoipTheme { // Names & values replicated from Android
@objc class VoipTheme : NSObject { // Names & values replicated from Android
// Voip Colors
static let voip_gray_blue_color = UIColor(hex:"#798791")
static let voip_light_gray = UIColor(hex:"#D0D8DE")
static let voip_dark_gray = UIColor(hex:"#4B5964")
@objc static let voip_dark_gray = UIColor(hex:"#4B5964")
static let voip_gray = UIColor(hex:"#96A5B1")
static let voip_gray_background = UIColor(hex:"#AFAFAF")
static let voip_call_record_background = UIColor(hex:"#EBEBEB")

View file

@ -20,6 +20,7 @@
import Foundation
import linphonesw
import linphone
import AVFoundation
class ConferenceViewModel {
@ -55,6 +56,8 @@ class ConferenceViewModel {
private var conferenceDelegate : ConferenceDelegateStub?
private var coreDelegate : CoreDelegateStub?
var conferenceScheduler:ConferenceScheduler? = nil
init () {
conferenceDelegate = ConferenceDelegateStub(
onParticipantAdded: { (conference: Conference, participant: Participant) in
@ -427,7 +430,8 @@ class ConferenceViewModel {
}
@objc class ConferenceViewModelBridge : NSObject {
@objc class ConferenceViewModelBridge : NSObject {
@objc static func updateParticipantsList(addresses:[String]) {
do {
try ConferenceViewModel.shared.updateParticipants(addresses: addresses.map { try Factory.Instance.createAddress(addr: $0)} )
@ -435,6 +439,25 @@ class ConferenceViewModel {
Log.e("[ParticipantsListView] unable to update participants list \(error)")
}
}
@objc static func startGroupCall(cChatRoom: OpaquePointer ) {
let core = Core.get()
let chatRoom = ChatRoom.getSwiftObject(cObject: cChatRoom)
guard let localAddress = chatRoom.localAddress?.clone() else {
Log.e("[Group Call] Couldn't get local address from default account!")
return
}
localAddress.clean() // Remove GRUU
ConferenceViewModel.shared.conferenceScheduler = try?Core.get().createConferenceScheduler()
let conferenceInfo = try?Factory.Instance.createConferenceInfo()
conferenceInfo?.participants = chatRoom.participants.map {$0.address!}
conferenceInfo?.organizer = localAddress
conferenceInfo?.subject = chatRoom.subject
ConferenceViewModel.shared.conferenceScheduler?.account = core.accountList.filter { $0.params?.identityAddress?.weakEqual(address2: localAddress) == true}.first
ConferenceViewModel.shared.conferenceScheduler?.info = conferenceInfo // Will trigger the conference creation automatically
}
}

File diff suppressed because one or more lines are too long