diff --git a/Classes/AudioHelper.m b/Classes/AudioHelper.m new file mode 100644 index 000000000..7298e65b3 --- /dev/null +++ b/Classes/AudioHelper.m @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "AudioHelper.h" + +@implementation AudioHelper + ++ (NSArray *)bluetoothRoutes { + return @[AVAudioSessionPortBluetoothHFP, AVAudioSessionPortCarAudio, AVAudioSessionPortBluetoothA2DP, AVAudioSessionPortBluetoothLE ]; +} + ++ (AVAudioSessionPortDescription *)bluetoothAudioDevice { + return [AudioHelper audioDeviceFromTypes:[AudioHelper bluetoothRoutes]]; +} + ++ (AVAudioSessionPortDescription *)builtinAudioDevice { + NSArray *builtinRoutes = @[ AVAudioSessionPortBuiltInMic ]; + return [AudioHelper audioDeviceFromTypes:builtinRoutes]; +} + ++ (AVAudioSessionPortDescription *)speakerAudioDevice { + NSArray *builtinRoutes = @[ AVAudioSessionPortBuiltInSpeaker ]; + return [AudioHelper audioDeviceFromTypes:builtinRoutes]; +} + ++ (AVAudioSessionPortDescription *)audioDeviceFromTypes:(NSArray *)types { + NSArray *routes = [[AVAudioSession sharedInstance] availableInputs]; + for (AVAudioSessionPortDescription *route in routes) { + if ([types containsObject:route.portType]) { + return route; + } + } + return nil; +} + +@end diff --git a/Classes/Base.lproj/CallIncomingView.xib b/Classes/Base.lproj/CallIncomingView.xib new file mode 100644 index 000000000..ae5bd9336 --- /dev/null +++ b/Classes/Base.lproj/CallIncomingView.xib @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/Base.lproj/CallOutgoingView.xib b/Classes/Base.lproj/CallOutgoingView.xib new file mode 100644 index 000000000..890553e00 --- /dev/null +++ b/Classes/Base.lproj/CallOutgoingView.xib @@ -0,0 +1,623 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/Base.lproj/CallView.xib b/Classes/Base.lproj/CallView.xib new file mode 100644 index 000000000..57a17a2c7 --- /dev/null +++ b/Classes/Base.lproj/CallView.xib @@ -0,0 +1,1857 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05T +S2V5ZWRBcmNoaXZlctEICVRyb290gAGvEBELDBkaHxQkKSoxNDdBSUpOUVUkbnVsbNYNDg8QERITFBUW +FxhWTlNTaXplXk5TUmVzaXppbmdNb2RlViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05TQ29sb3KA +AhAAgBASIMAAAIADgAtYezMzLCAzM33SGw8cHlpOUy5vYmplY3RzoR2ABIAK0hsPICOiISKABYAGgAnT +DyUmJygUXxAUTlNUSUZGUmVwcmVzZW50YXRpb25fEBlOU0ludGVybmFsTGF5b3V0RGlyZWN0aW9ugAiA +B08RGbpNTQAqAAARDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAABAwMDFQYGBiYGBgYiAgICDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAIGBgYhCQkJNgkJCTEJCQkzCQkJMwMDAxQAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAxUKCgo2BQUFIAEBAQgCAgIMCAgIKwkJCTEBAQEHAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAEAwMDFAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAYGBiMICAgwAAAABQAAAAAAAAAAAgIC +EQoKCjYCAgISAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAACAgIOCgoKNQcHBy4DAwMSAAAAAQAAAAAAAAAAAAAAAAYGBiEICAgxAQEB +BwAAAAAAAAAAAwMDFAoKCjYCAgIQAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMPCQkJMgkJCTUJCQk0BAQEGQAAAAAAAAAAAAAA +AAUFBRsKCgo3BQUFHwAAAAAAAAAEBwcHLAkJCTMCAgIMAAAAAAAAAAABAQEHCAgIKwkJCS0GBgYiAgIC +EQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQUFBRoJCQkyCQkJNAkJCTMKCgo1BAQE +FwAAAAAAAAAABAQEGQkJCTMICAgxAwMDFwAAAAAAAAADBQUFIgkJCTQHBwcuAgICDQAAAAAAAAAFBQUF +IQcHBykJCQkyCgoKNgcHBygBAQEKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBgYGHgoKCjYHBwcnBwcH +KAoKCjYHBwcnAAAAAgAAAAADAwMUCgoKNgcHBycBAQEJAAAAAAAAAAAAAAAAAAAAAQICAhIJCQkwCAgI +LwEBAQcAAAAAAAAAAAAAAAEAAAAGBQUFGwkJCTMICAgvAgICCgAAAAAAAAAAAAAAAAAAAAADAwMWCgoK +NgYGBiEAAAACAwMDEwgICC4CAgIKAAAAAAAAAAIHBwcsBwcHLAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAACAgIQCgoKNAUFBR0AAAAAAAAAAAAAAAAAAAAAAAAAAAMDAw8JCQkyCAgIKgAAAAIAAAAAAAAA +AAAAAAQHBwcuBwcHLAAAAAQAAAAAAAAAAAAAAAIAAAAAAAAAAAICAgkJCQk0BQUFHAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAABCQkJLQcHBygAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQaCgoK +NQUFBSEFBQUfAwMDEgMDAxIKCgo2BAQEFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQgJCQkzCAgI +LwUFBSIFBQUaAwMDFQMDAxQDAwMUBAQEFgUFBRwHBwclCQkJNQcHBycAAAAAAAAAAAAAAAAAAAAAAAAA +AQUFBR8ICAgwCQkJMwkJCTQKCgo3BQUFHwYGBiEJCQk0AQEBCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAEEBAQYBwcHKQgICDAJCQkzCQkJNQkJCTUJCQk1CQkJNAkJCTMICAgvBgYGJAICAg4AAAAAAAAA +AAAAAAAAAAAAAAAAAQUFBR8JCQk0CQkJNAkJCTQHBwcqAAAABAYGBiUICAgvAAAABgAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUCAgILAwMDDwICAhEDAwMPAwMDDgEBAQkAAAADAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMTCQkJLQkJCTIDAwMOAAAAAAEBAQcCAgIMAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAQEBBgICAgwAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBBwUFBSAHBwcsCAgIKwUFBRwAAAADAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAgoGBgYjBwcHLAcHByoEBAQYAAAAAQAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCAgIKgoKCjUICAgoCAgIKwkJCTYGBgYjAAAA +AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBCQgICC8JCQkzBwcHKAcHBywKCgo2BQUF +HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQXCgoKNgQEBBcAAAAAAAAA +AgUFBR8JCQk1AwMDDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFHwkJCTQCAgIRAAAA +AAAAAAMGBgYmCQkJMgEBAQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQUgCQkJ +MgAAAAQAAAAAAAAAAAICAgwJCQk1BAQEFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwcH +KQgICCsAAAABAAAAAAAAAAADAwMUCQkJNQICAhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAEBAQYCQkJNQICAhAAAAAAAAAAAAQEBBgJCQk1AgICEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAABQUFIQkJCTEBAQEKAAAAAAAAAAEFBQUgCQkJMwEBAQoAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAMGBgYeCgoKNwYGBiYAAAAAAAAAAggICC4JCQk1BAQEGAAAAAEAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAFBgYGJQoKCjgFBQUfAAAAAAEBAQgJCQkyCAgIMgICAhEAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwYGBiMJCQk2BwcHJwICAg0AAAAAAAAAAAMDAxIICAgrCQkJ +NgUFBR0AAAABAAAAAAAAAAAAAAAAAAAAAAAAAAYHBwcqCQkJNQYGBiMBAQEKAAAAAAAAAAEDAwMXCAgI +LgkJCTQEBAQWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFGgoKCjYFBQUdAAAAAQAAAAAAAAAAAAAA +AAAAAAAAAAAEBgYGJAoKCjUCAgIRAAAAAAAAAAAAAAAAAAAAAAYGBiEKCgo1BAQEFwAAAAAAAAAAAAAA +AAAAAAAAAAAAAQEBCAgICCoJCQkzAgICCwAAAAAAAAAAAAAAAAAAAAAAAAAECQkJLQcHBykAAAABAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQgICC8HBwcnAAAAAAAAAAAAAAAAAQEBCAkJCTIFBQUiAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQoJCQk0BQUFHgAAAAAAAAAAAAAAAAAAAAABAQEICQkJ +MQYGBiMAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAQEBBggICCoHBwctAAAAAgAAAAAAAAAAAgIC +DQoKCjUFBQUcAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgEBAQoICAgvBgYGJgAAAAAAAAAAAAAA +AAAAAAAAAAAEBwcHLAkJCTUICAgxCAgIKQYGBiQGBgYjBgYGIwYGBiQICAgqCQkJMgkJCTUHBwcmAAAA +AAAAAAAAAAAAAQEBCQgICDAJCQk1CAgILwcHBygGBgYjBgYGIwYGBiMGBgYlBwcHLAkJCTMJCQk2BgYG +HgAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBCQMDAxYFBQUiCAgIKggICDAICAgxCAgIMAgICC8HBwcpBQUF +IAMDAxQBAQEGAAAAAAAAAAAAAAAAAAAAAAICAgwEBAQYBgYGIwgICCsICAgwCAgIMAgICDAICAguBwcH +KAUFBR4DAwMSAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAADAAAA +AgAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAA +AwAAAAIAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAEBAQkDAwMPAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIFBQUfBwcHLQkJCTIJCQk1AwMDDwAAAAAAAAAAAAAA +AAAAAAAEBAQXBQUFHwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMICAguCQkJNAkJCTQHBwctAQEB +CAAAAAIAAAAFAgICDQYGBiQKCgo2BwcHJwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBgYlCQkJ +NQkJCTQJCQk0CQkJLQgICCoICAguCQkJNQkJCTMEBAQfAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAFBQUcCgoKNgUFBR8FBQUaBwcHJgcHBykHBwcmBQUFGwICAgoAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAABAQELBgYGIQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAQAAAwAAAAEA +IQAAAQEAAwAAAAEAIQAAAQIAAwAAAAQAABHSAQMAAwAAAAEAAQAAAQYAAwAAAAEAAgAAAQoAAwAAAAEA +AQAAAREABAAAAAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEABAAAARYAAwAAAAEAIQAAARcABAAAAAEA +ABEEARwAAwAAAAEAAQAAASgAAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAQAABHah3MABwAAB9gA +ABHiAAAAAAAIAAgACAAIAAEAAQABAAEAAAfYYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAth +Y3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkZXNjAAABCAAAAG9kc2NtAAABeAAABZxj +cHJ0AAAHFAAAADh3dHB0AAAHTAAAABRyWFlaAAAHYAAAABRnWFlaAAAHdAAAABRiWFlaAAAHiAAAABRy +VFJDAAAHnAAAAA5jaGFkAAAHrAAAACxiVFJDAAAHnAAAAA5nVFJDAAAHnAAAAA5kZXNjAAAAAAAAABRH +ZW5lcmljIFJHQiBQcm9maWxlAAAAAAAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAAAAAfAAAADHNrU0sA +AAAoAAABhGRhREsAAAAuAAABrGNhRVMAAAAkAAAB2nZpVk4AAAAkAAAB/nB0QlIAAAAmAAACInVrVUEA +AAAqAAACSGZyRlUAAAAoAAACcmh1SFUAAAAoAAACmnpoVFcAAAAWAAACwm5iTk8AAAAmAAAC2GNzQ1oA +AAAiAAAC/mhlSUwAAAAeAAADIGl0SVQAAAAoAAADPnJvUk8AAAAkAAADZmRlREUAAAAsAAADimtvS1IA +AAAWAAADtnN2U0UAAAAmAAAC2HpoQ04AAAAWAAADzGphSlAAAAAaAAAD4mVsR1IAAAAiAAAD/HB0UE8A +AAAmAAAEHm5sTkwAAAAoAAAERGVzRVMAAAAmAAAEHnRoVEgAAAAkAAAEbHRyVFIAAAAiAAAEkGZpRkkA +AAAoAAAEsmhySFIAAAAoAAAE2nBsUEwAAAAsAAAFAnJ1UlUAAAAiAAAFLmFyRUcAAAAmAAAFUGVuVVMA +AAAmAAAFdgBWAWEAZQBvAGIAZQBjAG4A/QAgAFIARwBCACAAcAByAG8AZgBpAGwARwBlAG4AZQByAGUA +bAAgAFIARwBCAC0AYgBlAHMAawByAGkAdgBlAGwAcwBlAFAAZQByAGYAaQBsACAAUgBHAEIAIABnAGUA +bgDoAHIAaQBjAEMepQB1ACAAaADsAG4AaAAgAFIARwBCACAAQwBoAHUAbgBnAFAAZQByAGYAaQBsACAA +UgBHAEIAIABHAGUAbgDpAHIAaQBjAG8EFwQwBDMEMAQ7BEwEPQQ4BDkAIAQ/BEAEPgREBDAEOQQ7ACAA +UgBHAEIAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCAMEAbAB0AGEAbADhAG4A +bwBzACAAUgBHAEIAIABwAHIAbwBmAGkAbJAadSgAIABSAEcAQgAggnJfaWPPj/AARwBlAG4AZQByAGkA +cwBrACAAUgBHAEIALQBwAHIAbwBmAGkAbABPAGIAZQBjAG4A/QAgAFIARwBCACAAcAByAG8AZgBpAGwF +5AXoBdUF5AXZBdwAIABSAEcAQgAgBdsF3AXcBdkAUAByAG8AZgBpAGwAbwAgAFIARwBCACAAZwBlAG4A +ZQByAGkAYwBvAFAAcgBvAGYAaQBsACAAUgBHAEIAIABnAGUAbgBlAHIAaQBjAEEAbABsAGcAZQBtAGUA +aQBuAGUAcwAgAFIARwBCAC0AUAByAG8AZgBpAGzHfLwYACAAUgBHAEIAINUEuFzTDMd8Zm6QGgAgAFIA +RwBCACBjz4/wZYdO9k4AgiwAIABSAEcAQgAgMNcw7TDVMKEwpDDrA5MDtQO9A7kDugPMACADwAPBA78D +xgOvA7sAIABSAEcAQgBQAGUAcgBmAGkAbAAgAFIARwBCACAAZwBlAG4A6QByAGkAYwBvAEEAbABnAGUA +bQBlAGUAbgAgAFIARwBCAC0AcAByAG8AZgBpAGUAbA5CDhsOIw5EDh8OJQ5MACAAUgBHAEIAIA4XDjEO +SA4nDkQOGwBHAGUAbgBlAGwAIABSAEcAQgAgAFAAcgBvAGYAaQBsAGkAWQBsAGUAaQBuAGUAbgAgAFIA +RwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAQ0AawBpACAAUgBHAEIAIABwAHIAbwBmAGkA +bABVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBmAGkAbAAgAFIARwBCBB4EMQRJBDgEOQAgBD8E +QAQ+BEQEOAQ7BEwAIABSAEcAQgZFBkQGQQAgBioGOQYxBkoGQQAgAFIARwBCACAGJwZEBjkGJwZFAEcA +ZQBuAGUAcgBpAGMAIABSAEcAQgAgAFAAcgBvAGYAaQBsAGV0ZXh0AAAAAENvcHlyaWdodCAyMDA3IEFw +cGxlIEluYy4sIGFsbCByaWdodHMgcmVzZXJ2ZWQuAFhZWiAAAAAAAADzUgABAAAAARbPWFlaIAAAAAAA +AHRNAAA97gAAA9BYWVogAAAAAAAAWnUAAKxzAAAXNFhZWiAAAAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAA +AAABAc0AAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBs0issLS5aJGNs +YXNzbmFtZVgkY2xhc3Nlc18QEE5TQml0bWFwSW1hZ2VSZXCjLS8wWk5TSW1hZ2VSZXBYTlNPYmplY3TS +KywyM1dOU0FycmF5ojIw0issNTZeTlNNdXRhYmxlQXJyYXmjNTIw1Tg5OjsPPD0+P0BXTlNXaGl0ZVxO +U0NvbXBvbmVudHNcTlNDb2xvclNwYWNlXxASTlNDdXN0b21Db2xvclNwYWNlRDAgMABDMCAwEAOADIAP +1EJDRA9FRkdIVE5TSURVTlNJQ0NXTlNNb2RlbBAJgA0QAIAOTxERnAAAEZxhcHBsAgAAAG1udHJHUkFZ +WFlaIAfcAAgAFwAPAC4AD2Fjc3BBUFBMAAAAAG5vbmUAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMt +YXBwbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWRlc2MAAADA +AAAAeWRzY20AAAE8AAAIGmNwcnQAAAlYAAAAI3d0cHQAAAl8AAAAFGtUUkMAAAmQAAAIDGRlc2MAAAAA +AAAAH0dlbmVyaWMgR3JheSBHYW1tYSAyLjIgUHJvZmlsZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVj +AAAAAAAAAB8AAAAMc2tTSwAAAC4AAAGEZGFESwAAADoAAAGyY2FFUwAAADgAAAHsdmlWTgAAAEAAAAIk +cHRCUgAAAEoAAAJkdWtVQQAAACwAAAKuZnJGVQAAAD4AAALaaHVIVQAAADQAAAMYemhUVwAAABoAAANM +a29LUgAAACIAAANmbmJOTwAAADoAAAOIY3NDWgAAACgAAAPCaGVJTAAAACQAAAPqcm9STwAAACoAAAQO +ZGVERQAAAE4AAAQ4aXRJVAAAAE4AAASGc3ZTRQAAADgAAATUemhDTgAAABoAAAUMamFKUAAAACYAAAUm +ZWxHUgAAACoAAAVMcHRQTwAAAFIAAAV2bmxOTAAAAEAAAAXIZXNFUwAAAEwAAAYIdGhUSAAAADIAAAZU +dHJUUgAAACQAAAaGZmlGSQAAAEYAAAaqaHJIUgAAAD4AAAbwcGxQTAAAAEoAAAcuYXJFRwAAACwAAAd4 +cnVSVQAAADoAAAekZW5VUwAAADwAAAfeAFYBYQBlAG8AYgBlAGMAbgDhACAAcwBpAHYA4QAgAGcAYQBt +AGEAIAAyACwAMgBHAGUAbgBlAHIAaQBzAGsAIABnAHIA5QAgADIALAAyACAAZwBhAG0AbQBhAC0AcABy +AG8AZgBpAGwARwBhAG0AbQBhACAAZABlACAAZwByAGkAcwBvAHMAIABnAGUAbgDoAHIAaQBjAGEAIAAy +AC4AMgBDHqUAdQAgAGgA7ABuAGgAIABNAOAAdQAgAHgA4QBtACAAQwBoAHUAbgBnACAARwBhAG0AbQBh +ACAAMgAuADIAUABlAHIAZgBpAGwAIABHAGUAbgDpAHIAaQBjAG8AIABkAGEAIABHAGEAbQBhACAAZABl +ACAAQwBpAG4AegBhAHMAIAAyACwAMgQXBDAEMwQwBDsETAQ9BDAAIABHAHIAYQB5AC0EMwQwBDwEMAAg +ADIALgAyAFAAcgBvAGYAaQBsACAAZwDpAG4A6QByAGkAcQB1AGUAIABnAHIAaQBzACAAZwBhAG0AbQBh +ACAAMgAsADIAwQBsAHQAYQBsAOEAbgBvAHMAIABzAHoA/AByAGsAZQAgAGcAYQBtAG0AYQAgADIALgAy +kBp1KHBwlo5RSV6mADIALgAygnJfaWPPj/DHfLwYACDWjMDJACCsELnIACAAMgAuADIAINUEuFzTDMd8 +AEcAZQBuAGUAcgBpAHMAawAgAGcAcgDlACAAZwBhAG0AbQBhACAAMgAsADIALQBwAHIAbwBmAGkAbABP +AGIAZQBjAG4A4QAgAWEAZQBkAOEAIABnAGEAbQBhACAAMgAuADIF0gXQBd4F1AAgBdAF5AXVBegAIAXb +BdwF3AXZACAAMgAuADIARwBhAG0AYQAgAGcAcgBpACAAZwBlAG4AZQByAGkAYwEDACAAMgAsADIAQQBs +AGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQAdQBmAGUAbgAtAFAAcgBvAGYAaQBsACAARwBh +AG0AbQBhACAAMgAsADIAUAByAG8AZgBpAGwAbwAgAGcAcgBpAGcAaQBvACAAZwBlAG4AZQByAGkAYwBv +ACAAZABlAGwAbABhACAAZwBhAG0AbQBhACAAMgAsADIARwBlAG4AZQByAGkAcwBrACAAZwByAOUAIAAy +ACwAMgAgAGcAYQBtAG0AYQBwAHIAbwBmAGkAbGZukBpwcF6mfPtlcAAyAC4AMmPPj/Blh072TgCCLDCw +MOwwpDCsMPMw3gAgADIALgAyACAw1zDtMNUwoTCkMOsDkwO1A70DuQO6A8wAIAOTA7oDwQO5ACADkwOs +A7wDvAOxACAAMgAuADIAUABlAHIAZgBpAGwAIABnAGUAbgDpAHIAaQBjAG8AIABkAGUAIABjAGkAbgB6 +AGUAbgB0AG8AcwAgAGQAYQAgAEcAYQBtAG0AYQAgADIALAAyAEEAbABnAGUAbQBlAGUAbgAgAGcAcgBp +AGoAcwAgAGcAYQBtAG0AYQAgADIALAAyAC0AcAByAG8AZgBpAGUAbABQAGUAcgBmAGkAbAAgAGcAZQBu +AOkAcgBpAGMAbwAgAGQAZQAgAGcAYQBtAG0AYQAgAGQAZQAgAGcAcgBpAHMAZQBzACAAMgAsADIOIw4x +DgcOKg41DkEOAQ4hDiEOMg5ADgEOIw4iDkwOFw4xDkgOJw5EDhsAIAAyAC4AMgBHAGUAbgBlAGwAIABH +AHIAaQAgAEcAYQBtAGEAIAAyACwAMgBZAGwAZQBpAG4AZQBuACAAaABhAHIAbQBhAGEAbgAgAGcAYQBt +AG0AYQAgADIALAAyACAALQBwAHIAbwBmAGkAaQBsAGkARwBlAG4AZQByAGkBDQBrAGkAIABHAHIAYQB5 +ACAARwBhAG0AbQBhACAAMgAuADIAIABwAHIAbwBmAGkAbABVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABw +AHIAbwBmAGkAbAAgAHMAegBhAHIAbwFbAGMAaQAgAGcAYQBtAG0AYQAgADIALAAyBjoGJwZFBicAIAAy +AC4AMgAgBkQGSAZGACAGMQZFBicGLwZKACAGOQYnBkUEHgQxBEkEMARPACAEQQQ1BEAEMARPACAEMwQw +BDwEPAQwACAAMgAsADIALQQ/BEAEPgREBDgEOwRMAEcAZQBuAGUAcgBpAGMAIABHAHIAYQB5ACAARwBh +AG0AbQBhACAAMgAuADIAIABQAHIAbwBmAGkAbABlAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBJbmMu +LCAyMDEyAABYWVogAAAAAAAA81EAAQAAAAEWzGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAt +ADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADB +AMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1 +AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJx +AnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6 +A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVY +BWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdP +B2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmk +CboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxc +DHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96 +D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMD +EyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6 +Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtj +G4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBB +IGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWX +Jccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitp +K50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6 +MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiM +OMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/i +QCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fA +SAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAn +UHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1ka +WWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKc +YvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yv +bQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdW +d7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKS +gvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45m +js6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrV +m0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfg +qFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WK +tgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPU +xFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB +00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT +4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM +8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//0issS0xcTlNDb2xv +clNwYWNlok0wXE5TQ29sb3JTcGFjZdIrLE9QV05TQ29sb3KiTzDSKyxSU1dOU0ltYWdlolIwAAgAEQAa +ACQAKQAyADcASQBMAFEAUwBnAG0AegCBAJAAlwCkAKsAswC1ALcAuQC+AMAAwgDLANAA2wDdAN8A4QDm +AOkA6wDtAO8A9gENASkBKwEtGusa8Br7GwQbFxsbGyYbLxs0GzwbPxtEG1MbVxtiG2obdxuEG5kbnhui +G6QbphuoG7Ebthu8G8QbxhvIG8obzC1sLXEtfi2BLY4tky2bLZ4toy2rAAAAAAAAAgEAAAAAAAAAVAAA +AAAAAAAAAAAAAAAALa4 + + + + + +YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05T +S2V5ZWRBcmNoaXZlctEICVRyb290gAGvEBELDBkaHxQkKSoxNDdBSUpOUVUkbnVsbNYNDg8QERITFBUW +FxhWTlNTaXplXk5TUmVzaXppbmdNb2RlViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05TQ29sb3KA +AhAAgBASIMAAAIADgAtYezQwLCAzNn3SGw8cHlpOUy5vYmplY3RzoR2ABIAK0hsPICOiISKABYAGgAnT +DyUmJygUXxAUTlNUSUZGUmVwcmVzZW50YXRpb25fEBlOU0ludGVybmFsTGF5b3V0RGlyZWN0aW9ugAiA +B08RHzZNTQAqAAAWiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAABhgAABkYAAAZBQAABgAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAOwABPJsABJ7IAAXMyAAFzJ0ABKA/AAFBAQAAAgAAAAAAAAAAAAAAAAAAAAACAgICAQEB +AQAAAAAKCgoKBAQEBAAAAAAAAAAACQkJCQkJCQkAAAAAAAAAAAAAAAAAAAAAAAAAAAkJCQkHBwcHAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASQACS9gABtz7AAf/+wAH +//sAB//7AAf/2wAG31AAAlIAAAAAAAAAAAAAAAAAAAAAW1tbW6KioqKZmZmZ29vb22BgYGIICAgIh4eH +icnJycnJycnKenp6fAcHBwcAAAAAEhISEpOTk5XS0tLTy8vLzHh4eHoHBwcHAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAF7wABcD7AAf/+wAH//sAB//7AAf/+wAH//sAB//AAAXEGgAA +GwAAAAAAAAAAAAAAAHBwcHD/////gYGBgygoKCoNDQ0NiIiIiq6urq8XFxcXFxcXGbm5ublycnJyAAAA +AJiYmJnBwcHBKCgoKC0tLS/T09PUV1dXVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AEQAAUbrAAbv+wAH//sAB//7AAf/+wAH//sAB//7AAf/7AAG8EoAAkwAAAAAAAAAAAAAAAB0dHR00NDQ +0AAAAAAAAAAABwcHB9TU1NWRkZGTY2NjY2NjY2Ojo6OjyMjIyBYWFhbd3d3dOzs7PQAAAAAAAAAAFxcX +GRUVFRUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSAAJU8gAG9vsAB//7AAf/+wAH +//sAB//7AAf/+wAH//QABvhcAAJeAAAAAAAAAAAAAAAAdnZ2dre3t7cAAAAAAAAAAA4ODg7g4ODhoaGh +oYyMjIyMjIyMhoaGhlJSUlQcHBwc4eHh4ioqKioAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAOAABOeQABuj7AAf/+wAH//sAB//7AAf/+wAH//sAB//mAAbqPgAB +PwAAAAAAAAAAAAAAAHZ2dna4uLi4AAAAAAAAAAAEBAQEwsLCw2JiYmIAAAAAAAAAADMzMzNeXl5eCQkJ +Cc3Nzc5paWlpAAAAAAAAAABxcXFzWVlZWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAsAAAyiAASl+wAH//sAB//7AAf/+wAH//sAB//7AAf/pgAEqQ8AABAAAAAAAAAAAAAAAAB4eHh4vLy8 +vAAAAAAAAAAAAAAAAEhISEjX19fYmZmZmouLi43a2trbYmJiZAAAAABRUVFT39/f35ubm5yenp6f3Nzc +3Tk5OTkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgABK7QABbf1AAb5+wAH +//sAB//2AAb6tgAFuSwAAS0AAAAAAAAAAAAAAAAAAAAAKioqKkFBQUMAAAAAAAAAAAAAAAAAAAAAJiYm +KG5ubnBxcXFzMjIyNAAAAAAAAAAAAAAAADAwMDB0dHR0bGxsbiMjIyMAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAaYwACZZYABJmVAASYZQACZxwAAB0AAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAFAAAGBAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAQAQAAAwAAAAEAKAAAAQEAAwAAAAEAJAAAAQIAAwAAAAQAABdOAQMAAwAAAAEA +AQAAAQYAAwAAAAEAAgAAAQoAAwAAAAEAAQAAAREABAAAAAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEA +BAAAARYAAwAAAAEAJAAAARcABAAAAAEAABaAARwAAwAAAAEAAQAAASgAAwAAAAEAAgAAAVIAAwAAAAEA +AQAAAVMAAwAAAAQAABdWh3MABwAAB9gAABdeAAAAAAAIAAgACAAIAAEAAQABAAEAAAfYYXBwbAIgAABt +bnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYA +AQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtk +ZXNjAAABCAAAAG9kc2NtAAABeAAABZxjcHJ0AAAHFAAAADh3dHB0AAAHTAAAABRyWFlaAAAHYAAAABRn +WFlaAAAHdAAAABRiWFlaAAAHiAAAABRyVFJDAAAHnAAAAA5jaGFkAAAHrAAAACxiVFJDAAAHnAAAAA5n +VFJDAAAHnAAAAA5kZXNjAAAAAAAAABRHZW5lcmljIFJHQiBQcm9maWxlAAAAAAAAAAAAAAAUR2VuZXJp +YyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAbWx1YwAAAAAAAAAfAAAADHNrU0sAAAAoAAABhGRhREsAAAAuAAABrGNhRVMAAAAkAAAB2nZpVk4A +AAAkAAAB/nB0QlIAAAAmAAACInVrVUEAAAAqAAACSGZyRlUAAAAoAAACcmh1SFUAAAAoAAACmnpoVFcA +AAAWAAACwm5iTk8AAAAmAAAC2GNzQ1oAAAAiAAAC/mhlSUwAAAAeAAADIGl0SVQAAAAoAAADPnJvUk8A +AAAkAAADZmRlREUAAAAsAAADimtvS1IAAAAWAAADtnN2U0UAAAAmAAAC2HpoQ04AAAAWAAADzGphSlAA +AAAaAAAD4mVsR1IAAAAiAAAD/HB0UE8AAAAmAAAEHm5sTkwAAAAoAAAERGVzRVMAAAAmAAAEHnRoVEgA +AAAkAAAEbHRyVFIAAAAiAAAEkGZpRkkAAAAoAAAEsmhySFIAAAAoAAAE2nBsUEwAAAAsAAAFAnJ1UlUA +AAAiAAAFLmFyRUcAAAAmAAAFUGVuVVMAAAAmAAAFdgBWAWEAZQBvAGIAZQBjAG4A/QAgAFIARwBCACAA +cAByAG8AZgBpAGwARwBlAG4AZQByAGUAbAAgAFIARwBCAC0AYgBlAHMAawByAGkAdgBlAGwAcwBlAFAA +ZQByAGYAaQBsACAAUgBHAEIAIABnAGUAbgDoAHIAaQBjAEMepQB1ACAAaADsAG4AaAAgAFIARwBCACAA +QwBoAHUAbgBnAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8EFwQwBDMEMAQ7BEwE +PQQ4BDkAIAQ/BEAEPgREBDAEOQQ7ACAAUgBHAEIAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIAaQBxAHUA +ZQAgAFIAVgBCAMEAbAB0AGEAbADhAG4AbwBzACAAUgBHAEIAIABwAHIAbwBmAGkAbJAadSgAIABSAEcA +QgAggnJfaWPPj/AARwBlAG4AZQByAGkAcwBrACAAUgBHAEIALQBwAHIAbwBmAGkAbABPAGIAZQBjAG4A +/QAgAFIARwBCACAAcAByAG8AZgBpAGwF5AXoBdUF5AXZBdwAIABSAEcAQgAgBdsF3AXcBdkAUAByAG8A +ZgBpAGwAbwAgAFIARwBCACAAZwBlAG4AZQByAGkAYwBvAFAAcgBvAGYAaQBsACAAUgBHAEIAIABnAGUA +bgBlAHIAaQBjAEEAbABsAGcAZQBtAGUAaQBuAGUAcwAgAFIARwBCAC0AUAByAG8AZgBpAGzHfLwYACAA +UgBHAEIAINUEuFzTDMd8Zm6QGgAgAFIARwBCACBjz4/wZYdO9k4AgiwAIABSAEcAQgAgMNcw7TDVMKEw +pDDrA5MDtQO9A7kDugPMACADwAPBA78DxgOvA7sAIABSAEcAQgBQAGUAcgBmAGkAbAAgAFIARwBCACAA +ZwBlAG4A6QByAGkAYwBvAEEAbABnAGUAbQBlAGUAbgAgAFIARwBCAC0AcAByAG8AZgBpAGUAbA5CDhsO +Iw5EDh8OJQ5MACAAUgBHAEIAIA4XDjEOSA4nDkQOGwBHAGUAbgBlAGwAIABSAEcAQgAgAFAAcgBvAGYA +aQBsAGkAWQBsAGUAaQBuAGUAbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAQ0A +awBpACAAUgBHAEIAIABwAHIAbwBmAGkAbABVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBmAGkA +bAAgAFIARwBCBB4EMQRJBDgEOQAgBD8EQAQ+BEQEOAQ7BEwAIABSAEcAQgZFBkQGQQAgBioGOQYxBkoG +QQAgAFIARwBCACAGJwZEBjkGJwZFAEcAZQBuAGUAcgBpAGMAIABSAEcAQgAgAFAAcgBvAGYAaQBsAGV0 +ZXh0AAAAAENvcHlyaWdodCAyMDA3IEFwcGxlIEluYy4sIGFsbCByaWdodHMgcmVzZXJ2ZWQuAFhZWiAA +AAAAAADzUgABAAAAARbPWFlaIAAAAAAAAHRNAAA97gAAA9BYWVogAAAAAAAAWnUAAKxzAAAXNFhZWiAA +AAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAAAAABAc0AAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH/ +//ui///9owAAA9wAAMBs0issLS5aJGNsYXNzbmFtZVgkY2xhc3Nlc18QEE5TQml0bWFwSW1hZ2VSZXCj +LS8wWk5TSW1hZ2VSZXBYTlNPYmplY3TSKywyM1dOU0FycmF5ojIw0issNTZeTlNNdXRhYmxlQXJyYXmj +NTIw1Tg5OjsPPD0+P0BXTlNXaGl0ZVxOU0NvbXBvbmVudHNcTlNDb2xvclNwYWNlXxASTlNDdXN0b21D +b2xvclNwYWNlRDAgMABDMCAwEAOADIAP1EJDRA9FRkdIVE5TSURVTlNJQ0NXTlNNb2RlbBAJgA0QAIAO +TxERnAAAEZxhcHBsAgAAAG1udHJHUkFZWFlaIAfcAAgAFwAPAC4AD2Fjc3BBUFBMAAAAAG5vbmUAAAAA +AAAAAAAAAAAAAAAAAAD21gABAAAAANMtYXBwbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAABWRlc2MAAADAAAAAeWRzY20AAAE8AAAIGmNwcnQAAAlYAAAAI3d0cHQAAAl8 +AAAAFGtUUkMAAAmQAAAIDGRlc2MAAAAAAAAAH0dlbmVyaWMgR3JheSBHYW1tYSAyLjIgUHJvZmlsZQAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAB8AAAAMc2tTSwAAAC4AAAGEZGFESwAAADoAAAGy +Y2FFUwAAADgAAAHsdmlWTgAAAEAAAAIkcHRCUgAAAEoAAAJkdWtVQQAAACwAAAKuZnJGVQAAAD4AAALa +aHVIVQAAADQAAAMYemhUVwAAABoAAANMa29LUgAAACIAAANmbmJOTwAAADoAAAOIY3NDWgAAACgAAAPC +aGVJTAAAACQAAAPqcm9STwAAACoAAAQOZGVERQAAAE4AAAQ4aXRJVAAAAE4AAASGc3ZTRQAAADgAAATU +emhDTgAAABoAAAUMamFKUAAAACYAAAUmZWxHUgAAACoAAAVMcHRQTwAAAFIAAAV2bmxOTAAAAEAAAAXI +ZXNFUwAAAEwAAAYIdGhUSAAAADIAAAZUdHJUUgAAACQAAAaGZmlGSQAAAEYAAAaqaHJIUgAAAD4AAAbw +cGxQTAAAAEoAAAcuYXJFRwAAACwAAAd4cnVSVQAAADoAAAekZW5VUwAAADwAAAfeAFYBYQBlAG8AYgBl +AGMAbgDhACAAcwBpAHYA4QAgAGcAYQBtAGEAIAAyACwAMgBHAGUAbgBlAHIAaQBzAGsAIABnAHIA5QAg +ADIALAAyACAAZwBhAG0AbQBhAC0AcAByAG8AZgBpAGwARwBhAG0AbQBhACAAZABlACAAZwByAGkAcwBv +AHMAIABnAGUAbgDoAHIAaQBjAGEAIAAyAC4AMgBDHqUAdQAgAGgA7ABuAGgAIABNAOAAdQAgAHgA4QBt +ACAAQwBoAHUAbgBnACAARwBhAG0AbQBhACAAMgAuADIAUABlAHIAZgBpAGwAIABHAGUAbgDpAHIAaQBj +AG8AIABkAGEAIABHAGEAbQBhACAAZABlACAAQwBpAG4AegBhAHMAIAAyACwAMgQXBDAEMwQwBDsETAQ9 +BDAAIABHAHIAYQB5AC0EMwQwBDwEMAAgADIALgAyAFAAcgBvAGYAaQBsACAAZwDpAG4A6QByAGkAcQB1 +AGUAIABnAHIAaQBzACAAZwBhAG0AbQBhACAAMgAsADIAwQBsAHQAYQBsAOEAbgBvAHMAIABzAHoA/ABy +AGsAZQAgAGcAYQBtAG0AYQAgADIALgAykBp1KHBwlo5RSV6mADIALgAygnJfaWPPj/DHfLwYACDWjMDJ +ACCsELnIACAAMgAuADIAINUEuFzTDMd8AEcAZQBuAGUAcgBpAHMAawAgAGcAcgDlACAAZwBhAG0AbQBh +ACAAMgAsADIALQBwAHIAbwBmAGkAbABPAGIAZQBjAG4A4QAgAWEAZQBkAOEAIABnAGEAbQBhACAAMgAu +ADIF0gXQBd4F1AAgBdAF5AXVBegAIAXbBdwF3AXZACAAMgAuADIARwBhAG0AYQAgAGcAcgBpACAAZwBl +AG4AZQByAGkAYwEDACAAMgAsADIAQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQAdQBm +AGUAbgAtAFAAcgBvAGYAaQBsACAARwBhAG0AbQBhACAAMgAsADIAUAByAG8AZgBpAGwAbwAgAGcAcgBp +AGcAaQBvACAAZwBlAG4AZQByAGkAYwBvACAAZABlAGwAbABhACAAZwBhAG0AbQBhACAAMgAsADIARwBl +AG4AZQByAGkAcwBrACAAZwByAOUAIAAyACwAMgAgAGcAYQBtAG0AYQBwAHIAbwBmAGkAbGZukBpwcF6m +fPtlcAAyAC4AMmPPj/Blh072TgCCLDCwMOwwpDCsMPMw3gAgADIALgAyACAw1zDtMNUwoTCkMOsDkwO1 +A70DuQO6A8wAIAOTA7oDwQO5ACADkwOsA7wDvAOxACAAMgAuADIAUABlAHIAZgBpAGwAIABnAGUAbgDp +AHIAaQBjAG8AIABkAGUAIABjAGkAbgB6AGUAbgB0AG8AcwAgAGQAYQAgAEcAYQBtAG0AYQAgADIALAAy +AEEAbABnAGUAbQBlAGUAbgAgAGcAcgBpAGoAcwAgAGcAYQBtAG0AYQAgADIALAAyAC0AcAByAG8AZgBp +AGUAbABQAGUAcgBmAGkAbAAgAGcAZQBuAOkAcgBpAGMAbwAgAGQAZQAgAGcAYQBtAG0AYQAgAGQAZQAg +AGcAcgBpAHMAZQBzACAAMgAsADIOIw4xDgcOKg41DkEOAQ4hDiEOMg5ADgEOIw4iDkwOFw4xDkgOJw5E +DhsAIAAyAC4AMgBHAGUAbgBlAGwAIABHAHIAaQAgAEcAYQBtAGEAIAAyACwAMgBZAGwAZQBpAG4AZQBu +ACAAaABhAHIAbQBhAGEAbgAgAGcAYQBtAG0AYQAgADIALAAyACAALQBwAHIAbwBmAGkAaQBsAGkARwBl +AG4AZQByAGkBDQBrAGkAIABHAHIAYQB5ACAARwBhAG0AbQBhACAAMgAuADIAIABwAHIAbwBmAGkAbABV +AG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBmAGkAbAAgAHMAegBhAHIAbwFbAGMAaQAgAGcAYQBt +AG0AYQAgADIALAAyBjoGJwZFBicAIAAyAC4AMgAgBkQGSAZGACAGMQZFBicGLwZKACAGOQYnBkUEHgQx +BEkEMARPACAEQQQ1BEAEMARPACAEMwQwBDwEPAQwACAAMgAsADIALQQ/BEAEPgREBDgEOwRMAEcAZQBu +AGUAcgBpAGMAIABHAHIAYQB5ACAARwBhAG0AbQBhACAAMgAuADIAIABQAHIAbwBmAGkAbABlAAB0ZXh0 +AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDEyAABYWVogAAAAAAAA81EAAQAAAAEWzGN1cnYAAAAA +AAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCG +AIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwEl +ASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gID +AgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMt +AzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSo +BLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7 +BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiq +CL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5 +C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4u +DkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGM +EaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVW +FXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmR +GbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5A +HmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNm +I5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkG +KTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8k +L1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXC +Nf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzj +PSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SK +RM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6 +TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1 +VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69 +Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iW +aOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMB +c11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4B +fmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZ +if6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJ +ljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKW +owajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AA +sHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74K +voS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1 +zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF +3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv7 +7IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY +/Sn9uv5L/tz/bf//0issS0xcTlNDb2xvclNwYWNlok0wXE5TQ29sb3JTcGFjZdIrLE9QV05TQ29sb3Ki +TzDSKyxSU1dOU0ltYWdlolIwAAgAEQAaACQAKQAyADcASQBMAFEAUwBnAG0AegCBAJAAlwCkAKsAswC1 +ALcAuQC+AMAAwgDLANAA2wDdAN8A4QDmAOkA6wDtAO8A9gENASkBKwEtIGcgbCB3IIAgkyCXIKIgqyCw +ILgguyDAIM8g0yDeIOYg8yEAIRUhGiEeISAhIiEkIS0hMiE4IUAhQiFEIUYhSDLoMu0y+jL9MwozDzMX +MxozHzMnAAAAAAAAAgEAAAAAAAAAVAAAAAAAAAAAAAAAAAAAMyo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/Base.lproj/CallView~ipad.xib b/Classes/Base.lproj/CallView~ipad.xib new file mode 100644 index 000000000..684d42dc6 --- /dev/null +++ b/Classes/Base.lproj/CallView~ipad.xib @@ -0,0 +1,1397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/SwiftUtil/Extensions/IOS/OptionalExtensions.swift b/Classes/CallConferenceTableView.h similarity index 79% rename from Classes/SwiftUtil/Extensions/IOS/OptionalExtensions.swift rename to Classes/CallConferenceTableView.h index 58f10f627..41698c257 100644 --- a/Classes/SwiftUtil/Extensions/IOS/OptionalExtensions.swift +++ b/Classes/CallConferenceTableView.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2010-2020 Belledonne Communications SARL. * - * This file is part of linphone-iphone + * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,16 +17,10 @@ * along with this program. If not, see . */ +#import -extension Optional { - var logable: Any { - switch self { - case .none: - return "|⭕️" - case let .some(value): - return value - } - } - - -} +@interface CallConferenceTableView : UITableViewController + +- (void)update; + +@end diff --git a/Classes/CallConferenceTableView.m b/Classes/CallConferenceTableView.m new file mode 100644 index 000000000..1abf56af9 --- /dev/null +++ b/Classes/CallConferenceTableView.m @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "CallConferenceTableView.h" +#import "UICallConferenceCell.h" +#import "LinphoneManager.h" +#import "Utils.h" +#import "linphoneapp-Swift.h" + +@implementation CallConferenceTableView + +#pragma mark - UI change + +- (void)update { + [self.tableView reloadData]; +} + +#pragma mark - UITableViewDataSource Functions + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + NSString *kCellId = NSStringFromClass(UICallConferenceCell.class); + UICallConferenceCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId]; + if (cell == nil) { + cell = [[UICallConferenceCell alloc] initWithIdentifier:kCellId]; + } + LinphoneConference *c = [CallManager.instance getConference]; + if (c != nil) { + [cell setParticipant:bctbx_list_nth_data(linphone_conference_get_participant_list(c),(int)indexPath.row)]; + } + cell.contentView.userInteractionEnabled = NO; + return cell; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [CallManager.instance getConference] ? linphone_conference_get_participant_count([CallManager.instance getConference]) : 0; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { + return 1e-5; +} +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + return 1e-5; +} + +@end diff --git a/Classes/CallIncomingView.h b/Classes/CallIncomingView.h new file mode 100644 index 000000000..8031a7b2e --- /dev/null +++ b/Classes/CallIncomingView.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import + +#import "UICompositeView.h" +#import "TPMultiLayoutViewController.h" +#import "UIRoundedImageView.h" +#include "LinphoneManager.h" + +@protocol IncomingCallViewDelegate + +- (void)incomingCallAccepted:(LinphoneCall *)call evenWithVideo:(BOOL)video; +- (void)incomingCallDeclined:(LinphoneCall *)call; +- (void)incomingCallAborted:(LinphoneCall *)call; + +@end + +@interface CallIncomingView : TPMultiLayoutViewController { +} + +@property(nonatomic) Boolean earlyMedia; + +@property(weak, nonatomic) IBOutlet UILabel *nameLabel; +@property(nonatomic, strong) IBOutlet UILabel *addressLabel; +@property(nonatomic, strong) IBOutlet UIRoundedImageView *avatarImage; +@property(nonatomic, assign) LinphoneCall *call; +@property(nonatomic, strong) id delegate; +@property(weak, nonatomic) IBOutlet UIView *tabVideoBar; +@property(weak, nonatomic) IBOutlet UIView *tabBar; +@property (weak, nonatomic) IBOutlet UIView *earlyMediaView; + + +- (IBAction)onAcceptClick:(id)event; +- (IBAction)onDeclineClick:(id)event; +- (IBAction)onAcceptAudioOnlyClick:(id)sender; + +@end diff --git a/Classes/CallIncomingView.m b/Classes/CallIncomingView.m new file mode 100644 index 000000000..ccf22052b --- /dev/null +++ b/Classes/CallIncomingView.m @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "CallIncomingView.h" +#import "LinphoneManager.h" +#import "FastAddressBook.h" +#import "PhoneMainView.h" +#import "Utils.h" + +@implementation CallIncomingView + +#pragma mark - ViewController Functions + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(callUpdateEvent:) + name:kLinphoneCallUpdate + object:nil]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [NSNotificationCenter.defaultCenter removeObserver:self name:kLinphoneCallUpdate object:nil]; + _call = NULL; +} + +#pragma mark - UICompositeViewDelegate Functions + +static UICompositeViewDescription *compositeDescription = nil; + ++ (UICompositeViewDescription *)compositeViewDescription { + if (compositeDescription == nil) { + compositeDescription = [[UICompositeViewDescription alloc] init:self.class + statusBar:StatusBarView.class + tabBar:nil + sideMenu:CallSideMenuView.class + fullscreen:false + isLeftFragment:YES + fragmentWith:nil]; + compositeDescription.darkBackground = true; + } + return compositeDescription; +} + +- (UICompositeViewDescription *)compositeViewDescription { + return self.class.compositeViewDescription; +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; + if (_earlyMedia && [LinphoneManager.instance lpConfigBoolForKey:@"pref_accept_early_media"] && linphone_core_get_calls_nb(LC) < 2) { + _earlyMediaView.hidden = NO; + linphone_core_set_native_video_window_id(LC, (__bridge void *)(_earlyMediaView)); + } + if (_call) { + [self update]; + } +} + +#pragma mark - Event Functions + +- (void)callUpdateEvent:(NSNotification *)notif { + LinphoneCall *acall = [[notif.userInfo objectForKey:@"call"] pointerValue]; + LinphoneCallState astate = [[notif.userInfo objectForKey:@"state"] intValue]; + [self callUpdate:acall state:astate]; +} + +- (void)callUpdate:(LinphoneCall *)acall state:(LinphoneCallState)astate { + if (_call == acall && (astate == LinphoneCallEnd || astate == LinphoneCallError)) { + [_delegate incomingCallAborted:_call]; + } else if ([LinphoneManager.instance lpConfigBoolForKey:@"auto_answer"]) { + LinphoneCallState state = linphone_call_get_state(_call); + if (state == LinphoneCallIncomingReceived) { + LOGI(@"Auto answering call"); + [self onAcceptClick:nil]; + } + } +} + +#pragma mark - + +- (void)update { + const LinphoneAddress *addr = linphone_call_get_remote_address(_call); + [ContactDisplay setDisplayNameLabel:_nameLabel forAddress:addr withAddressLabel:_addressLabel]; + char *uri = linphone_address_as_string_uri_only(addr); + ms_free(uri); + [_avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:YES withRoundedRadius:YES]; + + _tabBar.hidden = linphone_call_params_video_enabled(linphone_call_get_remote_params(_call)); + _tabVideoBar.hidden = !_tabBar.hidden; +} + +#pragma mark - Property Functions +static void hideSpinner(LinphoneCall *call, void *user_data) { + CallIncomingView *thiz = (__bridge CallIncomingView *)user_data; + thiz.earlyMedia = TRUE; + thiz.earlyMediaView.hidden = NO; + linphone_core_set_native_video_window_id(LC, (__bridge void *)(thiz.earlyMediaView)); +} + +- (void)setCall:(LinphoneCall *)call { + _call = call; + _earlyMedia = FALSE; + if ([LinphoneManager.instance lpConfigBoolForKey:@"pref_accept_early_media"] && linphone_core_get_calls_nb(LC) < 2) { + linphone_call_accept_early_media(_call); + // linphone_call_params_get_used_video_codec return 0 if no video stream enabled + if (linphone_call_params_get_used_video_codec(linphone_call_get_current_params(_call))) { + linphone_call_set_next_video_frame_decoded_callback(call, hideSpinner, (__bridge void *)(self)); + } + } else { + _earlyMediaView.hidden = YES; + } + + [self update]; + [self callUpdate:_call state:linphone_call_get_state(call)]; +} + +#pragma mark - Action Functions + +- (IBAction)onAcceptClick:(id)event { + [_delegate incomingCallAccepted:_call evenWithVideo:YES]; +} + +- (IBAction)onDeclineClick:(id)event { + [_delegate incomingCallDeclined:_call]; +} + +- (IBAction)onAcceptAudioOnlyClick:(id)sender { + [_delegate incomingCallAccepted:_call evenWithVideo:NO]; +} + +@end diff --git a/Classes/CallManager.swift b/Classes/CallManager.swift index cc2e380e2..6ea0686fb 100644 --- a/Classes/CallManager.swift +++ b/Classes/CallManager.swift @@ -37,13 +37,15 @@ import AVFoundation static var theCallManager: CallManager? let providerDelegate: ProviderDelegate! // to support callkit let callController: CXCallController! // to support callkit - var core: Core? + var lc: Core? + @objc var speakerBeforePause : Bool = false @objc var nextCallIsTransfer: Bool = false var referedFromCall: String? var referedToCall: String? var endCallkit: Bool = false var globalState : GlobalState = .Off var actionsToPerformOnceWhenCoreIsOn : [(()->Void)] = [] + var conference: Conference? @@ -64,8 +66,8 @@ import AVFoundation @objc func setCore(core: OpaquePointer) { - self.core = Core.getSwiftObject(cObject: core) - self.core?.addDelegate(delegate: self) + lc = Core.getSwiftObject(cObject: core) + lc?.addDelegate(delegate: self) } @objc static func getAppData(call: OpaquePointer) -> CallAppData? { @@ -105,7 +107,7 @@ import AVFoundation if (callId == nil) { return nil } - let calls = core?.calls + let calls = lc?.calls if let callTmp = calls?.first(where: { $0.callLog?.callId == callId }) { return callTmp } @@ -113,8 +115,8 @@ import AVFoundation } @objc func stopLinphoneCore() { - if (core?.callsNb == 0) { - core?.stopAsync() + if (lc?.callsNb == 0) { + lc?.stopAsync() } } @@ -138,6 +140,60 @@ import AVFoundation return false } + @objc func changeRouteToSpeaker() { + for device in lc!.audioDevices { + if (device.type == AudioDeviceType.Speaker) { + lc!.outputAudioDevice = device + break + } + } + UIDevice.current.isProximityMonitoringEnabled = false + } + + @objc func changeRouteToBluetooth() { + for device in lc!.audioDevices { + if (device.type == AudioDeviceType.Bluetooth || device.type == AudioDeviceType.BluetoothA2DP) { + lc!.outputAudioDevice = device + break + } + } + UIDevice.current.isProximityMonitoringEnabled = (lc!.callsNb > 0) + } + + @objc func changeRouteToDefault() { + lc!.outputAudioDevice = lc!.defaultOutputAudioDevice + } + + @objc func isBluetoothAvailable() -> Bool { + for device in lc!.audioDevices { + if (device.type == AudioDeviceType.Bluetooth || device.type == AudioDeviceType.BluetoothA2DP) { + return true; + } + } + return false; + } + + @objc func isSpeakerEnabled() -> Bool { + if let outputDevice = lc!.outputAudioDevice { + return outputDevice.type == AudioDeviceType.Speaker + } + return false + } + + @objc func isBluetoothEnabled() -> Bool { + if let outputDevice = lc!.outputAudioDevice { + return (outputDevice.type == AudioDeviceType.Bluetooth || outputDevice.type == AudioDeviceType.BluetoothA2DP) + } + return false + } + + @objc func isReceiverEnabled() -> Bool { + if let outputDevice = lc!.outputAudioDevice { + return outputDevice.type == AudioDeviceType.Microphone + } + return false + } + func requestTransaction(_ transaction: CXTransaction, action: String) { callController.request(transaction) { error in @@ -183,7 +239,7 @@ import AVFoundation func acceptCall(call: Call, hasVideo:Bool) { do { - let callParams = try core!.createCallParams(call: call) + let callParams = try lc!.createCallParams(call: call) callParams.videoEnabled = hasVideo if (ConfigManager.instance().lpConfigBoolForKey(key: "edge_opt_preference")) { let low_bandwidth = (AppManager.network() == .network_2g) @@ -214,7 +270,7 @@ import AVFoundation } let sAddr = Address.getSwiftObject(cObject: addr!) - if (CallManager.callKitEnabled() && !CallManager.instance().nextCallIsTransfer && core?.conference?.isIn != true) { + if (CallManager.callKitEnabled() && !CallManager.instance().nextCallIsTransfer && !isInConference()) { let uuid = UUID() let name = FastAddressBook.displayName(for: addr) ?? "unknow" let handle = CXHandle(type: .generic, value: sAddr.asStringUriOnly()) @@ -235,7 +291,7 @@ import AVFoundation func doCall(addr: Address, isSas: Bool) throws { let displayName = FastAddressBook.displayName(for: addr.getCobject) - let lcallParams = try CallManager.instance().core!.createCallParams(call: nil) + let lcallParams = try CallManager.instance().lc!.createCallParams(call: nil) if ConfigManager.instance().lpConfigBoolForKey(key: "edge_opt_preference") && AppManager.network() == .network_2g { Log.directLog(BCTBX_LOG_MESSAGE, text: "Enabling low bandwidth mode") lcallParams.lowBandwidthEnabled = true @@ -250,7 +306,7 @@ import AVFoundation } if (CallManager.instance().nextCallIsTransfer) { - let call = CallManager.instance().core!.currentCall + let call = CallManager.instance().lc!.currentCall try call?.transferTo(referTo: addr) CallManager.instance().nextCallIsTransfer = false } else { @@ -261,7 +317,7 @@ import AVFoundation if (isSas) { lcallParams.mediaEncryption = .ZRTP } - let call = CallManager.instance().core!.inviteAddressWithParams(addr: addr, params: lcallParams) + let call = CallManager.instance().lc!.inviteAddressWithParams(addr: addr, params: lcallParams) if (call != nil) { // The LinphoneCallAppData object should be set on call creation with callback // - (void)onCall:StateChanged:withMessage:. If not, we are in big trouble and expect it to crash @@ -278,6 +334,32 @@ import AVFoundation } } + @objc func groupCall() { + if (CallManager.callKitEnabled()) { + let calls = lc?.calls + if (calls == nil || calls!.isEmpty) { + return + } + let firstCall = calls!.first?.callLog?.callId ?? "" + let lastCall = (calls!.count > 1) ? calls!.last?.callLog?.callId ?? "" : "" + + let currentUuid = CallManager.instance().providerDelegate.uuids["\(firstCall)"] + if (currentUuid == nil) { + Log.directLog(BCTBX_LOG_ERROR, text: "Can not find correspondant call to group.") + return + } + + let newUuid = CallManager.instance().providerDelegate.uuids["\(lastCall)"] + let groupAction = CXSetGroupCallAction(call: currentUuid!, callUUIDToGroupWith: newUuid) + let transcation = CXTransaction(action: groupAction) + requestTransaction(transcation, action: "groupCall") + + setResumeCalls() + } else { + try? lc?.addAllToConference() + } + } + @objc func removeAllCallInfos() { providerDelegate.callInfos.removeAll() providerDelegate.uuids.removeAll() @@ -337,7 +419,7 @@ import AVFoundation } @objc func setHeldOtherCalls(exceptCallid: String) { - for call in CallManager.instance().core!.calls { + for call in CallManager.instance().lc!.calls { if (call.callLog?.callId != exceptCallid && call.state != .Paused && call.state != .Pausing && call.state != .PausedByRemote) { setHeld(call: call, hold: true) } @@ -345,7 +427,7 @@ import AVFoundation } func setResumeCalls() { - for call in CallManager.instance().core!.calls { + for call in CallManager.instance().lc!.calls { if (call.state == .Paused || call.state == .Pausing || call.state == .PausedByRemote) { setHeld(call: call, hold: false) } @@ -362,7 +444,7 @@ import AVFoundation @objc func acceptVideo(call: OpaquePointer, confirm: Bool) { let sCall = Call.getSwiftObject(cObject: call) - let params = try? core?.createCallParams(call: sCall) + let params = try? lc?.createCallParams(call: sCall) params?.videoEnabled = confirm try? sCall.acceptUpdate(params: params) } @@ -383,7 +465,7 @@ import AVFoundation for call in CallManager.instance().providerDelegate.uuids { let callId = CallManager.instance().providerDelegate.callInfos[call.value]?.callId if (callId != nil) { - let call = CallManager.instance().core?.getCallByCallid(callId: callId!) + let call = CallManager.instance().lc?.getCallByCallid(callId: callId!) if (call != nil && call?.state != .PushIncomingReceived) { // sometimes (for example) due to network, registration failed, in this case, keep the call continue @@ -397,6 +479,12 @@ import AVFoundation CallManager.instance().endCallkit = false } } + + func onConferenceStateChanged(core: Core, conference: Conference, state: Conference.State) { + if (state == .Terminated) { + CallManager.instance().conference = nil + } + } func onCallStateChanged(core: Core, call: Call, state cstate: Call.State, message: String) { let callLog = call.callLog @@ -448,6 +536,11 @@ import AVFoundation } } } + + if (CallManager.instance().speakerBeforePause) { + CallManager.instance().speakerBeforePause = false + CallManager.instance().changeRouteToSpeaker() + } break case .OutgoingInit, .OutgoingProgress, @@ -476,6 +569,14 @@ import AVFoundation displayName = contactName } + UIDevice.current.isProximityMonitoringEnabled = false + if (CallManager.instance().lc!.callsNb == 0) { + CallManager.instance().changeRouteToDefault() + // disable this because I don't find anygood reason for it: _bluetoothAvailable = FALSE; + // furthermore it introduces a bug when calling multiple times since route may not be + // reconfigured between cause leading to bluetooth being disabled while it should not + //CallManager.instance().bluetoothEnabled = false + } if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) { // Configure the notification's payload. @@ -534,6 +635,12 @@ import AVFoundation break } + if (cstate == .IncomingReceived || cstate == .OutgoingInit || cstate == .Connected || cstate == .StreamsRunning) { + let check = call.currentParams?.videoEnabled + if ((call.currentParams?.videoEnabled ?? false) && CallManager.instance().isReceiverEnabled()) { + CallManager.instance().changeRouteToSpeaker() + } + } } // post Notification kLinphoneCallUpdate NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self, userInfo: [ @@ -546,13 +653,13 @@ import AVFoundation // Audio messages @objc func activateAudioSession() { - core?.activateAudioSession(actived: true) + lc?.activateAudioSession(actived: true) } @objc func getSpeakerSoundCard() -> String? { var speakerCard: String? = nil var earpieceCard: String? = nil - core?.audioDevices.forEach { device in + lc?.audioDevices.forEach { device in if (device.hasCapability(capability: .CapabilityPlay)) { if (device.type == .Speaker) { speakerCard = device.id @@ -564,46 +671,116 @@ import AVFoundation return speakerCard != nil ? speakerCard : earpieceCard } - // Local Conference + + + // Conference + + @objc func hostConference() -> Bool { + return conference != nil + } - @objc func startLocalConference() { - if (CallManager.callKitEnabled()) { - let calls = core?.calls - if (calls == nil || calls!.isEmpty) { + func addAllToConference() { + if (conference == nil) { + guard let cp = try?lc?.createConferenceParams() else { + Log.directLog(BCTBX_LOG_ERROR, text: "Unable to create conference parameters") return } - let firstCall = calls!.first?.callLog?.callId ?? "" - let lastCall = (calls!.count > 1) ? calls!.last?.callLog?.callId ?? "" : "" - - let currentUuid = CallManager.instance().providerDelegate.uuids["\(firstCall)"] - if (currentUuid == nil) { - Log.directLog(BCTBX_LOG_ERROR, text: "Can not find correspondant call to group.") - return + if let currentCall = lc?.currentCall, let currentParams = currentCall.currentParams { + cp.videoEnabled = currentParams.videoEnabled + } + conference = try?lc?.createConferenceWithParams(params: cp) + } + lc?.calls.forEach { call in + if (call.conference == nil || call.conference?.participantCount == 1) { + try?conference?.addParticipant(call: call) } - - let newUuid = CallManager.instance().providerDelegate.uuids["\(lastCall)"] - let groupAction = CXSetGroupCallAction(call: currentUuid!, callUUIDToGroupWith: newUuid) - let transcation = CXTransaction(action: groupAction) - requestTransaction(transcation, action: "groupCall") - - setResumeCalls() - } else { - addAllToLocalConference() } } - func addAllToLocalConference() { - do { - if let core = core, let params = try? core.createConferenceParams() { - params.videoEnabled = false // We disable video for local conferencing (cf Android) - let conference = core.conference != nil ? core.conference : try core.createConferenceWithParams(params: params) - try conference?.addParticipants(calls: core.calls) - } - } catch { - Log.directLog(BCTBX_LOG_ERROR, text: "accept call failed \(error)") + @objc func getConference() -> OpaquePointer? { + guard let core = lc else { + return nil } + return (core.conference != nil) ? core.conference?.getCobject : (core.currentCall?.conference != nil) ? core.currentCall!.conference!.getCobject : nil } + func getConference() -> Conference? { + guard let core = lc else { + return nil + } + return (core.conference != nil) ? core.conference : (core.currentCall?.conference != nil) ? core.currentCall!.conference : nil + } + + @objc func isInConference() -> Bool { + return isInConferenceAsHost()||isInConferenceAsGuest() + } + + @objc func isInConferenceAsGuest() -> Bool { + guard let core = lc else { + return false + } + return !isInConferenceAsHost() && core.currentCall != nil && core.currentCall?.conference != nil && (core.currentCall?.conference!.participantCount)! > 1 + } + + @objc func isInConferenceAsHost() -> Bool { + guard let core = lc else { + return false + } + return core.conference?.isIn == true + } + + @objc func hasConferenceAsGuest() -> Bool { + guard let core = lc else { + return false + } + if (core.callsNb<=1) { + return false + } + var found = false + core.calls.forEach { + let c = $0.conference + if (c != nil && c!.participantCount > 1 && hostConference()) { + found = true + return + } + } + return found + } + + @objc func getCallFor(participant : OpaquePointer) -> OpaquePointer? { + let p = Participant.getSwiftObject(cObject: participant) + guard let core = lc else { + return nil + } + var call:Call? = nil + core.calls.forEach { (callIt) in + let c = callIt.conference + c?.participantList.forEach { (p2) in + if (p2.address?.asStringUriOnly() == p.address?.asStringUriOnly()) { + call = callIt + return + } + } + } + return call?.getCobject + } + + @objc func inVideoConf() -> Bool { + guard let core = lc else { + return false + } + let result = isInConference() && (getConference()?.currentParams?.isVideoEnabled == true || core.currentCall?.currentParams?.videoEnabled == true) + NSLog("cdes \(result) \(core.currentCall?.currentParams?.videoEnabled)") + return result + } + + + @objc func inAudioConf() -> Bool { + guard let core = lc else { + return false + } + return core.conference?.isIn == true && core.conference != nil && core.currentCall?.conference?.currentParams?.isVideoEnabled == false + } } diff --git a/Classes/CallOutgoingView.h b/Classes/CallOutgoingView.h new file mode 100644 index 000000000..1d4430efe --- /dev/null +++ b/Classes/CallOutgoingView.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import + +#import "UICompositeView.h" +#import "TPMultiLayoutViewController.h" +#include "linphone/linphonecore.h" +#import "UIRoundedImageView.h" +#import "UIDigitButton.h" + + +@interface CallOutgoingView : TPMultiLayoutViewController { +} +@property(weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage; +@property(weak, nonatomic) IBOutlet UILabel *nameLabel; +@property(weak, nonatomic) IBOutlet UISpeakerButton *speakerButton; +@property(weak, nonatomic) IBOutlet UILabel *addressLabel; +@property(weak, nonatomic) IBOutlet UIToggleButton *routesButton; +@property(weak, nonatomic) IBOutlet UIView *routesView; +@property(weak, nonatomic) IBOutlet UIBluetoothButton *routesBluetoothButton; +@property(weak, nonatomic) IBOutlet UIButton *routesEarpieceButton; +@property(weak, nonatomic) IBOutlet UISpeakerButton *routesSpeakerButton; +@property(weak, nonatomic) IBOutlet UIMutedMicroButton *microButton; +@property (weak, nonatomic) IBOutlet UIButton *declineButton; + +@property (weak, nonatomic) IBOutlet UIToggleButton *numpadButton; +@property (strong, nonatomic) IBOutlet UIView *numpadView; +@property(nonatomic, strong) IBOutlet UIDigitButton *oneButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *twoButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *threeButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *fourButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *fiveButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *sixButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *sevenButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *eightButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *nineButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *starButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *zeroButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *hashButton; +@property (weak, nonatomic) IBOutlet UIButton *declineButton_earlyMedia; + +- (IBAction)onDeclineClick:(id)sender; + +@end diff --git a/Classes/CallOutgoingView.m b/Classes/CallOutgoingView.m new file mode 100644 index 000000000..c5057377d --- /dev/null +++ b/Classes/CallOutgoingView.m @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "CallOutgoingView.h" +#import "PhoneMainView.h" + +@implementation CallOutgoingView + +#pragma mark - UICompositeViewDelegate Functions + +static UICompositeViewDescription *compositeDescription = nil; + ++ (UICompositeViewDescription *)compositeViewDescription { + if (compositeDescription == nil) { + compositeDescription = [[UICompositeViewDescription alloc] init:self.class + statusBar:StatusBarView.class + tabBar:nil + sideMenu:CallSideMenuView.class + fullscreen:false + isLeftFragment:NO + fragmentWith:nil]; + + compositeDescription.darkBackground = true; + } + return compositeDescription; +} + +- (UICompositeViewDescription *)compositeViewDescription { + return self.class.compositeViewDescription; +} + +- (void)viewDidLoad { + _routesEarpieceButton.enabled = !IPAD; + + [_zeroButton setDigit:'0']; + [_zeroButton setDtmf:true]; + [_oneButton setDigit:'1']; + [_oneButton setDtmf:true]; + [_twoButton setDigit:'2']; + [_twoButton setDtmf:true]; + [_threeButton setDigit:'3']; + [_threeButton setDtmf:true]; + [_fourButton setDigit:'4']; + [_fourButton setDtmf:true]; + [_fiveButton setDigit:'5']; + [_fiveButton setDtmf:true]; + [_sixButton setDigit:'6']; + [_sixButton setDtmf:true]; + [_sevenButton setDigit:'7']; + [_sevenButton setDtmf:true]; + [_eightButton setDigit:'8']; + [_eightButton setDtmf:true]; + [_nineButton setDigit:'9']; + [_nineButton setDtmf:true]; + [_starButton setDigit:'*']; + [_starButton setDtmf:true]; + [_hashButton setDigit:'#']; + [_hashButton setDtmf:true]; + +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(bluetoothAvailabilityUpdateEvent:) + name:kLinphoneBluetoothAvailabilityUpdate + object:nil]; + + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(callUpdateEvent:) + name:kLinphoneCallUpdate + object:nil]; + + LinphoneCall *call = linphone_core_get_current_call(LC); + if (!call) { + return; + } + + const LinphoneAddress *addr = linphone_call_get_remote_address(call); + [ContactDisplay setDisplayNameLabel:_nameLabel forAddress:addr withAddressLabel:_addressLabel]; + char *uri = linphone_address_as_string_uri_only(addr); + ms_free(uri); + [_avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:NO withRoundedRadius:YES]; + + [self hideSpeaker:LinphoneManager.instance.bluetoothAvailable]; + + [_speakerButton update]; + [_microButton update]; + [_routesButton update]; + [self hidePad:TRUE animated:FALSE]; + [self callUpdate:call state:linphone_call_get_state(call) animated:true]; + +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + // if there is no call (for whatever reason), we must wait viewDidAppear method + // before popping current view, because UICompositeView cannot handle view change + // directly in viewWillAppear (this would lead to crash in deallocated memory - easily + // reproductible on iPad mini). + if (!linphone_core_get_current_call(LC)) { + [PhoneMainView.instance popCurrentView]; + } +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +- (IBAction)onRoutesBluetoothClick:(id)sender { + [self hideRoutes:TRUE animated:TRUE]; + [CallManager.instance changeRouteToBluetooth]; +} + +- (IBAction)onRoutesEarpieceClick:(id)sender { + [self hideRoutes:TRUE animated:TRUE]; + [CallManager.instance changeRouteToDefault]; +} + +- (IBAction)onRoutesSpeakerClick:(id)sender { + [self hideRoutes:TRUE animated:TRUE]; + [CallManager.instance changeRouteToSpeaker]; +} + +- (IBAction)onRoutesClick:(id)sender { + if ([_routesView isHidden]) { + [self hideRoutes:FALSE animated:ANIMATED]; + } else { + [self hideRoutes:TRUE animated:ANIMATED]; + } +} + +- (IBAction)onNumpadClick:(id)sender { + if ([_numpadView isHidden]) { + [self hidePad:FALSE animated:ANIMATED]; + } else { + [self hidePad:TRUE animated:ANIMATED]; + } +} + +- (IBAction)onDeclineClick:(id)sender { + LinphoneCall *call = linphone_core_get_current_call(LC); + if (call) { + [CallManager.instance terminateCallWithCall:call]; + } +} + +- (void)hidePad:(BOOL)hidden animated:(BOOL)animated { + if (hidden) { + [_numpadButton setOff]; + } else { + [_numpadButton setOn]; + } + if (hidden != _numpadView.hidden) { + if (animated) { + [self hideAnimation:hidden forView:_numpadView completion:nil]; + } else { + [_numpadView setHidden:hidden]; + } + } +} + +- (void)hideRoutes:(BOOL)hidden animated:(BOOL)animated { + if (hidden) { + [_routesButton setOff]; + } else { + [_routesButton setOn]; + } + + _routesBluetoothButton.selected = [CallManager.instance isBluetoothEnabled]; + _routesSpeakerButton.selected = [CallManager.instance isSpeakerEnabled]; + _routesEarpieceButton.selected = !_routesBluetoothButton.selected && !_routesSpeakerButton.selected; + + if (hidden != _routesView.hidden) { + [_routesView setHidden:hidden]; + } +} + +- (void)hideSpeaker:(BOOL)hidden { + _speakerButton.hidden = hidden; + _routesButton.hidden = !hidden; +} + +#pragma mark - Event Functions + +- (void)bluetoothAvailabilityUpdateEvent:(NSNotification *)notif { + bool available = [[notif.userInfo objectForKey:@"available"] intValue]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self hideSpeaker:available]; + }); +} + +- (void)callUpdateEvent:(NSNotification *)notif { + LinphoneCall *call = [[notif.userInfo objectForKey:@"call"] pointerValue]; + LinphoneCallState state = [[notif.userInfo objectForKey:@"state"] intValue]; + [self callUpdate:call state:state animated:TRUE]; +} + +- (void)callUpdate:(LinphoneCall *)call state:(LinphoneCallState)state animated:(BOOL)animated { + _declineButton_earlyMedia.hidden = linphone_call_get_state(call) != LinphoneCallStateOutgoingEarlyMedia; + _declineButton.hidden = !_declineButton_earlyMedia.hidden; + _numpadButton.hidden = _declineButton_earlyMedia.hidden; +} + +#pragma mark - Animation + +- (void)hideAnimation:(BOOL)hidden forView:(UIView *)target completion:(void (^)(BOOL finished))completion { + if (hidden) { + int original_y = target.frame.origin.y; + CGRect newFrame = target.frame; + newFrame.origin.y = self.view.frame.size.height; + [UIView animateWithDuration:0.5 + delay:0.0 + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + target.frame = newFrame; + } + completion:^(BOOL finished) { + CGRect originFrame = target.frame; + originFrame.origin.y = original_y; + target.hidden = YES; + target.frame = originFrame; + if (completion) + completion(finished); + }]; + } else { + CGRect frame = target.frame; + int original_y = frame.origin.y; + frame.origin.y = self.view.frame.size.height; + target.frame = frame; + frame.origin.y = original_y; + target.hidden = NO; + + [UIView animateWithDuration:0.5 + delay:0.0 + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + target.frame = frame; + } + completion:^(BOOL finished) { + target.frame = frame; // in case application did not finish + if (completion) + completion(finished); + }]; + } +} + + +@end diff --git a/Classes/SwiftUtil/Extensions/IOS/UIImageViewExtensions.swift b/Classes/CallPausedTableView.h similarity index 78% rename from Classes/SwiftUtil/Extensions/IOS/UIImageViewExtensions.swift rename to Classes/CallPausedTableView.h index 9f926344a..622f19084 100644 --- a/Classes/SwiftUtil/Extensions/IOS/UIImageViewExtensions.swift +++ b/Classes/CallPausedTableView.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2010-2020 Belledonne Communications SARL. * - * This file is part of linphone-iphone + * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,11 +17,10 @@ * along with this program. If not, see . */ -import Foundation +#import -extension UIImageView { - func tint(_ color:UIColor) { - self.image = self.image?.withRenderingMode(.alwaysTemplate) - tintColor = color - } -} +@interface CallPausedTableView : UITableViewController + +- (void)update; + +@end diff --git a/Classes/CallPausedTableView.m b/Classes/CallPausedTableView.m new file mode 100644 index 000000000..2dc9b6c29 --- /dev/null +++ b/Classes/CallPausedTableView.m @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "CallPausedTableView.h" +#import "UICallPausedCell.h" +#import "LinphoneManager.h" +#import "Utils.h" + +@implementation CallPausedTableView + +#pragma mark - UI change + +- (void)update { + [self.tableView reloadData]; + CGRect newOrigin = self.tableView.frame; + newOrigin.size.height = + [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] * + [self tableView:self.tableView numberOfRowsInSection:0]; + newOrigin.origin.y += self.tableView.frame.size.height - newOrigin.size.height; + self.tableView.frame = newOrigin; +} + +#pragma mark - UITableViewDataSource Functions +- (LinphoneCall *)conferenceCallForRow:(NSInteger)row { + const MSList *calls = linphone_core_get_calls(LC); + int i = -1; + while (calls) { + if (linphone_call_get_state(calls->data) == LinphoneCallPaused) { + i++; + if (i == row) + break; + } + calls = calls->next; + } + // we should reach this only when we are querying for conference + return (calls ? calls->data : NULL); +} + +#pragma mark - UITableViewDataSource Functions + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + NSString *kCellId = NSStringFromClass(UICallPausedCell.class); + UICallPausedCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId]; + if (cell == nil) { + cell = [[UICallPausedCell alloc] initWithIdentifier:kCellId]; + } + [cell setCall:[self conferenceCallForRow:indexPath.row]]; + cell.contentView.userInteractionEnabled = false; + return cell; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + const MSList *calls = linphone_core_get_calls(LC); + int count = 0; + int conference_in_pause = 0; + int call_in_conference = 0; + while (calls) { + LinphoneCall *call = calls->data; + BOOL callInConference = linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); + if (linphone_call_get_state(call) == LinphoneCallPaused) { + count++; + } + if(callInConference) { + call_in_conference++; + if (!linphone_core_is_in_conference(LC)) { + conference_in_pause = 1; + } + } + calls = calls->next; + } + if(call_in_conference == 1) { + conference_in_pause = 0; + } + return count + conference_in_pause; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { + return 1e-5; +} +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + return 1e-5; +} + +@end diff --git a/Classes/SwiftUtil/Extensions/IOS/UIVIewControllerExtensions.swift b/Classes/CallSideMenuView.h similarity index 72% rename from Classes/SwiftUtil/Extensions/IOS/UIVIewControllerExtensions.swift rename to Classes/CallSideMenuView.h index 8c27c7dec..2a97f78d5 100644 --- a/Classes/SwiftUtil/Extensions/IOS/UIVIewControllerExtensions.swift +++ b/Classes/CallSideMenuView.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2010-2020 Belledonne Communications SARL. * - * This file is part of linphone-iphone + * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,13 +17,15 @@ * along with this program. If not, see . */ -import Foundation -import SnapKit -import UIKit +#import -extension UIViewController { - func VIEW( _ desc: UICompositeViewDescription) -> T{ - return PhoneMainView.instance().mainViewController.getCachedController(desc.name) as! T - } - -} +#import "SideMenuTableView.h" +#import "PhoneMainView.h" + +@interface CallSideMenuView : UIViewController + +@property(weak, nonatomic) IBOutlet UILabel *statsLabel; + +- (IBAction)onLateralSwipe:(id)sender; + +@end diff --git a/Classes/CallSideMenuView.m b/Classes/CallSideMenuView.m new file mode 100644 index 000000000..27ee4de48 --- /dev/null +++ b/Classes/CallSideMenuView.m @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "CallSideMenuView.h" +#import "LinphoneManager.h" +#import "PhoneMainView.h" + +@implementation CallSideMenuView { + NSTimer *updateTimer; +} + +#pragma mark - ViewController Functions + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + if (updateTimer != nil) { + [updateTimer invalidate]; + } + updateTimer = [NSTimer scheduledTimerWithTimeInterval:1 + target:self + selector:@selector(updateStats:) + userInfo:nil + repeats:YES]; + + [self updateStats:nil]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + if (updateTimer != nil) { + [updateTimer invalidate]; + updateTimer = nil; + } +} + +- (IBAction)onLateralSwipe:(id)sender { + [PhoneMainView.instance.mainViewController hideSideMenu:YES]; +} + ++ (NSString *)iceToString:(LinphoneIceState)state { + switch (state) { + case LinphoneIceStateNotActivated: + return NSLocalizedString(@"Not activated", @"ICE has not been activated for this call"); + break; + case LinphoneIceStateFailed: + return NSLocalizedString(@"Failed", @"ICE processing has failed"); + break; + case LinphoneIceStateInProgress: + return NSLocalizedString(@"In progress", @"ICE process is in progress"); + break; + case LinphoneIceStateHostConnection: + return NSLocalizedString(@"Direct connection", + @"ICE has established a direct connection to the remote host"); + break; + case LinphoneIceStateReflexiveConnection: + return NSLocalizedString( + @"NAT(s) connection", + @"ICE has established a connection to the remote host through one or several NATs"); + break; + case LinphoneIceStateRelayConnection: + return NSLocalizedString(@"Relay connection", @"ICE has established a connection through a relay"); + break; + } +} + ++ (NSString*)afinetToString:(int)remote_family { + return (remote_family == LinphoneAddressFamilyUnspec) ? @"Unspecified":(remote_family == LinphoneAddressFamilyInet) ? @"IPv4" : @"IPv6"; +} + ++ (NSString *)mediaEncryptionToString:(LinphoneMediaEncryption)enc { + switch (enc) { + case LinphoneMediaEncryptionDTLS: + return @"DTLS"; + case LinphoneMediaEncryptionSRTP: + return @"SRTP"; + case LinphoneMediaEncryptionZRTP: + return @"ZRTP"; + case LinphoneMediaEncryptionNone: + break; + } + return NSLocalizedString(@"None", nil); +} + +- (NSString *)updateStatsForCall:(LinphoneCall *)call stream:(LinphoneStreamType)stream { + NSMutableString *result = [[NSMutableString alloc] init]; + const PayloadType *payload = NULL; + const LinphoneCallStats *stats; + const LinphoneCallParams *params = linphone_call_get_current_params(call); + NSString *name; + + switch (stream) { + case LinphoneStreamTypeAudio: + name = @"Audio"; + payload = linphone_call_params_get_used_audio_codec(params); + stats = linphone_call_get_audio_stats(call); + break; + case LinphoneStreamTypeText: + name = @"Text"; + payload = linphone_call_params_get_used_text_codec(params); + stats = linphone_call_get_text_stats(call); + break; + case LinphoneStreamTypeVideo: + name = @"Video"; + payload = linphone_call_params_get_used_video_codec(params); + stats = linphone_call_get_video_stats(call); + break; + case LinphoneStreamTypeUnknown: + break; + } + if (payload == NULL) { + return result; + } + + [result appendString:@"\n"]; + [result appendString:name]; + [result appendString:@"\n"]; + + [result appendString:[NSString stringWithFormat:@"Codec: %s/%iHz", payload->mime_type, payload->clock_rate]]; + if (stream == LinphoneStreamTypeAudio) { + [result appendString:[NSString stringWithFormat:@"/%i channels", payload->channels]]; + } + [result appendString:@"\n"]; + // Encoder & decoder descriptions + const char *enc_desc = ms_factory_get_encoder(linphone_core_get_ms_factory(LC), payload->mime_type)->text; + const char *dec_desc = ms_factory_get_decoder(linphone_core_get_ms_factory(LC), payload->mime_type)->text; + if (strcmp(enc_desc, dec_desc) == 0) { + [result appendString:[NSString stringWithFormat:@"Encoder/Decoder: %s", enc_desc]]; + [result appendString:@"\n"]; + } else { + [result appendString:[NSString stringWithFormat:@"Encoder: %s", enc_desc]]; + [result appendString:@"\n"]; + [result appendString:[NSString stringWithFormat:@"Decoder: %s", dec_desc]]; + [result appendString:@"\n"]; + } + + if (stats != NULL) { + [result appendString:[NSString stringWithFormat:@"Download bandwidth: %1.1f kbits/s", + linphone_call_stats_get_download_bandwidth(stats)]]; + [result appendString:@"\n"]; + [result appendString:[NSString stringWithFormat:@"Upload bandwidth: %1.1f kbits/s", + linphone_call_stats_get_upload_bandwidth(stats)]]; + [result appendString:@"\n"]; + if (stream == LinphoneStreamTypeVideo) { + /*[result appendString:[NSString stringWithFormat:@"Estimated download bandwidth: %1.1f kbits/s", + linphone_call_stats_get_estimated_download_bandwidth(stats)]]; + [result appendString:@"\n"];*/ + } + [result + appendString:[NSString stringWithFormat:@"ICE state: %@", + [self.class iceToString:linphone_call_stats_get_ice_state(stats)]]]; + [result appendString:@"\n"]; + [result + appendString:[NSString + stringWithFormat:@"Afinet: %@", + [self.class afinetToString:linphone_call_stats_get_ip_family_of_remote( + stats)]]]; + [result appendString:@"\n"]; + + // RTP stats section (packet loss count, etc) + const rtp_stats_t rtp_stats = *linphone_call_stats_get_rtp_stats(stats); + [result + appendString:[NSString stringWithFormat: + @"RTP packets: %llu total, %lld cum loss, %llu discarded, %llu OOT, %llu bad", + rtp_stats.packet_recv, rtp_stats.cum_packet_loss, rtp_stats.discarded, + rtp_stats.outoftime, rtp_stats.bad]]; + [result appendString:@"\n"]; + [result appendString:[NSString stringWithFormat:@"Sender loss rate: %.2f%%", + linphone_call_stats_get_sender_loss_rate(stats)]]; + [result appendString:@"\n"]; + [result appendString:[NSString stringWithFormat:@"Receiver loss rate: %.2f%%", + linphone_call_stats_get_receiver_loss_rate(stats)]]; + [result appendString:@"\n"]; + + if (stream == LinphoneStreamTypeVideo) { + const LinphoneVideoDefinition *recv_definition = linphone_call_params_get_received_video_definition(params); + const LinphoneVideoDefinition *sent_definition = linphone_call_params_get_sent_video_definition(params); + float sentFPS = linphone_call_params_get_sent_framerate(params); + float recvFPS = linphone_call_params_get_received_framerate(params); + [result appendString:[NSString stringWithFormat:@"Sent video resolution: %dx%d (%.1fFPS)", linphone_video_definition_get_width(sent_definition), + linphone_video_definition_get_height(sent_definition), sentFPS]]; + [result appendString:@"\n"]; + [result appendString:[NSString stringWithFormat:@"Received video resolution: %dx%d (%.1fFPS)", + linphone_video_definition_get_width(recv_definition), + linphone_video_definition_get_height(recv_definition), recvFPS]]; + [result appendString:@"\n"]; + } + } + return result; +} + +- (void)updateStats:(NSTimer *)timer { + LinphoneCall *call = linphone_core_get_current_call(LC); + + if (!call) { + _statsLabel.text = NSLocalizedString(@"No call in progress", nil); + return; + } + + NSMutableString *stats = [[NSMutableString alloc] init]; + + LinphoneMediaEncryption enc = linphone_call_params_get_media_encryption(linphone_call_get_current_params(call)); + if (enc != LinphoneMediaEncryptionNone) { + [stats appendString:[NSString + stringWithFormat:@"Call encrypted using %@", [self.class mediaEncryptionToString:enc]]]; + } + + [stats appendString:[self updateStatsForCall:call stream:LinphoneStreamTypeAudio]]; + [stats appendString:[self updateStatsForCall:call stream:LinphoneStreamTypeVideo]]; + [stats appendString:[self updateStatsForCall:call stream:LinphoneStreamTypeText]]; + + _statsLabel.text = stats; +} + +@end diff --git a/Classes/CallSideMenuView.xib b/Classes/CallSideMenuView.xib new file mode 100644 index 000000000..a0208f810 --- /dev/null +++ b/Classes/CallSideMenuView.xib @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/CallView.h b/Classes/CallView.h new file mode 100644 index 000000000..fa188895d --- /dev/null +++ b/Classes/CallView.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import + +#import "VideoZoomHandler.h" +#import "UICamSwitch.h" + +#import "UICompositeView.h" +#import "CallPausedTableView.h" + +#import "UIMutedMicroButton.h" +#import "UIPauseButton.h" +#import "UISpeakerButton.h" +#import "UIVideoButton.h" +#import "UIHangUpButton.h" +#import "UIDigitButton.h" +#import "UIRoundedImageView.h" +#import "UIBouncingView.h" + +@class VideoView; + +@interface CallView : TPMultiLayoutViewController { + @private + UITapGestureRecognizer *singleFingerTap; + NSTimer *hideControlsTimer; + NSTimer *videoDismissTimer; + BOOL videoHidden; + BOOL callRecording; + VideoZoomHandler *videoZoomHandler; +} + +@property(nonatomic, strong) IBOutlet CallPausedTableView *pausedCallsTable; + +@property(nonatomic, strong) IBOutlet UIView *videoGroup; +@property(nonatomic, strong) IBOutlet UIView *videoView; +@property(nonatomic, strong) IBOutlet UIView *videoPreview; +@property(nonatomic, strong) IBOutlet UICamSwitch *videoCameraSwitch; +@property(nonatomic, strong) IBOutlet UIActivityIndicatorView *videoWaitingForFirstImage; +@property(weak, nonatomic) IBOutlet UIView *callView; + +@property(nonatomic, strong) IBOutlet UIPauseButton *callPauseButton; +@property(nonatomic, strong) IBOutlet UIButton *optionsConferenceButton; +@property(nonatomic, strong) IBOutlet UIVideoButton *videoButton; +@property(nonatomic, strong) IBOutlet UIMutedMicroButton *microButton; +@property(nonatomic, strong) IBOutlet UISpeakerButton *speakerButton; +@property(nonatomic, strong) IBOutlet UIToggleButton *routesButton; +@property(nonatomic, strong) IBOutlet UIToggleButton *optionsButton; +@property(nonatomic, strong) IBOutlet UIHangUpButton *hangupButton; +@property(nonatomic, strong) IBOutlet UIView *numpadView; +@property(nonatomic, strong) IBOutlet UIView *routesView; +@property(nonatomic, strong) IBOutlet UIView *optionsView; +@property(nonatomic, strong) IBOutlet UIButton *routesEarpieceButton; +@property(nonatomic, strong) IBOutlet UIButton *routesSpeakerButton; +@property(nonatomic, strong) IBOutlet UIButton *routesBluetoothButton; +@property(nonatomic, strong) IBOutlet UIButton *optionsAddButton; +@property(nonatomic, strong) IBOutlet UIButton *optionsTransferButton; +@property(nonatomic, strong) IBOutlet UIToggleButton *numpadButton; +@property(weak, nonatomic) IBOutlet UIPauseButton *conferencePauseButton; +@property(weak, nonatomic) IBOutlet UIBouncingView *chatNotificationView; +@property(weak, nonatomic) IBOutlet UILabel *chatNotificationLabel; +@property (weak, nonatomic) IBOutlet UIButton *recordButton; +@property (weak, nonatomic) IBOutlet UIButton *recordButtonOnView; + +@property(weak, nonatomic) IBOutlet UIView *bottomBar; +@property(nonatomic, strong) IBOutlet UIDigitButton *oneButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *twoButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *threeButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *fourButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *fiveButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *sixButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *sevenButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *eightButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *nineButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *starButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *zeroButton; +@property(nonatomic, strong) IBOutlet UIDigitButton *hashButton; +@property(weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage; +@property(weak, nonatomic) IBOutlet UILabel *nameLabel; +@property(weak, nonatomic) IBOutlet UILabel *durationLabel; +@property(weak, nonatomic) IBOutlet UIView *pausedByRemoteView; +@property(weak, nonatomic) IBOutlet UIView *noActiveCallView; +@property(weak, nonatomic) IBOutlet UIView *conferenceView; +@property(strong, nonatomic) IBOutlet CallPausedTableView *conferenceCallsTable; +@property (weak, nonatomic) IBOutlet UIView *waitView; +@property (weak, nonatomic) IBOutlet UIView *infoView; + +- (IBAction)onRoutesClick:(id)sender; +- (IBAction)onRoutesBluetoothClick:(id)sender; +- (IBAction)onRoutesEarpieceClick:(id)sender; +- (IBAction)onRoutesSpeakerClick:(id)sender; +- (IBAction)onOptionsClick:(id)sender; +- (IBAction)onOptionsTransferClick:(id)sender; +- (IBAction)onOptionsAddClick:(id)sender; +- (IBAction)onOptionsConferenceClick:(id)sender; +- (IBAction)onNumpadClick:(id)sender; +- (IBAction)onChatClick:(id)sender; +- (IBAction)onRecordClick:(id)sender; +- (IBAction)onRecordOnViewClick:(id)sender; + +@end diff --git a/Classes/CallView.m b/Classes/CallView.m new file mode 100644 index 000000000..2ae10de87 --- /dev/null +++ b/Classes/CallView.m @@ -0,0 +1,1006 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import +#import +#import +#import +#import +#import +#import +#import "UICallConferenceCell.h" + +#import "CallView.h" +#import "CallSideMenuView.h" +#import "LinphoneManager.h" +#import "PhoneMainView.h" +#import "Utils.h" + +#include "linphone/linphonecore.h" + +#import "linphoneapp-Swift.h" + +const NSInteger SECURE_BUTTON_TAG = 5; + +@implementation CallView { + BOOL hiddenVolume; +} + +#pragma mark - Lifecycle Functions + +- (id)init { + self = [super initWithNibName:NSStringFromClass(self.class) bundle:[NSBundle mainBundle]]; + if (self != nil) { + singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleControls:)]; + videoZoomHandler = [[VideoZoomHandler alloc] init]; + videoHidden = TRUE; + [self updateCallView]; + } + return self; +} + +#pragma mark - UICompositeViewDelegate Functions + +static UICompositeViewDescription *compositeDescription = nil; + ++ (UICompositeViewDescription *)compositeViewDescription { + if (compositeDescription == nil) { + compositeDescription = [[UICompositeViewDescription alloc] init:self.class + statusBar:StatusBarView.class + tabBar:nil + sideMenu:CallSideMenuView.class + fullscreen:false + isLeftFragment:YES + fragmentWith:nil]; + compositeDescription.darkBackground = true; + } + return compositeDescription; +} + +- (UICompositeViewDescription *)compositeViewDescription { + return self.class.compositeViewDescription; +} + +#pragma mark - ViewController Functions + +- (void)viewDidLoad { + [super viewDidLoad]; + + _routesEarpieceButton.enabled = !IPAD; + +// TODO: fixme! video preview frame is too big compared to openGL preview +// frame, so until this is fixed, temporary disabled it. +#if 0 + _videoPreview.layer.borderColor = UIColor.whiteColor.CGColor; + _videoPreview.layer.borderWidth = 1; +#endif + [singleFingerTap setNumberOfTapsRequired:1]; + [singleFingerTap setCancelsTouchesInView:FALSE]; + [self.videoView addGestureRecognizer:singleFingerTap]; + + [videoZoomHandler setup:_videoGroup]; + _videoGroup.alpha = 0; + + [_videoCameraSwitch setPreview:_videoPreview]; + + UIPanGestureRecognizer *dragndrop = + [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveVideoPreview:)]; + dragndrop.minimumNumberOfTouches = 1; + [_videoPreview addGestureRecognizer:dragndrop]; + + [_zeroButton setDigit:'0']; + [_zeroButton setDtmf:true]; + [_oneButton setDigit:'1']; + [_oneButton setDtmf:true]; + [_twoButton setDigit:'2']; + [_twoButton setDtmf:true]; + [_threeButton setDigit:'3']; + [_threeButton setDtmf:true]; + [_fourButton setDigit:'4']; + [_fourButton setDtmf:true]; + [_fiveButton setDigit:'5']; + [_fiveButton setDtmf:true]; + [_sixButton setDigit:'6']; + [_sixButton setDtmf:true]; + [_sevenButton setDigit:'7']; + [_sevenButton setDtmf:true]; + [_eightButton setDigit:'8']; + [_eightButton setDtmf:true]; + [_nineButton setDigit:'9']; + [_nineButton setDtmf:true]; + [_starButton setDigit:'*']; + [_starButton setDtmf:true]; + [_hashButton setDigit:'#']; + [_hashButton setDtmf:true]; +} + +- (void)dealloc { + [PhoneMainView.instance.view removeGestureRecognizer:singleFingerTap]; + // Remove all observer + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + _waitView.hidden = TRUE; + CallManager.instance.nextCallIsTransfer = FALSE; + + callRecording = FALSE; + _recordButtonOnView.hidden = TRUE; + + // Update on show + [self hideRoutes:TRUE animated:FALSE]; + [self hideOptions:TRUE animated:FALSE]; + [self hidePad:TRUE animated:FALSE]; + [self hideSpeaker:LinphoneManager.instance.bluetoothAvailable]; + [self callDurationUpdate]; + [self onCurrentCallChange]; + // Set windows (warn memory leaks) + linphone_core_set_native_video_window_id(LC, (__bridge void *)(_videoView)); + linphone_core_set_native_preview_window_id(LC, (__bridge void *)(_videoPreview)); + + [self previewTouchLift]; + // Enable tap + [singleFingerTap setEnabled:TRUE]; + + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(messageReceived:) + name:kLinphoneMessageReceived + object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(bluetoothAvailabilityUpdateEvent:) + name:kLinphoneBluetoothAvailabilityUpdate + object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(callUpdateEvent:) + name:kLinphoneCallUpdate + object:nil]; + + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(participantListChanged:) + name:kLinphoneConfStateParticipantListChanged + object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(confStateChanged:) + name:kLinphoneConfStateChanged + object:nil]; + + + + + [NSTimer scheduledTimerWithTimeInterval:1 + target:self + selector:@selector(callDurationUpdate) + userInfo:nil + repeats:YES]; + +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; + [[UIDevice currentDevice] setProximityMonitoringEnabled:TRUE]; + + [PhoneMainView.instance setVolumeHidden:TRUE]; + hiddenVolume = TRUE; + + // we must wait didAppear to reset fullscreen mode because we cannot change it in viewwillappear + LinphoneCall *call = linphone_core_get_current_call(LC); + LinphoneCallState state = (call != NULL) ? linphone_call_get_state(call) : 0; + [self callUpdate:call state:state animated:FALSE]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; +[[UIDevice currentDevice] setProximityMonitoringEnabled:FALSE]; + [self disableVideoDisplay:TRUE animated:NO]; + + if (hideControlsTimer != nil) { + [hideControlsTimer invalidate]; + hideControlsTimer = nil; + } + + if (hiddenVolume) { + [PhoneMainView.instance setVolumeHidden:FALSE]; + hiddenVolume = FALSE; + } + + if (videoDismissTimer) { + [self dismissVideoActionSheet:videoDismissTimer]; + [videoDismissTimer invalidate]; + videoDismissTimer = nil; + } + + // Remove observer + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + + [[UIApplication sharedApplication] setIdleTimerDisabled:false]; + [[UIDevice currentDevice] setProximityMonitoringEnabled:FALSE]; + + [PhoneMainView.instance fullScreen:false]; + // Disable tap + [singleFingerTap setEnabled:FALSE]; + + if (linphone_core_get_calls_nb(LC) == 0) { + // reseting speaker button because no more call + _speakerButton.selected = FALSE; + } + + NSString *address = [LinphoneManager.instance lpConfigStringForKey:@"sas_dialog_denied"]; + if (address) { + UIConfirmationDialog *securityDialog = [UIConfirmationDialog ShowWithMessage:NSLocalizedString(@"Trust has been denied. Make a call to start the authentication process again.", nil) + cancelMessage:NSLocalizedString(@"CANCEL", nil) + confirmMessage:NSLocalizedString(@"CALL", nil) + onCancelClick:^() { + } + onConfirmationClick:^() { + LinphoneAddress *addr = linphone_address_new(address.UTF8String); + [CallManager.instance startCallWithAddr:addr isSas:TRUE]; + linphone_address_unref(addr); + } ]; + [securityDialog.securityImage setImage:[UIImage imageNamed:@"security_alert_indicator.png"]]; + securityDialog.securityImage.hidden = FALSE; + [securityDialog setSpecialColor]; + [LinphoneManager.instance lpConfigSetString:nil forKey:@"sas_dialog_denied"]; + } +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; + [self updateUnreadMessage:NO]; + [self previewTouchLift]; + [_recordButtonOnView setHidden:!callRecording]; + [self updateCallView]; + LinphoneCall *call = linphone_core_get_current_call(LC) ; + if (call && linphone_call_get_state(call) == LinphoneCallStatePausedByRemote) { + _pausedByRemoteView.hidden = NO; + [self updateInfoView:TRUE]; + } + _conferenceView.hidden = ![CallManager.instance isInConference]; + [self onCurrentCallChange]; +} + +#pragma mark - UI modification + +- (void)updateInfoView:(BOOL)pausedByRemote { + CGRect infoFrame = _infoView.frame; + if (pausedByRemote || !videoHidden) { + infoFrame.origin.y = 0; + } else { + infoFrame.origin.y = (_avatarImage.frame.origin.y-66)/2; + } + _infoView.frame = infoFrame; +} + +- (void)updateCallView { + CGRect pauseFrame = _callPauseButton.frame; + CGRect recordFrame = _recordButtonOnView.frame; + if (videoHidden) { + pauseFrame.origin.y = _bottomBar.frame.origin.y - pauseFrame.size.height - 60; + } else { + pauseFrame.origin.y = _videoCameraSwitch.frame.origin.y+_videoGroup.frame.origin.y; + } + recordFrame.origin.y = _bottomBar.frame.origin.y - pauseFrame.size.height - 60; + _callPauseButton.frame = pauseFrame; + _recordButtonOnView.frame = recordFrame; + [self updateInfoView:FALSE]; +} + +- (void)hideSpinnerIndicator:(LinphoneCall *)call { + _videoWaitingForFirstImage.hidden = TRUE; +} + +static void hideSpinner(LinphoneCall *call, void *user_data) { + CallView *thiz = (__bridge CallView *)user_data; + [thiz hideSpinnerIndicator:call]; +} + +- (void)updateBottomBar:(LinphoneCall *)call state:(LinphoneCallState)state { + [_speakerButton update]; + [_microButton update]; + [_callPauseButton update]; + [_conferencePauseButton update]; + [_videoButton update]; + [_hangupButton update]; + + _optionsButton.enabled = (!call || !linphone_core_sound_resources_locked(LC)); + _optionsTransferButton.enabled = call && !linphone_core_sound_resources_locked(LC); + // enable conference button if 2 calls are presents and at least one is not in the conference + int confSize = linphone_core_get_conference_size(LC) - ([CallManager.instance isInConference] ? 1 : 0); + _optionsConferenceButton.enabled = (linphone_core_get_calls_nb(LC) > 1) && (linphone_core_get_calls_nb(LC) != confSize) && !CallManager.instance.hasConferenceAsGuest; + + // Disable transfert in conference + if (linphone_core_get_current_call(LC) == NULL) { + [_optionsTransferButton setEnabled:FALSE]; + } else { + [_optionsTransferButton setEnabled:TRUE]; + } + + switch (state) { + case LinphoneCallEnd: + case LinphoneCallError: + case LinphoneCallIncoming: + case LinphoneCallOutgoing: + [self hidePad:TRUE animated:TRUE]; + [self hideOptions:TRUE animated:TRUE]; + [self hideRoutes:TRUE animated:TRUE]; + default: + break; + } +} + +- (void)toggleControls:(id)sender { + bool controlsHidden = (_bottomBar.alpha == 0.0); + [self hideControls:!controlsHidden sender:sender]; +} + +- (void)timerHideControls:(id)sender { + [self hideControls:TRUE sender:sender]; +} + +- (void)hideControls:(BOOL)hidden sender:(id)sender { + if (videoHidden && hidden) + return; + + if (hideControlsTimer) { + [hideControlsTimer invalidate]; + hideControlsTimer = nil; + } + + if ([[PhoneMainView.instance currentView] equal:CallView.compositeViewDescription]) { + // show controls + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:0.35]; + _pausedCallsTable.tableView.alpha = _videoCameraSwitch.alpha = _callPauseButton.alpha = _routesView.alpha = + _optionsView.alpha = _numpadView.alpha = _bottomBar.alpha = _conferenceView.alpha = (hidden ? 0 : 1); + _infoView.alpha = (hidden ? 0 : .8f); + + if ([CallManager.instance inVideoConf]) { + _videoCameraSwitch.frame = CGRectMake(_videoCameraSwitch.frame.origin.x, _bottomBar.frame.origin.y - 75, _videoCameraSwitch.frame.size.width,_videoCameraSwitch.frame.size.height); + } + + if (CallManager.instance.isInConference) { + _callPauseButton.hidden = true; + _conferenceView.frame = CGRectMake(_conferenceView.frame.origin.x,_conferenceView.frame.origin.y,_conferenceView.frame.size.width,_conferenceCallsTable.tableView.frame.origin.y+[_conferenceCallsTable.tableView numberOfRowsInSection:0]*CONFERENCE_CELL_HEIGHT+10); + } + + + [UIView commitAnimations]; + + [PhoneMainView.instance hideTabBar:hidden]; + [PhoneMainView.instance hideStatusBar:hidden]; + + if (!hidden) { + // hide controls in 5 sec + hideControlsTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 + target:self + selector:@selector(timerHideControls:) + userInfo:nil + repeats:NO]; + } + } +} + +- (void)disableVideoDisplay:(BOOL)disabled animated:(BOOL)animation { + if (disabled == videoHidden && animation) + return; + videoHidden = disabled; + + if (!disabled) { + [videoZoomHandler resetZoom]; + } + if (animation) { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:1.0]; + } + + [_videoGroup setAlpha:disabled ? 0 : 1]; + + [self hideControls:!disabled sender:nil]; + + if (animation) { + [UIView commitAnimations]; + } + + // only show camera switch button if we have more than 1 camera + _videoCameraSwitch.hidden = (disabled || !LinphoneManager.instance.frontCamId); + _videoPreview.hidden = (disabled || !linphone_core_self_view_enabled(LC)); + + if (hideControlsTimer != nil) { + [hideControlsTimer invalidate]; + hideControlsTimer = nil; + } + + if(![PhoneMainView.instance isIphoneXDevice]){ + [PhoneMainView.instance fullScreen:!disabled]; + } + [PhoneMainView.instance hideTabBar:!disabled]; + + if (!disabled) { +#ifdef TEST_VIDEO_VIEW_CHANGE + [NSTimer scheduledTimerWithTimeInterval:5.0 + target:self + selector:@selector(_debugChangeVideoView) + userInfo:nil + repeats:YES]; +#endif + // [self batteryLevelChanged:nil]; + + [_videoWaitingForFirstImage setHidden:NO]; + [_videoWaitingForFirstImage startAnimating]; + + if ([CallManager.instance inVideoConf]) + [self hideSpinnerIndicator:nil]; + else { + LinphoneCall *call = linphone_core_get_current_call(LC); + // linphone_call_params_get_used_video_codec return 0 if no video stream enabled + if (call != NULL && linphone_call_params_get_used_video_codec(linphone_call_get_current_params(call))) { + linphone_call_set_next_video_frame_decoded_callback(call, hideSpinner, (__bridge void *)(self)); + } + } + } + + if ([CallManager.instance isInConference]) { + [_conferenceView removeFromSuperview]; + [_callView addSubview:_conferenceView]; + } else { + [_conferenceView removeFromSuperview]; + [self.view addSubview:_conferenceView]; + [self.view sendSubviewToBack:_conferenceView]; + } +} + +- (void)displayVideoCall:(BOOL)animated { + [self disableVideoDisplay:FALSE animated:animated]; +} + +- (void)displayAudioCall:(BOOL)animated { + [self disableVideoDisplay:TRUE animated:animated]; +} + +- (void)callDurationUpdate { + int duration = + linphone_core_get_current_call(LC) ? linphone_call_get_duration(linphone_core_get_current_call(LC)) : 0; + _durationLabel.text = [LinphoneUtils durationToString:duration]; + + [_pausedCallsTable update]; + [_conferenceCallsTable update]; +} + +- (void)onCurrentCallChange { + LinphoneCall *call = linphone_core_get_current_call(LC); + + _noActiveCallView.hidden = (call || CallManager.instance.isInConference); + _callView.hidden = !call && !CallManager.instance.isInConference; + _conferenceView.hidden = !CallManager.instance.isInConference; + _conferenceView.hidden = !CallManager.instance.isInConference; + _callPauseButton.hidden = !call; + + + [_callPauseButton setType:UIPauseButtonType_CurrentCall call:call]; + [_conferencePauseButton setType:UIPauseButtonType_Conference call:call]; + + if (call) { + const LinphoneAddress *addr = linphone_call_get_remote_address(call); + [ContactDisplay setDisplayNameLabel:_nameLabel forAddress:addr]; + char *uri = linphone_address_as_string_uri_only(addr); + ms_free(uri); + [_avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:YES withRoundedRadius:YES]; + } +} + +- (void)hidePad:(BOOL)hidden animated:(BOOL)animated { + if (hidden) { + [_numpadButton setOff]; + } else { + [_numpadButton setOn]; + } + if (hidden != _numpadView.hidden) { + if (animated) { + [self hideAnimation:hidden forView:_numpadView completion:nil]; + } else { + [_numpadView setHidden:hidden]; + } + } +} + +- (void)hideRoutes:(BOOL)hidden animated:(BOOL)animated { + if (hidden) { + [_routesButton setOff]; + } else { + [_routesButton setOn]; + } + + _routesBluetoothButton.selected = [CallManager.instance isBluetoothEnabled]; + _routesSpeakerButton.selected = [CallManager.instance isSpeakerEnabled]; + _routesEarpieceButton.selected = !_routesBluetoothButton.selected && !_routesSpeakerButton.selected; + + if (hidden != _routesView.hidden) { + if (animated) { + [self hideAnimation:hidden forView:_routesView completion:nil]; + } else { + [_routesView setHidden:hidden]; + } + } +} + +- (void)hideOptions:(BOOL)hidden animated:(BOOL)animated { + if (hidden) { + [_optionsButton setOff]; + } else { + [_optionsButton setOn]; + } + if (hidden != _optionsView.hidden) { + if (animated) { + [self hideAnimation:hidden forView:_optionsView completion:nil]; + } else { + [_optionsView setHidden:hidden]; + } + } +} + +- (void)hideSpeaker:(BOOL)hidden { + _speakerButton.hidden = hidden; + _routesButton.hidden = !hidden; +} + +#pragma mark - Event Functions + +- (void)bluetoothAvailabilityUpdateEvent:(NSNotification *)notif { + bool available = [[notif.userInfo objectForKey:@"available"] intValue]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self hideSpeaker:available]; + }); +} + +- (void)callUpdateEvent:(NSNotification *)notif { + LinphoneCall *call = [[notif.userInfo objectForKey:@"call"] pointerValue]; + LinphoneCallState state = [[notif.userInfo objectForKey:@"state"] intValue]; + [self callUpdate:call state:state animated:TRUE]; +} + +- (void)callUpdate:(LinphoneCall *)call state:(LinphoneCallState)state animated:(BOOL)animated { + [self updateBottomBar:call state:state]; + if (hiddenVolume) { + [PhoneMainView.instance setVolumeHidden:FALSE]; + hiddenVolume = FALSE; + } + + // Update tables + [_pausedCallsTable update]; + [_conferenceCallsTable update]; + + [self onCurrentCallChange]; + + LinphoneCall *currentCall = linphone_core_get_current_call(LC); + BOOL shouldDisableVideo = currentCall ? !linphone_call_params_video_enabled(linphone_call_get_current_params(currentCall)): ![CallManager.instance inVideoConf]; + + + if (videoHidden != shouldDisableVideo) { + if (!shouldDisableVideo) { + [self displayVideoCall:animated]; + } else { + [self displayAudioCall:animated]; + } + } + + // Fake call update + if (call == NULL) { + return; + } + + if (state != LinphoneCallPausedByRemote) { + _pausedByRemoteView.hidden = YES; + } + + switch (state) { + case LinphoneCallIncomingReceived: + case LinphoneCallOutgoingInit: + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: { + // check video, because video can be disabled because of the low bandwidth. + if (!linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { + const LinphoneCallParams *param = linphone_call_get_current_params(call); + CallAppData *data = [CallManager getAppDataWithCall:call]; + if (state == LinphoneCallStreamsRunning && data && data.videoRequested && linphone_call_params_low_bandwidth_enabled(param)) { + // too bad video was not enabled because low bandwidth + UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Low bandwidth", nil) + message:NSLocalizedString(@"Video cannot be activated because of low bandwidth " + @"condition, only audio is available", + nil) + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue", nil) + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) {}]; + + [errView addAction:defaultAction]; + [self presentViewController:errView animated:YES completion:nil]; + data.videoRequested = FALSE; + [CallManager setAppDataWithCall:call appData:data]; + } + } + break; + } + case LinphoneCallUpdatedByRemote: { + const LinphoneCallParams *current = linphone_call_get_current_params(call); + const LinphoneCallParams *remote = linphone_call_get_remote_params(call); + + /* remote wants to add video */ + if ((linphone_core_video_display_enabled(LC) && !linphone_call_params_video_enabled(current) && + linphone_call_params_video_enabled(remote)) && + (!linphone_core_get_video_policy(LC)->automatically_accept || + (([UIApplication sharedApplication].applicationState != UIApplicationStateActive) && + floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max))) { + linphone_core_defer_call_update(LC, call); + [self displayAskToEnableVideoCall:call]; + } else if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote) && ![CallManager.instance inVideoConf]) { + [self displayAudioCall:animated]; + } + break; + } + case LinphoneCallPausing: + case LinphoneCallPaused: + [self displayAudioCall:animated]; + break; + case LinphoneCallPausedByRemote: + if (![CallManager.instance inVideoConf]) { + [self displayAudioCall:animated]; + if (call == linphone_core_get_current_call(LC)) { + _pausedByRemoteView.hidden = NO; + [self updateInfoView:TRUE]; + } + } + break; + case LinphoneCallEnd: + case LinphoneCallError: + default: + break; + } +} + +#pragma mark - ActionSheet Functions + +- (void)displayAskToEnableVideoCall:(LinphoneCall *)call { + + if (CallManager.instance.inVideoConf) { // we are hosting a video conf, so just accept people wanting to activate video. + LinphoneCallParams *params = linphone_core_create_call_params(LC, call); + linphone_call_params_enable_video(params, TRUE); + linphone_call_accept_update(call, params); + return; + } + + if (linphone_core_get_video_policy(LC)->automatically_accept && + !([UIApplication sharedApplication].applicationState != UIApplicationStateActive)) + return; + + NSString *username = [FastAddressBook displayNameForAddress:linphone_call_get_remote_address(call)]; + NSString *title = [NSString stringWithFormat:NSLocalizedString(@"%@ would like to enable video", nil), username]; + if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive && + floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) { + UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; + content.title = NSLocalizedString(@"Video request", nil); + content.body = title; + content.categoryIdentifier = @"video_request"; + content.userInfo = @{ + @"CallId" : [NSString stringWithUTF8String:linphone_call_log_get_call_id(linphone_call_get_call_log(call))] + }; + + UNNotificationRequest *req = + [UNNotificationRequest requestWithIdentifier:@"video_request" content:content trigger:NULL]; + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:req + withCompletionHandler:^(NSError *_Nullable error) { + // Enable or disable features based on authorization. + if (error) { + LOGD(@"Error while adding notification request :"); + LOGD(error.description); + } + }]; + } else { + UIConfirmationDialog *sheet = [UIConfirmationDialog ShowWithMessage:title + cancelMessage:nil + confirmMessage:NSLocalizedString(@"ACCEPT", nil) + onCancelClick:^() { + LOGI(@"User declined video proposal"); + if (call == linphone_core_get_current_call(LC)) { + [CallManager.instance acceptVideoWithCall:call confirm:FALSE]; + [videoDismissTimer invalidate]; + videoDismissTimer = nil; + } + } + onConfirmationClick:^() { + LOGI(@"User accept video proposal"); + if (call == linphone_core_get_current_call(LC)) { + [CallManager.instance acceptVideoWithCall:call confirm:TRUE]; + [videoDismissTimer invalidate]; + videoDismissTimer = nil; + } + } + inController:self]; + videoDismissTimer = [NSTimer scheduledTimerWithTimeInterval:30 + target:self + selector:@selector(dismissVideoActionSheet:) + userInfo:sheet + repeats:NO]; + } +} + +- (void)dismissVideoActionSheet:(NSTimer *)timer { + UIConfirmationDialog *sheet = (UIConfirmationDialog *)timer.userInfo; + [sheet dismiss]; +} + +#pragma mark VideoPreviewMoving + +- (void)moveVideoPreview:(UIPanGestureRecognizer *)dragndrop { + CGPoint center = [dragndrop locationInView:_videoPreview.superview]; + _videoPreview.center = center; + if (dragndrop.state == UIGestureRecognizerStateEnded) { + [self previewTouchLift]; + } +} + +- (CGFloat)coerce:(CGFloat)value betweenMin:(CGFloat)min andMax:(CGFloat)max { + return MAX(min, MIN(value, max)); +} + +- (void)previewTouchLift { + CGRect previewFrame = _videoPreview.frame; + previewFrame.origin.x = [self coerce:previewFrame.origin.x + betweenMin:5 + andMax:(UIScreen.mainScreen.bounds.size.width - 5 - previewFrame.size.width)]; + previewFrame.origin.y = [self coerce:previewFrame.origin.y + betweenMin:5 + andMax:(UIScreen.mainScreen.bounds.size.height - 5 - previewFrame.size.height)]; + + if (!CGRectEqualToRect(previewFrame, _videoPreview.frame)) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:0.3 + animations:^{ + LOGD(@"Recentering preview to %@", NSStringFromCGRect(previewFrame)); + _videoPreview.frame = previewFrame; + }]; + }); + } +} + +#pragma mark - Action Functions + +- (IBAction)onNumpadClick:(id)sender { + if ([_numpadView isHidden]) { + [self hidePad:FALSE animated:ANIMATED]; + } else { + [self hidePad:TRUE animated:ANIMATED]; + } +} + +- (IBAction)onChatClick:(id)sender { + const LinphoneCall *currentCall = linphone_core_get_current_call(LC); + const LinphoneAddress *addr = currentCall ? linphone_call_get_remote_address(currentCall) : NULL; + // TODO encrpted or unencrpted + [LinphoneManager.instance lpConfigSetBool:TRUE forKey:@"create_chat"]; + [PhoneMainView.instance getOrCreateOneToOneChatRoom:addr waitView:_waitView isEncrypted:FALSE]; +} + +- (IBAction)onRecordClick:(id)sender { + if (![_optionsView isHidden]) + [self hideOptions:TRUE animated:ANIMATED]; + if (callRecording) { + [self onRecordOnViewClick:nil]; + } else { + LOGD(@"Recording Starts"); + + [_recordButton setImage:[UIImage imageNamed:@"rec_off_default.png"] forState:UIControlStateNormal]; + [_recordButtonOnView setHidden:FALSE]; + + LinphoneCall *call = linphone_core_get_current_call(LC); + linphone_call_start_recording(call); + + callRecording = TRUE; + } +} + +- (IBAction)onRecordOnViewClick:(id)sender { + LOGD(@"Recording Stops"); + [_recordButton setImage:[UIImage imageNamed:@"rec_on_default.png"] forState:UIControlStateNormal]; + [_recordButtonOnView setHidden:TRUE]; + + LinphoneCall *call = linphone_core_get_current_call(LC); + linphone_call_stop_recording(call); + + callRecording = FALSE; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *writablePath = [paths objectAtIndex:0]; + writablePath = [writablePath stringByAppendingString:@"/"]; + NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:writablePath error:NULL]; + if (directoryContent) { + return; + } +} + +- (IBAction)onRoutesBluetoothClick:(id)sender { + [self hideRoutes:TRUE animated:TRUE]; + [CallManager.instance changeRouteToBluetooth]; +} + +- (IBAction)onRoutesEarpieceClick:(id)sender { + [self hideRoutes:TRUE animated:TRUE]; + [CallManager.instance changeRouteToDefault]; +} + +- (IBAction)onRoutesSpeakerClick:(id)sender { + [self hideRoutes:TRUE animated:TRUE]; + [CallManager.instance changeRouteToSpeaker]; +} + +- (IBAction)onRoutesClick:(id)sender { + if ([_routesView isHidden]) { + [self hideRoutes:FALSE animated:ANIMATED]; + } else { + [self hideRoutes:TRUE animated:ANIMATED]; + } +} + +- (IBAction)onOptionsClick:(id)sender { + int confSize = linphone_core_get_conference_size(LC) - (CallManager.instance.isInConference ? 1 : 0); + _optionsConferenceButton.enabled = (linphone_core_get_calls_nb(LC) > 1) && (linphone_core_get_calls_nb(LC) != confSize) && !CallManager.instance.hasConferenceAsGuest; + + if ([_optionsView isHidden]) { + [self hideOptions:FALSE animated:ANIMATED]; + } else { + [self hideOptions:TRUE animated:ANIMATED]; + } +} + +- (IBAction)onOptionsTransferClick:(id)sender { + [self hideOptions:TRUE animated:TRUE]; + DialerView *view = VIEW(DialerView); + [view setAddress:@""]; + CallManager.instance.nextCallIsTransfer = TRUE; + [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; +} + +- (IBAction)onOptionsAddClick:(id)sender { + [self hideOptions:TRUE animated:TRUE]; + DialerView *view = VIEW(DialerView); + [view setAddress:@""]; + CallManager.instance.nextCallIsTransfer = FALSE; + [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; +} + +- (IBAction)onOptionsConferenceClick:(id)sender { + [self hideOptions:TRUE animated:TRUE]; + [CallManager.instance groupCall]; +} + +#pragma mark - Animation + +- (void)hideAnimation:(BOOL)hidden forView:(UIView *)target completion:(void (^)(BOOL finished))completion { + if (hidden) { + int original_y = target.frame.origin.y; + CGRect newFrame = target.frame; + newFrame.origin.y = self.view.frame.size.height; + [UIView animateWithDuration:0.5 + delay:0.0 + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + target.frame = newFrame; + } + completion:^(BOOL finished) { + CGRect originFrame = target.frame; + originFrame.origin.y = original_y; + target.hidden = YES; + target.frame = originFrame; + if (completion) + completion(finished); + }]; + } else { + CGRect frame = target.frame; + int original_y = frame.origin.y; + frame.origin.y = self.view.frame.size.height; + target.frame = frame; + frame.origin.y = original_y; + target.hidden = NO; + + [UIView animateWithDuration:0.5 + delay:0.0 + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + target.frame = frame; + } + completion:^(BOOL finished) { + target.frame = frame; // in case application did not finish + if (completion) + completion(finished); + }]; + } +} + +#pragma mark - Bounce +- (void)messageReceived:(NSNotification *)notif { + [self updateUnreadMessage:TRUE]; +} +- (void)updateUnreadMessage:(BOOL)appear { + int unreadMessage = [LinphoneManager unreadMessageCount]; + if (unreadMessage > 0) { + _chatNotificationLabel.text = [NSString stringWithFormat:@"%i", unreadMessage]; + [_chatNotificationView startAnimating:appear]; + } else { + [_chatNotificationView stopAnimating:appear]; + } +} + +#pragma mark - Conference + +- (void)participantListChanged:(NSNotification *)notif { + [self confStateChanged:nil]; + [_conferenceCallsTable update]; + _conferenceView.frame = CGRectMake(_conferenceView.frame.origin.x,_conferenceView.frame.origin.y,_conferenceView.frame.size.width,_conferenceCallsTable.tableView.frame.origin.y+[_conferenceCallsTable.tableView numberOfRowsInSection:0]*CONFERENCE_CELL_HEIGHT+10); + [self onCurrentCallChange]; + _conferenceView.hidden = !CallManager.instance.isInConference; +} + +- (void)confStateChanged:(NSNotification *)notif { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + if ([CallManager.instance inVideoConf]) { + [self displayVideoCall:true]; + } else if (CallManager.instance.isInConference) { + [self displayAudioConference]; + } else { + [self displayAudioCall:true]; + _callPauseButton.hidden = NO; + _nameLabel.hidden = NO; + _durationLabel.hidden = NO; + _avatarImage.hidden = NO; + } + [_conferenceCallsTable update]; + _conferenceView.frame = CGRectMake(_conferenceView.frame.origin.x,_conferenceView.frame.origin.y,_conferenceView.frame.size.width,_conferenceCallsTable.tableView.frame.origin.y+[_conferenceCallsTable.tableView numberOfRowsInSection:0]*CONFERENCE_CELL_HEIGHT+10); + }); +} + +-(void) displayAudioConference { + _callPauseButton.hidden = true; + _nameLabel.hidden = true; + _conferenceView.frame = CGRectMake(_conferenceView.frame.origin.x,_conferenceView.frame.origin.y,_conferenceView.frame.size.width,_conferenceCallsTable.tableView.frame.origin.y+[_conferenceCallsTable.tableView numberOfRowsInSection:0]*CONFERENCE_CELL_HEIGHT+10); + _durationLabel.hidden = true; + _avatarImage.hidden = true; + + [_conferenceView removeFromSuperview]; + [_callView addSubview:_conferenceView]; + + if ([CallManager.instance isInConference]) { + [_conferenceView removeFromSuperview]; + [_callView addSubview:_conferenceView]; + _conferenceView.hidden = NO; + } else { + [_conferenceView removeFromSuperview]; + [self.view addSubview:_conferenceView]; + [self.view sendSubviewToBack:_conferenceView]; + } +} + + + +@end diff --git a/Classes/ChatConversationImdnView.h b/Classes/ChatConversationImdnView.h index 26607f58d..78a9042b6 100644 --- a/Classes/ChatConversationImdnView.h +++ b/Classes/ChatConversationImdnView.h @@ -24,7 +24,6 @@ #import "UICompositeView.h" #import "UIRoundBorderedButton.h" -#import "UIChatBubbleTextCell.h" @interface ChatConversationImdnView : UIViewController { diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h index 7d8fd00dc..7c76cb286 100644 --- a/Classes/ChatConversationView.h +++ b/Classes/ChatConversationView.h @@ -32,6 +32,7 @@ #import "UIImageViewDeletable.h" #import "UIConfirmationDialog.h" #import "UIInterfaceStyleButton.h" +#import "linphoneapp-Swift.h" #import "UIChatReplyBubbleView.h" #include "linphone/linphonecore.h" diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m index 6ae1f25b4..40e86856f 100644 --- a/Classes/ChatConversationView.m +++ b/Classes/ChatConversationView.m @@ -28,8 +28,6 @@ #import "SVProgressHUD.h" #import "EphemeralSettingsView.h" #import "Utils.h" -#import "linphoneapp-Swift.h" - @implementation FileContext @@ -1855,7 +1853,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:linphone_player_get_user_data(_sharedVoicePlayer)]}; [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerLostFocus object:nil userInfo:userInfo]; } - [AudioRouteUtils routeAudioToSpeaker]; + [CallManager.instance changeRouteToSpeaker]; linphone_player_set_user_data(_sharedVoicePlayer, (void *)path); linphone_player_open(_sharedVoicePlayer, path); linphone_player_start(_sharedVoicePlayer); diff --git a/Classes/Contact.m b/Classes/Contact.m index 03a7e4174..fd27e9078 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -120,7 +120,6 @@ return nil; } - - (NSString *)displayName { if (_friend) { const char *friend_name = linphone_friend_get_name(_friend); diff --git a/Classes/DevicesListView.m b/Classes/DevicesListView.m index 60e005dc9..4913b6173 100644 --- a/Classes/DevicesListView.m +++ b/Classes/DevicesListView.m @@ -20,8 +20,6 @@ #import "DevicesListView.h" #import "PhoneMainView.h" #import "UIDeviceCell.h" -#import "linphoneapp-Swift.h" - @implementation DevicesMenuEntry - (id)init:(LinphoneParticipantDevice *)dev isMe:(BOOL)isMe isFirst:(BOOL)first isUnique:(BOOL)unique index:(NSInteger)idx{ diff --git a/Classes/DialerView.m b/Classes/DialerView.m index d24f91ee2..df1a5d70f 100644 --- a/Classes/DialerView.m +++ b/Classes/DialerView.m @@ -21,7 +21,6 @@ #import "LinphoneManager.h" #import "PhoneMainView.h" -#import "linphoneapp-Swift.h" @implementation DialerView @@ -398,7 +397,7 @@ static UICompositeViewDescription *compositeDescription = nil; } - (IBAction)onBackClick:(id)event { - [PhoneMainView.instance popToView:ActiveCallOrConferenceView.compositeViewDescription]; + [PhoneMainView.instance popToView:CallView.compositeViewDescription]; } - (IBAction)onAddressChange:(id)sender { diff --git a/Classes/ImagePickerView.m b/Classes/ImagePickerView.m index d4e4cebb7..ab1850f74 100644 --- a/Classes/ImagePickerView.m +++ b/Classes/ImagePickerView.m @@ -301,83 +301,96 @@ static UICompositeViewDescription *compositeDescription = nil; inView:(UIView *)ipadView withDocumentMenuDelegate:(id)documentMenuDelegate { void (^block)(UIImagePickerControllerSourceType) = ^(UIImagePickerControllerSourceType type) { - ImagePickerView *view = VIEW(ImagePickerView); - view.sourceType = type; - - // Displays a control that allows the user to choose picture or - // movie capture, if both are available: - view.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeMovie,(NSString *)kUTTypeImage,nil]; - - // Hides the controls for moving & scaling pictures, or for - // trimming movies. To instead show the controls, use YES. - view.allowsEditing = NO; - view.imagePickerDelegate = delegate; - - if (IPAD && ipadView && ipadPopoverView) { - UIView *iterview = ipadPopoverView; - CGRect ipadPopoverPosition = iterview.frame; - do { - ipadPopoverPosition = - [iterview.superview convertRect:ipadPopoverPosition toView:iterview.superview.superview]; - iterview = iterview.superview; - } while (iterview && iterview.superview != ipadView); - [view.popoverController presentPopoverFromRect:ipadPopoverPosition - inView:ipadView - permittedArrowDirections:UIPopoverArrowDirectionAny - animated:FALSE]; - } else { - [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; - } + ImagePickerView *view = VIEW(ImagePickerView); + view.sourceType = type; + + // Displays a control that allows the user to choose picture or + // movie capture, if both are available: + view.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeMovie,(NSString *)kUTTypeImage,nil]; + + // Hides the controls for moving & scaling pictures, or for + // trimming movies. To instead show the controls, use YES. + view.allowsEditing = NO; + view.imagePickerDelegate = delegate; + + if (IPAD && ipadView && ipadPopoverView) { + UIView *iterview = ipadPopoverView; + CGRect ipadPopoverPosition = iterview.frame; + do { + ipadPopoverPosition = + [iterview.superview convertRect:ipadPopoverPosition toView:iterview.superview.superview]; + iterview = iterview.superview; + } while (iterview && iterview.superview != ipadView); + [view.popoverController presentPopoverFromRect:ipadPopoverPosition + inView:ipadView + permittedArrowDirections:UIPopoverArrowDirectionAny + animated:FALSE]; + } else { + [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; + } }; - DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Select the source", nil)]; - if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - [sheet addButtonWithTitle:NSLocalizedString(@"Camera", nil) - block:^() { - if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized ) { - [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Camera's permission", nil) message:NSLocalizedString(@"Camera not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show]; - return; - } - if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) - block(UIImagePickerControllerSourceTypeCamera); - else { - [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { - dispatch_async(dispatch_get_main_queue(), ^{ - if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { - block(UIImagePickerControllerSourceTypeCamera); - } else { - [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Ok", nil] show]; - } - }); - }]; - } - }]; - } - if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { - [sheet addButtonWithTitle:NSLocalizedString(@"Photo library", nil) - block:^() { - if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) - block(UIImagePickerControllerSourceTypePhotoLibrary); - else { - [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { - dispatch_async(dispatch_get_main_queue(), ^{ - if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { - block(UIImagePickerControllerSourceTypePhotoLibrary); - } else { - [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Ok", nil] show]; - } - }); - }]; - } - }]; - } - if (documentMenuDelegate) { - [sheet addButtonWithTitle:NSLocalizedString(@"Document",nil) block:^(){ - [self pickDocumentForDelegate:documentMenuDelegate]; - }]; - } - [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; - - [sheet showInView:PhoneMainView.instance.view]; + if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { + DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Select the source", nil)]; + if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { + [sheet addButtonWithTitle:NSLocalizedString(@"Camera", nil) + block:^() { + if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized ) { + [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Camera's permission", nil) message:NSLocalizedString(@"Camera not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show]; + return; + } + block(UIImagePickerControllerSourceTypeCamera); + }]; + } + if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { + [sheet addButtonWithTitle:NSLocalizedString(@"Photo library", nil) + block:^() { + block(UIImagePickerControllerSourceTypePhotoLibrary); + }]; + } + + if (documentMenuDelegate) { + [sheet addButtonWithTitle:NSLocalizedString(@"Document",nil) block:^(){ + [self pickDocumentForDelegate:documentMenuDelegate]; + }]; + } + [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; + + [sheet showInView:PhoneMainView.instance.view]; + } else { + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + dispatch_async(dispatch_get_main_queue(), ^{ + if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { + DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Select the source", nil)]; + if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { + [sheet addButtonWithTitle:NSLocalizedString(@"Camera", nil) + block:^() { + if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized ) { + [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Camera's permission", nil) message:NSLocalizedString(@"Camera not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show]; + return; + } + block(UIImagePickerControllerSourceTypeCamera); + }]; + } + if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { + [sheet addButtonWithTitle:NSLocalizedString(@"Photo library", nil) + block:^() { + block(UIImagePickerControllerSourceTypePhotoLibrary); + }]; + } + if (documentMenuDelegate) { + [sheet addButtonWithTitle:NSLocalizedString(@"Document",nil) block:^(){ + [self pickDocumentForDelegate:documentMenuDelegate]; + }]; + } + [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; + + [sheet showInView:PhoneMainView.instance.view]; + } else { + [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show]; + } + }); + }]; + } } +(void) pickDocumentForDelegate:(id)documentMenuDelegate { diff --git a/Classes/LinphoneAppDelegate.h b/Classes/LinphoneAppDelegate.h index 9a4768d11..d3820267b 100644 --- a/Classes/LinphoneAppDelegate.h +++ b/Classes/LinphoneAppDelegate.h @@ -23,6 +23,7 @@ #import #import #import +#import "linphoneapp-Swift.h" @interface LinphoneAppDelegate : NSObject { diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 1d4c152c3..be99479de 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -140,7 +140,7 @@ if ((floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max)) { if ([LinphoneManager.instance lpConfigBoolForKey:@"autoanswer_notif_preference"]) { linphone_call_accept(call); - [PhoneMainView.instance changeCurrentView:ActiveCallOrConferenceView.compositeViewDescription]; + [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; } else { [PhoneMainView.instance displayIncomingCall:call]; } @@ -321,8 +321,6 @@ return NO; } - VIEW(ActiveCallOrConferenceView); // to get created and all observers added - return YES; } @@ -411,9 +409,16 @@ } // used for callkit. Called when active video. -- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler { +- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler +{ - if ([userActivity.activityType isEqualToString:@"INStartAudioCallIntent"]||[userActivity.activityType isEqualToString:@"INStartVideoCallIntent"]) { // tel URI handler. + + if ([userActivity.activityType isEqualToString:@"INStartVideoCallIntent"]) { + LOGI(@"CallKit: satrt video."); + CallView *view = VIEW(CallView); + [view.videoButton setOn]; + } + if ([userActivity.activityType isEqualToString:@"INStartAudioCallIntent"]) { // tel URI handler. INInteraction *interaction = userActivity.interaction; INStartAudioCallIntent *startAudioCallIntent = (INStartAudioCallIntent *)interaction.intent; INPerson *contact = startAudioCallIntent.contacts[0]; @@ -532,7 +537,8 @@ if ([response.actionIdentifier isEqual:@"Answer"]) { // use the standard handler - [CallManager.instance acceptCallWithCall:call hasVideo:NO]; + [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; + linphone_call_accept(call); } else if ([response.actionIdentifier isEqual:@"Decline"]) { linphone_call_decline(call, LinphoneReasonDeclined); } else if ([response.actionIdentifier isEqual:@"Reply"]) { @@ -569,6 +575,7 @@ return; [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications]; + [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; [CallManager.instance acceptVideoWithCall:call confirm:TRUE]; } else if ([response.actionIdentifier isEqual:@"Confirm"]) { if (linphone_core_get_current_call(LC) == call) @@ -601,7 +608,7 @@ } } else if ([response.notification.request.content.categoryIdentifier isEqual:@"video_request"]) { if (!call) return; - [PhoneMainView.instance changeCurrentView:ActiveCallOrConferenceView.compositeViewDescription]; + [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; NSTimer *videoDismissTimer = nil; UIConfirmationDialog *sheet = [UIConfirmationDialog ShowWithMessage:response.notification.request.content.body cancelMessage:nil @@ -685,7 +692,8 @@ if ([notification.category isEqualToString:@"incoming_call"]) { if ([identifier isEqualToString:@"answer"]) { // use the standard handler - [CallManager.instance acceptCallWithCall:call hasVideo:NO]; + [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; + linphone_call_accept(call); } else if ([identifier isEqualToString:@"decline"]) { LinphoneCall *call = linphone_core_get_current_call(LC); if (call) @@ -722,7 +730,8 @@ if ([notification.category isEqualToString:@"incoming_call"]) { if ([identifier isEqualToString:@"answer"]) { // use the standard handler - [CallManager.instance acceptCallWithCall:call hasVideo:NO]; + [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; + linphone_call_accept(call); } else if ([identifier isEqualToString:@"decline"]) { LinphoneCall *call = linphone_core_get_current_call(LC); if (call) diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index d9a59ac84..a48f5f294 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -25,8 +25,6 @@ #include "linphone/lpconfig.h" #include #include -#import "linphoneapp-Swift.h" - @implementation LinphoneCoreSettingsStore diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index f0027fb6f..53be84967 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -35,6 +35,7 @@ #include "bctoolbox/list.h" #import "OrderedDictionary.h" +#import "linphoneapp-Swift.h" extern NSString *const LINPHONERC_APPLICATION_KEY; @@ -48,6 +49,7 @@ extern NSString *const kLinphoneMainViewChange; extern NSString *const kLinphoneAddressBookUpdate; extern NSString *const kLinphoneLogsUpdate; extern NSString *const kLinphoneSettingsUpdate; +extern NSString *const kLinphoneBluetoothAvailabilityUpdate; extern NSString *const kLinphoneConfiguringStateUpdate; extern NSString *const kLinphoneGlobalStateUpdate; extern NSString *const kLinphoneNotifyReceived; @@ -202,6 +204,7 @@ typedef struct _LinphoneManagerSounds { @property (readonly) sqlite3* database; @property (readonly) LinphoneManagerSounds sounds; @property (readonly) NSMutableArray *logs; +@property (nonatomic, assign) BOOL bluetoothAvailable; @property (readonly) NSString* contactSipField; @property (readonly,copy) NSString* contactFilter; @property (copy) void (^silentPushCompletion)(UIBackgroundFetchResult); diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 8cb934663..c980e5644 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -31,6 +31,7 @@ #import "LinphoneCoreSettingsStore.h" #import "LinphoneAppDelegate.h" #import "LinphoneManager.h" +#import "Utils/AudioHelper.h" #import "Utils/FileTransferDelegate.h" #include "linphone/factory.h" @@ -45,7 +46,6 @@ #import "ChatsListView.h" #import "ChatConversationView.h" #import -#import "linphoneapp-Swift.h" #define LINPHONE_LOGS_MAX_ENTRY 5000 @@ -233,7 +233,11 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre - (id)init { if ((self = [super init])) { - + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(audioRouteChangeListenerCallback:) + name:AVAudioSessionRouteChangeNotification + object:nil]; + NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"]; self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil]; @@ -1763,7 +1767,20 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { _configDb = linphone_config_new_for_shared_core(kLinphoneMsgNotificationAppGroupId.UTF8String, @"linphonerc".UTF8String, factory.UTF8String); linphone_config_clean_entry(_configDb, "misc", "max_calls"); } +#pragma mark - Audio route Functions +- (void)audioRouteChangeListenerCallback:(NSNotification *)notif { + if (IPAD) + return; + + _bluetoothAvailable = [CallManager.instance isBluetoothAvailable]; + + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:_bluetoothAvailable], @"available", nil]; + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneBluetoothAvailabilityUpdate + object:self + userInfo:dict]; + +} #pragma mark - Call Functions - (void)send:(NSString *)replyText toChatRoom:(LinphoneChatRoom *)room { @@ -2145,6 +2162,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { if ([ct currentCalls] != nil) { if (call) { LOGI(@"Pausing SIP call because GSM call"); + CallManager.instance.speakerBeforePause = [CallManager.instance isSpeakerEnabled]; linphone_call_pause(call); [self startCallPausedLongRunningTask]; } else if (linphone_core_is_in_conference(theLinphoneCore)) { diff --git a/Classes/LinphoneUI/Base.lproj/StatusBarView.xib b/Classes/LinphoneUI/Base.lproj/StatusBarView.xib index 341bcf9a8..0830037cb 100644 --- a/Classes/LinphoneUI/Base.lproj/StatusBarView.xib +++ b/Classes/LinphoneUI/Base.lproj/StatusBarView.xib @@ -1,10 +1,8 @@ - - - + + - - + @@ -23,15 +21,15 @@ - - + + - + + + + + + + + + + + + + + + diff --git a/Classes/LinphoneUI/Base.lproj/UICallPausedCell.xib b/Classes/LinphoneUI/Base.lproj/UICallPausedCell.xib new file mode 100644 index 000000000..423378a9e --- /dev/null +++ b/Classes/LinphoneUI/Base.lproj/UICallPausedCell.xib @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/LinphoneUI/UIBackToCallButton.m b/Classes/LinphoneUI/UIBackToCallButton.m index 3a272f5a8..60c9f4df4 100644 --- a/Classes/LinphoneUI/UIBackToCallButton.m +++ b/Classes/LinphoneUI/UIBackToCallButton.m @@ -20,7 +20,6 @@ #import "UIBackToCallButton.h" #import "LinphoneManager.h" #import "PhoneMainView.h" -#import "linphoneapp-Swift.h" @implementation UIBackToCallButton @@ -47,7 +46,7 @@ } - (IBAction)onBackToCallClick:(id)sender { - [PhoneMainView.instance popToView:ActiveCallOrConferenceView.compositeViewDescription]; + [PhoneMainView.instance popToView:CallView.compositeViewDescription]; } @end diff --git a/Classes/LinphoneUI/UIBluetoothButton.m b/Classes/LinphoneUI/UIBluetoothButton.m index f14af83b3..53abc1818 100644 --- a/Classes/LinphoneUI/UIBluetoothButton.m +++ b/Classes/LinphoneUI/UIBluetoothButton.m @@ -18,8 +18,10 @@ */ #import "UIBluetoothButton.h" +#import "../Utils/AudioHelper.h" #import "Utils.h" #import + #include "linphone/linphonecore.h" @implementation UIBluetoothButton diff --git a/Classes/LinphoneUI/UICallButton.m b/Classes/LinphoneUI/UICallButton.m index aa925fc22..c84a7dafd 100644 --- a/Classes/LinphoneUI/UICallButton.m +++ b/Classes/LinphoneUI/UICallButton.m @@ -21,8 +21,6 @@ #import "LinphoneManager.h" #import -#import "linphoneapp-Swift.h" - @implementation UICallButton diff --git a/Classes/LinphoneUI/UICallConferenceCell.h b/Classes/LinphoneUI/UICallConferenceCell.h new file mode 100644 index 000000000..cf59dfe3c --- /dev/null +++ b/Classes/LinphoneUI/UICallConferenceCell.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "UIRoundedImageView.h" +#import "LinphoneManager.h" +#import "UIInterfaceStyleButton.h" + +#define CONFERENCE_CELL_HEIGHT 60 + +@interface UICallConferenceCell : UITableViewCell + +@property(weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage; +@property(weak, nonatomic) IBOutlet UILabel *nameLabel; +@property(weak, nonatomic) IBOutlet UILabel *durationLabel; +@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *kickButton; +@property(nonatomic, setter=setParticipant:) LinphoneParticipant *participant; + +- (id)initWithIdentifier:(NSString *)identifier; +- (IBAction)onKickClick:(id)sender; + +@end diff --git a/Classes/LinphoneUI/UICallConferenceCell.m b/Classes/LinphoneUI/UICallConferenceCell.m new file mode 100644 index 000000000..0e64ca4b1 --- /dev/null +++ b/Classes/LinphoneUI/UICallConferenceCell.m @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "UICallConferenceCell.h" +#import "Utils.h" +#import "PhoneMainView.h" + +@implementation UICallConferenceCell + +- (id)initWithIdentifier:(NSString *)identifier { + self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; + if (self != nil) { + NSArray *arrayOfViews = + [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil]; + if ([arrayOfViews count] >= 1) { + // resize cell to match .nib size. It is needed when resized the cell to + // correctly adapt its height too + UIView *sub = ((UIView *)[arrayOfViews objectAtIndex:0]); + [self setFrame:CGRectMake(0, 0, sub.frame.size.width, sub.frame.size.height)]; + [self addSubview:sub]; + } + } + return self; +} + +- (void)setParticipant:(LinphoneParticipant *)p { + _participant = p; + if (!p) { + return; + } + const LinphoneAddress *addr = linphone_participant_get_address(p); + [ContactDisplay setDisplayNameLabel:_nameLabel forAddress:addr]; + _durationLabel.text = [LinphoneUtils durationToString:[NSDate date].timeIntervalSince1970 - linphone_participant_get_creation_time(p)]; + _kickButton.hidden = CallManager.instance.isInConferenceAsGuest; +} + + +- (IBAction)onKickClick:(id)sender { + if (!_participant) { + return; + } + + if ([CallManager callKitEnabled]) { + LinphoneCall *call = [CallManager.instance getCallForParticipant:_participant]; + if (call) { + [CallManager.instance setHeldWithCall:call hold:true]; + } + } + linphone_conference_remove_participant_2([CallManager.instance getConference], _participant); + + +} +@end diff --git a/Classes/SwiftUtil/Extensions/LinphoneCore/ConferenceExtensions.swift b/Classes/LinphoneUI/UICallPausedCell.h similarity index 58% rename from Classes/SwiftUtil/Extensions/LinphoneCore/ConferenceExtensions.swift rename to Classes/LinphoneUI/UICallPausedCell.h index 483f3bc16..77bdedd71 100644 --- a/Classes/SwiftUtil/Extensions/LinphoneCore/ConferenceExtensions.swift +++ b/Classes/LinphoneUI/UICallPausedCell.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2010-2020 Belledonne Communications SARL. * - * This file is part of linphone-iphone + * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,17 +17,18 @@ * along with this program. If not, see . */ -import Foundation -import linphonesw +#import "UIRoundedImageView.h" +#import "LinphoneManager.h" +#import "UIPauseButton.h" +@interface UICallPausedCell : UITableViewCell +@property(weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage; +@property(weak, nonatomic) IBOutlet UILabel *nameLabel; +@property(weak, nonatomic) IBOutlet UILabel *durationLabel; +@property(weak, nonatomic) IBOutlet UIPauseButton *pauseButton; -extension Conference : CustomStringConvertible { - public var description: String { - if let username = conferenceAddress?.username { - return "<\(username)>" - } - return "" - } -} +- (id)initWithIdentifier:(NSString *)identifier; +- (void)setCall:(LinphoneCall *)call; +@end diff --git a/Classes/LinphoneUI/UICallPausedCell.m b/Classes/LinphoneUI/UICallPausedCell.m new file mode 100644 index 000000000..fe51d9c5d --- /dev/null +++ b/Classes/LinphoneUI/UICallPausedCell.m @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "UICallPausedCell.h" +#import "Utils.h" + +@implementation UICallPausedCell + +- (id)initWithIdentifier:(NSString *)identifier { + self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; + if (self != nil) { + NSArray *arrayOfViews = + [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil]; + if ([arrayOfViews count] >= 1) { + // resize cell to match .nib size. It is needed when resized the cell to + // correctly adapt its height too + UIView *sub = ((UIView *)[arrayOfViews objectAtIndex:0]); + [self setFrame:CGRectMake(0, 0, sub.frame.size.width, sub.frame.size.height)]; + [self addSubview:sub]; + } + } + return self; +} + +- (void)setCall:(LinphoneCall *)call { + // if no call is provided, we assume that this is a conference + if (!call || linphone_call_get_conference(call)) { + [_pauseButton setType:UIPauseButtonType_Conference call:call]; + _nameLabel.text = NSLocalizedString(@"Conference", nil); + [_avatarImage setImage:[UIImage imageNamed:@"options_start_conference_default.png"] + bordered:NO + withRoundedRadius:YES]; + _durationLabel.text = @""; + } else { + [_pauseButton setType:UIPauseButtonType_Call call:call]; + const LinphoneAddress *addr = linphone_call_get_remote_address(call); + [ContactDisplay setDisplayNameLabel:_nameLabel forAddress:addr]; + [_avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:NO withRoundedRadius:YES]; + _durationLabel.text = [LinphoneUtils durationToString:linphone_call_get_duration(call)]; + } + [_pauseButton update]; +} + +@end diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index 01b13c93b..ccf47d7aa 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -25,8 +25,6 @@ #import #import #import -#import "linphoneapp-Swift.h" - #define voicePlayer VIEW(ChatConversationView).sharedVoicePlayer #define chatView VIEW(ChatConversationView) diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m index 079891029..4038ac799 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.m +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m @@ -25,8 +25,6 @@ #import #import #import -#import "linphoneapp-Swift.h" - @implementation UIChatBubbleTextCell diff --git a/Classes/Voip/Views/SharedLayoutConstants.swift b/Classes/LinphoneUI/UIHangUpButton.h similarity index 79% rename from Classes/Voip/Views/SharedLayoutConstants.swift rename to Classes/LinphoneUI/UIHangUpButton.h index 163d8ba07..784369828 100644 --- a/Classes/Voip/Views/SharedLayoutConstants.swift +++ b/Classes/LinphoneUI/UIHangUpButton.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2010-2020 Belledonne Communications SARL. * - * This file is part of linphone-iphone + * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,11 +17,13 @@ * along with this program. If not, see . */ +#import -import Foundation - -class SharedLayoutConstants { - static let buttons_bottom_margin = 15 - static let margin_call_view_side_controls_buttons = 12 +#import "UIIconButton.h" +@interface UIHangUpButton : UIIconButton { } + +- (void)update; + +@end diff --git a/Classes/LinphoneUI/UIHangUpButton.m b/Classes/LinphoneUI/UIHangUpButton.m new file mode 100644 index 000000000..6ab96297d --- /dev/null +++ b/Classes/LinphoneUI/UIHangUpButton.m @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "UIHangUpButton.h" +#import "LinphoneManager.h" + +#import "linphoneapp-Swift.h" + +@implementation UIHangUpButton + +#pragma mark - Static Functions + ++ (bool)isInConference:(LinphoneCall *)call { + if (!call) + return false; + return linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); +} + ++ (int)callCount { + int count = 0; + const MSList *calls = linphone_core_get_calls(LC); + + while (calls != 0) { + if (![UIHangUpButton isInConference:((LinphoneCall *)calls->data)]) { + count++; + } + calls = calls->next; + } + return count; +} + +#pragma mark - Lifecycle Functions + +- (void)initUIHangUpButton { + [self addTarget:self action:@selector(touchUp:) forControlEvents:UIControlEventTouchUpInside]; +} + +- (id)init { + self = [super init]; + if (self) { + [self initUIHangUpButton]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (self) { + [self initUIHangUpButton]; + } + return self; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self initUIHangUpButton]; + } + return self; +} + +#pragma mark - + +- (void)update { + if (linphone_core_get_calls_nb(LC) == 1 || // One call + linphone_core_get_current_call(LC) != NULL || // In call + linphone_core_is_in_conference(LC) || // In conference + (linphone_core_get_conference_size(LC) > 0 && [UIHangUpButton callCount] == 0) // Only one conf + ) { + [self setEnabled:true]; + return; + } + [self setEnabled:false]; +} + +#pragma mark - Action Functions + +- (void)touchUp:(id)sender { + LinphoneCall *currentcall = linphone_core_get_current_call(LC); + if (linphone_core_is_in_conference(LC) || // In conference + (linphone_core_get_conference_size(LC) > 0 && [UIHangUpButton callCount] == 0) // Only one conf + ) { + LinphoneManager.instance.conf = TRUE; + linphone_core_terminate_conference(LC); + } else if (currentcall != NULL) { + [CallManager.instance terminateCallWithCall:currentcall]; + } else { + const MSList *calls = linphone_core_get_calls(LC); + if (bctbx_list_size(calls) == 1) { // Only one call + [CallManager.instance terminateCallWithCall:(calls->data)]; + } + } +} + +@end diff --git a/Classes/SwiftUtil/Extensions/LinphoneCore/ParticipantExtensions.swift b/Classes/LinphoneUI/UIPauseButton.h similarity index 61% rename from Classes/SwiftUtil/Extensions/LinphoneCore/ParticipantExtensions.swift rename to Classes/LinphoneUI/UIPauseButton.h index 9b7b07652..0146c3174 100644 --- a/Classes/SwiftUtil/Extensions/LinphoneCore/ParticipantExtensions.swift +++ b/Classes/LinphoneUI/UIPauseButton.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2010-2020 Belledonne Communications SARL. * - * This file is part of linphone-iphone + * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,17 +17,22 @@ * along with this program. If not, see . */ -import Foundation -import linphonesw +#import "UIToggleButton.h" +#include "linphone/linphonecore.h" +typedef enum _UIPauseButtonType { + UIPauseButtonType_CurrentCall, + UIPauseButtonType_Call, + UIPauseButtonType_Conference +} UIPauseButtonType; -extension Participant : CustomStringConvertible { - public var description: String { - if let address = address?.asStringUriOnly() { - return "" - } - return "" - } +@interface UIPauseButton : UIToggleButton { + @private + UIPauseButtonType type; + LinphoneCall* call; } +- (void)setType:(UIPauseButtonType) type call:(LinphoneCall*)call; + +@end diff --git a/Classes/LinphoneUI/UIPauseButton.m b/Classes/LinphoneUI/UIPauseButton.m new file mode 100644 index 000000000..797e88675 --- /dev/null +++ b/Classes/LinphoneUI/UIPauseButton.m @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "UIPauseButton.h" +#import "LinphoneManager.h" +#import "Utils.h" + +@implementation UIPauseButton + +#pragma mark - Lifecycle Functions + +- (void)initUIPauseButton { + type = UIPauseButtonType_CurrentCall; +} + +- (id)init { + self = [super init]; + if (self) { + [self initUIPauseButton]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder { + self = [super initWithCoder:decoder]; + if (self) { + [self initUIPauseButton]; + } + return self; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self initUIPauseButton]; + } + return self; +} + +#pragma mark - Static Functions + ++ (bool)isInConference:(LinphoneCall *)call { + if (!call) + return false; + return linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); +} + ++ (LinphoneCall *)getCall { + LinphoneCall *currentCall = linphone_core_get_current_call(LC); + if (currentCall == nil && linphone_core_get_calls_nb(LC) == 1) { + currentCall = (LinphoneCall *)linphone_core_get_calls(LC)->data; + } + return currentCall; +} + +#pragma mark - + +- (void)setType:(UIPauseButtonType)atype call:(LinphoneCall *)acall { + type = atype; + call = acall; +} + +#pragma mark - UIToggleButtonDelegate Functions + +- (void)onOn { + switch (type) { + case UIPauseButtonType_Call: { + if (call != nil) { + if ([CallManager callKitEnabled]) { + [CallManager.instance setHeldWithCall:call hold:true]; + } else { + CallManager.instance.speakerBeforePause = [CallManager.instance isSpeakerEnabled]; + linphone_call_pause(call); + } + } else { + LOGW(@"Cannot toggle pause buttton, because no current call"); + } + break; + } + case UIPauseButtonType_Conference: { + linphone_core_leave_conference(CallManager.instance.getConference); + // Fake event + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; + break; + } + case UIPauseButtonType_CurrentCall: { + LinphoneCall *currentCall = [UIPauseButton getCall]; + if (currentCall != nil) { + if ([CallManager callKitEnabled]) { + [CallManager.instance setHeldWithCall:currentCall hold:true]; + } else { + CallManager.instance.speakerBeforePause = [CallManager.instance isSpeakerEnabled]; + linphone_call_pause(currentCall); + } + } else { + LOGW(@"Cannot toggle pause buttton, because no current call"); + } + break; + } + } +} + +- (void)onOff { + switch (type) { + case UIPauseButtonType_Call: { + if (call != nil) { + if ([CallManager callKitEnabled]) { + [CallManager.instance setHeldWithCall:call hold:false]; + } else { + linphone_call_resume(call); + } + } else { + LOGW(@"Cannot toggle pause buttton, because no current call"); + } + break; + } + case UIPauseButtonType_Conference: { + linphone_core_enter_conference(CallManager.instance.getConference); + // Fake event + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; + break; + } + case UIPauseButtonType_CurrentCall: { + LinphoneCall *currentCall = [UIPauseButton getCall]; + if ([CallManager callKitEnabled]) { + [CallManager.instance setHeldWithCall:currentCall hold:false]; + } else { + linphone_call_resume(currentCall); + } + break; + } + } +} + +- (bool)onUpdate { + bool ret = false; + LinphoneCall *c = call; + switch (type) { + case UIPauseButtonType_Conference: { + self.enabled = CallManager.instance.getConference && (linphone_conference_get_participant_count(CallManager.instance.getConference)> 0); + if (self.enabled) { + ret = (!CallManager.instance.isInConference); + } + break; + } + case UIPauseButtonType_CurrentCall: + c = [UIPauseButton getCall]; + case UIPauseButtonType_Call: { + if (c != nil) { + LinphoneCallState state = linphone_call_get_state(c); + ret = (state == LinphoneCallPaused || state == LinphoneCallPausing); + self.enabled = !linphone_core_sound_resources_locked(LC) && + (state == LinphoneCallPaused || state == LinphoneCallPausing || + state == LinphoneCallStreamsRunning); + } else { + self.enabled = FALSE; + } + break; + } + } + return ret; +} + +@end diff --git a/Classes/SwiftUtil/Extensions/LinphoneCore/PayloadType.swift b/Classes/LinphoneUI/UISpeakerButton.h similarity index 85% rename from Classes/SwiftUtil/Extensions/LinphoneCore/PayloadType.swift rename to Classes/LinphoneUI/UISpeakerButton.h index 197a8d733..34361634e 100644 --- a/Classes/SwiftUtil/Extensions/LinphoneCore/PayloadType.swift +++ b/Classes/LinphoneUI/UISpeakerButton.h @@ -17,11 +17,12 @@ * along with this program. If not, see . */ -import Foundation -import linphonesw -import linphone +#import + +#import "UIToggleButton.h" + +@interface UISpeakerButton : UIToggleButton { -extension linphonesw.PayloadType { - - } + +@end diff --git a/Classes/LinphoneUI/UISpeakerButton.m b/Classes/LinphoneUI/UISpeakerButton.m new file mode 100644 index 000000000..64c12d5b9 --- /dev/null +++ b/Classes/LinphoneUI/UISpeakerButton.m @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import +#import "UISpeakerButton.h" +#import "Utils.h" +#import "LinphoneManager.h" + +#include "linphone/linphonecore.h" + +@implementation UISpeakerButton + +INIT_WITH_COMMON_CF { + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(audioRouteChangeListenerCallback:) + name:AVAudioSessionRouteChangeNotification + object:nil]; + return self; +} + +- (void)onOn { + [CallManager.instance changeRouteToSpeaker]; +} + +- (void)onOff { + [CallManager.instance changeRouteToDefault]; +} + + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +#pragma mark - UIToggleButtonDelegate Functions + +- (void)audioRouteChangeListenerCallback:(NSNotification *)notif { + dispatch_async(dispatch_get_main_queue(), ^{ + [self update];}); +} + +- (bool)onUpdate { + return [CallManager.instance isSpeakerEnabled]; +} + +@end diff --git a/Classes/LinphoneUI/UIVideoButton.h b/Classes/LinphoneUI/UIVideoButton.h new file mode 100644 index 000000000..79def1378 --- /dev/null +++ b/Classes/LinphoneUI/UIVideoButton.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import + +#import "UIToggleButton.h" + +@interface UIVideoButton : UIToggleButton { +} + +@property(nonatomic, strong) IBOutlet UIActivityIndicatorView *waitView; + +@end diff --git a/Classes/LinphoneUI/UIVideoButton.m b/Classes/LinphoneUI/UIVideoButton.m new file mode 100644 index 000000000..af97c4295 --- /dev/null +++ b/Classes/LinphoneUI/UIVideoButton.m @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "UIVideoButton.h" +#include "LinphoneManager.h" +#import "Log.h" + +@implementation UIVideoButton { + BOOL last_update_state; +} + +@synthesize waitView; + +INIT_WITH_COMMON_CF { + last_update_state = FALSE; + return self; +} + +- (void)onOn { + + if (!linphone_core_video_display_enabled(LC)) + return; + + [self setEnabled:FALSE]; + [waitView startAnimating]; + + LinphoneCall *call = linphone_core_get_current_call(LC); + if (call) { + CallAppData *data = [CallManager getAppDataWithCall:call]; + data.videoRequested = TRUE;/* will be used later to notify user if video was not activated because of the linphone core*/ + [CallManager setAppDataWithCall:call appData:data]; + LinphoneCallParams *call_params = linphone_core_create_call_params(LC,call); + linphone_call_params_enable_video(call_params, TRUE); + linphone_call_update(call, call_params); + linphone_call_params_unref(call_params); + } else if (self.inAudioConf) { + LinphoneConferenceParams *cp = linphone_core_create_conference_params(LC); + linphone_conference_params_set_video_enabled(cp, true); + linphone_conference_update_params(linphone_core_get_conference(LC), cp); + } else { + LOGW(@"Cannot toggle video button, because no current call"); + } +} + +- (void)onOff { + + if (!linphone_core_video_display_enabled(LC)) + return; + [CallManager.instance changeRouteToDefault]; + //[CallManager.instance enableSpeakerWithEnable:FALSE]; + [self setEnabled:FALSE]; + [waitView startAnimating]; + + LinphoneCall *call = linphone_core_get_current_call(LC); + if (call) { + LinphoneCallParams *call_params = linphone_core_create_call_params(LC,call); + linphone_call_params_enable_video(call_params, FALSE); + linphone_core_update_call(LC, call, call_params); + linphone_call_params_unref(call_params); + } else if (self.inVideoConf) { + LinphoneConferenceParams *cp = linphone_core_create_conference_params(LC); + linphone_conference_params_set_video_enabled(cp, false); + linphone_conference_update_params(linphone_core_get_conference(LC), cp); + } else { + LOGW(@"Cannot toggle video button, because no current call or no video conference"); + } +} + +- (bool)onUpdate { + bool video_enabled = false; + LinphoneCall *currentCall = linphone_core_get_current_call(LC); + if (linphone_core_video_supported(LC)) { + if (self.inAudioConf || self.inVideoConf || (linphone_core_video_display_enabled(LC) && currentCall && !linphone_core_sound_resources_locked(LC) && + linphone_call_get_state(currentCall) == LinphoneCallStreamsRunning)){ + video_enabled = TRUE; + } + } + + [self setEnabled:video_enabled]; + if (last_update_state != video_enabled) + [waitView stopAnimating]; + if (video_enabled) { + video_enabled = self.inVideoConf || (currentCall && linphone_call_params_video_enabled(linphone_call_get_current_params(currentCall))); + } + last_update_state = video_enabled; + + return video_enabled; +} + +-(BOOL) inVideoConf { + return (linphone_core_is_in_conference(LC) && linphone_core_get_conference(LC) != nil && linphone_conference_params_is_video_enabled(linphone_conference_get_current_params(linphone_core_get_conference(LC)))); +} + +-(BOOL) inAudioConf { + return (linphone_core_is_in_conference(LC) && linphone_core_get_conference(LC) != nil && !linphone_conference_params_is_video_enabled(linphone_conference_get_current_params(linphone_core_get_conference(LC)))); +} + +@end diff --git a/Classes/LinphoneUI/fr.lproj/UICallConferenceCell.strings b/Classes/LinphoneUI/fr.lproj/UICallConferenceCell.strings new file mode 100644 index 000000000..629130fa2 Binary files /dev/null and b/Classes/LinphoneUI/fr.lproj/UICallConferenceCell.strings differ diff --git a/Classes/LinphoneUI/fr.lproj/UICallPausedCell.strings b/Classes/LinphoneUI/fr.lproj/UICallPausedCell.strings new file mode 100644 index 000000000..4d0eb9bb9 Binary files /dev/null and b/Classes/LinphoneUI/fr.lproj/UICallPausedCell.strings differ diff --git a/Classes/LinphoneUI/hu.lproj/UICallConferenceCell.strings b/Classes/LinphoneUI/hu.lproj/UICallConferenceCell.strings new file mode 100644 index 000000000..c90ef96ac Binary files /dev/null and b/Classes/LinphoneUI/hu.lproj/UICallConferenceCell.strings differ diff --git a/Classes/LinphoneUI/hu.lproj/UICallPausedCell.strings b/Classes/LinphoneUI/hu.lproj/UICallPausedCell.strings new file mode 100644 index 000000000..7e626165f Binary files /dev/null and b/Classes/LinphoneUI/hu.lproj/UICallPausedCell.strings differ diff --git a/Classes/Log.h b/Classes/Log.h index c838afa12..c2ee3d897 100644 --- a/Classes/Log.h +++ b/Classes/Log.h @@ -32,11 +32,6 @@ + (void)log:(OrtpLogLevel)severity file:(const char *)file line:(int)line format:(NSString *)format, ...; + (void)enableLogs:(OrtpLogLevel)level; + (void)directLog:(OrtpLogLevel)level text:(NSString *)text; -+ (void)d:(NSString *)text; -+ (void)i:(NSString *)text; -+ (void)w:(NSString *)text; -+ (void)e:(NSString *)text; -+ (void)f:(NSString *)text; void linphone_iphone_log_handler(const char *domain, OrtpLogLevel lev, const char *fmt, va_list args); @end diff --git a/Classes/PhoneMainView.h b/Classes/PhoneMainView.h index 672030668..adfe87b5a 100644 --- a/Classes/PhoneMainView.h +++ b/Classes/PhoneMainView.h @@ -27,6 +27,10 @@ #import "AboutView.h" #import "AssistantLinkView.h" #import "AssistantView.h" +#import "CallIncomingView.h" +#import "CallOutgoingView.h" +#import "CallSideMenuView.h" +#import "CallView.h" #import "ChatConversationCreateView.h" #import "ChatConversationInfoView.h" #import "ChatConversationImdnView.h" @@ -74,7 +78,7 @@ @end -@interface PhoneMainView : UIViewController { +@interface PhoneMainView : UIViewController { @private NSMutableArray *inhibitedEvents; } @@ -92,7 +96,6 @@ - (void)changeCurrentView:(UICompositeViewDescription *)view; - (UIViewController*)popCurrentView; -- (UIViewController *)popView:(UICompositeViewDescription *)view; - (UIViewController *)popToView:(UICompositeViewDescription *)currentView; - (void) setPreviousViewName:(NSString*)previous; - (NSString*) getPreviousViewName; diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index a45b51376..3d0ad4962 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -22,8 +22,6 @@ #import "LinphoneAppDelegate.h" #import "Log.h" #import "PhoneMainView.h" -#import "linphoneapp-Swift.h" - static RootViewManager *rootViewManagerInstance = nil; @@ -375,9 +373,7 @@ static RootViewManager *rootViewManagerInstance = nil; break; } case LinphoneCallOutgoingInit: { - OutgoingCallView *v = VIEW(OutgoingCallView); - [self changeCurrentView:OutgoingCallView.compositeViewDescription]; - [v setCallWithCall:call]; + [self changeCurrentView:CallOutgoingView.compositeViewDescription]; break; } case LinphoneCallPausedByRemote: @@ -385,12 +381,39 @@ static RootViewManager *rootViewManagerInstance = nil; if (![LinphoneManager.instance isCTCallCenterExist]) { /*only register CT call center CB for connected call*/ [LinphoneManager.instance setupGSMInteraction]; + [[UIDevice currentDevice] setProximityMonitoringEnabled:!([CallManager.instance isSpeakerEnabled] || [CallManager.instance isBluetoothEnabled])]; + } + break; + } + case LinphoneCallStreamsRunning: { + [self changeCurrentView:CallView.compositeViewDescription]; + break; + } + case LinphoneCallUpdatedByRemote: { + const LinphoneCallParams *current = linphone_call_get_current_params(call); + const LinphoneCallParams *remote = linphone_call_get_remote_params(call); + + if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote)) { + [self changeCurrentView:CallView.compositeViewDescription]; } break; } case LinphoneCallError: { [self displayCallError:call message:message]; } + case LinphoneCallEnd: { + const MSList *calls = linphone_core_get_calls(LC); + if (!calls || calls->data == call) { + while ((currentView == CallView.compositeViewDescription) || + (currentView == CallIncomingView.compositeViewDescription) || + (currentView == CallOutgoingView.compositeViewDescription)) { + [self popCurrentView]; + } + } else { + [self changeCurrentView:CallView.compositeViewDescription]; + } + break; + } case LinphoneCallEarlyUpdatedByRemote: case LinphoneCallEarlyUpdating: case LinphoneCallIdle: @@ -610,15 +633,6 @@ static RootViewManager *rootViewManagerInstance = nil; return [mainViewController getCurrentViewController]; } -- (UIViewController *)popView:(UICompositeViewDescription *)view { - NSMutableArray *viewStack = [RootViewManager instance].viewDescriptionStack; - while (viewStack.count > 0 && [[viewStack lastObject] equal:view]) { - [viewStack removeLastObject]; - } - return [self popToView:viewStack.lastObject ?: DialerView.compositeViewDescription]; -} - - - (void)changeCurrentView:(UICompositeViewDescription *)view { [self _changeCurrentView:view transition:nil animated:ANIMATED]; } @@ -750,10 +764,10 @@ static RootViewManager *rootViewManagerInstance = nil; [CallManager.instance acceptCallWithCall:call hasVideo:YES]; } else { AudioServicesPlaySystemSound(lm.sounds.vibrate); - IncomingCallView *view = VIEW(IncomingCallView); + CallIncomingView *view = VIEW(CallIncomingView); [self changeCurrentView:view.compositeViewDescription]; - [view setCallWithCall:call]; - //CDFIX [view setDelegate:self]; + [view setCall:call]; + [view setDelegate:self]; } } } diff --git a/Classes/ProviderDelegate.swift b/Classes/ProviderDelegate.swift index 5f4ecd512..c9eb1dbb1 100644 --- a/Classes/ProviderDelegate.swift +++ b/Classes/ProviderDelegate.swift @@ -99,7 +99,7 @@ class ProviderDelegate: NSObject { provider.reportNewIncomingCall(with: uuid, update: update) { error in if error == nil { if CallManager.instance().endCallkit { - let call = CallManager.instance().core?.getCallByCallid(callId: callId!) + let call = CallManager.instance().lc?.getCallByCallid(callId: callId!) if (call?.state == .PushIncomingReceived) { try? call?.terminate() } @@ -191,7 +191,7 @@ extension ProviderDelegate: CXProviderDelegate { CallManager.instance().backgroundContextCameraIsEnabled = call!.params?.videoEnabled ?? false call?.cameraEnabled = false // Disable camera while app is not on foreground } - CallManager.instance().core?.configureAudioSession() + CallManager.instance().lc?.configureAudioSession() CallManager.instance().acceptCall(call: call!, hasVideo: call!.params?.videoEnabled ?? false) action.fulfill() } @@ -206,8 +206,8 @@ extension ProviderDelegate: CXProviderDelegate { } do { - if (CallManager.instance().core?.isInConference ?? false && action.isOnHold) { - try CallManager.instance().core?.leaveConference() + if (CallManager.instance().lc?.isInConference ?? false && action.isOnHold) { + try CallManager.instance().lc?.leaveConference() Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: call-id: [\(String(describing: callId))] leaving conference") NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) return @@ -219,10 +219,11 @@ extension ProviderDelegate: CXProviderDelegate { if (call!.params?.localConferenceMode ?? false) { return } + CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled() try call!.pause() } else { - if (CallManager.instance().core?.conference != nil && CallManager.instance().core?.callsNb ?? 0 > 1) { - try CallManager.instance().core?.enterConference() + if (CallManager.instance().lc?.conference != nil && CallManager.instance().lc?.callsNb ?? 0 > 1) { + try CallManager.instance().lc?.enterConference() NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) } else { try call!.resume() @@ -251,7 +252,7 @@ extension ProviderDelegate: CXProviderDelegate { action.fail() } - CallManager.instance().core?.configureAudioSession() + CallManager.instance().lc?.configureAudioSession() try CallManager.instance().doCall(addr: addr!, isSas: callInfo?.sasEnabled ?? false) } catch { Log.directLog(BCTBX_LOG_ERROR, text: "CallKit: Call started failed because \(error)") @@ -262,7 +263,7 @@ extension ProviderDelegate: CXProviderDelegate { func provider(_ provider: CXProvider, perform action: CXSetGroupCallAction) { Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: Call grouped callUUid : \(action.callUUID) with callUUID: \(String(describing: action.callUUIDToGroupWith)).") - CallManager.instance().addAllToLocalConference() + CallManager.instance().addAllToConference() action.fulfill() } @@ -270,7 +271,7 @@ extension ProviderDelegate: CXProviderDelegate { let uuid = action.callUUID let callId = callInfos[uuid]?.callId Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: Call muted with call-id: \(String(describing: callId)) an UUID: \(uuid.description).") - CallManager.instance().core!.micEnabled = !CallManager.instance().core!.micEnabled + CallManager.instance().lc!.micEnabled = !CallManager.instance().lc!.micEnabled action.fulfill() } @@ -303,12 +304,12 @@ extension ProviderDelegate: CXProviderDelegate { func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: audio session activated.") - CallManager.instance().core?.activateAudioSession(actived: true) + CallManager.instance().lc?.activateAudioSession(actived: true) } func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: audio session deactivated.") - CallManager.instance().core?.activateAudioSession(actived: false) + CallManager.instance().lc?.activateAudioSession(actived: false) } } diff --git a/Classes/SwiftUtil/Extensions/IOS/UIApplication+Extension.swift b/Classes/SwiftUtil/Extensions/IOS/UIApplication+Extension.swift deleted file mode 100644 index 50f5e9353..000000000 --- a/Classes/SwiftUtil/Extensions/IOS/UIApplication+Extension.swift +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2010-2020 Belledonne Communications SARL. -* -* This file is part of linhome -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - - - -import Foundation -import UIKit - - -extension UIApplication { - - class func getTopMostViewController() -> UIViewController? { - let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first - if var topController = keyWindow?.rootViewController { - while let presentedViewController = topController.presentedViewController { - topController = presentedViewController - } - return topController - } else { - return nil - } - } -} diff --git a/Classes/SwiftUtil/Extensions/IOS/UIColorExtensions.swift b/Classes/SwiftUtil/Extensions/IOS/UIColorExtensions.swift deleted file mode 100644 index 2d4b8efc9..000000000 --- a/Classes/SwiftUtil/Extensions/IOS/UIColorExtensions.swift +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation - -extension UIColor { - public convenience init(hex: String) { - let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) - var int = UInt64() - Scanner(string: hex).scanHexInt64(&int) - let a, r, g, b: UInt64 - switch hex.count { - case 3: // RGB (12-bit) - (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) - case 6: // RGB (24-bit) - (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) - case 8: // ARGB (32-bit) - (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) - default: - (a, r, g, b) = (255, 0, 0, 0) - } - self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) - } -} diff --git a/Classes/SwiftUtil/Extensions/IOS/UIDeviceExtensions.swift b/Classes/SwiftUtil/Extensions/IOS/UIDeviceExtensions.swift deleted file mode 100644 index fa00d6236..000000000 --- a/Classes/SwiftUtil/Extensions/IOS/UIDeviceExtensions.swift +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Copyright (c) 2010-2020 Belledonne Communications SARL. -* -* This file is part of linhome -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - - - -import Foundation -import UIKit -import AVFoundation - -extension UIDevice { - static func ipad() -> Bool { - return UIDevice.current.userInterfaceIdiom == .pad - } - static func vibrate() { - if (!ipad()) { - AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) - } - } - static func is5SorSEGen1() -> Bool { - return UIScreen.main.nativeBounds.height == 1136 - } - - static func hasNotch() -> Bool { - if (UserDefaults.standard.bool(forKey: "hasNotch")) { - return true - } - guard #available(iOS 11.0, *), let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, topPadding > 24 else { - return false - } - UserDefaults.standard.setValue(true, forKey: "hasNotch") - return true - } - - static func notchHeight() -> CGFloat { - guard #available(iOS 11.0, *), let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top else { - return 0 - } - return topPadding - } - -} diff --git a/Classes/SwiftUtil/Extensions/IOS/UIImageExtensions.swift b/Classes/SwiftUtil/Extensions/IOS/UIImageExtensions.swift deleted file mode 100644 index a409d782a..000000000 --- a/Classes/SwiftUtil/Extensions/IOS/UIImageExtensions.swift +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation - -extension UIImage { - func tinted(with color: UIColor?) -> UIImage? { - if (color == nil) { - return self - } - defer { UIGraphicsEndImageContext() } - UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) - color!.set() - self.withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: .zero, size: self.size)) - return UIGraphicsGetImageFromCurrentImageContext() - } - - func withInsets(insets: UIEdgeInsets) -> UIImage? { - UIGraphicsBeginImageContextWithOptions( - CGSize(width: self.size.width + insets.left + insets.right, - height: self.size.height + insets.top + insets.bottom), false, self.scale) - let _ = UIGraphicsGetCurrentContext() - let origin = CGPoint(x: insets.left, y: insets.top) - self.draw(at: origin) - let imageWithInsets = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - return imageWithInsets - } - - func withPadding(padding: CGFloat) -> UIImage? { - let insets = UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding) - return withInsets(insets: insets) - } -} diff --git a/Classes/SwiftUtil/Extensions/IOS/UIVIewExtensions.swift b/Classes/SwiftUtil/Extensions/IOS/UIVIewExtensions.swift deleted file mode 100644 index 7e99f532f..000000000 --- a/Classes/SwiftUtil/Extensions/IOS/UIVIewExtensions.swift +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import SnapKit -import UIKit - -extension UIView { - - // Few constraints wrapper to abstract SnapKit functions - - func removeConstraints() -> UIView { - snp.removeConstraints() - return self - } - - func square(_ size:Int) -> UIView { - snp.makeConstraints { (make) in - make.width.equalTo(size) - make.height.equalTo(size) - } - return self - } - - func size(w:CGFloat,h:CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.width.equalTo(w) - make.height.equalTo(h) - } - return self - } - - func height(_ h:CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.height.equalTo(h) - } - return self - } - - func height(_ h:Int) -> UIView { - return height(CGFloat(h)) - } - - func width(_ h:CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.width.equalTo(h) - } - return self - } - - func width(_ h:Int) -> UIView { - return width(CGFloat(h)) - } - - func maxHeight(_ h:CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.height.lessThanOrEqualTo(h) - } - return self - } - - func minWidth(_ h:CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.width.greaterThanOrEqualTo(h) - } - return self - } - - - func matchParentSideBorders(insetedByDx:CGFloat = 0) -> UIView { - snp.makeConstraints { (make) in - make.left.equalToSuperview().offset(insetedByDx) - make.right.equalToSuperview().offset(-insetedByDx) - } - return self - } - - func matchParentDimmensions() -> UIView { - snp.makeConstraints { (make) in - make.left.right.top.bottom.equalToSuperview() - } - return self - } - - func matchDimentionsOf(view:UIView) -> UIView { - snp.makeConstraints { (make) in - make.left.right.top.bottom.equalTo(view) - } - return self - } - - func matchParentHeight() -> UIView { - snp.makeConstraints { (make) in - make.top.bottom.equalToSuperview() - } - return self - } - - func matchParentHeightDividedBy(_ divider : CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.height.equalToSuperview().dividedBy(divider) - } - return self - } - - func matchParentWidthDividedBy(_ divider : CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.width.equalToSuperview().dividedBy(divider) - } - return self - } - - func center() -> UIView { - snp.makeConstraints { (make) in - make.center.equalToSuperview() - } - return self - } - - func alignParentTop(withMargin:CGFloat = 0.0) -> UIView { - snp.makeConstraints { (make) in - make.top.equalToSuperview().offset(withMargin) - } - return self - } - - func alignParentTop(withMargin:Int ) -> UIView { - return alignParentTop(withMargin:CGFloat(withMargin)) - } - - - func alignUnder(view:UIView, withMargin:CGFloat = 0.0) -> UIView { - snp.makeConstraints { (make) in - make.top.equalTo(view.snp.bottom).offset(withMargin) - } - return self - } - func alignUnder(view:UIView, withMargin:Int) -> UIView { - return alignUnder(view: view,withMargin:CGFloat(withMargin)) - } - - func matchRightOf(view:UIView, withMargin:CGFloat = 0) -> UIView { - snp.makeConstraints { (make) in - make.right.equalTo(view).offset(withMargin) - } - return self - } - - func updateAlignUnder(view:UIView, withMargin:CGFloat = 0.0) -> UIView { - snp.updateConstraints { (make) in - make.top.equalTo(view.snp.bottom).offset(withMargin) - } - return self - } - - func alignParentBottom(withMargin:CGFloat = 0.0) -> UIView { - snp.makeConstraints { (make) in - make.bottom.equalToSuperview().offset(-withMargin) - } - return self - } - - func alignParentBottom(withMargin:Int) -> UIView { - return alignParentBottom(withMargin:CGFloat(withMargin)) - } - - func alignAbove(view:UIView, withMargin:CGFloat = 0.0) -> UIView { - snp.makeConstraints { (make) in - make.bottom.equalTo(view.snp.top).offset(-withMargin) - } - return self - } - - func alignAbove(view:UIView, withMargin:Int) -> UIView { - return alignAbove(view: view,withMargin:CGFloat(withMargin)) - } - - func alignBottomWith(otherView:UIView) -> UIView { - snp.makeConstraints { (make) in - make.bottom.equalTo(otherView) - } - return self - } - - func marginLeft(_ m:CGFloat) -> UIView { - snp.makeConstraints { (make) in - make.left.equalToSuperview().offset(m) - } - return self - } - - func alignParentLeft(withMargin:CGFloat = 0.0) -> UIView { - snp.makeConstraints { (make) in - make.left.equalToSuperview().offset(withMargin) - } - return self - } - - func alignParentLeft(withMargin:Int) -> UIView { - return alignParentLeft(withMargin:CGFloat(withMargin)) - } - - func alignParentRight(withMargin:Int = 0) -> UIView { - snp.makeConstraints { (make) in - make.right.equalToSuperview().offset(-withMargin) - } - return self - } - - func alignParentRight(withMargin:CGFloat) -> UIView { - return alignParentRight(withMargin:Int(withMargin)) - } - - - func toRightOf(_ view:UIView, withLeftMargin:Int = 0) -> UIView { - snp.makeConstraints { (make) in - make.left.equalTo(view.snp.right).offset(withLeftMargin) - } - return self - } - - func toRightOf(_ view:UIView, withLeftMargin:CGFloat) -> UIView { - return toRightOf(view,withLeftMargin: Int(withLeftMargin)) - } - - func toLeftOf(_ view:UIView) -> UIView { - snp.makeConstraints { (make) in - make.right.equalTo(view.snp.left) - } - return self - } - - - func centerX(withDx:Int = 0) -> UIView { - snp.makeConstraints { (make) in - make.centerX.equalToSuperview().offset(withDx) - } - return self - } - - func centerY(withDy:Int = 0) -> UIView { - snp.makeConstraints { (make) in - make.centerY.equalToSuperview().offset(withDy) - } - return self - } - - func matchCenterXOf(view:UIView, withDx:Int = 0) -> UIView { - snp.makeConstraints { (make) in - make.centerX.equalTo(view).offset(withDx) - } - return self - } - - func matchCenterYOf(view:UIView, withDy:Int = 0) -> UIView { - snp.makeConstraints { (make) in - make.centerY.equalTo(view).offset(withDy) - } - return self - } - - func wrapContentY() -> UIView { - subviews.first?.snp.makeConstraints({ make in - make.top.equalToSuperview() - }) - subviews.last?.snp.makeConstraints({ make in - make.bottom.equalToSuperview() - }) - return self - } - - func wrapContentX() -> UIView { - subviews.first?.snp.makeConstraints({ make in - make.left.equalToSuperview() - }) - subviews.last?.snp.makeConstraints({ make in - make.right.equalToSuperview() - }) - return self - } - - func done() { - // to avoid the unused variable warning - } - - // Onclick - - class TapGestureRecognizer: UITapGestureRecognizer { - var action : (()->Void)? = nil - } - - func onClick(action : @escaping ()->Void ){ - let tap = TapGestureRecognizer(target: self , action: #selector(self.handleTap(_:))) - tap.action = action - tap.numberOfTapsRequired = 1 - tap.cancelsTouchesInView = false - - self.addGestureRecognizer(tap) - self.isUserInteractionEnabled = true - - } - @objc func handleTap(_ sender: TapGestureRecognizer) { - sender.action!() - } - - func VIEW( _ desc: UICompositeViewDescription) -> T{ - return PhoneMainView.instance().mainViewController.getCachedController(desc.name) as! T - } - -} diff --git a/Classes/SwiftUtil/Extensions/LinphoneCore/AddressExtensions.swift b/Classes/SwiftUtil/Extensions/LinphoneCore/AddressExtensions.swift deleted file mode 100644 index 39bd741f8..000000000 --- a/Classes/SwiftUtil/Extensions/LinphoneCore/AddressExtensions.swift +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -extension Address { - - func initials() -> String? { - var initials = initials(displayName: addressBookEnhancedDisplayName()) - if (initials == nil || initials!.isEmpty) { - initials = String(username.prefix(1)) - } - return initials - } - - private func initials(displayName: String?) -> String? { // Basic ImproveMe - return displayName?.components(separatedBy: " ") - .reduce("") { - ($0.isEmpty ? "" : "\($0.first?.uppercased() ?? "")") + - ($1.isEmpty ? "" : "\($1.first?.uppercased() ?? "")") - } - } - - func addressBookEnhancedDisplayName() -> String? { - if let contact = FastAddressBook.getContactWith(getCobject) { - return contact.displayName - } else if (!displayName.isEmpty) { - return displayName - } else { - return username - } - } - - func contact() -> Contact? { - return FastAddressBook.getContactWith(getCobject) - } - -} diff --git a/Classes/SwiftUtil/Extensions/LinphoneCore/CallExtensions.swift b/Classes/SwiftUtil/Extensions/LinphoneCore/CallExtensions.swift deleted file mode 100644 index 197f48fbc..000000000 --- a/Classes/SwiftUtil/Extensions/LinphoneCore/CallExtensions.swift +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -extension Call { - func answerVideoUpdateRequest(accept:Bool) { - guard let params = try?core? .createCallParams(call: self) else { - Log.i("[Call] \(self) unable to answerVideoUpdateRequest : could not create params ") - return - } - if (accept) { - params.videoEnabled = true - core?.videoCaptureEnabled = true - core?.videoDisplayEnabled = true - } else { - params.videoEnabled = false - } - try?acceptUpdate(params: params) - } -} - -extension Call : CustomStringConvertible { - public var description: String { - if let callId = callLog?.callId { - return "" - } - return "" - } -} - diff --git a/Classes/SwiftUtil/Extensions/LinphoneCore/CoreExtensions.swift b/Classes/SwiftUtil/Extensions/LinphoneCore/CoreExtensions.swift deleted file mode 100644 index ee0c99edb..000000000 --- a/Classes/SwiftUtil/Extensions/LinphoneCore/CoreExtensions.swift +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -extension Core { - static func get() -> Core { - return CallManager.instance().core! - } - - func showSwitchCameraButton() -> Bool { - return videoDevicesList.count > 2 // Count StaticImage camera - } - - func toggleCamera() { - Log.i("[Core] Current camera device is \(videoDevice)") - - videoDevicesList.forEach { - if ($0 != videoDevice && $0 != "StaticImage: Static picture") { - Log.i("[Core] New camera device will be \($0)") - try?setVideodevice(newValue: $0) - return - } - } - - let inConference = conference != nil && conference!.isIn - if !inConference, let call = currentCall { - try?call.update(params: nil) - } - } -} diff --git a/Classes/SwiftUtil/Extensions/LinphoneCore/IceState.swift b/Classes/SwiftUtil/Extensions/LinphoneCore/IceState.swift deleted file mode 100644 index 7274e2f7e..000000000 --- a/Classes/SwiftUtil/Extensions/LinphoneCore/IceState.swift +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -extension IceState { - func toString()->String { - switch (self) { - case .NotActivated: return NSLocalizedString("Not activated", tableName:"ICE has not been activated for this call",comment : "") - case .Failed: return NSLocalizedString("Failed", tableName:"ICE processing has failed",comment :"") - case .InProgress: return NSLocalizedString("In progress", tableName:"ICE process is in progress",comment :"") - case .HostConnection: return NSLocalizedString("Direct connection", tableName:"ICE has established a direct connection to the remote host",comment :"") - case .ReflexiveConnection: return NSLocalizedString( "NAT(s) connection", tableName:"ICE has established a connection to the remote host through one or several NATs",comment :"") - case .RelayConnection: return NSLocalizedString("Relay connection", tableName:"ICE has established a connection through a relay",comment :"") - } - - } -} diff --git a/Classes/SwiftUtil/ViewModel/MutableLiveData.swift b/Classes/SwiftUtil/ViewModel/MutableLiveData.swift deleted file mode 100644 index 125939785..000000000 --- a/Classes/SwiftUtil/ViewModel/MutableLiveData.swift +++ /dev/null @@ -1,138 +0,0 @@ -/* -* Copyright (c) 2010-2020 Belledonne Communications SARL. -* -* This file is part of linhome -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - - -import Foundation - - -class MutableLiveDataOnChangeClosure: NSObject { - let value: (Type?) -> Void - let onlyOnce: Bool - init(_ function: @escaping (Type?) -> Void, onlyOnce:Bool = false) { - value = function - self.onlyOnce = onlyOnce - } -} - -class MutableLiveData { - - private var _value : T? = nil - private var observers = [MutableLiveDataOnChangeClosure] () - private var _opposite : MutableLiveData? = nil - - init(_ initial:T) { - self.value = initial - } - - init() { - } - - var value : T? { - get { - return self._value - } - set { - self._value = newValue - self.notifyAllObservers(with: newValue) - } - } - - - func addObserver(observer: MutableLiveDataOnChangeClosure, andNotifyOnce: Bool = false) { - observers.append(observer) - if (andNotifyOnce) { - notifyValue() - } - } - - func removeObserver(observer: MutableLiveDataOnChangeClosure) { - observers = observers.filter({$0 !== observer}) - } - - - func clearObservers() { - observers.forEach { - removeObserver(observer: $0) - } - } - - - func notifyAllObservers(with newValue: T?) { - for observer in observers { - observer.value(newValue) - if (observer.onlyOnce) { - removeObserver(observer: observer) - } - } - } - - func notifyValue() { - for observer in observers { - observer.value(value) - if (observer.onlyOnce) { - removeObserver(observer: observer) - } - } - } - - func observe(onChange : @escaping (T?)->Void) { - let observer = MutableLiveDataOnChangeClosure({ value in - onChange(value) - }, onlyOnce: false) - addObserver(observer: observer) - } - - func readCurrentAndObserve(onChange : @escaping (T?)->Void) { - let observer = MutableLiveDataOnChangeClosure({ value in - onChange(value) - }, onlyOnce: false) - addObserver(observer: observer) - observer.value(value) - } - - func observeAsUniqueObserver (onChange : @escaping (T?)->Void, unique: Bool = false) { - let observer = MutableLiveDataOnChangeClosure({ value in - onChange(value) - }, onlyOnce: false) - if (unique) { - clearObservers() - } - addObserver(observer: observer) - } - - func observeOnce(onChange : @escaping (T?)->Void) { - let observer = MutableLiveDataOnChangeClosure({ value in - onChange(value) - }, onlyOnce: true) - addObserver(observer: observer) - } - - func opposite() -> MutableLiveData? { - if (_opposite != nil) { - return _opposite - } - _opposite = MutableLiveData(!(value! as! Bool)) - observe { (value) in - self._opposite!.value = !(value! as! Bool) - } - return _opposite - } - - -} diff --git a/Classes/Voip/Theme/ButtonTheme.swift b/Classes/Utils/AudioHelper.h similarity index 60% rename from Classes/Voip/Theme/ButtonTheme.swift rename to Classes/Utils/AudioHelper.h index 88b8306bb..fdf2845b1 100644 --- a/Classes/Voip/Theme/ButtonTheme.swift +++ b/Classes/Utils/AudioHelper.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2010-2020 Belledonne Communications SARL. * - * This file is part of linphone-iphone + * This file is part of linphone-iphone * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,17 +17,20 @@ * along with this program. If not, see . */ +#ifndef AudioHelper_h +#define AudioHelper_h -import Foundation -import UIKit +#import +@import AVFoundation; -struct ButtonTheme { - var tintableStateIcons: [UInt: TintableIcon] // State indexed - var backgroundStateColors: [UInt: LightDarkColor] // State indexed -} +@interface AudioHelper : NSObject -struct TintableIcon { - var name:String - var tintColor: LightDarkColor? = nil -} ++ (NSArray *)bluetoothRoutes; ++ (AVAudioSessionPortDescription *)bluetoothAudioDevice; ++ (AVAudioSessionPortDescription *)builtinAudioDevice; ++ (AVAudioSessionPortDescription *)speakerAudioDevice; ++ (AVAudioSessionPortDescription *)audioDeviceFromTypes:(NSArray *)types; +@end + +#endif /* AudioHelper_h */ diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m index 413c6c0b5..0738c54b4 100644 --- a/Classes/Utils/FileTransferDelegate.m +++ b/Classes/Utils/FileTransferDelegate.m @@ -21,8 +21,6 @@ #import "LinphoneManager.h" #import "PhoneMainView.h" #import "Utils.h" -#import "linphoneapp-Swift.h" - @interface FileTransferDelegate () @property(strong) NSMutableData *data; diff --git a/Classes/Utils/Log.m b/Classes/Utils/Log.m index 9c0b29c96..c7fe474c8 100644 --- a/Classes/Utils/Log.m +++ b/Classes/Utils/Log.m @@ -67,24 +67,6 @@ bctbx_log(BCTBX_LOG_DOMAIN, level, "%s", [text cStringUsingEncoding:NSUTF8StringEncoding]); } - -+(void)d:(NSString *)text { - [Log directLog:BCTBX_LOG_DEBUG text:text]; -} -+(void)i:(NSString *)text { - [Log directLog:BCTBX_LOG_MESSAGE text:text]; -} -+(void)w:(NSString *)text { - [Log directLog:BCTBX_LOG_WARNING text:text]; -} -+(void)e:(NSString *)text { - [Log directLog:BCTBX_LOG_ERROR text:text]; -} -+(void)f:(NSString *)text { - [Log directLog:BCTBX_LOG_FATAL text:text]; -} - - #pragma mark - Logs Functions callbacks void linphone_iphone_log_handler(const char *domain, OrtpLogLevel lev, const char *fmt, va_list args) { diff --git a/Classes/Voip/AudioRouteUtils.swift b/Classes/Voip/AudioRouteUtils.swift deleted file mode 100644 index 94a26f71e..000000000 --- a/Classes/Voip/AudioRouteUtils.swift +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2010-2021 Belledonne Communications SARL. - * - * This file is part of linphone-android - * (see https://www.linphone.org). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import AVFoundation -import linphonesw - -@objc class AudioRouteUtils : NSObject { - - static let core = Core.get() - - static private func applyAudioRouteChange( call: Call?, types: [AudioDeviceType], output: Bool = true) { - let typesNames = types.map { String(describing: $0) }.joined(separator: "/") - - let currentCall = core.callsNb > 0 ? (call != nil) ? call : core.currentCall != nil ? core.currentCall : core.calls[0] : nil - if (currentCall == nil) { - Log.w("[Audio Route Helper] No call found, setting audio route on Core") - } - let conference = core.conference - let capability = output ? AudioDeviceCapabilities.CapabilityPlay : AudioDeviceCapabilities.CapabilityRecord - - var found = false - - core.audioDevices.forEach { (audioDevice) in - Log.i("[Audio Route Helper] cdes [\(audioDevice.deviceName)] [\(audioDevice.type)] [\(audioDevice.capabilities)] ") - } - - core.audioDevices.forEach { (audioDevice) in - if (!found && types.contains(audioDevice.type) && audioDevice.hasCapability(capability: capability)) { - if (conference != nil && conference?.isIn == true) { - Log.i("[Audio Route Helper] Found [\(audioDevice.type)] \(output ? "playback" : "recorder") audio device [\(audioDevice.deviceName)], routing conference audio to it") - if (output) { - conference?.outputAudioDevice = audioDevice - } else { - conference?.inputAudioDevice = audioDevice - } - } else if (currentCall != nil) { - Log.i("[Audio Route Helper] Found [\(audioDevice.type)] \(output ? "playback" : "recorder") audio device [\(audioDevice.deviceName)], routing call audio to it") - if (output) { - currentCall?.outputAudioDevice = audioDevice - } - else { - currentCall?.inputAudioDevice = audioDevice - } - } else { - Log.i("[Audio Route Helper] Found [\(audioDevice.type)] \(output ? "playback" : "recorder") audio device [\(audioDevice.deviceName)], changing core default audio device") - if (output) { - core.outputAudioDevice = audioDevice - } else { - core.inputAudioDevice = audioDevice - } - } - found = true - } - } - if (!found) { - Log.e("[Audio Route Helper] Couldn't find \(typesNames) audio device") - } - } - - static private func changeCaptureDeviceToMatchAudioRoute(call: Call?, types: [AudioDeviceType]) { - switch (types.first) { - case .Bluetooth :if (isBluetoothAudioRecorderAvailable()) { - Log.i("[Audio Route Helper] Bluetooth device is able to record audio, also change input audio device") - applyAudioRouteChange(call: call, types: [AudioDeviceType.Bluetooth], output: false) - } - case .Headset, .Headphones : if (isHeadsetAudioRecorderAvailable()) { - Log.i("[Audio Route Helper] Headphones/headset device is able to record audio, also change input audio device") - applyAudioRouteChange(call:call,types: [AudioDeviceType.Headphones, AudioDeviceType.Headset], output:false) - } - default: break - } - } - - static private func routeAudioTo( call: Call?, types: [AudioDeviceType]) { - let currentCall = call != nil ? call : core.currentCall != nil ? core.currentCall : core.calls[0] - if (call != nil || currentCall != nil) { - let callToUse = call != nil ? call : currentCall - applyAudioRouteChange(call: callToUse, types: types) - changeCaptureDeviceToMatchAudioRoute(call: callToUse, types: types) - } else { - applyAudioRouteChange(call: call, types: types) - changeCaptureDeviceToMatchAudioRoute(call: call, types: types) - } - } - - static func routeAudioToEarpiece(call: Call? = nil) { - routeAudioTo(call: call, types: [AudioDeviceType.Microphone]) // on iOS Earpiece = Microphone - } - - static func routeAudioToSpeaker(call: Call? = nil) { - routeAudioTo(call: call, types: [AudioDeviceType.Speaker]) - } - - @objc static func routeAudioToSpeaker() { - routeAudioTo(call: nil, types: [AudioDeviceType.Speaker]) - } - - static func routeAudioToBluetooth(call: Call? = nil) { - routeAudioTo(call: call, types: [AudioDeviceType.Bluetooth]) - } - - static func routeAudioToHeadset(call: Call? = nil) { - routeAudioTo(call: call, types: [AudioDeviceType.Headphones, AudioDeviceType.Headset]) - } - - static func isSpeakerAudioRouteCurrentlyUsed(call: Call? = nil) -> Bool { - - let currentCall = core.callsNb > 0 ? (call != nil) ? call : core.currentCall != nil ? core.currentCall : core.calls[0] : nil - if (currentCall == nil) { - Log.w("[Audio Route Helper] No call found, setting audio route on Core") - } - - let conference = core.conference - let audioDevice = conference != nil && conference?.isIn == true ? conference!.outputAudioDevice : currentCall != nil ? currentCall!.outputAudioDevice : core.outputAudioDevice - Log.i("[Audio Route Helper] Playback audio currently in use is [\(audioDevice?.deviceName ?? "n/a")] with type (\(audioDevice?.type ?? .Unknown)") - return audioDevice?.type == AudioDeviceType.Speaker - } - - static func isBluetoothAudioRouteCurrentlyUsed(call: Call? = nil) -> Bool { - if (core.callsNb == 0) { - Log.w("[Audio Route Helper] No call found, so bluetooth audio route isn't used") - return false - } - let currentCall = call != nil ? call : core.currentCall != nil ? core.currentCall : core.calls[0] - let conference = core.conference - - let audioDevice = conference != nil && conference?.isIn == true ? conference!.outputAudioDevice : currentCall?.outputAudioDevice - Log.i("[Audio Route Helper] Playback audio device currently in use is [\(audioDevice?.deviceName ?? "n/a")] with type (\(audioDevice?.type ?? .Unknown)") - return audioDevice?.type == AudioDeviceType.Bluetooth - } - - static func isBluetoothAudioRouteAvailable() -> Bool { - if let device = core.audioDevices.first(where: { $0.type == AudioDeviceType.Bluetooth && $0.hasCapability(capability: .CapabilityPlay) }) { - Log.i("[Audio Route Helper] Found bluetooth audio device [\(device.deviceName)]") - return true - } - return false - } - - static private func isBluetoothAudioRecorderAvailable() -> Bool { - if let device = core.audioDevices.first(where: { $0.type == AudioDeviceType.Bluetooth && $0.hasCapability(capability: .CapabilityRecord) }) { - Log.i("[Audio Route Helper] Found bluetooth audio recorder [\(device.deviceName)]") - return true - } - return false - } - - static func isHeadsetAudioRouteAvailable() -> Bool { - if let device = core.audioDevices.first(where: { ($0.type == AudioDeviceType.Headset||$0.type == AudioDeviceType.Headphones) && $0.hasCapability(capability: .CapabilityPlay) }) { - Log.i("[Audio Route Helper] Found headset/headphones audio device [\(device.deviceName)]") - return true - } - return false - } - - static private func isHeadsetAudioRecorderAvailable() -> Bool { - if let device = core.audioDevices.first(where: { ($0.type == AudioDeviceType.Headset||$0.type == AudioDeviceType.Headphones) && $0.hasCapability(capability: .CapabilityRecord) }) { - Log.i("[Audio Route Helper] Found headset/headphones audio recorder [\(device.deviceName)]") - return true - } - return false - } - - - - static func isReceiverEnabled() -> Bool { - if let outputDevice = core.outputAudioDevice { - return outputDevice.type == AudioDeviceType.Microphone - } - return false - } - -} diff --git a/Classes/Voip/Models/CallData.swift b/Classes/Voip/Models/CallData.swift deleted file mode 100644 index 49f5fa2a5..000000000 --- a/Classes/Voip/Models/CallData.swift +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linhome - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import linphonesw -import Foundation - -class CallData { - - var call : Call - let address :String? - - let isPaused = MutableLiveData() - let isRemotelyPaused = MutableLiveData() - let canBePaused = MutableLiveData() - let isRecording = MutableLiveData() - let isRemotelyRecorded = MutableLiveData() - let isInRemoteConference = MutableLiveData() - let remoteConferenceSubject = MutableLiveData() - let isOutgoing = MutableLiveData() - let isIncoming = MutableLiveData() - let callState = MutableLiveData() - let iFrameReceived = MutableLiveData(false) - let outgoingEarlyMedia = MutableLiveData() - let enteredDTMF = MutableLiveData(" ") - - var chatRoom: ChatRoom? = nil - - private var callDelegate : CallDelegateStub? - - init (call:Call) { - self.call = call - address = call.remoteAddress?.asStringUriOnly() - callDelegate = CallDelegateStub( - onStateChanged : { (call: linphonesw.Call, state: linphonesw.Call.State, message: String) -> Void in - self.update() - }, - onNextVideoFrameDecoded : { (call: linphonesw.Call) -> Void in - self.iFrameReceived.value = true - }, - onRemoteRecording: { (call: linphonesw.Call, recording:Bool) -> Void in - self.isRemotelyRecorded.value = true - } - ) - call.addDelegate(delegate: callDelegate!) - update() - initChatRoom() - } - - - private func isCallPaused() -> Bool { - return [Call.State.Paused, Call.State.Pausing].contains(call.state) - } - - private func isCallRemotelyPaused() -> Bool { - return [Call.State.PausedByRemote].contains(call.state) - } - - private func isOutGoing() -> Bool { - return [Call.State.OutgoingInit, Call.State.OutgoingEarlyMedia, Call.State.OutgoingProgress, Call.State.OutgoingRinging].contains(call.state) - } - - private func isInComing() -> Bool { - return [Call.State.IncomingReceived, Call.State.IncomingEarlyMedia].contains(call.state) - } - - private func canCallBePaused() -> Bool { - return !call.mediaInProgress() && [Call.State.StreamsRunning, Call.State.PausedByRemote].contains(call.state) - } - - private func update() { - isPaused.value = isCallPaused() - isRemotelyPaused.value = isCallRemotelyPaused() - canBePaused.value = canCallBePaused() - let conference = call.conference - isInRemoteConference.value = conference != nil - if (conference != nil) { - remoteConferenceSubject.value = conference?.subject != nil && (conference?.subject.count)! > 0 ? conference!.subject : VoipTexts.conference_default_title - } - isOutgoing.value = isOutGoing() - isIncoming.value = isInComing() - if (call.mediaInProgress()) { - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { - self.update() - } - } - outgoingEarlyMedia.value = callState.value == .OutgoingEarlyMedia - isRecording.value = call.params?.isRecording - callState.value = call.state - } - - private func initChatRoom() { - let localSipUri = Core.get().defaultAccount?.params?.identityAddress?.asStringUriOnly() - let remoteSipUri = call.remoteAddress?.asStringUriOnly() - - guard - let localSipUri = Core.get().defaultAccount?.params?.identityAddress?.asStringUriOnly(), - let remoteSipUri = call.remoteAddress?.asStringUriOnly(), - let localAddress = try?Factory.Instance.createAddress(addr: localSipUri), - let remoteSipAddress = try?Factory.Instance.createAddress(addr: remoteSipUri) - else { - Log.e("[Call] Failed to get either local \(localSipUri.logable) or remote \(remoteSipUri.logable) SIP address!") - return - } - do { - chatRoom = Core.get().searchChatRoom(params: nil, localAddr: localAddress, remoteAddr: remoteSipAddress, participants: []) - if (chatRoom == nil) { - chatRoom = Core.get().searchChatRoom(params: nil, localAddr: localAddress, remoteAddr: nil, participants: [remoteSipAddress]) - } - if (chatRoom == nil) { - Log.w("[Call] Failed to find existing chat room for local address [$localSipUri] and remote address [$remoteSipUri]") - let chatRoomParams = try Core.get().createDefaultChatRoomParams() - // TODO: configure chat room params - chatRoom = try Core.get().createChatRoom(params: chatRoomParams, localAddr: localAddress, participants: [remoteSipAddress]) - } - - if (chatRoom == nil) { - Log.e("[Call] Failed to create a chat room for local address \(localSipUri) and remote address \(remoteSipUri)!") - } - } catch { - Log.e("[Call] Exception caught initiating a chat room for local address \(localSipUri) and remote address \(remoteSipUri) Error : \(error)!") - } - } - - func sendDTMF(dtmf:String) { - enteredDTMF.value = enteredDTMF.value! + dtmf - Core.get().playDtmf(dtmf: dtmf.utf8CString[0], durationMs: 1000) - try?call.sendDtmf(dtmf: dtmf.utf8CString[0]) - } - - func destroy() { - call.removeDelegate(delegate: callDelegate!) - isPaused.clearObservers() - isRemotelyPaused.clearObservers() - canBePaused.clearObservers() - isRecording.clearObservers() - isRemotelyRecorded.clearObservers() - isInRemoteConference.clearObservers() - remoteConferenceSubject.clearObservers() - isOutgoing.clearObservers() - isIncoming.clearObservers() - callState.clearObservers() - iFrameReceived.clearObservers() - outgoingEarlyMedia.clearObservers() - enteredDTMF.clearObservers() - } - - func toggleRecord() { - if (call.params?.isRecording == true) { - call.stopRecording() - } else { - call.startRecording() - } - isRecording.value = call.params?.isRecording - } - - func togglePause() { - if (isCallPaused()) { - try?call.resume() - } else { - try?call.pause() - } - isPaused.value = isCallPaused() - } - -} diff --git a/Classes/Voip/Models/CallStatisticsData.swift b/Classes/Voip/Models/CallStatisticsData.swift deleted file mode 100644 index 5d075d063..000000000 --- a/Classes/Voip/Models/CallStatisticsData.swift +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2010-2021 Belledonne Communications SARL. - * - * This file is part of linphone-android - * (see https://www.linphone.org). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import linphonesw - -class CallStatisticsData { - - var call : Call - var audioStats:[StatItemData] = [] - var videoStats:[StatItemData] = [] - let isVideoEnabled = MutableLiveData() - let statsUpdated = MutableLiveData(true) - - private var callDelegate : CallDelegateStub? - - init (call:Call) { - self.call = call - callDelegate = CallDelegateStub( - onStatsUpdated : { (call: Call, stats: CallStats) -> Void in - self.isVideoEnabled.value = call.currentParams?.videoEnabled - self.updateCallStats(stats: stats) - self.statsUpdated.value = true - } - - ) - call.addDelegate(delegate: callDelegate!) - initCallStats() - isVideoEnabled.value = call.currentParams?.videoEnabled - call.audioStats.map { updateCallStats(stats: $0) } - call.videoStats.map { updateCallStats(stats: $0) } - } - - private func initCallStats() { - - audioStats.append(StatItemData(type: StatType.CAPTURE)) - audioStats.append(StatItemData(type: StatType.PLAYBACK)) - audioStats.append(StatItemData(type: StatType.PAYLOAD)) - audioStats.append(StatItemData(type: StatType.ENCODER)) - audioStats.append(StatItemData(type: StatType.DECODER)) - audioStats.append(StatItemData(type: StatType.DOWNLOAD_BW)) - audioStats.append(StatItemData(type: StatType.UPLOAD_BW)) - audioStats.append(StatItemData(type: StatType.ICE)) - audioStats.append(StatItemData(type: StatType.IP_FAM)) - audioStats.append(StatItemData(type: StatType.SENDER_LOSS)) - audioStats.append(StatItemData(type: StatType.RECEIVER_LOSS)) - audioStats.append(StatItemData(type: StatType.JITTER)) - - videoStats.append(StatItemData(type: StatType.CAPTURE)) - videoStats.append(StatItemData(type: StatType.PLAYBACK)) - videoStats.append(StatItemData(type: StatType.PAYLOAD)) - videoStats.append(StatItemData(type: StatType.ENCODER)) - videoStats.append(StatItemData(type: StatType.DECODER)) - videoStats.append(StatItemData(type: StatType.DOWNLOAD_BW)) - videoStats.append(StatItemData(type: StatType.UPLOAD_BW)) - videoStats.append(StatItemData(type: StatType.ESTIMATED_AVAILABLE_DOWNLOAD_BW)) - videoStats.append(StatItemData(type: StatType.ICE)) - videoStats.append(StatItemData(type: StatType.IP_FAM)) - videoStats.append(StatItemData(type: StatType.SENDER_LOSS)) - videoStats.append(StatItemData(type: StatType.RECEIVER_LOSS)) - videoStats.append(StatItemData(type: StatType.SENT_RESOLUTION)) - videoStats.append(StatItemData(type: StatType.RECEIVED_RESOLUTION)) - videoStats.append(StatItemData(type: StatType.SENT_FPS)) - videoStats.append(StatItemData(type: StatType.RECEIVED_FPS)) - } - - private func updateCallStats(stats: CallStats) { - if (stats.type == StreamType.Audio) { - audioStats.forEach{ $0.update(call: call, stats: stats)} - } else if (stats.type == StreamType.Video) { - videoStats.forEach{ $0.update(call: call, stats: stats)} - } - } -} - - -enum StatType { - case CAPTURE - case PLAYBACK - case PAYLOAD - case ENCODER - case DECODER - case DOWNLOAD_BW - case UPLOAD_BW - case ICE - case IP_FAM - case SENDER_LOSS - case RECEIVER_LOSS - case JITTER - case SENT_RESOLUTION - case RECEIVED_RESOLUTION - case SENT_FPS - case RECEIVED_FPS - case ESTIMATED_AVAILABLE_DOWNLOAD_BW -} - -struct StatItemData { - var type:StatType - - let value = MutableLiveData() - - func update(call: Call, stats: CallStats) { - guard let payloadType = stats.type == StreamType.Audio ? call.currentParams?.usedAudioPayloadType : call.currentParams?.usedVideoPayloadType, let core = call.core else { - value.value = "n/a" - return - } - switch(type) { - case StatType.CAPTURE: value.value = stats.type == StreamType.Audio ? core.captureDevice : core.videoDevice - case StatType.PLAYBACK: value.value = stats.type == StreamType.Audio ? core.playbackDevice : core.videoDisplayFilter - case StatType.PAYLOAD: value.value = "\(payloadType.mimeType)/\(payloadType.clockRate / 1000) kHz" - case StatType.ENCODER: value.value = payloadType.description - case StatType.DECODER: value.value = payloadType.description - case StatType.DOWNLOAD_BW: value.value = "\(stats.downloadBandwidth) kbits/s" - case StatType.UPLOAD_BW: value.value = "\(stats.uploadBandwidth) kbits/s" - case StatType.ICE: value.value = stats.iceState.toString() - case StatType.IP_FAM: value.value = stats.ipFamilyOfRemote == AddressFamily.Inet6 ? "IPv6" : "IPv4" - case StatType.SENDER_LOSS: value.value = String(format: "%.2f%",stats.senderLossRate) - case StatType.RECEIVER_LOSS: value.value = String(format: "%.2f%",stats.receiverLossRate) - case StatType.JITTER: value.value = String(format: "%.2f ms",stats.jitterBufferSizeMs) - case StatType.SENT_RESOLUTION: value.value = call.currentParams?.sentVideoDefinition?.name - case StatType.RECEIVED_RESOLUTION: value.value = call.currentParams?.receivedVideoDefinition?.name - case StatType.SENT_FPS: value.value = "\(call.currentParams?.sentFramerate ?? 0.0)" - case StatType.RECEIVED_FPS: value.value = "\(call.currentParams?.receivedFramerate ?? 0.0)" - case StatType.ESTIMATED_AVAILABLE_DOWNLOAD_BW: value.value = "\(stats.estimatedDownloadBandwidth) kbit/s" - } - } - - - func getTypeTitle() -> String { - switch (type) { - case .CAPTURE: return VoipTexts.call_stats_capture_filter - case .PLAYBACK: return VoipTexts.call_stats_player_filter - case .PAYLOAD: return VoipTexts.call_stats_codec - case .ENCODER: return VoipTexts.call_stats_encoder_name - case .DECODER: return VoipTexts.call_stats_decoder_name - case .DOWNLOAD_BW: return VoipTexts.call_stats_download - case .UPLOAD_BW: return VoipTexts.call_stats_upload - case .ICE: return VoipTexts.call_stats_ice - case .IP_FAM: return VoipTexts.call_stats_ip - case .SENDER_LOSS: return VoipTexts.call_stats_sender_loss_rate - case .RECEIVER_LOSS: return VoipTexts.call_stats_receiver_loss_rate - case .JITTER: return VoipTexts.call_stats_jitter_buffer - case .SENT_RESOLUTION: return VoipTexts.call_stats_video_resolution_sent - case .RECEIVED_RESOLUTION: return VoipTexts.call_stats_video_resolution_received - case .SENT_FPS: return VoipTexts.call_stats_video_fps_sent - case .RECEIVED_FPS: return VoipTexts.call_stats_video_fps_received - case .ESTIMATED_AVAILABLE_DOWNLOAD_BW: return VoipTexts.call_stats_estimated_download - } - } - - - - - -} diff --git a/Classes/Voip/Models/CallsViewModel.swift b/Classes/Voip/Models/CallsViewModel.swift deleted file mode 100644 index 2caa75232..000000000 --- a/Classes/Voip/Models/CallsViewModel.swift +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linhome - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import Foundation -import linphonesw -import AVFoundation - - -class CallsViewModel { - - let currentCallData = MutableLiveData(nil) - let callsData = MutableLiveData<[CallData]>([]) - let inactiveCallsCount = MutableLiveData(0) - let currentCallUnreadChatMessageCount = MutableLiveData(0) - let chatAndCallsCount = MutableLiveData(0) - let callConnectedEvent = MutableLiveData() - let callUpdateEvent = MutableLiveData() - let noMoreCallEvent = MutableLiveData(false) - let core = Core.get() - - static let shared = CallsViewModel() - - private var coreDelegate : CoreDelegateStub? - - init () { - coreDelegate = CoreDelegateStub( - onCallStateChanged : { (core: Core, call: Call, state: Call.State, message:String) -> Void in - Log.i("[Calls] Call state changed: \(call) : \(state)") - let currentCall = core.currentCall - if (currentCall != nil && self.currentCallData.value??.call.getCobject != currentCall?.getCobject) { - self.updateCurrentCallData(currentCall: currentCall) - } else if (currentCall == nil && core.callsNb > 1) { - self.updateCurrentCallData(currentCall: currentCall) - } - if ([.End,.Released,.Error].contains(state)) { - self.removeCallFromList(call: call) - } else if ([.OutgoingInit].contains(state)) { - self.addCallToList(call:call) - } else if ([.IncomingReceived].contains(state)) { - self.addCallToList(call:call) - } else if (state == .UpdatedByRemote) { - let remoteVideo = call.remoteParams?.videoEnabled == true - let localVideo = call.currentParams?.videoEnabled == true - let autoAccept = call.core?.videoActivationPolicy?.automaticallyAccept == true - if (remoteVideo && !localVideo && !autoAccept) { - if (core.videoCaptureEnabled || core.videoDisplayEnabled) { - try?call.deferUpdate() - self.callUpdateEvent.value = call - } else { - call.answerVideoUpdateRequest(accept: false) - } - } - }else if (state == Call.State.Connected) { - self.callConnectedEvent.value = call - } else if (state == Call.State.StreamsRunning) { - self.callUpdateEvent.value = call - } - self.updateInactiveCallsCount() - self.callsData.notifyValue() - }, - - onMessageReceived : { (core: Core, room: ChatRoom, message: ChatMessage) -> Void in - self.updateUnreadChatCount() - }, - onChatRoomRead : { (core: Core, room: ChatRoom) -> Void in - self.updateUnreadChatCount() - }, - onLastCallEnded: { (core: Core) -> Void in - self.currentCallData.value??.destroy() - self.currentCallData.value = nil - self.noMoreCallEvent.value = true - } - ) - - Core.get().addDelegate(delegate: coreDelegate!) - - if let currentCall = core.currentCall { - currentCallData.value??.destroy() - currentCallData.value = CallData(call:currentCall) - } - - chatAndCallsCount.value = 0 - inactiveCallsCount.readCurrentAndObserve { (_) in - self.updateCallsAndChatCount() - } - currentCallUnreadChatMessageCount.readCurrentAndObserve { (_) in - self.updateCallsAndChatCount() - } - - initCallList() - updateInactiveCallsCount() - updateUnreadChatCount() - - } - - private func initCallList() { - core.calls.forEach { addCallToList(call: $0) } - } - - private func removeCallFromList(call: Call) { - Log.i("[Calls] Removing call \(call) from calls list") - if let removeCandidate = callsData.value?.filter{$0.call.getCobject == call.getCobject}.first { - removeCandidate.destroy() - } - - callsData.value = callsData.value?.filter(){$0.call.getCobject != call.getCobject} - callsData.notifyValue() - } - - private func addCallToList(call: Call) { - Log.i("[Calls] Adding call \(call) to calls list") - callsData.value?.append(CallData(call: call)) - callsData.notifyValue() - } - - private func updateUnreadChatCount() { - guard let unread = currentCallData.value??.chatRoom?.unreadMessagesCount else { - currentCallUnreadChatMessageCount.value = 0 - return - } - currentCallUnreadChatMessageCount.value = unread - } - - private func updateInactiveCallsCount() { - inactiveCallsCount.value = core.callsNb - 1 - } - - private func updateCallsAndChatCount() { - var value = 0 - if let calls = inactiveCallsCount.value { - value += calls - } - if let chats = currentCallUnreadChatMessageCount.value { - value += chats - } - chatAndCallsCount.value = value - } - - func mergeCallsIntoLocalConference() { - CallManager.instance().startLocalConference() - } - - private func updateCurrentCallData(currentCall: Call?) { - var callToUse = currentCall - if (currentCall == nil) { - Log.w("[Calls] Current call is now null") - - let firstCall = core.calls.first - if (firstCall != nil && currentCallData.value??.call.getCobject != firstCall?.getCobject) { - Log.i("[Calls] Using first call as \"current\" call") - callToUse = firstCall - } - } - - guard let callToUse = callToUse else { - Log.w("[Calls] No call found to be used as \"current\"") - return - } - - let firstToUse = callsData.value?.filter{$0.call.getCobject != callToUse.getCobject}.first - if (firstToUse != nil) { - currentCallData.value = firstToUse - } else { - Log.w("[Calls] Call not found in calls data list, shouldn't happen!") - currentCallData.value = CallData(call: callToUse) - } - - updateUnreadChatCount() - } - - -} diff --git a/Classes/Voip/Models/ConferenceParticipantData.swift b/Classes/Voip/Models/ConferenceParticipantData.swift deleted file mode 100644 index 2ccdf95d9..000000000 --- a/Classes/Voip/Models/ConferenceParticipantData.swift +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linhome - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import linphonesw -import Foundation - -class ConferenceParticipantData { - - var conference:Conference - var participant:Participant - - let isAdmin = MutableLiveData() - let isMeAdmin = MutableLiveData() - - private var callDelegate : CallDelegateStub? - - init (conference:Conference, participant:Participant) { - self.conference = conference - self.participant = participant - isAdmin.value = participant.isAdmin - isMeAdmin.value = conference.me?.isAdmin - Log.i("[Conference Participant] Participant \(sipUri!) is admin=\(isAdmin.value!)") - - } - - var sipUri:String? { - get { - return self.participant.address?.asString() - } - } - - func destroy() { - isAdmin.clearObservers() - isMeAdmin.clearObservers() - } -} diff --git a/Classes/Voip/Models/ConferenceParticipantDeviceData.swift b/Classes/Voip/Models/ConferenceParticipantDeviceData.swift deleted file mode 100644 index b10dd635f..000000000 --- a/Classes/Voip/Models/ConferenceParticipantDeviceData.swift +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linhome - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import linphonesw -import Foundation - -class ConferenceParticipantDeviceData { - - var participantDevice:ParticipantDevice - let isMe:Bool - - let videoEnabled = MutableLiveData() - let activeSpeaker = MutableLiveData() - let isInConference = MutableLiveData() - let core = Core.get() - - private var participantDeviceDelegate : ParticipantDeviceDelegate? - - init (participantDevice:ParticipantDevice, isMe:Bool) { - self.isMe = isMe - self.participantDevice = participantDevice - participantDeviceDelegate = ParticipantDeviceDelegateStub( - onIsSpeakingChanged: { (participantDevice, isSpeaking) in - Log.i("[Conference Participant Device] Participant \(participantDevice ) isspeaking = \(isSpeaking)") - self.activeSpeaker.value = isSpeaking - }, onConferenceJoined: { (participantDevice) in - Log.i("[Conference Participant Device] Participant \(participantDevice) has joined the conference") - self.isInConference.value = true - }, onConferenceLeft: { (participantDevice) in - Log.i("[Conference Participant Device] Participant \(participantDevice) has left the conference") - self.isInConference.value = false - }, onAudioDirectionChanged: { (participantDevice, direction) in - Log.i("[Conference Participant Device] Participant \(participantDevice) audio stream direction changed: \(direction)") - }, onVideoDirectionChanged: { (participantDevice, direction) in - Log.i("[Conference Participant Device] Participant \(participantDevice) video stream direction changed: \(direction)") - self.videoEnabled.value = direction == MediaDirection.SendOnly || direction == MediaDirection.SendRecv - }, onTextDirectionChanged: { (participantDevice, direction) in - Log.i("[Conference Participant Device] Participant \(participantDevice) text stream direction changed: \(direction)") - }) - - participantDevice.addDelegate(delegate: participantDeviceDelegate!) - activeSpeaker.value = false - - // TODO: What happens if we have disabled video locally? - videoEnabled.value = participantDevice.videoDirection == MediaDirection.SendOnly || participantDevice.videoDirection == MediaDirection.SendRecv - isInConference.value = participantDevice.isInConference - - } - - func destroy() { - participantDevice.removeDelegate(delegate: participantDeviceDelegate!) - } - - func switchCamera() { - Core.get().toggleCamera() - } - - func isSwitchCameraAvailable() -> Bool { - return isMe && Core.get().showSwitchCameraButton() - } - - func setVideoView(view:UIView) { - if (!isMe && participantDevice.videoDirection != MediaDirection.SendRecv) { - Log.e("[Conference Participant Device] Participant \(participantDevice) device video direction is \(participantDevice.videoDirection), don't set video window!") - return - } - Log.i("[Conference Participant Device] Setting textureView \(view) for participant \(participantDevice)") - if (isMe) { // TODO: remove - core.nativePreviewWindow = view - } else { - participantDevice.nativeVideoWindowId = UnsafeMutableRawPointer(Unmanaged.passRetained(view).toOpaque()) - } - } -} diff --git a/Classes/Voip/Models/ConferenceViewModel.swift b/Classes/Voip/Models/ConferenceViewModel.swift deleted file mode 100644 index 26206c306..000000000 --- a/Classes/Voip/Models/ConferenceViewModel.swift +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linhome - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import Foundation -import linphonesw -import AVFoundation - -class ConferenceViewModel { - - let core = Core.get() - static let shared = ConferenceViewModel() - - - let isConferencePaused = MutableLiveData() - let canResumeConference = MutableLiveData() - - let isMeConferenceFocus = MutableLiveData() - let isMeAdmin = MutableLiveData() - - let conferenceAddress = MutableLiveData
() - - let conferenceParticipants = MutableLiveData<[ConferenceParticipantData]>() - let conferenceParticipantDevices = MutableLiveData<[ConferenceParticipantDeviceData]>() - let conferenceDisplayMode = MutableLiveData() - - let isInConference = MutableLiveData() - - let isVideoConference = MutableLiveData() - - let isRecording = MutableLiveData() - let isRemotelyRecorded = MutableLiveData() - - let subject = MutableLiveData() - - let conference = MutableLiveData() - - let maxParticipantsForMosaicLayout = ConfigManager.instance().lpConfigIntForKey(key: "max_conf_part_mosaic_layout",defaultValue: 6) - - private var conferenceDelegate : ConferenceDelegateStub? - private var coreDelegate : CoreDelegateStub? - - init () { - conferenceDelegate = ConferenceDelegateStub(onParticipantAdded: { (conference: Conference, participant: Participant)in - if (conference.isMe(uri: participant.address!)) { - Log.i("[Conference] \(conference) Entered conference") - self.isConferencePaused.value = false - } else { - Log.i("[Conference] \(conference) Participant \(participant) added") - } - self.updateParticipantsList(conference) - self.updateParticipantsDevicesList(conference) - - let count = self.conferenceParticipantDevices.value!.count - if (count > self.maxParticipantsForMosaicLayout) { - Log.w("[Conference] \(conference) More than \(self.maxParticipantsForMosaicLayout) participants \(count), forcing active speaker layout") - self.conferenceDisplayMode.value = .ActiveSpeaker - } - }, onParticipantRemoved: {(conference: Conference, participant: Participant) in - if (conference.isMe(uri: participant.address!)) { - Log.i("[Conference] \(conference) \(participant) Left conference") - self.isConferencePaused.value = true - } else { - Log.i("[Conference] \(conference) \(participant) Participant removed") - } - self.updateParticipantsList(conference) - self.updateParticipantsDevicesList(conference) - }, onParticipantDeviceAdded: {(conference: Conference, participantDevice: ParticipantDevice) in - Log.i("[Conference] \(conference) Participant device \(participantDevice) added") - self.updateParticipantsDevicesList(conference) - }, onParticipantDeviceRemoved: { (conference: Conference, participantDevice: ParticipantDevice) in - Log.i("[Conference] \(conference) Participant device \(participantDevice) removed") - self.updateParticipantsDevicesList(conference) - }, onParticipantAdminStatusChanged: { (conference: Conference, participant: Participant) in - Log.i("[Conference] \(conference) Participant admin status changed") - self.isMeAdmin.value = conference.me?.isAdmin - self.updateParticipantsList(conference) - } - ) - - coreDelegate = CoreDelegateStub( - onConferenceStateChanged: { (core, conference, state) in - Log.i("[Conference] \(conference) Conference state changed: \(state)") - self.isConferencePaused.value = !conference.isIn - self.canResumeConference.value = true // TODO: How can this value be false? - self.isVideoConference.value = conference.currentParams?.isVideoEnabled == true - - if (state == Conference.State.Instantiated) { - self.conference.value = conference - self.isInConference.value = true - conference.addDelegate(delegate: self.conferenceDelegate!) - } else if (state == Conference.State.Created) { - self.updateParticipantsList(conference) - self.updateParticipantsDevicesList(conference) - self.isMeConferenceFocus.value = conference.me?.isFocus == true - self.isMeAdmin.value = conference.me?.isAdmin == true - self.conferenceAddress.value = conference.conferenceAddress - self.subject.value = conference.subject.isEmpty ? ( - conference.me?.isFocus == true ? ( - VoipTexts.conference_local_title - ) : ( - VoipTexts.conference_default_title - ) - ) : ( - conference.subject - ) - } else if (state == Conference.State.Terminated || state == Conference.State.TerminationFailed) { - self.isInConference.value = false - self.isVideoConference.value = false - conference.removeDelegate(delegate: self.conferenceDelegate!) - self.conferenceParticipants.value?.forEach{ $0.destroy()} - self.conferenceParticipantDevices.value?.forEach{ $0.destroy()} - self.conferenceParticipants.value = [] - self.conferenceParticipantDevices.value = [] - } - - let layout = conference.layout == .None ? .Grid : conference.layout - self.conferenceDisplayMode.value = layout - Log.i("[Conference] \(conference) Conference current layout is: \(layout)") - } - ) - - Core.get().addDelegate(delegate: coreDelegate!) - - - conferenceParticipants.value = [] - conferenceParticipantDevices.value = [] - conferenceDisplayMode.value = .Grid - - subject.value = VoipTexts.conference_default_title - - if let conference = core.conference != nil ? core.conference : core.currentCall?.conference { - Log.i("[Conference] Found an existing conference: \(conference)") - self.conference.value = conference - conference.addDelegate(delegate: self.conferenceDelegate!) - - - isInConference.value = true - isConferencePaused.value = !conference.isIn - isMeConferenceFocus.value = conference.me?.isFocus == true - isMeAdmin.value = conference.me?.isAdmin == true - isVideoConference.value = conference.currentParams?.isVideoEnabled == true - conferenceAddress.value = conference.conferenceAddress - if (!conference.subject.isEmpty) { - subject.value = conference.subject - } - - let layout = conference.layout == .None ? .Grid : conference.layout - conferenceDisplayMode.value = layout - Log.i("[Conference] \(conference) Conference current layout is: \(layout)") - - updateParticipantsList(conference) - updateParticipantsDevicesList(conference) - } - - - } - - - func destroy() { - core.removeDelegate(delegate: self.coreDelegate!) - self.conferenceParticipants.value?.forEach{ $0.destroy()} - self.conferenceParticipantDevices.value?.forEach{ $0.destroy()} - } - - - func pauseConference() { - let defaultProxyConfig = core.defaultProxyConfig - let localAddress = defaultProxyConfig?.identityAddress - let participants : [Address] = [] - let remoteConference = core.searchConference(params: nil, localAddr: localAddress, remoteAddr: conferenceAddress.value, participants: participants) - let localConference = core.searchConference(params: nil, localAddr: conferenceAddress.value, remoteAddr: conferenceAddress.value, participants: participants) - let conference = remoteConference != nil ? remoteConference : localConference - - if (conference != nil) { - Log.i("[Conference] Leaving conference with address \(conference) temporarily") - conference!.leave() - } else { - Log.w("[Conference] Unable to find conference with address \(conference)") - } - } - - func resumeConference() { - let defaultProxyConfig = core.defaultProxyConfig - let localAddress = defaultProxyConfig?.identityAddress - let participants : [Address] = [] - let remoteConference = core.searchConference(params: nil, localAddr: localAddress, remoteAddr: conferenceAddress.value, participants: participants) - let localConference = core.searchConference(params: nil, localAddr: conferenceAddress.value, remoteAddr: conferenceAddress.value, participants: participants) - - if let conference = remoteConference != nil ? remoteConference : localConference { - Log.i("[Conference] Entering again conference with address \(conference)") - conference.enter() - } else { - Log.w("[Conference] Unable to find conference with address \(conference)") - } - } - - func togglePlayPause () { - if (isConferencePaused.value == true) { - resumeConference() - isConferencePaused.value = false - } else { - pauseConference() - isConferencePaused.value = true - } - } - - func toggleRecording() { - guard let conference = core.conference else { - Log.e("[Conference] Failed to find conference!") - return - } - - if (conference.isRecording == true) { - conference.stopRecording() - } else { - let path = AppManager.recordingFilePathFromCall(address: conference.conferenceAddress?.asStringUriOnly() ?? "") - Log.i("[Conference] Starting recording \(conference) in file \(path)") - conference.startRecording(path: path) - } - isRecording.value = conference.isRecording - } - - private func updateParticipantsList(_ conference: Conference) { - self.conferenceParticipants.value?.forEach{ $0.destroy()} - var participants :[ConferenceParticipantData] = [] - - let participantsList = conference.participantList - Log.i("[Conference] \(conference) Conference has \(participantsList.count) participants") - - participantsList.forEach { (participant) in - let participantDevices = participant.devices - Log.i("[Conference] \(conference) Participant found: \(participant) with \(participantDevices.count) device(s)") - let participantData = ConferenceParticipantData(conference: conference, participant: participant) - participants.append(participantData) - } - - conferenceParticipants.value = participants - } - - private func updateParticipantsDevicesList(_ conference: Conference) { - self.conferenceParticipantDevices.value?.forEach{ $0.destroy()} - var devices :[ConferenceParticipantDeviceData] = [] - - let participantsList = conference.participantList - Log.i("[Conference] \(conference) Conference has \(participantsList.count) participants") - - participantsList.forEach { (participant) in - let participantDevices = participant.devices - Log.i("[Conference] \(conference) Participant found: \(participant) with \(participantDevices.count) device(s)") - - participantDevices.forEach { (device) in - Log.i("[Conference] \(conference) Participant device found: \(device.name) (\(device.address!.asStringUriOnly()))") - let deviceData = ConferenceParticipantDeviceData(participantDevice: device, isMe: false) - devices.append(deviceData) - } - - } - conference.me?.devices.forEach { (device) in - Log.i("[Conference] \(conference) Participant device for myself found: \(device.name) (\(device.address!.asStringUriOnly()))") - let deviceData = ConferenceParticipantDeviceData(participantDevice: device, isMe: true) - devices.append(deviceData) - } - - - conferenceParticipantDevices.value = devices - } - -} - -enum FlexDirection { - case ROW - case ROW_REVERSE - case COLUMN - case COLUMN_REVERSE -} diff --git a/Classes/Voip/Models/ControlsViewModel.swift b/Classes/Voip/Models/ControlsViewModel.swift deleted file mode 100644 index 51109541e..000000000 --- a/Classes/Voip/Models/ControlsViewModel.swift +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linhome - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import Foundation -import linphonesw -import AVFoundation - - -class ControlsViewModel { - let core = Core.get() - - let isSpeakerSelected = MutableLiveData() - let isMicrophoneMuted = MutableLiveData() - let isMuteMicrophoneEnabled = MutableLiveData() - let isBluetoothHeadsetSelected = MutableLiveData() - let nonEarpieceOutputAudioDevice = MutableLiveData() - let audioRoutesSelected = MutableLiveData() - let audioRoutesEnabled = MutableLiveData() - - let isVideoUpdateInProgress = MutableLiveData() - let isVideoEnabled = MutableLiveData() - let isVideoAvailable = MutableLiveData() - - let fullScreenMode = MutableLiveData(false) - let numpadVisible = MutableLiveData(false) - let callStatsVisible = MutableLiveData(false) - let goToConferenceLayoutSettings = MutableLiveData(false) - let goToConferenceParticipantsListEvent = MutableLiveData(false) - let goToChatEvent = MutableLiveData(false) - let goToCallsListEvent = MutableLiveData(false) - let hideExtraButtons = MutableLiveData(true) - - let proximitySensorEnabled = MutableLiveData() - - - static let shared = ControlsViewModel() - private var coreDelegate : CoreDelegateStub? - private var previousCallState = Call.State.Idle - - - init () { - coreDelegate = CoreDelegateStub( - onCallStateChanged : { (core: Core, call: Call, state: Call.State, message:String) -> Void in - Log.i("[Call Controls] Call state changed: \(call) : \(state)") - if (state == Call.State.StreamsRunning) { - self.isVideoUpdateInProgress.value = false - } - self.updateUI() - self.setAudioRoutes(call,state) - self.previousCallState = state - }, - onAudioDeviceChanged : { (core: Core, audioDevice: AudioDevice) -> Void in - Log.i("[Call Controls] Audio device changed: \(audioDevice.deviceName)") - self.nonEarpieceOutputAudioDevice.value = audioDevice.type != AudioDeviceType.Microphone // on iOS Earpiece = Microphone - self.updateSpeakerState() - self.updateBluetoothHeadsetState() - } - ) - Core.get().addDelegate(delegate: coreDelegate!) - proximitySensorEnabled.value = shouldProximitySensorBeEnabled() - isVideoEnabled.readCurrentAndObserve { _ in - self.proximitySensorEnabled.value = self.shouldProximitySensorBeEnabled() - } - nonEarpieceOutputAudioDevice.readCurrentAndObserve { _ in - self.proximitySensorEnabled.value = self.shouldProximitySensorBeEnabled() - } - proximitySensorEnabled.readCurrentAndObserve { (enabled) in - UIDevice.current.isProximityMonitoringEnabled = enabled == true - } - updateUI() - } - - private func setAudioRoutes(_ call:Call,_ state:Call.State) { - if (state == .OutgoingProgress) { - if (core.callsNb == 1 && ConfigManager.instance().lpConfigBoolForKey(key: "route_audio_to_bluetooth_if_available",defaultValue:true)) { - AudioRouteUtils.routeAudioToBluetooth(call: call) - } - } - if (state == .StreamsRunning) { - if (core.callsNb == 1) { - // Only try to route bluetooth / headphone / headset when the call is in StreamsRunning for the first time - if (previousCallState == Call.State.Connected) { - Log.i("[Context] First call going into StreamsRunning state for the first time, trying to route audio to headset or bluetooth if available") - if (AudioRouteUtils.isHeadsetAudioRouteAvailable()) { - AudioRouteUtils.routeAudioToHeadset(call: call) - } else if (ConfigManager.instance().lpConfigBoolForKey(key: "route_audio_to_bluetooth_if_available",defaultValue:true) && - AudioRouteUtils.isBluetoothAudioRouteAvailable()) { - AudioRouteUtils.routeAudioToBluetooth(call: call) - } - } - } - - if (ConfigManager.instance().lpConfigBoolForKey(key: "route_audio_to_speaker_when_video_enabled",defaultValue:true) && call.currentParams?.videoEnabled == true) { - // Do not turn speaker on when video is enabled if headset or bluetooth is used - if (!AudioRouteUtils.isHeadsetAudioRouteAvailable() && - !AudioRouteUtils.isBluetoothAudioRouteCurrentlyUsed(call: call) - ) { - Log.i("[Context] Video enabled and no wired headset not bluetooth in use, routing audio to speaker") - AudioRouteUtils.routeAudioToSpeaker(call: call) - } - } - } - } - - - private func shouldProximitySensorBeEnabled() -> Bool { - return isVideoEnabled.value != true && nonEarpieceOutputAudioDevice.value != true - } - - - func hangUp() { - if (core.currentCall != nil) { - try?core.currentCall?.terminate() - } else if (core.conference?.isIn == true) { - try?core.terminateConference() - } else { - try?core.terminateAllCalls() - } - } - - func toggleVideo() { - if let conference = core.conference, conference.isIn { - if let params = try?core.createConferenceParams() { - let videoEnabled = conference.currentParams?.isVideoEnabled == true - params.videoEnabled = !videoEnabled - _ = conference.updateParams(params: params) - } - } else if let currentCall = core.currentCall { - let state = currentCall.state - if (state == Call.State.End || state == Call.State.Released || state == Call.State.Error) { - return - } - isVideoUpdateInProgress.value = true - if let params = try?core.createCallParams(call: currentCall) { - params.videoEnabled = !(currentCall.currentParams?.videoEnabled == true) - try?currentCall.update(params: params) - if (params.videoEnabled) { - currentCall.requestNotifyNextVideoFrameDecoded() - } - } - } - } - - - private func updateUI() { - updateVideoAvailable() - updateVideoEnabled() - updateMicState() - updateSpeakerState() - updateAudioRoutesState() - proximitySensorEnabled.value = shouldProximitySensorBeEnabled() - } - - private func updateAudioRoutesState() { - let bluetoothDeviceAvailable = AudioRouteUtils.isBluetoothAudioRouteAvailable() - audioRoutesEnabled.value = bluetoothDeviceAvailable - - if (!bluetoothDeviceAvailable) { - audioRoutesSelected.value = false - audioRoutesEnabled.value = false - } - } - - private func updateSpeakerState() { - isSpeakerSelected.value = AudioRouteUtils.isSpeakerAudioRouteCurrentlyUsed() - } - - private func updateBluetoothHeadsetState() { - isBluetoothHeadsetSelected.value = AudioRouteUtils.isBluetoothAudioRouteCurrentlyUsed() - } - - private func updateVideoAvailable() { - let currentCall = core.currentCall - isVideoAvailable.value = (core.videoCaptureEnabled || core.videoPreviewEnabled) && - ((currentCall != nil && currentCall?.mediaInProgress() != true) || core.conference?.isIn == true) - } - - private func updateVideoEnabled() { - let enabled = isVideoCallOrConferenceActive() - isVideoEnabled.value = enabled - } - - func updateMicState() { - isMicrophoneMuted.value = !micAuthorized() || !core.micEnabled - isMuteMicrophoneEnabled.value = core.currentCall != nil || core.conference?.isIn == true - } - - func micAuthorized() -> Bool { - return AVCaptureDevice.authorizationStatus(for: .audio) == .authorized - } - - func isVideoCallOrConferenceActive() -> Bool { - if let conference = core.conference, conference.isIn { - return conference.currentParams?.videoEnabled == true - } else { - return core.currentCall?.currentParams?.videoEnabled == true - } - } - - func toggleFullScreen() { - if (isVideoEnabled.value == true) { - fullScreenMode.value = fullScreenMode.value != true - } - } - - func toggleMuteMicrophone() { - if (!micAuthorized()) { - AVAudioSession.sharedInstance().requestRecordPermission { granted in - if granted { - self.core.micEnabled = !self.core.micEnabled - self.updateMicState() - } - } - } - core.micEnabled = !core.micEnabled - updateMicState() - } - - func forceEarpieceAudioRoute() { - if (AudioRouteUtils.isHeadsetAudioRouteAvailable()) { - Log.i("[Call Controls] Headset found, route audio to it instead of earpiece") - AudioRouteUtils.routeAudioToHeadset() - } else { - AudioRouteUtils.routeAudioToEarpiece() - } - } - - func forceSpeakerAudioRoute() { - AudioRouteUtils.routeAudioToSpeaker() - } - - func forceBluetoothAudioRoute() { - AudioRouteUtils.routeAudioToBluetooth() - } - - func toggleSpeaker() { - if (AudioRouteUtils.isSpeakerAudioRouteCurrentlyUsed()) { - forceEarpieceAudioRoute() - } else { - forceSpeakerAudioRoute() - } - } - - func toggleRoutesMenu() { - audioRoutesSelected.value = audioRoutesSelected.value != true - } - -} diff --git a/Classes/Voip/Theme/LightDarkColor.swift b/Classes/Voip/Theme/LightDarkColor.swift deleted file mode 100644 index a01e375b2..000000000 --- a/Classes/Voip/Theme/LightDarkColor.swift +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation - -class LightDarkColor { - var light: UIColor - var dark : UIColor - init(_ l:UIColor,_ d:UIColor){ - light = l - dark = d - } - - func get() -> UIColor { - if #available(iOS 13.0, *) { - if UITraitCollection.current.userInterfaceStyle == .light { - return light - } else { - return dark - } - } else { - return light - } - } - -} diff --git a/Classes/Voip/Theme/TextStyle.swift b/Classes/Voip/Theme/TextStyle.swift deleted file mode 100644 index ceff5a5eb..000000000 --- a/Classes/Voip/Theme/TextStyle.swift +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import UIKit - -struct TextStyle { - var fgColor:LightDarkColor - var bgColor:LightDarkColor - var allCaps:Bool - var align:NSTextAlignment - var font:String - var size:Float - - func boldEd() -> TextStyle { - return self.font.contains("Bold") ? self : TextStyle(fgColor: self.fgColor,bgColor: self.bgColor,allCaps: self.allCaps,align: self.align,font: self.font.replacingOccurrences(of: "Regular", with: "Bold"), size: self.size) - } -} - - -extension UILabel { - func applyStyle(_ style:TextStyle) { - textColor = style.fgColor.get() - backgroundColor = style.bgColor.get() - if (style.allCaps) { - text = self.text?.uppercased() - tag = 1 - } - textAlignment = style.align - let fontSizeMultiplier: Float = (UIDevice.ipad() ? 1.25 : UIDevice.is5SorSEGen1() ? 0.9 : 1.0) - font = UIFont.init(name: style.font, size: CGFloat(style.size*fontSizeMultiplier)) - } -} - -extension UIButton { - func applyTitleStyle(_ style:TextStyle) { - titleLabel?.applyStyle(style) - if (style.allCaps) { - setTitle(self.title(for: .normal)?.uppercased(), for: .normal) - tag = 1 - } - setTitleColor(style.fgColor.get(), for: .normal) - contentHorizontalAlignment = style.align == .left ? .left : style.align == .center ? .center : style.align == .right ? .right : .left - } -} diff --git a/Classes/Voip/Theme/VoipTexts.swift b/Classes/Voip/Theme/VoipTexts.swift deleted file mode 100644 index 4df37ec4d..000000000 --- a/Classes/Voip/Theme/VoipTexts.swift +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import UIKit - -class VoipTexts { // From android key names. Added intentionnally with NSLocalizedString calls for each key, so it can be picked up by translation system (Weblate or Xcode). - - static let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String - - // Calls - static let call_incoming_title = NSLocalizedString("Incoming Call",comment:"") - static let call_outgoing_title = NSLocalizedString("Outgoing Call",comment:"") - static let call_notification_paused = NSLocalizedString("Paused call",comment:"") - static let call_notification_outgoing = NSLocalizedString("Outgoing call",comment:"") - static let call_notification_active = NSLocalizedString("Call running",comment:"") - static let call_error_declined = NSLocalizedString("Call has been declined",comment:"") - static let call_error_user_busy = NSLocalizedString("User is busy",comment:"") - static let call_error_user_not_found = NSLocalizedString("User hasn't been found",comment:"") - static let call_error_incompatible_media_params = NSLocalizedString("Incompatible media parameters",comment:"") - static let call_error_network_unreachable = NSLocalizedString("Network is unreachable",comment:"") - static let call_error_io_error = NSLocalizedString("Service unavailable or network error",comment:"") - static let call_error_server_timeout = NSLocalizedString("Server timeout",comment:"") - static let call_error_temporarily_unavailable = NSLocalizedString("Temporarily unavailable",comment:"") - static let call_error_generic = NSLocalizedString("Error: %s",comment:"") - static let call_video_update_requested_dialog = NSLocalizedString("Correspondent would like to turn the video on",comment:"") - static let call_action_participants_list = NSLocalizedString("Participants list",comment:"") - static let call_action_chat = NSLocalizedString("Chat",comment:"") - static let call_action_calls_list = NSLocalizedString("Calls list",comment:"") - static let call_action_numpad = NSLocalizedString("Numpad",comment:"") - static let call_action_change_conf_layout = NSLocalizedString("Change layout",comment:"") - static let call_action_transfer_call = NSLocalizedString("Transfer call",comment:"") - static let call_action_add_call = NSLocalizedString("Start new call",comment:"") - - static let call_action_statistics = NSLocalizedString("Call statistics",comment:"") - static let call_context_action_resume = NSLocalizedString("Resume call",comment:"") - static let call_context_action_pause = NSLocalizedString("Pause call",comment:"") - static let call_context_action_transfer = NSLocalizedString("Transfer call",comment:"") - static let call_context_action_answer = NSLocalizedString("Answer call",comment:"") - static let call_context_action_hangup = NSLocalizedString("Terminate call",comment:"") - static let call_remote_recording = NSLocalizedString("This call is being recorded.",comment:"") - static let call_remotely_paused_title = NSLocalizedString("Call has been paused by remote.",comment:"") - - // Conference - static let conference_schedule_title = NSLocalizedString("Start a conference",comment:"") - static let conference_schedule_later = NSLocalizedString("Do you want to schedule this conference for later?",comment:"") - static let conference_schedule_mandatory_field = NSLocalizedString("Mandatory",comment:"") - static let conference_schedule_subject_title = NSLocalizedString("Subject",comment:"") - static let conference_schedule_subject_hint = NSLocalizedString("Conference subject",comment:"") - static let conference_schedule_address_title = NSLocalizedString("Conference address",comment:"") - static let conference_schedule_description_title = NSLocalizedString("Add a description",comment:"") - static let conference_schedule_description_hint = NSLocalizedString("Description",comment:"") - static let conference_schedule_date = NSLocalizedString("Date",comment:"") - static let conference_schedule_time = NSLocalizedString("Time",comment:"") - static let conference_schedule_duration = NSLocalizedString("Duration",comment:"") - static let conference_schedule_timezone = NSLocalizedString("Timezone",comment:"") - static let conference_schedule_send_invite_chat = NSLocalizedString("Send invite via \(appName)",comment:"") - static let conference_schedule_send_invite_email = NSLocalizedString("Send invite via email",comment:"") - static let conference_schedule_encryption = NSLocalizedString("Would you like to encrypt the conference?",comment:"") - static let conference_schedule_send_invite_chat_summary = NSLocalizedString("Invite will be sent out from my \(appName) account",comment:"") - static let conference_schedule_participants_list = NSLocalizedString("Participants list",comment:"") - static let conference_schedule_summary = NSLocalizedString("Conference info",comment:"") - static let conference_schedule_create = NSLocalizedString("Create conference",comment:"") - static let conference_schedule = NSLocalizedString("Schedule conference",comment:"") - static let conference_schedule_address_copied_to_clipboard = NSLocalizedString("Conference address copied into clipboard",comment:"") - static let conference_schedule_creation_failure = NSLocalizedString("Failed to create conference!",comment:"") - static let conference_schedule_info_not_sent_to_participant = NSLocalizedString("Failed to send conference info to a participant",comment:"") - static let conference_paused_title = NSLocalizedString("You are currently out of the conference.",comment:"") - static let conference_paused_subtitle = NSLocalizedString("Click on play button to join it back.",comment:"") - static let conference_default_title = NSLocalizedString("Remote conference",comment:"") - static let conference_local_title = NSLocalizedString("Local conference",comment:"") - static let conference_invite_title = NSLocalizedString("Conference invite:",comment:"") - static let conference_description_title = NSLocalizedString("Description:",comment:"") - static let conference_invite_join = NSLocalizedString("Join",comment:"") - static let conference_invite_participants_count = NSLocalizedString("%d participants",comment:"") - static let conference_display_mode_mosaic = NSLocalizedString("Mosaic mode",comment:"") - static let conference_display_mode_active_speaker = NSLocalizedString("Active speaker mode",comment:"") - static let conference_display_no_active_speaker = NSLocalizedString("No active speaker",comment:"") - static let conference_waiting_room_start_call = NSLocalizedString("Start",comment:"") - static let conference_waiting_room_cancel_call = NSLocalizedString("Cancel",comment:"") - static let conference_scheduled = NSLocalizedString("Conferences",comment:"") - static let conference_too_many_participants_for_mosaic_layout = NSLocalizedString("You can't change conference layout as there is too many participants",comment:"") - static let conference_participant_paused = NSLocalizedString("(paused)",comment:"") - - - // Call Stats - - static let call_stats_audio = "Audio" - static let call_stats_video = "Video" - static let call_stats_codec = "Codec:" - static let call_stats_ip = "IP Family:" - static let call_stats_upload = "Upload bandwidth:" - static let call_stats_download = "Download bandwidth:" - static let call_stats_estimated_download = "Estimated download bandwidth:" - static let call_stats_ice = "ICE connectivity:" - static let call_stats_video_resolution_sent = "Sent video resolution:" - static let call_stats_video_resolution_received = "Received video resolution:" - static let call_stats_video_fps_sent = "Sent video fps:" - static let call_stats_video_fps_received = "Received video fps:" - static let call_stats_sender_loss_rate = "Sender loss rate:" - static let call_stats_receiver_loss_rate = "Receiver loss rate:" - static let call_stats_jitter_buffer = "Jitter buffer:" - static let call_stats_encoder_name = "Encoder:" - static let call_stats_decoder_name = "Decoder:" - static let call_stats_player_filter = "Player filter:" - static let call_stats_capture_filter = "Capture filter:" - - - // Added in iOS - static let camera_required_for_video = NSLocalizedString("Camera use is not Authorized for \(appName). This permission is required to activate Video.",comment:"") - static let ok = NSLocalizedString("ok",comment:"") - static let cancel = NSLocalizedString("cancel",comment:"") - - static let dialog_accept = NSLocalizedString("Accept",comment:"") - static let dialog_decline = NSLocalizedString("Decline",comment:"") - - // Participants list : - static let chat_room_group_info_admin = NSLocalizedString("Admin",comment:"") - - -} diff --git a/Classes/Voip/Theme/VoipTheme.swift b/Classes/Voip/Theme/VoipTheme.swift deleted file mode 100644 index 1a5d77d9d..000000000 --- a/Classes/Voip/Theme/VoipTheme.swift +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import UIKit - -class VoipTheme { // 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") - static let voip_gray = UIColor(hex:"#96A5B1") - static let voip_gray_background = UIColor(hex:"#D8D8D8") - static let voip_call_record_background = UIColor(hex:"#EBEBEB") - static let voip_calls_list_inactive_background = UIColor(hex:"#F0F1F2") - static let voip_translucent_popup_background = UIColor(hex:"#A64B5964") - static let voip_translucent_popup_alt_background = UIColor(hex:"#E64B5964") - static let voip_numpad_background = UIColor(hex:"#E4E4E4") - static let voip_contact_avatar_background_alt = UIColor(hex:"#AFAFAF") - static let voip_contact_avatar_calls_list = UIColor(hex:"#A1A1A1") - static let voip_conference_participant_paused_background = UIColor(hex:"#303030") - static let voip_drawable_color = UIColor(hex:"#A6B2BC") - static let voip_dark_color = UIColor(hex:"#252E35") - static let voip_dark_color2 = UIColor(hex:"#3F464B") - static let voip_dark_color3 = UIColor(hex:"#475663") - static let voip_dark_color4 = UIColor(hex:"#2D3841") - - // General colors (used by VoIP) - - static let primary_color = UIColor(hex:"#ff5e00") - static let primary_dark_color = UIColor(hex:"#e65000") - static let green_color = UIColor(hex:"#96c11f") - static let dark_green_color = UIColor(hex:"#7d9f21") - static let toolbar_color = UIColor(hex:"#e1e1e1") - static let form_field_gray_background = UIColor(hex:"#F7F7F7") - static let light_grey_color = UIColor(hex:"#c4c4c4") - static let header_background_color = UIColor(hex:"#f3f3f3") - static let dark_grey_color = UIColor(hex:"#444444") - - // Light / Dark variations - static let voipBackgroundColor = LightDarkColor(voip_gray_blue_color,voip_dark_color) - static let voipBackgroundBWColor = LightDarkColor(UIColor.white,voip_dark_color) - static let voipParticipantBackgroundColor = LightDarkColor(voip_gray_background,voip_dark_color2) - static let voipExtraButtonsBackgroundColor = LightDarkColor(voip_gray,voip_dark_color3) - static let voipToolbarBackgroundColor = LightDarkColor(toolbar_color,voip_dark_color4) - static let voipDrawableColor = LightDarkColor(voip_dark_gray,.white) - static let voipDrawableColorHighlighted = LightDarkColor(voip_gray,voip_gray) - static let voipTextColor = LightDarkColor(voip_dark_gray,UIColor.white) - static let voipFormBackgroundColor = LightDarkColor(form_field_gray_background,voip_dark_color4) - static let voipFormFieldBackgroundColor = LightDarkColor(light_grey_color,voip_dark_color4) - static let voipFormDisabledFieldBackgroundColor = LightDarkColor(header_background_color,voip_dark_color4) - static let primarySubtextLightColor = LightDarkColor(light_grey_color,toolbar_color) - static let primaryTextColor = LightDarkColor(dark_grey_color,.white) - - - - - // Text styles - static let fontName = "Roboto" - static let call_header_title = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Bold", size: 18.0) - static let call_header_subtitle = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 14.0) - static let call_generated_avatar_large = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: true, align: .center, font: fontName+"-Regular", size: 53.0) - static let call_generated_avatar_medium = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: true, align: .center, font: fontName+"-Regular", size: 27.0) - static let call_generated_avatar_small = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: true, align: .center, font: fontName+"-Regular", size: 16.0) - - static let dtmf_label = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 30.0) - static let call_remote_name = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Regular", size: 18.0) - static let call_remote_recording = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 16.0) - static let call_or_conference_title = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Bold", size: 30.0) - static let call_or_conference_subtitle = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Bold", size: 20.0) - static let basic_popup_title = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 21.0) - static let big_button = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: true, align: .center, font: fontName+"-Bold", size: 17.0) - - static let call_display_name_duration = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Regular", size: 17.0) - static let call_sip_address = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Regular", size: 14.0) - static let voip_extra_button = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 12.0) - static let unread_count_font = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 11.0) - static let call_stats_font = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 12.0) - static let call_stats_font_title = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 18.0) - static let calls_list_header_font = TextStyle(fgColor: voipTextColor, bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 20.0) - - static let call_list_active_name_font = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 18.0) - static let call_list_active_sip_uri_font = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 12.0) - - static let call_list_name_font = TextStyle(fgColor: voipTextColor, bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 18.0) - static let call_list_sip_uri_font = TextStyle(fgColor: voipTextColor, bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 12.0) - - static let call_context_menu_item_font = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: true, align: .left, font: fontName+"-Bold", size: 16.0) - - static let conference_participant_admin_label = TextStyle(fgColor: primarySubtextLightColor, bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Bold", size: 13.0) - static let conference_participant_name_font = TextStyle(fgColor: LightDarkColor(dark_grey_color,dark_grey_color), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 18.0) - static let conference_participant_sip_uri_font = TextStyle(fgColor: LightDarkColor(primary_color,primary_color), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 12.0) - static let conference_participant_name_font_grid = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Bold", size: 15.0) - static let conference_participant_name_font_as = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Bold", size: 12.0) - - - static let conference_mode_title = TextStyle(fgColor: LightDarkColor(dark_grey_color,dark_grey_color), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Regular", size: 17.0) - static let conference_mode_title_selected = conference_mode_title.boldEd() - - - - // Buttons Background (State colors) - - static let button_background = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_gray,voip_gray), - UIButton.State.highlighted.rawValue : LightDarkColor(voip_dark_gray,voip_dark_gray), - UIButton.State.selected.union(.highlighted).rawValue : LightDarkColor(voip_dark_gray,voip_dark_gray), - UIButton.State.disabled.rawValue : LightDarkColor(voip_light_gray,voip_light_gray) - ] - - static let button_background_reverse = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_dark_gray,voip_dark_gray), - UIButton.State.highlighted.rawValue : LightDarkColor(voip_gray,voip_gray), - UIButton.State.selected.union(.highlighted).rawValue : LightDarkColor(voip_gray,voip_gray), - UIButton.State.disabled.rawValue : LightDarkColor(voip_light_gray,voip_light_gray) - ] - - static let button_call_recording_background = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_call_record_background,voip_call_record_background), - UIButton.State.selected.rawValue : LightDarkColor(primary_color,primary_color), - UIButton.State.disabled.rawValue : LightDarkColor(voip_light_gray,voip_light_gray) - ] - - static let button_toggle_background = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_gray,voip_gray), - UIButton.State.selected.rawValue : LightDarkColor(primary_color,primary_color), - UIButton.State.highlighted.rawValue : LightDarkColor(voip_dark_gray,voip_dark_gray), - UIButton.State.disabled.rawValue : LightDarkColor(voip_light_gray,voip_light_gray) - ] - - static let button_toggle_background_reverse = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_dark_gray,voip_dark_gray), - UIButton.State.selected.rawValue : LightDarkColor(primary_color,primary_color), - UIButton.State.highlighted.rawValue : LightDarkColor(voip_gray,voip_gray), - UIButton.State.disabled.rawValue : LightDarkColor(voip_light_gray,voip_light_gray) - ] - - - - static let primary_colors_background = [ - UIButton.State.normal.rawValue : LightDarkColor(primary_color,primary_color), - UIButton.State.highlighted.rawValue : LightDarkColor(primary_dark_color,primary_dark_color), - ] - - static let primary_colors_background_gray = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_gray,voip_gray), - UIButton.State.highlighted.rawValue : LightDarkColor(voip_dark_gray,voip_dark_gray), - ] - - static let numpad_digit_background = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_numpad_background,voip_numpad_background), - UIButton.State.highlighted.rawValue : LightDarkColor(voip_gray_blue_color,voip_gray_blue_color) - ] - - static let button_round_background = [ - UIButton.State.normal.rawValue : LightDarkColor(primary_color,primary_color), - UIButton.State.highlighted.rawValue : LightDarkColor(dark_grey_color,dark_grey_color), - UIButton.State.disabled.rawValue : LightDarkColor(voip_light_gray,voip_light_gray) - ] - - static let button_call_context_menu_background = [ - UIButton.State.normal.rawValue : LightDarkColor(voip_gray,voip_gray), - UIButton.State.highlighted.rawValue : LightDarkColor(primary_color,primary_color), - ] - - // Buttons Icons (State colors) + Background colors - - - static let call_terminate = ButtonTheme( - tintableStateIcons:[UIButton.State.normal.rawValue : TintableIcon(name: "voip_hangup",tintColor: LightDarkColor(.white,.white))], - backgroundStateColors: [ - UIButton.State.normal.rawValue : LightDarkColor(primary_color,primary_color), - UIButton.State.highlighted.rawValue : LightDarkColor(primary_dark_color,primary_dark_color) - ]) - - static let call_record = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_call_record",tintColor: LightDarkColor(voip_gray_blue_color,voip_gray_blue_color)), - UIButton.State.selected.rawValue : TintableIcon(name: "voip_call_record",tintColor: LightDarkColor(.white,.white)), - UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_call_record",tintColor: LightDarkColor(primary_color,primary_color)), - ], - backgroundStateColors: button_call_recording_background) - - static let call_pause = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_pause",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_toggle_background) - - static let call_accept = ButtonTheme( - tintableStateIcons:[UIButton.State.normal.rawValue : TintableIcon(name: "voip_call",tintColor: LightDarkColor(.white,.white))], - backgroundStateColors: [ - UIButton.State.normal.rawValue : LightDarkColor(green_color,green_color), - UIButton.State.highlighted.rawValue : LightDarkColor(dark_green_color,dark_green_color) - ]) - - static let call_mute = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_micro_on",tintColor: LightDarkColor(.white,.white)), - UIButton.State.selected.rawValue : TintableIcon(name: "voip_micro_off",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_background_reverse) - - static let call_speaker = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_speaker_off",tintColor: LightDarkColor(.white,.white)), - UIButton.State.selected.rawValue : TintableIcon(name: "voip_speaker_on",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_background_reverse) - - static let call_audio_route = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_audio_routes",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_toggle_background_reverse) - - - static let call_video = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_camera_off",tintColor: LightDarkColor(.white,.white)), - UIButton.State.selected.rawValue : TintableIcon(name: "voip_camera_on",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_background_reverse) - - static let call_numpad = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_call_numpad",tintColor: LightDarkColor(.white,.white)), - UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_call_numpad",tintColor: LightDarkColor(voip_dark_gray,voip_dark_gray)), - UIButton.State.disabled.rawValue : TintableIcon(name: "voip_call_numpad",tintColor: LightDarkColor(voip_light_gray,voip_light_gray)), - ], - backgroundStateColors: button_background) - - // AUdio routes - static let route_bluetooth = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_bluetooth",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_toggle_background_reverse) - - static let route_earpiece = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_earpiece",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_toggle_background_reverse) - - static let route_speaker = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_speaker_on",tintColor: LightDarkColor(.white,.white)), - ], - backgroundStateColors: button_toggle_background_reverse) - - - - static let call_more = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_call_more",tintColor: LightDarkColor(.white,.white)) - ], - backgroundStateColors: button_background) - - - static let voip_cancel = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_cancel",tintColor: voipDrawableColor), - UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_cancel",tintColor: voipDrawableColorHighlighted) - ], - backgroundStateColors: [UIButton.State.normal.rawValue : LightDarkColor(.clear,.clear)]) - - - static let voip_cancel_light = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_cancel",tintColor: LightDarkColor(voip_gray,voip_gray)), - UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_cancel",tintColor: LightDarkColor(voip_dark_gray,voip_dark_gray)) - ], - backgroundStateColors: [UIButton.State.normal.rawValue : LightDarkColor(.clear,.clear)]) - - static let voip_edit = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_edit",tintColor: LightDarkColor(dark_grey_color,dark_grey_color)), - UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_edit",tintColor: voipDrawableColorHighlighted) - ], - backgroundStateColors: [UIButton.State.normal.rawValue : LightDarkColor(.clear,.clear)]) - - static let radio_button = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_radio_off",tintColor: LightDarkColor(dark_grey_color,dark_grey_color)), - UIButton.State.selected.rawValue : TintableIcon(name: "voip_radio_on",tintColor: LightDarkColor(primary_color,primary_color)) - ], - backgroundStateColors: [UIButton.State.normal.rawValue : LightDarkColor(.clear,.clear)]) - - static let voip_call_list_active_menu = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_call_list_menu",tintColor: LightDarkColor(.white,.white)), - UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_call_list_menu",tintColor: voipDrawableColorHighlighted) - ], - backgroundStateColors: [UIButton.State.normal.rawValue : LightDarkColor(.clear,.clear)]) - - static let voip_call_list_menu = ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: "voip_call_list_menu",tintColor: voipTextColor), - UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_call_list_menu",tintColor: voipDrawableColorHighlighted) - ], - backgroundStateColors: [UIButton.State.normal.rawValue : LightDarkColor(.clear,.clear)]) - - - static func call_action(_ iconName:String) -> ButtonTheme { - return ButtonTheme( - tintableStateIcons:[ - UIButton.State.normal.rawValue : TintableIcon(name: iconName,tintColor: LightDarkColor(.white,.white)), - UIButton.State.highlighted.rawValue : TintableIcon(name: iconName,tintColor: LightDarkColor(voip_dark_gray,voip_dark_gray)), - UIButton.State.disabled.rawValue : TintableIcon(name: iconName,tintColor: LightDarkColor(voip_light_gray,voip_light_gray)), - ], - backgroundStateColors: [:]) - } - - static let call_add = ButtonTheme( - tintableStateIcons:[UIButton.State.normal.rawValue : TintableIcon(name: "voip_call_add",tintColor: LightDarkColor(.white,.white))], - backgroundStateColors: button_round_background) - - static let call_merge = ButtonTheme( - tintableStateIcons:[UIButton.State.normal.rawValue : TintableIcon(name: "voip_merge_calls",tintColor: LightDarkColor(.white,.white))], - backgroundStateColors: button_round_background) - -} - - diff --git a/Classes/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift b/Classes/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift deleted file mode 100644 index f85be7062..000000000 --- a/Classes/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import linphonesw - - -class ActiveCallOrConferenceView: UIViewController, UICompositeViewDelegate { // Replaces CallView - - // Layout constants - let content_inset = 12.0 - - var callPausedByRemoteView : PausedCallOrConferenceView? = nil - var conferencePausedView : PausedCallOrConferenceView? = nil - - var currentCallView : ActiveCallView? = nil - var conferenceGridView: VoipConferenceGridView? = nil - var conferenceActiveSpeakerView: VoipConferenceActiveSpeakerView? = nil - - let extraButtonsView = VoipExtraButtonsView() - var numpadView : NumpadView? = nil - var currentCallStatsVew : CallStatsView? = nil - var shadingMask = UIView() - var videoAcceptDialog : VoipDialog? = nil - var dismissableView : DismissableView? = nil - var participantsListView : ParticipantsListView? = nil - - var audioRoutesView : AudioRoutesView? = nil - - - static let compositeDescription = UICompositeViewDescription(ActiveCallOrConferenceView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: nil, fullscreen: false, isLeftFragment: false,fragmentWith: nil) - static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription } - func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription } - - override func viewDidLoad() { - super.viewDidLoad() - - view.backgroundColor = VoipTheme.voipBackgroundColor.get() - - // Hangup - let hangup = CallControlButton(width: 65, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { - ControlsViewModel.shared.hangUp() - }) - view.addSubview(hangup) - hangup.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - - // Controls - let controlsView = ControlsView(showVideo: true) - view.addSubview(controlsView) - controlsView.alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() - - - // Container fiew - let fullScreenMutableContainerView = UIView() - fullScreenMutableContainerView.backgroundColor = .clear - self.view.addSubview(fullScreenMutableContainerView) - fullScreenMutableContainerView.matchParentSideBorders(insetedByDx: content_inset).matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - // Current (Single) Call (VoipCallView) - currentCallView = ActiveCallView() - currentCallView!.isHidden = true - fullScreenMutableContainerView.addSubview(currentCallView!) - CallsViewModel.shared.currentCallData.readCurrentAndObserve { (currentCallData) in - self.updateNavigation() - self.currentCallView!.isHidden = currentCallData == nil || ConferenceViewModel.shared.isInConference.value == true - self.currentCallView!.callData = currentCallData != nil ? currentCallData! : nil - currentCallData??.isRemotelyPaused.readCurrentAndObserve { remotelyPaused in - self.callPausedByRemoteView?.isHidden = remotelyPaused != true - } - if (currentCallData == nil) { - self.callPausedByRemoteView?.isHidden = true - } else { - currentCallData??.isIncoming.readCurrentAndObserve { _ in self.updateNavigation() } - currentCallData??.isOutgoing.readCurrentAndObserve { _ in self.updateNavigation() } - } - self.extraButtonsView.isHidden = true - self.conferencePausedView?.isHidden = true - } - - currentCallView!.matchParentDimmensions().done() - - // Paused by remote (Call) - callPausedByRemoteView = PausedCallOrConferenceView(iconName: "voip_conference_paused_big",titleText: VoipTexts.call_remotely_paused_title,subTitleText: nil) - view.addSubview(callPausedByRemoteView!) - callPausedByRemoteView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - callPausedByRemoteView?.isHidden = true - - // Conference paused - conferencePausedView = PausedCallOrConferenceView(iconName: "voip_conference_paused_big",titleText: VoipTexts.conference_paused_title,subTitleText: VoipTexts.conference_paused_subtitle) - view.addSubview(conferencePausedView!) - conferencePausedView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - conferencePausedView?.isHidden = true - - // Conference grid - conferenceGridView = VoipConferenceGridView() - fullScreenMutableContainerView.addSubview(conferenceGridView!) - conferenceGridView?.matchParentDimmensions().done() - conferenceGridView?.isHidden = true - ConferenceViewModel.shared.isInConference.readCurrentAndObserve { (isInConference) in - self.updateNavigation() - if (isInConference == true) { - self.currentCallView!.isHidden = true - self.extraButtonsView.isHidden = true - self.conferencePausedView?.isHidden = true - self.conferenceGridView!.isHidden = false - self.conferenceActiveSpeakerView!.isHidden = true - self.conferenceGridView?.conferenceViewModel = ConferenceViewModel.shared - } else { - self.conferenceGridView?.isHidden = true - } - } - - // Conference active speaker - conferenceActiveSpeakerView = VoipConferenceActiveSpeakerView() - fullScreenMutableContainerView.addSubview(conferenceActiveSpeakerView!) - conferenceActiveSpeakerView?.matchParentDimmensions().done() - conferenceActiveSpeakerView?.isHidden = true - - // Conference mode switching - - ConferenceViewModel.shared.conferenceDisplayMode.readCurrentAndObserve { (conferenceMode) in - if (ConferenceViewModel.shared.isInConference.value == true) { - self.conferenceGridView!.isHidden = conferenceMode != .Grid - self.conferenceActiveSpeakerView!.isHidden = conferenceMode != .ActiveSpeaker - self.conferenceActiveSpeakerView?.conferenceViewModel = ConferenceViewModel.shared - } else { - self.conferenceActiveSpeakerView?.isHidden = true - } - } - - ConferenceViewModel.shared.isInConference.readCurrentAndObserve { (isInConference) in - self.updateNavigation() - } - - // Calls List - ControlsViewModel.shared.goToCallsListEvent.observe { (_) in - self.dismissableView = CallsListView() - self.view.addSubview(self.dismissableView!) - self.dismissableView?.matchParentDimmensions().done() - } - - // Conference Participants List - ControlsViewModel.shared.goToConferenceParticipantsListEvent.observe { (_) in - self.participantsListView = ParticipantsListView() - self.view.addSubview(self.participantsListView!) - self.participantsListView?.matchParentDimmensions().done() - } - - // Goto chat - ControlsViewModel.shared.goToChatEvent.observe { (_) in - self.goToChat() - } - - // Conference mode selection - ControlsViewModel.shared.goToConferenceLayoutSettings.observe { (_) in - self.dismissableView = VoipConferenceDisplayModeSelectionView() - self.view.addSubview(self.dismissableView!) - self.dismissableView?.matchParentDimmensions().done() - let activeDisplayMode = ConferenceViewModel.shared.conferenceDisplayMode.value! - let indexPath = IndexPath(row: activeDisplayMode == .Grid ? 0 : 1, section: 0) - (self.dismissableView as! VoipConferenceDisplayModeSelectionView).optionsListView.selectRow(at:indexPath, animated: true, scrollPosition: .bottom) - - } - - // Shading mask, everything before will be shaded upon displaying of the mask - shadingMask.backgroundColor = VoipTheme.voip_translucent_popup_background - shadingMask.isHidden = true - self.view.addSubview(shadingMask) - shadingMask.matchParentDimmensions().done() - - // Extra Buttons - let showextraButtons = CallControlButton(imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_more, onClickAction: { - self.showModalSubview(view: self.extraButtonsView) - ControlsViewModel.shared.audioRoutesSelected.value = false - }) - view.addSubview(showextraButtons) - showextraButtons.alignParentRight(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - let boucingCounter = BouncingCounter(inButton:showextraButtons) - view.addSubview(boucingCounter) - boucingCounter.dataSource = CallsViewModel.shared.chatAndCallsCount - - view.addSubview(extraButtonsView) - extraButtonsView.matchParentSideBorders(insetedByDx: content_inset).alignParentBottom().done() - ControlsViewModel.shared.hideExtraButtons.readCurrentAndObserve { (_) in - self.hideModalSubview(view: self.extraButtonsView) - } - self.view.onClick { - if (!self.extraButtonsView.isHidden) { - self.hideModalSubview(view: self.extraButtonsView) - } - ControlsViewModel.shared.audioRoutesSelected.value = false - } - - // Numpad - ControlsViewModel.shared.numpadVisible.readCurrentAndObserve { (visible) in - if (visible == true && CallsViewModel.shared.currentCallData.value != nil ) { - self.numpadView?.removeFromSuperview() - self.shadingMask.isHidden = false - self.numpadView = NumpadView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!, onDismissAction: { - self.numpadView?.removeFromSuperview() - self.shadingMask.isHidden = true - }) - } - } - - // Call stats - ControlsViewModel.shared.callStatsVisible.readCurrentAndObserve { (visible) in - if (visible == true && CallsViewModel.shared.currentCallData.value != nil ) { - self.currentCallStatsVew?.removeFromSuperview() - self.shadingMask.isHidden = false - self.currentCallStatsVew = CallStatsView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!, onDismissAction: { - self.currentCallStatsVew?.removeFromSuperview() - self.shadingMask.isHidden = true - }) - } - } - - // Video activation dialog request - CallsViewModel.shared.callUpdateEvent.observe { (call) in - let core = Core.get() - if (call?.state == .StreamsRunning) { - self.videoAcceptDialog?.removeFromSuperview() - self.videoAcceptDialog = nil - } else if (call?.state == .UpdatedByRemote) { - if (core.videoCaptureEnabled || core.videoDisplayEnabled) { - if (call?.currentParams?.videoEnabled != call?.remoteParams?.videoEnabled) { - let accept = ButtonAttributes(text:VoipTexts.dialog_accept, action: {call?.answerVideoUpdateRequest(accept: true)}, isDestructive:false) - let cancel = ButtonAttributes(text:VoipTexts.dialog_decline, action: {call?.answerVideoUpdateRequest(accept: false)}, isDestructive:true) - self.videoAcceptDialog = VoipDialog(message:VoipTexts.call_video_update_requested_dialog, givenButtons: [cancel,accept]) - self.videoAcceptDialog?.show() - } - } else { - Log.w("[Call] Video display & capture are disabled, don't show video dialog") - } - } - } - - // Audio Routes - audioRoutesView = AudioRoutesView() - view.addSubview(audioRoutesView!) - audioRoutesView!.alignBottomWith(otherView: controlsView).done() - ControlsViewModel.shared.audioRoutesSelected.readCurrentAndObserve { (audioRoutesSelected) in - self.audioRoutesView!.isHidden = audioRoutesSelected != true - } - audioRoutesView!.alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() - - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(true) - extraButtonsView.refresh() - ControlsViewModel.shared.callStatsVisible.notifyValue() - CallsViewModel.shared.currentCallData.notifyValue() - ControlsViewModel.shared.audioRoutesSelected.value = false - } - - override func viewWillDisappear(_ animated: Bool) { - dismissableView?.removeFromSuperview() - dismissableView = nil - - participantsListView?.removeFromSuperview() - participantsListView = nil - - ControlsViewModel.shared.fullScreenMode.value = false - super.viewWillDisappear(animated) - } - - func showModalSubview(view:UIView) { - view.isHidden = false - shadingMask.isHidden = false - } - func hideModalSubview(view:UIView) { - view.isHidden = true - shadingMask.isHidden = true - } - - func updateNavigation() { - if (Core.get().callsNb == 0) { - PhoneMainView.instance().popView(self.compositeViewDescription()) - } else { - if let data = CallsViewModel.shared.currentCallData.value { - if (data?.isOutgoing.value == true || data?.isIncoming.value == true) { - PhoneMainView.instance().popView(self.compositeViewDescription()) - } else { - PhoneMainView.instance().changeCurrentView(self.compositeViewDescription()) - } - } else { - PhoneMainView.instance().changeCurrentView(self.compositeViewDescription()) - } - } - } - - func goToChat() { - let core = Core.get() - guard - let localSipUri = core.defaultAccount?.params?.identityAddress?.asStringUriOnly(), - let remoteSipUri = ConferenceViewModel.shared.isInConference.value == true ? ConferenceViewModel.shared.conferenceAddress.value?.asStringUriOnly() : core.currentCall?.remoteAddress?.asStringUriOnly(), - let localAddress = try?Factory.Instance.createAddress(addr: localSipUri), - let remoteSipAddress = try?Factory.Instance.createAddress(addr: remoteSipUri), - let chatRoomParams = try?core.createDefaultChatRoomParams() - else { - return - } - - var chatRoom = core.searchChatRoom(params: nil, localAddr: localAddress, remoteAddr: remoteSipAddress, participants: []) - if (chatRoom == nil) { - chatRoom = core.searchChatRoom(params: nil, localAddr: localAddress, remoteAddr: nil, participants: [remoteSipAddress]) - } - if (chatRoom == nil) { - Log.w("[Call] Failed to find existing chat room for local address \(localSipUri) and remote address \(remoteSipUri)") - - // TODO: configure chat room params - if (ConferenceViewModel.shared.isInConference.value == true) { - // TODO: compute conference participants addresses list - } else { - chatRoom = try?core.createChatRoom(params: chatRoomParams, localAddr: localAddress, participants: [remoteSipAddress]) - } - } - - if (chatRoom != nil) { - PhoneMainView.instance().go(to: chatRoom?.getCobject) - } else { - Log.w("[Call] Failed to create chat room for local address \(localSipUri) and remote address \(remoteSipUri)") - } - - } - - -} diff --git a/Classes/Voip/Views/CompositeViewControllers/IncomingCallView.swift b/Classes/Voip/Views/CompositeViewControllers/IncomingCallView.swift deleted file mode 100644 index 6009bf0a5..000000000 --- a/Classes/Voip/Views/CompositeViewControllers/IncomingCallView.swift +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import linphonesw - -@objc class IncomingCallView: IncomingOutgoingCommonView, UICompositeViewDelegate { - - // Layout constants - let buttons_distance_from_center_x = 38 - - static let compositeDescription = UICompositeViewDescription(IncomingCallView.self, statusBar: nil, tabBar: nil, sideMenu: nil, fullscreen: true, isLeftFragment: false,fragmentWith: nil) - static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription } - func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription } - - var earlyMediaView : UIView? = nil - - override func viewDidLoad() { - - super.viewDidLoad(forCallType: VoipTexts.call_incoming_title) - - // Accept - let accept = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_accept, onClickAction: { - self.callData.map { CallManager.instance().acceptCall(call: $0.call.getCobject, hasVideo: false)} - }) - view.addSubview(accept) - accept.centerX(withDx: buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - // Decline - let decline = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { - self.callData.map { CallManager.instance().terminateCall(call: $0.call.getCobject)} - }) - view.addSubview(decline) - decline.centerX(withDx: -buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - } - - @objc override func setCall(call:OpaquePointer) { - super.setCall(call: call) - callData?.iFrameReceived.observe(onChange: { (video) in - if (video == true) { - Core.get().nativeVideoWindow = self.earlyMediaView - self.earlyMediaView?.isHidden = false - } - }) - callData?.callState.readCurrentAndObserve(onChange: { (state) in - if (ConfigManager.instance().lpConfigBoolForKey(key: "pref_accept_early_media") && state == .IncomingReceived) { - try?self.callData?.call.acceptEarlyMedia() - self.callData?.call.requestNotifyNextVideoFrameDecoded() - } - }) - callData?.isIncoming.readCurrentAndObserve { (incoming) in - if (incoming != true) { - PhoneMainView.instance().popView(self.compositeViewDescription()) - } - } - - if (ConfigManager.instance().lpConfigBoolForKey(key: "auto_answer")) { - CallManager.instance().acceptCall(call: call, hasVideo: false) // TODO check with old version for Video accept separate button - Not implemented in Android - } - } - - -} diff --git a/Classes/Voip/Views/CompositeViewControllers/OutgoingCallView.swift b/Classes/Voip/Views/CompositeViewControllers/OutgoingCallView.swift deleted file mode 100644 index d2898a148..000000000 --- a/Classes/Voip/Views/CompositeViewControllers/OutgoingCallView.swift +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import linphonesw - -@objc class OutgoingCallView: IncomingOutgoingCommonView, UICompositeViewDelegate { - - // Layout constants - let numpad_icon_padding = 10.0 - - var numpadView : NumpadView? = nil - var showNumPad : CallControlButton? = nil - var shadingMask = UIView() - - - static let compositeDescription = UICompositeViewDescription(OutgoingCallView.self, statusBar: nil, tabBar: nil, sideMenu: nil, fullscreen: true, isLeftFragment: false,fragmentWith: nil) - static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription } - func compositeViewDescription() -> UICompositeViewDescription! { return OutgoingCallView.compositeDescription } - - override func viewDidLoad() { - super.viewDidLoad(forCallType: VoipTexts.call_outgoing_title) - - // Cancel - let cancelCall = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { - self.callData.map { CallManager.instance().terminateCall(call: $0.call.getCobject)} - }) - view.addSubview(cancelCall) - cancelCall.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - // Controls - let controlsView = ControlsView(showVideo: false) - view.addSubview(controlsView) - controlsView.alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() - - // Shading mask, everything after will be shaded upon displayed - shadingMask.backgroundColor = VoipTheme.voip_translucent_popup_background - shadingMask.isHidden = true - self.view.addSubview(shadingMask) - shadingMask.matchParentDimmensions().done() - - // Numpad - showNumPad = CallControlButton(imageInset:UIEdgeInsets(top: numpad_icon_padding, left: numpad_icon_padding, bottom: numpad_icon_padding, right: numpad_icon_padding), buttonTheme: VoipTheme.call_numpad, onClickAction: { - self.numpadView?.removeFromSuperview() - self.shadingMask.isHidden = false - self.numpadView = NumpadView(superView: self.view,callData: self.callData!, onDismissAction: { - self.numpadView?.removeFromSuperview() - self.shadingMask.isHidden = true - }) - }) - view.addSubview(showNumPad!) - showNumPad?.alignParentRight(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - showNumPad!.isHidden = true - - // Audio Routes - let audioRoutesView = AudioRoutesView() - view.addSubview(audioRoutesView) - audioRoutesView.alignBottomWith(otherView: controlsView).done() - ControlsViewModel.shared.audioRoutesSelected.readCurrentAndObserve { (audioRoutesSelected) in - audioRoutesView.isHidden = audioRoutesSelected != true - } - audioRoutesView.alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).matchRightOf(view: controlsView, withMargin:+ControlsView.controls_button_spacing).done() - } - - - override func viewWillAppear(_ animated: Bool) { - ControlsViewModel.shared.audioRoutesSelected.value = false - super.viewWillAppear(animated) - } - - @objc override func setCall(call:OpaquePointer) { - super.setCall(call: call) - self.callData?.outgoingEarlyMedia.readCurrentAndObserve(onChange: { (outgoingEM) in - self.showNumPad!.isHidden = outgoingEM != true - }) - callData?.isOutgoing.readCurrentAndObserve { (outgoing) in - if (outgoing != true) { - PhoneMainView.instance().popView(self.compositeViewDescription()) - } - } - } - - -} diff --git a/Classes/Voip/Views/Fragments/ActiveCall/ActiveCallView.swift b/Classes/Voip/Views/Fragments/ActiveCall/ActiveCallView.swift deleted file mode 100644 index 2b8194b70..000000000 --- a/Classes/Voip/Views/Fragments/ActiveCall/ActiveCallView.swift +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class ActiveCallView: UIView { // = currentCall - - // Layout constants : - static let top_displayname_margin_top = 20.0 - let sip_address_margin_top = 4.0 - static let remote_recording_margin_top = 10.0 - static let remote_recording_height = 30 - static let bottom_displayname_margin_bottom = 10.0 - static let bottom_displayname_margin_left = 12.0 - static let center_view_margin_top = 15.0 - static let center_view_corner_radius = 20.0 - let record_pause_button_size = 40 - let record_pause_button_inset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7) - let record_pause_button_margin = 10.0 - static let local_video_width = 150.0 - static let local_video_margins = 15.0 - - - let displayNameTop = StyledLabel(VoipTheme.call_display_name_duration) - let duration = CallTimer(nil, VoipTheme.call_display_name_duration) - let sipAddress = StyledLabel(VoipTheme.call_sip_address) - let remotelyRecordedIndicator = RemotelyRecordingView(height: ActiveCallView.remote_recording_height,text: VoipTexts.call_remote_recording) - let avatar = Avatar(diameter: CGFloat(Avatar.diameter_for_call_views), color:VoipTheme.voipBackgroundColor, textStyle: VoipTheme.call_generated_avatar_large) - let displayNameBottom = StyledLabel(VoipTheme.call_remote_name) - var recordCallButtons : [CallControlButton] = [] - var pauseCallButtons : [CallControlButton] = [] - let remoteVideo = UIView() - let localVideo = LocalVideoView(width: local_video_width) - - var callData: CallData? = nil { - didSet { - duration.call = callData?.call - callData?.call.remoteAddress.map { - avatar.fillFromAddress(address: $0) - if let displayName = $0.addressBookEnhancedDisplayName() { - displayNameTop.text = displayName+" - " - displayNameBottom.text = displayName - } - sipAddress.text = $0.asStringUriOnly() - } - self.remotelyRecordedIndicator.isRemotelyRecorded = callData?.isRemotelyRecorded - callData?.isRecording.readCurrentAndObserve { (selected) in - self.recordCallButtons.forEach { - $0.isSelected = selected == true - } - } - callData?.isPaused.readCurrentAndObserve { (paused) in - self.pauseCallButtons.forEach { - $0.isSelected = paused == true - } - if (paused == true) { - self.localVideo.isHidden = true - } - } - - Core.get().nativeVideoWindow = remoteVideo - Core.get().nativePreviewWindow = localVideo - - ControlsViewModel.shared.isVideoEnabled.readCurrentAndObserve{ (video) in - self.remoteVideo.isHidden = video != true - self.localVideo.isHidden = video != true - self.recordCallButtons.first?.isHidden = video != true - self.pauseCallButtons.first?.isHidden = video != true - self.recordCallButtons.last?.isHidden = video == true - self.pauseCallButtons.last?.isHidden = video == true - } - - } - } - - init() { - super.init(frame: .zero) - let stack = UIStackView() - stack.distribution = .equalSpacing - stack.alignment = .bottom - stack.spacing = record_pause_button_margin - stack.axis = .vertical - - let displayNameDurationSipAddress = UIView() - - displayNameDurationSipAddress.addSubview(displayNameTop) - displayNameTop.alignParentLeft().done() - - displayNameDurationSipAddress.addSubview(duration) - duration.toRightOf(displayNameTop).alignParentRight().done() - - displayNameDurationSipAddress.addSubview(sipAddress) - sipAddress.matchParentSideBorders().alignUnder(view: displayNameTop,withMargin:sip_address_margin_top).done() - - let upperSection = UIStackView() - upperSection.distribution = .equalSpacing - upperSection.alignment = .center - upperSection.spacing = record_pause_button_margin - upperSection.axis = .horizontal - - upperSection.addArrangedSubview(displayNameDurationSipAddress) - displayNameDurationSipAddress.wrapContentY().done() - - let recordPauseView = UIStackView() - recordPauseView.spacing = record_pause_button_margin - - // Record (with video) - var recordCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_record, onClickAction: { - self.callData.map { $0.toggleRecord() } - }) - recordCallButtons.append(recordCall) - recordPauseView.addArrangedSubview(recordCall) - - // Pause (with video) - var pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: { - self.callData.map { $0.togglePause() } - }) - pauseCallButtons.append(pauseCall) - recordPauseView.addArrangedSubview(pauseCall) - upperSection.addArrangedSubview(recordPauseView) - - - stack.addArrangedSubview(upperSection) - upperSection.matchParentSideBorders().alignParentTop(withMargin:ActiveCallView.top_displayname_margin_top).done() - - - stack.addArrangedSubview(remotelyRecordedIndicator) - remotelyRecordedIndicator.matchParentSideBorders().alignUnder(view:upperSection, withMargin:ActiveCallView.remote_recording_margin_top).height(CGFloat(ActiveCallView.remote_recording_height)).done() - - // Center Section : Avatar + video + record/pause buttons + videos - let centerSection = UIView() - centerSection.layer.cornerRadius = ActiveCallView.center_view_corner_radius - centerSection.clipsToBounds = true - centerSection.backgroundColor = VoipTheme.voipParticipantBackgroundColor.get() - - // Record (w/o video) - recordCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_record, onClickAction: { - self.callData.map { $0.toggleRecord() } - }) - recordCallButtons.append(recordCall) - centerSection.addSubview(recordCall) - recordCall.alignParentLeft(withMargin:record_pause_button_margin).alignParentTop(withMargin:record_pause_button_margin).done() - - // Pause (w/o video) - pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: { - self.callData.map { $0.togglePause() } - }) - pauseCallButtons.append(pauseCall) - centerSection.addSubview(pauseCall) - pauseCall.alignParentRight(withMargin:record_pause_button_margin).alignParentTop(withMargin:record_pause_button_margin).done() - - // Avatar - centerSection.addSubview(avatar) - avatar.square(Avatar.diameter_for_call_views).center().done() - - // Remote Video Display - centerSection.addSubview(remoteVideo) - remoteVideo.isHidden = true - remoteVideo.matchParentDimmensions().done() - - // Local Video Display - centerSection.addSubview(localVideo) - localVideo.backgroundColor = .black - localVideo.alignParentBottom(withMargin: ActiveCallView.local_video_margins).alignParentRight(withMargin: ActiveCallView.local_video_margins).done() - localVideo.isHidden = true - localVideo.dragZone = centerSection - - // Full screen video togggle - remoteVideo.onClick { - ControlsViewModel.shared.toggleFullScreen() - } - ControlsViewModel.shared.fullScreenMode.observe { (fullScreen) in - if (self.isHidden) { - return - } - self.remoteVideo.removeConstraints().done() - self.localVideo.removeConstraints().done() - if (fullScreen == true) { - self.remoteVideo.removeFromSuperview() - self.localVideo.removeFromSuperview() - PhoneMainView.instance().mainViewController.view?.addSubview(self.remoteVideo) - PhoneMainView.instance().mainViewController.view?.addSubview(self.localVideo) - } else { - self.remoteVideo.removeFromSuperview() - self.localVideo.removeFromSuperview() - centerSection.addSubview(self.remoteVideo) - centerSection.addSubview(self.localVideo) - } - self.remoteVideo.matchParentDimmensions().done() - self.localVideo.alignParentBottom(withMargin: ActiveCallView.local_video_margins).alignParentRight(withMargin: ActiveCallView.local_video_margins).done() - self.localVideo.setSizeConstraint() - } - - - // Bottom display name - centerSection.addSubview(displayNameBottom) - displayNameBottom.alignParentLeft(withMargin:ActiveCallView.bottom_displayname_margin_left).alignParentRight().alignParentBottom(withMargin:ActiveCallView.bottom_displayname_margin_bottom).done() - - stack.addArrangedSubview(centerSection) - centerSection.matchParentSideBorders().alignUnder(view:upperSection,withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done() - - addSubview(stack) - stack.matchParentDimmensions().done() - - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} diff --git a/Classes/Voip/Views/Fragments/AudioRoutesView.swift b/Classes/Voip/Views/Fragments/AudioRoutesView.swift deleted file mode 100644 index 1618e3727..000000000 --- a/Classes/Voip/Views/Fragments/AudioRoutesView.swift +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import UIKit - -class AudioRoutesView: UIStackView { - - // Layout constants - let corner_radius = 6.7 - let margin = 10.0 - - init () { - super.init(frame: .zero) - axis = .vertical - distribution = .equalCentering - alignment = .center - spacing = ControlsView.controls_button_spacing - backgroundColor = VoipTheme.voip_gray - layer.cornerRadius = corner_radius - clipsToBounds = true - - // bluetooth - let blueTooth = CallControlButton(buttonTheme: VoipTheme.route_bluetooth, onClickAction: { - ControlsViewModel.shared.forceBluetoothAudioRoute() - }) - addArrangedSubview(blueTooth) - - ControlsViewModel.shared.isBluetoothHeadsetSelected.readCurrentAndObserve { (selected) in - blueTooth.isSelected = selected == true - } - - // Earpiece - let earpiece = CallControlButton(buttonTheme: VoipTheme.route_earpiece, onClickAction: { - ControlsViewModel.shared.forceEarpieceAudioRoute() - }) - addArrangedSubview(earpiece) - ControlsViewModel.shared.isSpeakerSelected.readCurrentAndObserve { (isSpeakerSelected) in - earpiece.isSelected = isSpeakerSelected != true && ControlsViewModel.shared.isBluetoothHeadsetSelected.value != true - } - ControlsViewModel.shared.isBluetoothHeadsetSelected.readCurrentAndObserve { (isBluetoothHeadsetSelected) in - earpiece.isSelected = isBluetoothHeadsetSelected != true && ControlsViewModel.shared.isSpeakerSelected.value != true - } - - // Speaker - let speaker = CallControlButton(buttonTheme: VoipTheme.route_speaker, onClickAction: { - ControlsViewModel.shared.forceSpeakerAudioRoute() - }) - addArrangedSubview(speaker) - ControlsViewModel.shared.isSpeakerSelected.readCurrentAndObserve { (selected) in - speaker.isSelected = selected == true - } - - size(w:CGFloat(CallControlButton.default_size)+margin, h : 3*CGFloat(CallControlButton.default_size)+2*CGFloat(ControlsView.controls_button_spacing)+margin).done() - - } - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - - diff --git a/Classes/Voip/Views/Fragments/CallStatsView.swift b/Classes/Voip/Views/Fragments/CallStatsView.swift deleted file mode 100644 index 142cc03d6..000000000 --- a/Classes/Voip/Views/Fragments/CallStatsView.swift +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -@objc class CallStatsView: UIView { - - // Layout constants - let side_margins = 10.0 - let margin_top = 50 - let corner_radius = 20.0 - let view_height = 600 - let audio_video_margin = 20 - - init(superView:UIView, callData:CallData, onDismissAction : @escaping ()->Void) { - super.init(frame:.zero) - backgroundColor = VoipTheme.voip_translucent_popup_background - layer.cornerRadius = corner_radius - clipsToBounds = true - superView.addSubview(self) - snp.makeConstraints { make in - make.left.equalToSuperview().offset(side_margins) - make.right.equalToSuperview().offset(-side_margins) - make.height.equalTo(view_height) - make.bottom.equalToSuperview().offset(-side_margins) - } - callData.callState.observe { state in - if (state == Call.State.End) { - onDismissAction() - } - } - - let hide = CallControlButton(buttonTheme: VoipTheme.voip_cancel_light, onClickAction: { - onDismissAction() - }) - addSubview(hide) - hide.alignParentRight(withMargin: side_margins).alignParentTop(withMargin: side_margins).done() - - - let model = CallStatisticsData(call: callData.call) - let audioTitle = StyledLabel(VoipTheme.call_stats_font_title,NSLocalizedString("Audio", comment: "")) - addSubview(audioTitle) - audioTitle.matchParentSideBorders().alignParentTop(withMargin: margin_top).done() - - let audioStats = StyledLabel(VoipTheme.call_stats_font) - - audioStats.numberOfLines = 0 - addSubview(audioStats) - audioStats.matchParentSideBorders().alignUnder(view: audioTitle).done() - - let videoTitle = StyledLabel(VoipTheme.call_stats_font_title,NSLocalizedString("Video", comment: "")) - addSubview(videoTitle) - videoTitle.alignUnder(view: audioStats, withMargin:audio_video_margin).matchParentSideBorders().done() - - let videoStats = StyledLabel(VoipTheme.call_stats_font) - - videoStats.numberOfLines = 0 - addSubview(videoStats) - videoStats.matchParentSideBorders().alignUnder(view: videoTitle).done() - - model.isVideoEnabled.readCurrentAndObserve { (video) in - videoTitle.isHidden = video != true - videoStats.isHidden = video != true - } - - model.statsUpdated.readCurrentAndObserve { (updated) in - var stats = "" - model.audioStats.forEach { - stats += "\n\($0.getTypeTitle())\($0.value.value ?? "n/a")" - } - audioStats.text = stats - stats = "" - model.videoStats.forEach { - stats += "\n\($0.getTypeTitle())\($0.value.value ?? "n/a")" - } - videoStats.text = stats - } - - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - -} - - - diff --git a/Classes/Voip/Views/Fragments/CallsList/CallsListView.swift b/Classes/Voip/Views/Fragments/CallsList/CallsListView.swift deleted file mode 100644 index 6fad29f47..000000000 --- a/Classes/Voip/Views/Fragments/CallsList/CallsListView.swift +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import linphonesw - -@objc class CallsListView: DismissableView, UITableViewDataSource { - - // Layout constants - let buttons_distance_from_center_x = 38 - let buttons_size = 60 - - let callsListTableView = UITableView() - let menuView = VoipCallContextMenu() - - var callsDataObserver : MutableLiveDataOnChangeClosure<[CallData]>? = nil - - init() { - super.init(title: VoipTexts.call_action_calls_list) - - // New Call - let newCall = CallControlButton(width: buttons_size,height: buttons_size, buttonTheme: VoipTheme.call_add, onClickAction: { - let view: DialerView = self.VIEW(DialerView.compositeViewDescription()); - view.setAddress("") - CallManager.instance().nextCallIsTransfer = false - PhoneMainView.instance().changeCurrentView(view.compositeViewDescription()) - }) - addSubview(newCall) - newCall.centerX(withDx: -buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - // Merge Calls - let mergeIntoLocalConference = CallControlButton(width: buttons_size,height: buttons_size, buttonTheme: VoipTheme.call_merge, onClickAction: { - self.removeFromSuperview() - CallsViewModel.shared.mergeCallsIntoLocalConference() - }) - addSubview(mergeIntoLocalConference) - mergeIntoLocalConference.centerX(withDx: buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - - CallsViewModel.shared.callsData.readCurrentAndObserve{ (callsData) in - if let callsData = callsData { - mergeIntoLocalConference.isEnabled = callsData.count >= 2 && Core.get().conference?.isIn != true - } else { - mergeIntoLocalConference.isEnabled = false - } - self.callsListTableView.reloadData() - } - - - // CallsList - super.contentView.addSubview(callsListTableView) - callsListTableView.matchParentDimmensions().done() - callsListTableView.dataSource = self - callsListTableView.register(VoipCallCell.self, forCellReuseIdentifier: "VoipCallCell") - callsListTableView.allowsSelection = false - if #available(iOS 15.0, *) { - callsListTableView.allowsFocus = false - } - callsListTableView.separatorStyle = .singleLine - callsListTableView.separatorColor = .white - callsListTableView.onClick { - self.hideMenu() - } - - // Floating menu - super.contentView.addSubview(menuView) - - menuView.isHidden = true - - } - - - func toggleMenu(forCell:VoipCallCell) { - if (menuView.isHidden) { - showMenu(forCell: forCell) - } else if (menuView.callData?.call.callLog?.callId != forCell.callData?.call.callLog?.callId) { - hideMenu() - showMenu(forCell: forCell) - } else { - hideMenu() - } - } - - func showMenu(forCell:VoipCallCell) { - menuView.removeConstraints().alignUnder(view: forCell).alignParentRight().done() - menuView.callData = forCell.callData - menuView.isHidden = false - } - - func hideMenu() { - menuView.isHidden = true - } - - // TableView datasource delegate - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - guard let callsData = CallsViewModel.shared.callsData.value else { - return 0 - } - return callsData.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell:VoipCallCell = tableView.dequeueReusableCell(withIdentifier: "VoipCallCell") as! VoipCallCell - guard let callData = CallsViewModel.shared.callsData.value?[indexPath.row] else { - return cell - } - cell.selectionStyle = .none - cell.callData = callData - cell.owningCallsListView = self - return cell - } - - // View controller - - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} diff --git a/Classes/Voip/Views/Fragments/CallsList/VoipCallCell.swift b/Classes/Voip/Views/Fragments/CallsList/VoipCallCell.swift deleted file mode 100644 index 22c92def4..000000000 --- a/Classes/Voip/Views/Fragments/CallsList/VoipCallCell.swift +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipCallCell: UITableViewCell { - - // Layout Constants - let cell_height = 80.0 - let call_status_icon_size = 65.0 - static let avatar_size = 45.0 - let avatar_left_margin = 40.0 - let texts_left_margin = 20.0 - let side_menu_icon_size = 80.0 - - - var onMenuClickAction : (()->Void) = {} - let callStatusIcon = UIImageView() - let avatar = Avatar(diameter:VoipCallCell.avatar_size,color:LightDarkColor(VoipTheme.voip_contact_avatar_calls_list,VoipTheme.voip_contact_avatar_calls_list), textStyle: VoipTheme.call_generated_avatar_small) - let conferenceAvatar = UIImageView(image:UIImage(named:"voip_multiple_contacts_avatar")) - let displayName = StyledLabel(VoipTheme.call_list_active_name_font) - let sipAddress = StyledLabel(VoipTheme.call_list_active_sip_uri_font) - var menuButton : CallControlButton? = nil - var owningCallsListView : CallsListView? = nil - - var callData: CallData? = nil { - didSet { - if let data = callData { - contentView.backgroundColor = data.isPaused.value == true ? VoipTheme.voip_calls_list_inactive_background : VoipTheme.voip_dark_gray - callStatusIcon.image = - data.isIncoming.value == true ? UIImage(named:"voip_call_header_incoming") : - data.isOutgoing.value == true ? UIImage(named:"voip_call_header_outgoing") : - data.isPaused.value == true ? UIImage(named:"voip_call_header_paused") : - UIImage(named:"voip_call_header_active") - if (data.isInRemoteConference.value == true) { - avatar.isHidden = true - conferenceAvatar.isHidden = false - displayName.text = data.remoteConferenceSubject.value - } else { - displayName.text = data.call.remoteAddress?.addressBookEnhancedDisplayName() - avatar.fillFromAddress(address: data.call.remoteAddress!) - avatar.isHidden = false - conferenceAvatar.isHidden = true - } - sipAddress.text = data.call.remoteAddress?.asStringUriOnly() - displayName.applyStyle(data.isPaused.value == true ? VoipTheme.call_list_name_font : VoipTheme.call_list_active_name_font) - sipAddress.applyStyle(data.isPaused.value == true ? VoipTheme.call_list_sip_uri_font : VoipTheme.call_list_active_sip_uri_font) - menuButton?.applyTintedIcons(tintedIcons: data.isPaused.value == true ? VoipTheme.voip_call_list_menu.tintableStateIcons : VoipTheme.voip_call_list_active_menu.tintableStateIcons) - } - } - } - - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - contentView.height(cell_height).matchParentSideBorders().done() - - contentView.addSubview(callStatusIcon) - callStatusIcon.size(w: call_status_icon_size, h: call_status_icon_size).done() - - contentView.addSubview(avatar) - avatar.size(w: VoipCallCell.avatar_size, h: VoipCallCell.avatar_size).centerY().alignParentLeft(withMargin: avatar_left_margin).done() - - contentView.addSubview(conferenceAvatar) - conferenceAvatar.size(w: VoipCallCell.avatar_size, h: VoipCallCell.avatar_size).centerY().alignParentLeft(withMargin: avatar_left_margin).done() - - let nameAddress = UIView() - nameAddress.addSubview(displayName) - nameAddress.addSubview(sipAddress) - displayName.alignParentTop().done() - sipAddress.alignUnder(view: displayName).done() - contentView.addSubview(nameAddress) - nameAddress.toRightOf(avatar,withLeftMargin:texts_left_margin).toRightOf(conferenceAvatar,withLeftMargin:texts_left_margin).wrapContentY().centerY().done() - - menuButton = CallControlButton(buttonTheme: VoipTheme.voip_call_list_active_menu, onClickAction: { - self.owningCallsListView?.toggleMenu(forCell: self) - }) - contentView.addSubview(menuButton!) - menuButton!.size(w: side_menu_icon_size, h: side_menu_icon_size).alignParentRight().centerY().done() - - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/Classes/Voip/Views/Fragments/CallsList/VoipCallContextMenu.swift b/Classes/Voip/Views/Fragments/CallsList/VoipCallContextMenu.swift deleted file mode 100644 index 79cdaa063..000000000 --- a/Classes/Voip/Views/Fragments/CallsList/VoipCallContextMenu.swift +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipCallContextMenu: UIStackView { - - //Layout constants - static let item_height = 50.0 - let width = 250.0 - let margin_bw_items = 1.0 - static let texts_margin_left = 10.0 - - - let resume : ButtonWithStateBackgrounds - let pause : ButtonWithStateBackgrounds - let transfer : ButtonWithStateBackgrounds - let answer : ButtonWithStateBackgrounds - let terminate : ButtonWithStateBackgrounds - - var callData: CallData? = nil { - didSet { - callData?.callState.readCurrentAndObserve(onChange: { (state) in - self.resume.isHidden = false - self.pause.isHidden = false - self.transfer.isHidden = false - self.answer.isHidden = false - self.terminate.isHidden = false - var count = 5.0 - - if let callData = self.callData { - if (callData.isPaused.value == true || - callData.isIncoming.value == true || - callData.isOutgoing.value == true || - callData.isInRemoteConference.value == true - ) { - self.pause.isHidden = true - count -= 1 - } - - if (callData.isIncoming.value == true || - callData.isOutgoing.value == true || - callData.isInRemoteConference.value == true - ) { - self.resume.isHidden = true - self.transfer.isHidden = true - count -= 2 - } else if (callData.isPaused.value == false) { - self.resume.isHidden = true - count -= 1 - } - - if (callData.isIncoming.value == false) { - count -= 1 - self.answer.isHidden = true - } - self.size(w:self.width,h:count*VoipCallContextMenu.item_height).done() - } - - }) - } - } - - - init () { - - resume = VoipCallContextMenu.getButton(title: VoipTexts.call_context_action_resume) - pause = VoipCallContextMenu.getButton(title: VoipTexts.call_context_action_pause) - transfer = VoipCallContextMenu.getButton(title: VoipTexts.call_context_action_transfer) - answer = VoipCallContextMenu.getButton(title: VoipTexts.call_context_action_answer) - terminate = VoipCallContextMenu.getButton(title: VoipTexts.call_context_action_hangup) - - super.init(frame: .zero) - backgroundColor = .white - axis = .vertical - spacing = margin_bw_items - - - addArrangedSubview(resume) - addArrangedSubview(pause) - addArrangedSubview(transfer) - addArrangedSubview(answer) - addArrangedSubview(terminate) - - resume.onClick { - self.isHidden = true - guard let call = self.callData?.call else { return } - if (CallManager.callKitEnabled()) { - CallManager.instance().setHeld(call:call,hold:false); - } else { - try?call.resume() - } - } - pause.onClick { - self.isHidden = true - guard let call = self.callData?.call else { return } - if (CallManager.callKitEnabled()) { - CallManager.instance().setHeld(call:call,hold:true); - } else { - try?call.pause() - } - } - transfer.onClick { - let view: DialerView = self.VIEW(DialerView.compositeViewDescription()); - view.setAddress("") - CallManager.instance().nextCallIsTransfer = true - PhoneMainView.instance().changeCurrentView(view.compositeViewDescription()) - } - answer.onClick { - self.isHidden = true - guard let call = self.callData?.call else { return } - if (CallManager.callKitEnabled()) { - CallManager.instance().acceptCall(call: call, hasVideo: false) - } else { - try?call.accept() - } - } - terminate.onClick { - self.isHidden = true - guard let call = self.callData?.call else { return } - try?call.terminate() - } - } - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - static func getButton(title:String) -> ButtonWithStateBackgrounds { - let button = ButtonWithStateBackgrounds(backgroundStateColors: VoipTheme.button_call_context_menu_background) - button.setTitle(title, for: .normal) - button.applyTitleStyle(VoipTheme.call_context_menu_item_font) - button.titleEdgeInsets = UIEdgeInsets(top: 0, left: texts_margin_left, bottom: 0, right: 0) - button.height(VoipCallContextMenu.item_height).done() - return button - } - - - -} diff --git a/Classes/Voip/Views/Fragments/Conference/VoipActiveSpeakerParticipantCell.swift b/Classes/Voip/Views/Fragments/Conference/VoipActiveSpeakerParticipantCell.swift deleted file mode 100644 index 02c2f384f..000000000 --- a/Classes/Voip/Views/Fragments/Conference/VoipActiveSpeakerParticipantCell.swift +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipActiveSpeakerParticipantCell: UICollectionViewCell { - - // Layout Constants - let corner_radius = 20.0 - static let avatar_size = 80.0 - let switch_camera_button_margins = 8.0 - let switch_camera_button_size = 30 - - - let videoView = UIView() - let avatar = Avatar(diameter:VoipGridParticipantCell.avatar_size,color:VoipTheme.voipBackgroundColor, textStyle: VoipTheme.call_generated_avatar_medium) - let pause = UIImageView(image: UIImage(named: "voip_pause")?.tinted(with: .white)) - let switchCamera = UIImageView(image: UIImage(named:"voip_change_camera")?.tinted(with:.white)) - let displayName = StyledLabel(VoipTheme.conference_participant_name_font_as) - let pauseLabel = StyledLabel(VoipTheme.conference_participant_name_font_as,VoipTexts.conference_participant_paused) - - var participantData: ConferenceParticipantDeviceData? = nil { - didSet { - if let data = participantData { - data.isInConference.readCurrentAndObserve { (isIn) in - self.updateBackground() - self.pause.isHidden = isIn == true - self.pauseLabel.isHidden = self.pause.isHidden - } - data.videoEnabled.readCurrentAndObserve { (videoEnabled) in - self.updateBackground() - if (videoEnabled == true) { - data.setVideoView(view: self.videoView) - self.avatar.isHidden = true - } else { - self.avatar.isHidden = false - } - self.switchCamera.isHidden = videoEnabled != true || !data.isSwitchCameraAvailable() - } - data.participantDevice.address.map { - avatar.fillFromAddress(address: $0) - if let displayName = $0.addressBookEnhancedDisplayName() { - self.displayName.text = displayName - } - } - } - } - } - - func updateBackground() { - if let data = participantData { - if (data.isInConference.value != true) { - self.contentView.backgroundColor = VoipTheme.voip_conference_participant_paused_background - } else if (data.videoEnabled.value == true) { - self.contentView.backgroundColor = .black - } else { - self.contentView.backgroundColor = VoipTheme.voipParticipantBackgroundColor.get() - - } - } - } - - - override init(frame:CGRect) { - super.init(frame:.zero) - layer.cornerRadius = corner_radius - clipsToBounds = true - - contentView.addSubview(videoView) - videoView.matchParentDimmensions().done() - - contentView.addSubview(avatar) - avatar.size(w: VoipGridParticipantCell.avatar_size, h: VoipGridParticipantCell.avatar_size).center().done() - - contentView.addSubview(pause) - pause.layer.cornerRadius = VoipGridParticipantCell.avatar_size/2 - pause.clipsToBounds = true - pause.backgroundColor = VoipTheme.voip_gray - pause.size(w: VoipGridParticipantCell.avatar_size, h: VoipGridParticipantCell.avatar_size).center().done() - - contentView.addSubview(switchCamera) - switchCamera.alignParentTop(withMargin: switch_camera_button_margins).alignParentRight(withMargin: switch_camera_button_margins).square(switch_camera_button_size).done() - switchCamera.contentMode = .scaleAspectFit - - switchCamera.onClick { - Core.get().toggleCamera() - } - - contentView.addSubview(displayName) - displayName.matchParentSideBorders(insetedByDx:ActiveCallView.bottom_displayname_margin_left).alignParentBottom(withMargin:ActiveCallView.bottom_displayname_margin_bottom).done() - - contentView.addSubview(pauseLabel) - pauseLabel.toRightOf(displayName).alignParentBottom(withMargin:ActiveCallView.bottom_displayname_margin_bottom).done() - - contentView.matchParentDimmensions().done() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/Classes/Voip/Views/Fragments/Conference/VoipConferenceActiveSpeakerView.swift b/Classes/Voip/Views/Fragments/Conference/VoipConferenceActiveSpeakerView.swift deleted file mode 100644 index e0bc2d937..000000000 --- a/Classes/Voip/Views/Fragments/Conference/VoipConferenceActiveSpeakerView.swift +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipConferenceActiveSpeakerView: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { - - // Layout constants : - let inter_cell = 10.0 - let record_pause_button_margin = 10.0 - let duration_margin_top = 4.0 - let record_pause_button_size = 40 - let record_pause_button_inset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7) - let grid_height = 150.0 - let cell_width = 100.0 - - - let subjectLabel = StyledLabel(VoipTheme.call_display_name_duration) - let duration = CallTimer(nil, VoipTheme.call_display_name_duration) - - let remotelyRecording = RemotelyRecordingView(height: ActiveCallView.remote_recording_height,text: VoipTexts.call_remote_recording) - var recordCallButtons : [CallControlButton] = [] - var pauseCallButtons : [CallControlButton] = [] - - let activeSpeakerView = UIView() - let activeSpeakerVideoView = UIView() - let activeSpeakerAvatar = Avatar(diameter: CGFloat(Avatar.diameter_for_call_views), color:VoipTheme.voipBackgroundColor, textStyle: VoipTheme.call_generated_avatar_large) - let activeSpeakerDisplayName = StyledLabel(VoipTheme.call_remote_name) - var activeSpeakerMonitorTimer : Timer? = nil - - var grid : UICollectionView - - - var conferenceViewModel: ConferenceViewModel? = nil { - didSet { - if let model = conferenceViewModel { - model.subject.readCurrentAndObserve { (subject) in - self.subjectLabel.text = subject - } - duration.conference = model.conference.value - self.remotelyRecording.isRemotelyRecorded = model.isRemotelyRecorded - model.conferenceParticipantDevices.readCurrentAndObserve { (_) in - self.grid.reloadData() - } - model.isConferencePaused.readCurrentAndObserve { (paused) in - self.pauseCallButtons.forEach { - $0.isSelected = paused == true - } - } - model.isRecording.readCurrentAndObserve { (selected) in - self.recordCallButtons.forEach { - $0.isSelected = selected == true - } - } - Core.get().nativeVideoWindow = self.activeSpeakerVideoView - activeSpeakerMonitorTimer?.invalidate() - activeSpeakerMonitorTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in - var thereIsAnActiveSpeaker = false - model.conferenceParticipantDevices.value?.forEach { (data) in - if (data.activeSpeaker.value == true) { - thereIsAnActiveSpeaker = true - data.participantDevice.address.map { - self.activeSpeakerAvatar.isHidden = false - self.activeSpeakerAvatar.fillFromAddress(address: $0) - self.activeSpeakerDisplayName.text = $0.addressBookEnhancedDisplayName() - } - self.activeSpeakerVideoView.isHidden = data.videoEnabled.value != true - return - } - } - if (!thereIsAnActiveSpeaker) { - self.activeSpeakerAvatar.isHidden = true - self.activeSpeakerVideoView.isHidden = true - self.activeSpeakerDisplayName.text = VoipTexts.conference_display_no_active_speaker - } - } - } else { - activeSpeakerMonitorTimer?.invalidate() - } - self.grid.reloadData() - - } - } - - init() { - - let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() - layout.minimumInteritemSpacing = 0 - layout.minimumLineSpacing = 0 - layout.scrollDirection = .horizontal - layout.itemSize = CGSize(width:cell_width, height:grid_height) - grid = UICollectionView(frame:.zero, collectionViewLayout: layout) - - super.init(frame: .zero) - - let headerView = UIStackView() - addSubview(headerView) - headerView.matchParentSideBorders().alignParentTop().done() - - headerView.distribution = .equalSpacing - headerView.alignment = .bottom - headerView.spacing = record_pause_button_margin - headerView.axis = .vertical - - let subjectDuration = UIView() - - subjectDuration.addSubview(subjectLabel) - subjectLabel.alignParentLeft().done() - - subjectDuration.addSubview(duration) - duration.alignParentLeft().alignUnder(view: subjectLabel,withMargin:duration_margin_top).done() - - let upperSection = UIStackView() - upperSection.distribution = .equalSpacing - upperSection.alignment = .center - upperSection.spacing = record_pause_button_margin - upperSection.axis = .horizontal - - upperSection.addArrangedSubview(subjectDuration) - subjectDuration.wrapContentY().done() - - // Record (with video) - let recordCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_record, onClickAction: { - self.conferenceViewModel?.toggleRecording() - }) - - let recordPauseView = UIStackView() - recordPauseView.spacing = record_pause_button_margin - recordCallButtons.append(recordCall) - recordPauseView.addArrangedSubview(recordCall) - - // Pause (with video) - let pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: { - self.conferenceViewModel?.togglePlayPause() - - }) - pauseCallButtons.append(pauseCall) - recordPauseView.addArrangedSubview(pauseCall) - - upperSection.addArrangedSubview(recordPauseView) - - headerView.addArrangedSubview(upperSection) - upperSection.matchParentSideBorders().alignParentTop(withMargin:ActiveCallView.top_displayname_margin_top).done() - - headerView.addArrangedSubview(remotelyRecording) - remotelyRecording.matchParentSideBorders().alignUnder(view:upperSection, withMargin:ActiveCallView.remote_recording_margin_top).height(CGFloat(ActiveCallView.remote_recording_height)).done() - - - // Container view that can toggle full screen by ckick - let fullScreenMutableView = UIView() - addSubview(fullScreenMutableView) - fullScreenMutableView.backgroundColor = VoipTheme.voipBackgroundColor.get() - fullScreenMutableView.matchParentSideBorders().alignUnder(view:headerView,withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done() - - - // Active speaker - fullScreenMutableView.addSubview(activeSpeakerView) - activeSpeakerView.layer.cornerRadius = ActiveCallView.center_view_corner_radius - activeSpeakerView.clipsToBounds = true - activeSpeakerView.backgroundColor = VoipTheme.voipParticipantBackgroundColor.get() - activeSpeakerView.matchParentSideBorders().alignParentTop().done() - - activeSpeakerView.addSubview(activeSpeakerAvatar) - activeSpeakerAvatar.square(Avatar.diameter_for_call_views).center().done() - - activeSpeakerView.addSubview(activeSpeakerVideoView) - activeSpeakerVideoView.matchParentDimmensions().done() - - activeSpeakerView.addSubview(activeSpeakerDisplayName) - activeSpeakerDisplayName.alignParentLeft(withMargin:ActiveCallView.bottom_displayname_margin_left).alignParentRight().alignParentBottom(withMargin:ActiveCallView.bottom_displayname_margin_bottom).done() - - // CollectionView - grid.dataSource = self - grid.delegate = self - grid.register(VoipActiveSpeakerParticipantCell.self, forCellWithReuseIdentifier: "VoipActiveSpeakerParticipantCell") - grid.backgroundColor = .clear - grid.isScrollEnabled = true - fullScreenMutableView.addSubview(grid) - - grid.matchParentSideBorders().height(grid_height).alignParentBottom().alignUnder(view: activeSpeakerView, withMargin:ActiveCallView.center_view_margin_top).done() - - // Full screen video togggle - activeSpeakerView.onClick { - ControlsViewModel.shared.toggleFullScreen() - } - - ControlsViewModel.shared.fullScreenMode.observe { (fullScreen) in - if (self.isHidden) { - return - } - fullScreenMutableView.removeConstraints().done() - if (fullScreen == true) { - fullScreenMutableView.removeFromSuperview() - PhoneMainView.instance().mainViewController.view?.addSubview(fullScreenMutableView) - fullScreenMutableView.matchParentDimmensions().done() - } else { - fullScreenMutableView.removeFromSuperview() - self.addSubview(fullScreenMutableView) - fullScreenMutableView.matchParentSideBorders().alignUnder(view:headerView,withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done() - } - } - - } - - - // UICollectionView related delegates - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { - return inter_cell - } - - func collectionView(_ collectionView: UICollectionView, layout - collectionViewLayout: UICollectionViewLayout, - minimumLineSpacingForSectionAt section: Int) -> CGFloat { - return inter_cell - } - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let participantsCount = conferenceViewModel?.conferenceParticipantDevices.value?.count else { - return .zero - } - return participantsCount - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let cell:VoipActiveSpeakerParticipantCell = collectionView.dequeueReusableCell(withReuseIdentifier: "VoipActiveSpeakerParticipantCell", for: indexPath) as! VoipActiveSpeakerParticipantCell - guard let participantData = conferenceViewModel?.conferenceParticipantDevices.value?[indexPath.row] else { - return cell - } - cell.participantData = participantData - return cell - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - - -} diff --git a/Classes/Voip/Views/Fragments/Conference/VoipConferenceDisplayModeSelectionView.swift b/Classes/Voip/Views/Fragments/Conference/VoipConferenceDisplayModeSelectionView.swift deleted file mode 100644 index 42a694bbd..000000000 --- a/Classes/Voip/Views/Fragments/Conference/VoipConferenceDisplayModeSelectionView.swift +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import linphonesw - -@objc class VoipConferenceDisplayModeSelectionView: DismissableView, UITableViewDataSource, UITableViewDelegate{ - - // Layout constants - let buttons_distance_from_center_x = 38 - let buttons_size = 60 - - let optionsListView = UITableView() - - init() { - super.init(title: VoipTexts.call_action_change_conf_layout) - - super.contentView.addSubview(optionsListView) - optionsListView.matchParentDimmensions().done() - optionsListView.dataSource = self - optionsListView.delegate = self - optionsListView.register(ConferenceDisplayModeSelectionCell.self, forCellReuseIdentifier: "ConferenceDisplayModeSelectionCell") - optionsListView.separatorStyle = .singleLine - optionsListView.separatorColor = VoipTheme.light_grey_color - optionsListView.isScrollEnabled = false - } - - // TableView datasource delegate - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 2 - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell:ConferenceDisplayModeSelectionCell = tableView.dequeueReusableCell(withIdentifier: "ConferenceDisplayModeSelectionCell") as! ConferenceDisplayModeSelectionCell - cell.selectionStyle = .none - if (indexPath.row == 0) { - cell.setOption(title: VoipTexts.conference_display_mode_mosaic, onSelectAction: { - ConferenceViewModel.shared.conference.value?.layout = .Grid - ConferenceViewModel.shared.conferenceDisplayMode.value = .Grid - }, image:(UIImage(named: "voip_conference_mosaic")?.tinted(with: VoipTheme.voipDrawableColor.get())!)!) - cell.isUserInteractionEnabled = ConferenceViewModel.shared.conferenceParticipantDevices.value!.count <= ConferenceViewModel.shared.maxParticipantsForMosaicLayout - } - if (indexPath.row == 1) { - cell.setOption(title: VoipTexts.conference_display_mode_active_speaker, onSelectAction: { - ConferenceViewModel.shared.conference.value?.layout = .ActiveSpeaker - ConferenceViewModel.shared.conferenceDisplayMode.value = .ActiveSpeaker - }, image:(UIImage(named: "voip_conference_active_speaker")?.tinted(with: VoipTheme.voipDrawableColor.get())!)!) - cell.isUserInteractionEnabled = true - } - - cell.separatorInset = .zero - cell.selectionStyle = .none - return cell - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let cell = tableView.cellForRow(at: indexPath) as! ConferenceDisplayModeSelectionCell - cell.onSelectAction?() - cell.isSelected = true - if (indexPath.row == 0) { - tableView.deselectRow(at: IndexPath(row: 1, section: 0), animated: false) - } - if (indexPath.row == 1) { - tableView.deselectRow(at: IndexPath(row: 0, section: 0), animated: false) - } - } - - func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { - let cell = tableView.cellForRow(at: indexPath) as! ConferenceDisplayModeSelectionCell - cell.isSelected = false - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -class ConferenceDisplayModeSelectionCell : UITableViewCell { - - let cell_height = 60.0 - let icon_size = 40.0 - let side_margins = 20.0 - - let radio = CallControlButton(buttonTheme: VoipTheme.radio_button) - let label = StyledLabel(VoipTheme.conference_mode_title) - let icon = UIImageView() - - var onSelectAction : (()->Void)? = nil - - override var isSelected: Bool { - didSet { - radio.isSelected = isSelected - label.applyStyle(isSelected ? VoipTheme.conference_mode_title_selected : VoipTheme.conference_mode_title) - } - } - - - func setOption(title:String, onSelectAction:@escaping ()->Void, image:UIImage) { - self.onSelectAction = onSelectAction - label.text = title - icon.image = image - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - contentView.height(cell_height).matchParentSideBorders().done() - contentView.addSubview(radio) - radio.alignParentLeft(withMargin: side_margins).centerY().done() - contentView.addSubview(label) - label.toRightOf(radio).centerY().done() - contentView.addSubview(icon) - icon.size(w: icon_size, h: icon_size).alignParentRight(withMargin: side_margins).centerY().done() - radio.isUserInteractionEnabled = false - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} diff --git a/Classes/Voip/Views/Fragments/Conference/VoipConferenceGridView.swift b/Classes/Voip/Views/Fragments/Conference/VoipConferenceGridView.swift deleted file mode 100644 index 1b6509c03..000000000 --- a/Classes/Voip/Views/Fragments/Conference/VoipConferenceGridView.swift +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipConferenceGridView: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { - - // Layout constants : - let inter_cell = 10.0 - let record_pause_button_margin = 10.0 - let duration_margin_top = 4.0 - let record_pause_button_size = 40 - let record_pause_button_inset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7) - - - let subjectLabel = StyledLabel(VoipTheme.call_display_name_duration) - let duration = CallTimer(nil, VoipTheme.call_display_name_duration) - - let remotelyRecording = RemotelyRecordingView(height: ActiveCallView.remote_recording_height,text: VoipTexts.call_remote_recording) - var recordCallButtons : [CallControlButton] = [] - var pauseCallButtons : [CallControlButton] = [] - var grid : UICollectionView - - - var conferenceViewModel: ConferenceViewModel? = nil { - didSet { - if let model = conferenceViewModel { - model.subject.readCurrentAndObserve { (subject) in - self.subjectLabel.text = subject - } - duration.conference = model.conference.value - self.remotelyRecording.isRemotelyRecorded = model.isRemotelyRecorded - model.conferenceParticipantDevices.readCurrentAndObserve { (_) in - self.grid.reloadData() - } - model.isConferencePaused.readCurrentAndObserve { (paused) in - self.pauseCallButtons.forEach { - $0.isSelected = paused == true - } - } - model.isRecording.readCurrentAndObserve { (selected) in - self.recordCallButtons.forEach { - $0.isSelected = selected == true - } - } - } - self.grid.reloadData() - } - } - - init() { - - let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() - layout.minimumInteritemSpacing = 0 - layout.minimumLineSpacing = 0 - grid = UICollectionView(frame:.zero, collectionViewLayout: layout) - - super.init(frame: .zero) - - let headerView = UIStackView() - addSubview(headerView) - - headerView.distribution = .equalSpacing - headerView.alignment = .bottom - headerView.spacing = record_pause_button_margin - headerView.axis = .vertical - - let subjectDuration = UIView() - - subjectDuration.addSubview(subjectLabel) - subjectLabel.alignParentLeft().done() - - subjectDuration.addSubview(duration) - duration.alignParentLeft().alignUnder(view: subjectLabel,withMargin:duration_margin_top).done() - - let upperSection = UIStackView() - upperSection.distribution = .equalSpacing - upperSection.alignment = .center - upperSection.spacing = record_pause_button_margin - upperSection.axis = .horizontal - - upperSection.addArrangedSubview(subjectDuration) - subjectDuration.wrapContentY().done() - - // Record (with video) - let recordCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_record, onClickAction: { - self.conferenceViewModel?.toggleRecording() - }) - - let recordPauseView = UIStackView() - recordPauseView.spacing = record_pause_button_margin - recordCallButtons.append(recordCall) - recordPauseView.addArrangedSubview(recordCall) - - // Pause (with video) - let pauseCall = CallControlButton(width: record_pause_button_size, height: record_pause_button_size, imageInset:record_pause_button_inset, buttonTheme: VoipTheme.call_pause, onClickAction: { - self.conferenceViewModel?.togglePlayPause() - - }) - pauseCallButtons.append(pauseCall) - recordPauseView.addArrangedSubview(pauseCall) - - upperSection.addArrangedSubview(recordPauseView) - - headerView.addArrangedSubview(upperSection) - upperSection.matchParentSideBorders().alignParentTop(withMargin:ActiveCallView.top_displayname_margin_top).done() - - headerView.addArrangedSubview(remotelyRecording) - remotelyRecording.matchParentSideBorders().alignUnder(view:upperSection, withMargin:ActiveCallView.remote_recording_margin_top).height(CGFloat(ActiveCallView.remote_recording_height)).done() - - // CollectionView - grid.dataSource = self - grid.delegate = self - grid.register(VoipGridParticipantCell.self, forCellWithReuseIdentifier: "VoipGridParticipantCell") - grid.backgroundColor = VoipTheme.voipBackgroundColor.get() - grid.isScrollEnabled = false - addSubview(grid) - grid.matchParentSideBorders().alignUnder(view:headerView,withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done() - - headerView.matchParentSideBorders().alignParentTop().done() - - - // Full screen video togggle - grid.onClick { - ControlsViewModel.shared.toggleFullScreen() - } - - ControlsViewModel.shared.fullScreenMode.observe { (fullScreen) in - if (self.isHidden) { - return - } - self.grid.removeConstraints().done() - if (fullScreen == true) { - self.grid.removeFromSuperview() - PhoneMainView.instance().mainViewController.view?.addSubview(self.grid) - self.grid.matchParentDimmensions().center().done() - self.grid.reloadData() // Cauz of the frames - } else { - self.grid.removeFromSuperview() - self.addSubview(self.grid) - self.grid.matchParentSideBorders().alignUnder(view:headerView,withMargin: ActiveCallView.center_view_margin_top).alignParentBottom().done() - self.grid.reloadData() - } - } - } - - - // UICollectionView related delegates - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { - return inter_cell - } - - func collectionView(_ collectionView: UICollectionView, layout - collectionViewLayout: UICollectionViewLayout, - minimumLineSpacingForSectionAt section: Int) -> CGFloat { - return inter_cell - } - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let participantsCount = conferenceViewModel?.conferenceParticipantDevices.value?.count else { - return .zero - } - return participantsCount - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let cell:VoipGridParticipantCell = collectionView.dequeueReusableCell(withReuseIdentifier: "VoipGridParticipantCell", for: indexPath) as! VoipGridParticipantCell - guard let participantData = conferenceViewModel?.conferenceParticipantDevices.value?[indexPath.row] else { - return cell - } - cell.participantData = participantData - return cell - } - - func collectionView(_ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath) -> CGSize { - - guard let participantsCount = conferenceViewModel?.conferenceParticipantDevices.value?.count else { - return .zero - } - - var cellSize : CGSize = .zero - let availableSize = collectionView.frame.size - - if (participantsCount == 1) { - cellSize = availableSize - } else if (participantsCount == 2) { - cellSize = CGSize(width:availableSize.width, height:availableSize.height/2) - cellSize.height -= inter_cell/2 - } else if (participantsCount == 3) { - cellSize = CGSize(width:availableSize.width, height:availableSize.height/3) - cellSize.height -= 2*inter_cell/3 - } else if (participantsCount == 4) { - cellSize = CGSize(width:availableSize.width/2, height:availableSize.height/2) - cellSize.height -= inter_cell/2 - cellSize.width -= inter_cell/2 - } else if (participantsCount == 5) { - if (indexPath.row == 4) { // last (local) participant takes full width (under discussion) - cellSize = CGSize(width:availableSize.width, height:availableSize.height/3) - } else { - cellSize = CGSize(width:availableSize.width/2, height:availableSize.height/3) - cellSize.width -= inter_cell/2 - } - cellSize.height -= 2*inter_cell/3 - } else { - cellSize = CGSize(width:availableSize.width/2, height:availableSize.height/CGFloat((participantsCount/2))) - cellSize.height -= 2*inter_cell/3 - cellSize.width -= inter_cell/2 - } - return cellSize - - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - - -} diff --git a/Classes/Voip/Views/Fragments/Conference/VoipGridParticipantCell.swift b/Classes/Voip/Views/Fragments/Conference/VoipGridParticipantCell.swift deleted file mode 100644 index 6339a0d15..000000000 --- a/Classes/Voip/Views/Fragments/Conference/VoipGridParticipantCell.swift +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipGridParticipantCell: UICollectionViewCell { - - // Layout Constants - let corner_radius = 20.0 - static let avatar_size = 80.0 - let switch_camera_button_margins = 8.0 - let switch_camera_button_size = 30 - - - let videoView = UIView() - let avatar = Avatar(diameter:VoipGridParticipantCell.avatar_size,color:VoipTheme.voipBackgroundColor, textStyle: VoipTheme.call_generated_avatar_medium) - let pause = UIImageView(image: UIImage(named: "voip_pause")?.tinted(with: .white)) - let switchCamera = UIImageView(image: UIImage(named:"voip_change_camera")?.tinted(with:.white)) - let displayName = StyledLabel(VoipTheme.conference_participant_name_font_grid) - let pauseLabel = StyledLabel(VoipTheme.conference_participant_name_font_grid,VoipTexts.conference_participant_paused) - - var participantData: ConferenceParticipantDeviceData? = nil { - didSet { - if let data = participantData { - data.isInConference.readCurrentAndObserve { (isIn) in - self.updateBackground() - self.pause.isHidden = isIn == true - self.pauseLabel.isHidden = self.pause.isHidden - } - data.videoEnabled.readCurrentAndObserve { (videoEnabled) in - self.updateBackground() - if (videoEnabled == true) { - data.setVideoView(view: self.videoView) - self.avatar.isHidden = true - } else { - self.avatar.isHidden = false - } - self.switchCamera.isHidden = videoEnabled != true || !data.isSwitchCameraAvailable() - } - data.participantDevice.address.map { - avatar.fillFromAddress(address: $0) - if let displayName = $0.addressBookEnhancedDisplayName() { - self.displayName.text = displayName - } - } - data.activeSpeaker.readCurrentAndObserve { (active) in - if (active == true) { - self.layer.borderWidth = 2 - } else { - self.layer.borderWidth = 0 - } - } - } - } - } - - func updateBackground() { - if let data = participantData { - if (data.isInConference.value != true) { - self.contentView.backgroundColor = VoipTheme.voip_conference_participant_paused_background - } else if (data.videoEnabled.value == true) { - self.contentView.backgroundColor = .black - } else { - self.contentView.backgroundColor = VoipTheme.voipParticipantBackgroundColor.get() - - } - } - } - - - override init(frame:CGRect) { - super.init(frame:.zero) - layer.cornerRadius = corner_radius - clipsToBounds = true - layer.borderColor = VoipTheme.primary_color.cgColor - - contentView.addSubview(videoView) - videoView.matchParentDimmensions().done() - - contentView.addSubview(avatar) - avatar.size(w: VoipGridParticipantCell.avatar_size, h: VoipGridParticipantCell.avatar_size).center().done() - - contentView.addSubview(pause) - pause.layer.cornerRadius = VoipGridParticipantCell.avatar_size/2 - pause.clipsToBounds = true - pause.backgroundColor = VoipTheme.voip_gray - pause.size(w: VoipGridParticipantCell.avatar_size, h: VoipGridParticipantCell.avatar_size).center().done() - - contentView.addSubview(switchCamera) - switchCamera.alignParentTop(withMargin: switch_camera_button_margins).alignParentRight(withMargin: switch_camera_button_margins).square(switch_camera_button_size).done() - switchCamera.contentMode = .scaleAspectFit - - switchCamera.onClick { - Core.get().toggleCamera() - } - - contentView.addSubview(displayName) - displayName.alignParentLeft(withMargin:ActiveCallView.bottom_displayname_margin_left).alignParentBottom(withMargin:ActiveCallView.bottom_displayname_margin_bottom).done() - - contentView.addSubview(pauseLabel) - pauseLabel.toRightOf(displayName).alignParentBottom(withMargin:ActiveCallView.bottom_displayname_margin_bottom).done() - - contentView.matchParentDimmensions().done() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/Classes/Voip/Views/Fragments/ControlsView.swift b/Classes/Voip/Views/Fragments/ControlsView.swift deleted file mode 100644 index 58c285aa5..000000000 --- a/Classes/Voip/Views/Fragments/ControlsView.swift +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import UIKit - -class ControlsView: UIStackView { - - // Layout constants - static let controls_button_spacing = 5.0 - - init (showVideo:Bool) { - super.init(frame: .zero) - axis = .horizontal - distribution = .equalSpacing - alignment = .center - spacing = ControlsView.controls_button_spacing - - // Mute - let mute = CallControlButton(buttonTheme: VoipTheme.call_mute, onClickAction: { - ControlsViewModel.shared.toggleMuteMicrophone() - }) - addArrangedSubview(mute) - ControlsViewModel.shared.isMicrophoneMuted.readCurrentAndObserve { (muted) in - mute.isSelected = muted == true - } - ControlsViewModel.shared.isMuteMicrophoneEnabled.readCurrentAndObserve { (enabled) in - mute.isEnabled = enabled == true - } - - // Speaker - let speaker = CallControlButton(buttonTheme: VoipTheme.call_speaker, onClickAction: { - ControlsViewModel.shared.toggleSpeaker() - }) - addArrangedSubview(speaker) - ControlsViewModel.shared.isSpeakerSelected.readCurrentAndObserve { (selected) in - speaker.isSelected = selected == true - } - - // Audio routes - let routes = CallControlButton(buttonTheme: VoipTheme.call_audio_route, onClickAction: { - ControlsViewModel.shared.toggleRoutesMenu() - }) - addArrangedSubview(routes) - ControlsViewModel.shared.audioRoutesSelected.readCurrentAndObserve { (selected) in - routes.isSelected = selected == true - } - - ControlsViewModel.shared.audioRoutesEnabled.readCurrentAndObserve { (routesEnabled) in - speaker.isHidden = routesEnabled == true - routes.isHidden = !speaker.isHidden - } - - // Video - if (showVideo) { - let video = CallControlButton(buttonTheme: VoipTheme.call_video, onClickAction: { - if AVCaptureDevice.authorizationStatus(for: .video) == .authorized { - ControlsViewModel.shared.toggleVideo() - } else { - AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in - if granted { - ControlsViewModel.shared.toggleVideo() - } else { - VoipDialog(message:VoipTexts.camera_required_for_video).show() - } - }) - } - }) - addArrangedSubview(video) - video.showActivityIndicatorDataSource = ControlsViewModel.shared.isVideoUpdateInProgress - ControlsViewModel.shared.isVideoEnabled.readCurrentAndObserve { (selected) in - video.isSelected = selected == true - } - ControlsViewModel.shared.isVideoAvailable.readCurrentAndObserve { (available) in - video.isEnabled = available == true && ControlsViewModel.shared.isVideoUpdateInProgress.value != true - } - ControlsViewModel.shared.isVideoUpdateInProgress.readCurrentAndObserve { (updateInProgress) in - video.isEnabled = updateInProgress != true && ControlsViewModel.shared.isVideoAvailable.value == true - } - - } - - height(CallControlButton.default_size).done() - - } - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - - diff --git a/Classes/Voip/Views/Fragments/DismissableView.swift b/Classes/Voip/Views/Fragments/DismissableView.swift deleted file mode 100644 index 9bb1f7d9b..000000000 --- a/Classes/Voip/Views/Fragments/DismissableView.swift +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation - -class DismissableView: UIView { - - // Layout constants - let header_height = 60.0 - let title_left_margin = 20 - let dismiss_right_margin = 10 - let dismiss_icon_inset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) - let headerView = UIView() - let contentView = UIView() - var dismiss : CallControlButton? = nil - - init(title:String) { - super.init(frame:.zero) - - headerView.backgroundColor = VoipTheme.voipToolbarBackgroundColor.get() - self.addSubview(headerView) - headerView.matchParentSideBorders().alignParentTop().height(header_height).done() - - dismiss = CallControlButton(imageInset:dismiss_icon_inset,buttonTheme: VoipTheme.voip_cancel, onClickAction: { - self.removeFromSuperview() - }) - headerView.addSubview(dismiss!) - dismiss?.alignParentRight(withMargin: dismiss_right_margin).centerY().done() - - let title = StyledLabel(VoipTheme.calls_list_header_font,title) - headerView.addSubview(title) - title.alignParentTop().alignParentLeft(withMargin: title_left_margin).centerY().done() - - self.addSubview(contentView) - contentView.alignUnder(view: headerView).matchParentSideBorders().alignParentBottom().done() - - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} diff --git a/Classes/Voip/Views/Fragments/IncomingOuntgoingCommonView.swift b/Classes/Voip/Views/Fragments/IncomingOuntgoingCommonView.swift deleted file mode 100644 index 40a21da83..000000000 --- a/Classes/Voip/Views/Fragments/IncomingOuntgoingCommonView.swift +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import linphonesw - -@objc class IncomingOutgoingCommonView: UIViewController { // Shared between IncomingCallView and OutgoingCallVIew (all upper part except control buttons) - - // Layout constants - static let spinner_size = 50 - static let spinner_margin_top = 8.0 - static let call_type_margin_top = 10.0 - static let duration_margin_top = 10.0 - static let display_name_height = 20.0 - static let display_name_margin_top = 18.0 - static let sip_address_height = 16.0 - static let sip_address_margin_top = 6.0 - static let answer_decline_inset = UIEdgeInsets(top: 2, left: 7, bottom: 2, right: 7) - - let spinner = RotatingSpinner() - let duration = CallTimer(nil, VoipTheme.call_header_subtitle) - let avatar = Avatar(diameter: CGFloat(Avatar.diameter_for_call_views),color:VoipTheme.voipParticipantBackgroundColor, textStyle: VoipTheme.call_generated_avatar_large) - let displayName = StyledLabel(VoipTheme.call_header_title) - let sipAddress = StyledLabel(VoipTheme.call_header_subtitle) - - var callData: CallData? = nil { - didSet { - duration.call = callData?.call - callData?.call.remoteAddress.map { - avatar.fillFromAddress(address: $0) - displayName.text = $0.addressBookEnhancedDisplayName() - sipAddress.text = $0.asStringUriOnly() - } - } - } - - func viewDidLoad(forCallType:String) { - super.viewDidLoad() - - view.backgroundColor = VoipTheme.voipBackgroundColor.get() - - view.addSubview(spinner) - spinner.square(IncomingOutgoingCommonView.spinner_size).matchParentSideBorders().alignParentTop(withMargin:IncomingOutgoingCommonView.spinner_margin_top + UIDevice.notchHeight()).done() - - let callType = StyledLabel(VoipTheme.call_header_title,forCallType) - view.addSubview(callType) - callType.matchParentSideBorders().alignUnder(view:spinner,withMargin:IncomingOutgoingCommonView.call_type_margin_top).done() - - self.view.addSubview(duration) - duration.matchParentSideBorders().alignUnder(view:callType,withMargin:IncomingOutgoingCommonView.duration_margin_top).done() - - // Center : Avatar + Display name + SIP Address - let centerSection = UIView() - centerSection.addSubview(avatar) - avatar.square(Avatar.diameter_for_call_views).center().done() - centerSection.addSubview(displayName) - displayName.height(IncomingOutgoingCommonView.display_name_height).matchParentSideBorders().alignUnder(view:avatar,withMargin:IncomingOutgoingCommonView.display_name_margin_top).done() - centerSection.addSubview(sipAddress) - sipAddress.height(IncomingOutgoingCommonView.sip_address_height).matchParentSideBorders().alignUnder(view:displayName,withMargin:IncomingOutgoingCommonView.sip_address_margin_top).done() - self.view.addSubview(centerSection) - centerSection.matchParentSideBorders().center().done() - - - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - spinner.startRotation() - } - - override func viewWillDisappear(_ animated: Bool) { - spinner.stopRotation() - super.viewWillDisappear(animated) - } - - @objc func setCall(call:OpaquePointer) { - callData = CallData(call: Call.getSwiftObject(cObject: call)) - } - -} diff --git a/Classes/Voip/Views/Fragments/LocalVideoView.swift b/Classes/Voip/Views/Fragments/LocalVideoView.swift deleted file mode 100644 index dba74002d..000000000 --- a/Classes/Voip/Views/Fragments/LocalVideoView.swift +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class LocalVideoView: UIView { - - //Layout constants - let corner_radius = 15.0 - let aspect_ratio = 4.0/3.0 - let switch_camera_button_margins = 8.0 - let switch_camera_button_size = 30 - - var width : CGFloat - - var dragZone : UIView? { - didSet { - let panGesture = UIPanGestureRecognizer(target: self, action: #selector(drag)) - isUserInteractionEnabled = true - addGestureRecognizer(panGesture) - } - } - - let switchCamera = UIImageView(image: UIImage(named:"voip_change_camera")?.tinted(with:.white)) - - var callData: CallData? = nil { - didSet { - callData?.isRemotelyRecorded.readCurrentAndObserve(onChange: { (isRemotelyRecording) in - self.isHidden = !(isRemotelyRecording == true) - }) - } - } - - required init?(coder: NSCoder) { - width = 0.0 - super.init(coder: coder) - } - - init (width:CGFloat) { - self.width = width - super.init(frame: .zero) - layer.cornerRadius = corner_radius - clipsToBounds = true - - addSubview(switchCamera) - switchCamera.alignParentTop(withMargin: switch_camera_button_margins).alignParentRight(withMargin: switch_camera_button_margins).square(switch_camera_button_size).done() - switchCamera.contentMode = .scaleAspectFit - - switchCamera.onClick { - Core.get().toggleCamera() - } - setSizeConstraint() - } - - func setSizeConstraint() { - size(w: width, h: width*aspect_ratio).done() - } - - - @objc func drag(_ sender:UIPanGestureRecognizer){ - dragZone?.bringSubviewToFront(self) - let translation = sender.translation(in: dragZone) - center = CGPoint(x: center.x + translation.x, y: center.y + translation.y) - sender.setTranslation(CGPoint.zero, in: dragZone) - } - -} diff --git a/Classes/Voip/Views/Fragments/NumpadView.swift b/Classes/Voip/Views/Fragments/NumpadView.swift deleted file mode 100644 index e949e82f8..000000000 --- a/Classes/Voip/Views/Fragments/NumpadView.swift +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -@objc class NumpadView: UIView { - - // Layout constants - let side_margins = 10.0 - let margin_top = 100.0 - let button_size = 70 - let button_vertical_space = 17.0 - let button_horizontal_space = 14.0 - let digit_icon_inset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) - let corner_radius = 20.0 - let pad_height = 550 - let side_padding = 50.0 - - - init(superView:UIView, callData:CallData, onDismissAction : @escaping ()->Void) { - super.init(frame:.zero) - backgroundColor = VoipTheme.voip_translucent_popup_background - layer.cornerRadius = corner_radius - clipsToBounds = true - superView.addSubview(self) - snp.makeConstraints { make in - make.left.equalToSuperview().offset(side_margins) - make.right.equalToSuperview().offset(-side_margins) - make.height.equalTo(pad_height) - make.bottom.equalToSuperview().offset(-side_margins) - } - callData.callState.observe { state in - if (state == Call.State.End) { - onDismissAction() - } - } - - // Hide numpad button - let hide = CallControlButton(buttonTheme: VoipTheme.voip_cancel_light, onClickAction: { - onDismissAction() - }) - addSubview(hide) - hide.alignParentRight(withMargin: side_margins).alignParentTop(withMargin: side_margins).done() - - // DTMF History : - - let eneteredDtmf = StyledLabel(VoipTheme.dtmf_label) - addSubview(eneteredDtmf) - _ = eneteredDtmf.matchParentSideBorders().alignUnder(view:hide,withMargin:side_margins) - callData.enteredDTMF.readCurrentAndObserve { (dtmfs) in - eneteredDtmf.text = dtmfs - } - - // Digit buttons - - let allRows = UIStackView() - allRows.axis = .vertical - allRows.distribution = .equalSpacing - allRows.alignment = .center - allRows.spacing = button_vertical_space - allRows.layoutMargins = UIEdgeInsets(top: 0, left: side_padding, bottom: 0, right: side_padding) - allRows.isLayoutMarginsRelativeArrangement = true - addSubview(allRows) - _ = allRows.matchParentSideBorders().alignUnder(view:eneteredDtmf,withMargin: side_margins) - - - for key in [["1","2","3"],["4","5","6"],["7","8","9"],["*","0","#"]] { - let newRow = addRow(allRows: allRows) - for subkey in key { - let digit = CallControlButton(width:button_size, height:button_size, imageInset: digit_icon_inset, buttonTheme: ButtonTheme(tintableStateIcons:[UIButton.State.normal.rawValue : TintableIcon(name: "voip_numpad_\(iconNameForDigit(digit: subkey))")],backgroundStateColors:VoipTheme.numpad_digit_background), onClickAction: { - callData.sendDTMF(dtmf: "\(subkey)") - }) - newRow.addArrangedSubview(digit) - } - } - } - - func iconNameForDigit(digit:String) -> String { - if (digit == "*") { - return "star" - } - if (digit == "#") { - return "hash" - } - return digit - } - - func addRow(allRows:UIStackView) -> UIStackView { - let row = UIStackView() - row.axis = .horizontal - row.distribution = .equalSpacing - row.alignment = .center - row.spacing = button_vertical_space - row.isLayoutMarginsRelativeArrangement = true - allRows.addArrangedSubview(row) - return row - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - -} - - - diff --git a/Classes/Voip/Views/Fragments/ParticipantsList/ParticipantsListView.swift b/Classes/Voip/Views/Fragments/ParticipantsList/ParticipantsListView.swift deleted file mode 100644 index b81357bb7..000000000 --- a/Classes/Voip/Views/Fragments/ParticipantsList/ParticipantsListView.swift +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import linphonesw - -@objc class ParticipantsListView: DismissableView, UITableViewDataSource { - - // Layout constants - - - let participantsListTableView = UITableView() - - var callsDataObserver : MutableLiveDataOnChangeClosure<[CallData]>? = nil - - init() { - super.init(title: VoipTexts.call_action_participants_list) - - - let edit = CallControlButton(buttonTheme: VoipTheme.voip_edit, onClickAction: { - // Todo (not implemented in Android yet as of 22.11.21) - }) - super.headerView.addSubview(edit) - edit.centerY().done() - super.dismiss?.toRightOf(edit,withLeftMargin: dismiss_right_margin).centerY().done() - - - // ParticipantsList - super.contentView.addSubview(participantsListTableView) - participantsListTableView.matchParentDimmensions().done() - participantsListTableView.dataSource = self - participantsListTableView.register(VoipParticipantCell.self, forCellReuseIdentifier: "VoipParticipantCell") - participantsListTableView.allowsSelection = false - if #available(iOS 15.0, *) { - participantsListTableView.allowsFocus = false - } - participantsListTableView.separatorStyle = .singleLine - participantsListTableView.separatorColor = .white - - - CallsViewModel.shared.callsData.readCurrentAndObserve{ (callsData) in - self.participantsListTableView.reloadData() - } - - ConferenceViewModel.shared.isMeAdmin.readCurrentAndObserve { (meAdmin) in - edit.isHidden = meAdmin != true - } - - } - - - // TableView datasource delegate - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - guard let participants = ConferenceViewModel.shared.conferenceParticipants.value else { - return 0 - } - return participants.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell:VoipParticipantCell = tableView.dequeueReusableCell(withIdentifier: "VoipParticipantCell") as! VoipParticipantCell - guard let participantData = ConferenceViewModel.shared.conferenceParticipants.value?[indexPath.row] else { - return cell - } - cell.selectionStyle = .none - cell.participantData = participantData - cell.owningParticpantsListView = self - return cell - } - - // View controller - - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} diff --git a/Classes/Voip/Views/Fragments/ParticipantsList/VoipParticipantCell.swift b/Classes/Voip/Views/Fragments/ParticipantsList/VoipParticipantCell.swift deleted file mode 100644 index c57a4e7a0..000000000 --- a/Classes/Voip/Views/Fragments/ParticipantsList/VoipParticipantCell.swift +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipParticipantCell: UITableViewCell { - - // Layout Constants - - let dismiss_icon_inset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) - let dismiss_right_margin = 10 - let check_box_size = 20.0 - let cell_height = 80.0 - let avatar_left_margin = 15.0 - let texts_left_margin = 20.0 - - - let avatar = Avatar(diameter:VoipCallCell.avatar_size,color:VoipTheme.primaryTextColor, textStyle: VoipTheme.call_generated_avatar_small) - let displayName = StyledLabel(VoipTheme.conference_participant_name_font) - let sipAddress = StyledLabel(VoipTheme.conference_participant_sip_uri_font) - let isAdminView = UIView() - var removePart : CallControlButton? - - - var owningParticpantsListView : ParticipantsListView? = nil - - var participantData: ConferenceParticipantData? = nil { - didSet { - if let data = participantData { - avatar.fillFromAddress(address: data.participant.address!) - displayName.text = data.participant.address?.addressBookEnhancedDisplayName() - sipAddress.text = data.participant.address?.asStringUriOnly() - data.isAdmin.readCurrentAndObserve { (isAdmin) in self.isAdminView.isHidden = isAdmin != true - - } - data.isMeAdmin.readCurrentAndObserve { (isMeAdmin) in - self.removePart!.isHidden = isMeAdmin != true - self.isAdminView.alpha = isMeAdmin == true ? 1.0 : 0.6 - self.isAdminView.isUserInteractionEnabled = isMeAdmin == true - } - self.isAdminView.onClick { - data.conference.setParticipantAdminStatus(participant: data.participant, isAdmin: data.isAdmin.value != true) - self.owningParticpantsListView?.participantsListTableView.reloadData() - } - self.removePart?.onClick { - try?data.conference.removeParticipant(participant: data.participant) - self.owningParticpantsListView?.participantsListTableView.reloadData() - } - } - } - } - - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - contentView.height(cell_height).matchParentSideBorders().done() - - - contentView.addSubview(avatar) - avatar.size(w: VoipCallCell.avatar_size, h: VoipCallCell.avatar_size).centerY().alignParentLeft(withMargin: avatar_left_margin).done() - - let nameAddress = UIView() - nameAddress.addSubview(displayName) - nameAddress.addSubview(sipAddress) - displayName.alignParentTop().done() - sipAddress.alignUnder(view: displayName).done() - contentView.addSubview(nameAddress) - nameAddress.toRightOf(avatar,withLeftMargin:texts_left_margin).wrapContentY().centerY().done() - - removePart = CallControlButton(imageInset:dismiss_icon_inset,buttonTheme: VoipTheme.voip_cancel, onClickAction: { - self.removeFromSuperview() - }) - contentView.addSubview(removePart!) - removePart!.alignParentRight(withMargin: dismiss_right_margin).centerY().done() - - let isAdminLabel = StyledLabel(VoipTheme.conference_participant_admin_label,VoipTexts.chat_room_group_info_admin) - isAdminView.addSubview(isAdminLabel) - isAdminLabel.alignParentRight().centerY().done() - - let isAdminCheck = UIImageView(image: UIImage(named:("check_unselected"))) - isAdminView.addSubview(isAdminCheck) - isAdminCheck.size(w: check_box_size, h: check_box_size).toLeftOf(isAdminLabel).done() - - contentView.addSubview(isAdminView) - isAdminView.height(check_box_size).toLeftOf(removePart!).centerY().done() - - - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/Classes/Voip/Views/Fragments/PausedCallOrConferenceView.swift b/Classes/Voip/Views/Fragments/PausedCallOrConferenceView.swift deleted file mode 100644 index 45a1a9a98..000000000 --- a/Classes/Voip/Views/Fragments/PausedCallOrConferenceView.swift +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class PausedCallOrConferenceView: UIView { - - // Layout constants - let icon_size = 200 - let icon_padding = 80.0 - let title_margin_top = 20 - - var icon : UIImageView? = nil - let title = StyledLabel(VoipTheme.call_or_conference_title) - let subtitle = StyledLabel(VoipTheme.call_or_conference_subtitle) - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - init (iconName:String, titleText:String, subTitleText:String? = nil) { - super.init(frame: .zero) - - backgroundColor = VoipTheme.voip_translucent_popup_background - - let centeredView = UIView() - icon = UIImageView(image: UIImage(named:iconName)?.withPadding(padding: icon_padding)) - icon!.backgroundColor = VoipTheme.primary_color - icon!.layer.cornerRadius = CGFloat(icon_size/2) - icon!.clipsToBounds = true - icon!.contentMode = .scaleAspectFit - centeredView.addSubview(icon!) - icon!.square(icon_size).centerX().done() - - title.numberOfLines = 0 - centeredView.addSubview(title) - title.alignUnder(view:icon!, withMargin:title_margin_top).matchParentSideBorders().done() - title.text = titleText - - subtitle.numberOfLines = 0 - centeredView.addSubview(subtitle) - subtitle.alignUnder(view: title).matchParentSideBorders().done() - subtitle.text = subTitleText - - self.addSubview(centeredView) - centeredView.center().matchParentSideBorders().wrapContentY().done() - - } - -} diff --git a/Classes/Voip/Views/Fragments/RemotelyRecording.swift b/Classes/Voip/Views/Fragments/RemotelyRecording.swift deleted file mode 100644 index a3e957865..000000000 --- a/Classes/Voip/Views/Fragments/RemotelyRecording.swift +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class RemotelyRecordingView: UIView { - - let label = StyledLabel(VoipTheme.call_remote_recording) - let icon = UIImageView(image: UIImage(named:"voip_remote_recording")) - - var isRemotelyRecorded: MutableLiveData? = nil { - didSet { - isRemotelyRecorded?.readCurrentAndObserve(onChange: { (isRemotelyRecording) in - self.isHidden = !(isRemotelyRecording == true) - }) - } - } - - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - init (height:Int, text:String) { - super.init(frame: .zero) - backgroundColor = VoipTheme.dark_grey_color - layer.cornerRadius = CGFloat(height/2) - clipsToBounds = true - - addSubview(label) - label.center().height(CGFloat(height)).done() - label.text = text - - addSubview(icon) - icon.square(height).toLeftOf(label).done() - - isHidden = true - - } - -} diff --git a/Classes/Voip/Views/Fragments/VoipExtraButtonsView.swift b/Classes/Voip/Views/Fragments/VoipExtraButtonsView.swift deleted file mode 100644 index 2a7deca61..000000000 --- a/Classes/Voip/Views/Fragments/VoipExtraButtonsView.swift +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import Foundation -import SnapKit -import linphonesw - -class VoipExtraButtonsView: UIStackView { - - //Layout constants - let height = 200.0 - let corner_radius = 20.0 - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - init () { - super.init(frame: .zero) - - axis = .vertical - distribution = .fillEqually - alignment = .center - - layer.cornerRadius = corner_radius - clipsToBounds = true - - backgroundColor = VoipTheme.voipExtraButtonsBackgroundColor.get() - height(height).done() - - let row1 = UIStackView() - row1.axis = .horizontal - row1.distribution = .fillEqually - row1.alignment = .center - - - // First row - let numpad = VoipExtraButton(text: VoipTexts.call_action_numpad, buttonTheme: VoipTheme.call_action("voip_call_numpad"),onClickAction: { - ControlsViewModel.shared.numpadVisible.notifyAllObservers(with: true) - }) - row1.addArrangedSubview(numpad) - - let stats = VoipExtraButton(text: VoipTexts.call_action_statistics, buttonTheme: VoipTheme.call_action("voip_call_stats"),onClickAction: { - ControlsViewModel.shared.callStatsVisible.notifyAllObservers(with: true) - }) - row1.addArrangedSubview(stats) - - let chats = VoipExtraButton(text: VoipTexts.call_action_chat, buttonTheme: VoipTheme.call_action("voip_call_chat"),withbBoucinCounterDataSource:CallsViewModel.shared.currentCallUnreadChatMessageCount, onClickAction: { - ControlsViewModel.shared.goToChatEvent.notifyAllObservers(with: true) - }) - row1.addArrangedSubview(chats) - - addArrangedSubview(row1) - row1.matchParentSideBorders().done() - - // Second row - - let row2 = UIStackView() - row2.axis = .horizontal - row2.distribution = .fillEqually - row2.alignment = .center - - let transfer = VoipExtraButton(text: VoipTexts.call_action_transfer_call, buttonTheme: VoipTheme.call_action("voip_call_forward"),onClickAction: { - let view: DialerView = self.VIEW(DialerView.compositeViewDescription()); - view.setAddress("") - CallManager.instance().nextCallIsTransfer = true - PhoneMainView.instance().changeCurrentView(view.compositeViewDescription()) - }) - row2.addArrangedSubview(transfer) - - let participants = VoipExtraButton(text: VoipTexts.call_action_participants_list, buttonTheme: VoipTheme.call_action("voip_call_participants"),onClickAction: { - ControlsViewModel.shared.goToConferenceParticipantsListEvent.notifyAllObservers(with: true) - }) - row2.addArrangedSubview(participants) - - - let addcall = VoipExtraButton(text: VoipTexts.call_action_add_call, buttonTheme: VoipTheme.call_action("voip_call_add"),onClickAction: { - let view: DialerView = self.VIEW(DialerView.compositeViewDescription()); - view.setAddress("") - CallManager.instance().nextCallIsTransfer = false - PhoneMainView.instance().changeCurrentView(view.compositeViewDescription()) - }) - row2.addArrangedSubview(addcall) - - - let layoutselect = VoipExtraButton(text: VoipTexts.call_action_change_conf_layout, buttonTheme: VoipTheme.call_action("voip_conference_mosaic"),onClickAction: { - ControlsViewModel.shared.goToConferenceLayoutSettings.notifyAllObservers(with: true) - }) - row2.addArrangedSubview(layoutselect) - - let calls = VoipExtraButton(text: VoipTexts.call_action_calls_list, buttonTheme: VoipTheme.call_action("voip_calls_list"), withbBoucinCounterDataSource: CallsViewModel.shared.inactiveCallsCount, onClickAction: { - ControlsViewModel.shared.goToCallsListEvent.notifyAllObservers(with: true) - }) - row2.addArrangedSubview(calls) - - addArrangedSubview(row2) - row2.matchParentSideBorders().done() - - ConferenceViewModel.shared.isInConference.readCurrentAndObserve { (isIn) in - participants.isHidden = isIn != true - layoutselect.isHidden = isIn != true - transfer.isHidden = isIn == true - addcall.isHidden = isIn == true - } - - } - - func refresh() { - CallsViewModel.shared.currentCallUnreadChatMessageCount.notifyValue() - CallsViewModel.shared.inactiveCallsCount.notifyValue() - } - - - -} diff --git a/Classes/Voip/VoipDialog.swift b/Classes/Voip/VoipDialog.swift deleted file mode 100644 index 8488e8764..000000000 --- a/Classes/Voip/VoipDialog.swift +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import UIKit - -class VoipDialog : UIView{ - - // Layout constants - let center_corner_radius = 7.0 - let title_margin_top = 20 - let button_margin = 20.0 - let button_width = 135.0 - let button_height = 40.0 - let button_radius = 3.0 - let button_spacing = 15.0 - - let center_view_sides_margin = 13.0 - - - let title = StyledLabel(VoipTheme.basic_popup_title) - - init(message:String, givenButtons:[ButtonAttributes]? = nil) { - - super.init(frame: .zero) - backgroundColor = VoipTheme.voip_translucent_popup_background - - let centerView = UIView() - centerView.backgroundColor = VoipTheme.dark_grey_color.withAlphaComponent(0.8) - centerView.layer.cornerRadius = center_corner_radius - centerView.clipsToBounds = true - addSubview(centerView) - - title.numberOfLines = 0 - centerView.addSubview(title) - title.alignParentTop(withMargin:title_margin_top).matchParentSideBorders().done() - title.text = message - - let buttonsView = UIStackView() - buttonsView.axis = .horizontal - buttonsView.spacing = button_spacing - - var buttons = givenButtons - - if (buttons == nil) { // assuming info popup, just putting an ok button - let ok = ButtonAttributes(text:VoipTexts.ok, action: {}, isDestructive:false) - buttons = [ok] - } - - buttons?.forEach { - let b = ButtonWithStateBackgrounds(backgroundStateColors: $0.isDestructive ? VoipTheme.primary_colors_background_gray : VoipTheme.primary_colors_background) - b.setTitle($0.text, for: .normal) - b.layer.cornerRadius = button_radius - b.clipsToBounds = true - buttonsView.addArrangedSubview(b) - b.applyTitleStyle(VoipTheme.big_button) - let action = $0.action - b.onClick { - self.removeFromSuperview() - action() - } - b.size(w: button_width,h: button_height).done() - } - centerView.addSubview(buttonsView) - buttonsView.alignUnder(view:title,withMargin:button_margin).alignParentBottom(withMargin:button_margin).centerX().done() - - - - centerView.matchParentSideBorders(insetedByDx: center_view_sides_margin).center().done() - } - - func show() { - rootVC()?.view.addSubview(self) - matchParentDimmensions().done() - } - - private func rootVC() -> UIViewController? { - return UIApplication.getTopMostViewController() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - -} - -struct ButtonAttributes { - let text:String - let action: (()->Void) - let isDestructive: Bool -} diff --git a/Classes/Voip/Widgets/Avatar.swift b/Classes/Voip/Widgets/Avatar.swift deleted file mode 100644 index 8e4084fa5..000000000 --- a/Classes/Voip/Widgets/Avatar.swift +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -class Avatar : UIImageView { - - static let diameter_for_call_views = 191 - - required init?(coder: NSCoder) { - initialsLabel = StyledLabel(VoipTheme.call_generated_avatar_large) - super.init(coder: coder) - } - - let initialsLabel: StyledLabel - - init (diameter: CGFloat, color:LightDarkColor,textStyle:TextStyle) { - initialsLabel = StyledLabel(textStyle) - super.init(frame: .zero) - layer.cornerRadius = diameter/2.0 - clipsToBounds = true - self.backgroundColor = color.get() - addSubview(initialsLabel) - _ = initialsLabel.matchParentSideBorders().matchParentHeight() - } - - - - func fillFromAddress(address:Address) { - if let image = address.contact()?.avatar() { - self.image = image - initialsLabel.isHidden = true - } else { - self.image = nil - initialsLabel.text = address.initials() - initialsLabel.isHidden = false - } - } - - - -} - diff --git a/Classes/Voip/Widgets/BouncingCounter.swift b/Classes/Voip/Widgets/BouncingCounter.swift deleted file mode 100644 index a07f5124b..000000000 --- a/Classes/Voip/Widgets/BouncingCounter.swift +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import Foundation -import UIKit -import SwiftUI - -class BouncingCounter : UIBouncingView { - - // Layout constants - let size = 20.0 - let center_offset = 20 - - let owningButton : UIButton - let label : StyledLabel - - var dataSource : MutableLiveData? { - didSet { - if let dataSource = dataSource { - self.size(w:self.size,h:self.size).matchCenterXOf(view: self.owningButton, withDx: self.center_offset).matchCenterYOf(view: self.owningButton, withDy: -self.center_offset).done() - dataSource.readCurrentAndObserve { (value) in - if (value! > 0) { - self.label.text = value! < 100 ? String(value!) : "99+" - self.isHidden = true // to force legacy startAnimating to unhide and animate - self.startAnimating(true) - } else { - self.isHidden = false // to force legacy startAnimating to hide and animate - self.stopAnimating(true) - } - } - } else { - self.isHidden = false - self.stopAnimating(true) - } - } - } - - - init (inButton:UIButton) { - owningButton = inButton - label = StyledLabel(VoipTheme.unread_count_font) - super.init(frame:.zero) - addSubview(label) - label.matchParentDimmensions().done() - backgroundColor = VoipTheme.primary_color - layer.masksToBounds = true - layer.cornerRadius = size/2 - self.isHidden = true - } - - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - - -} diff --git a/Classes/Voip/Widgets/ButtonWithStateBackgrounds.swift b/Classes/Voip/Widgets/ButtonWithStateBackgrounds.swift deleted file mode 100644 index fa437dc8f..000000000 --- a/Classes/Voip/Widgets/ButtonWithStateBackgrounds.swift +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import Foundation -import UIKit -import SwiftUI - -class ButtonWithStateBackgrounds : UIButton { - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - init (backgroundStateColors: [UInt: LightDarkColor]) { - super.init(frame: .zero) - backgroundStateColors.keys.forEach { (stateRawValue) in - setBackgroundColor(color: backgroundStateColors[stateRawValue]!.get(), forState: UIButton.State(rawValue: stateRawValue)) - } - } - - func setBackgroundColor(color: UIColor, forState: UIControl.State) { - UIGraphicsBeginImageContext(CGSize(width: 1, height: 1)) - UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor) - UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1)) - let colorImage = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - self.setBackgroundImage(colorImage, for: forState) - } - - - -} diff --git a/Classes/Voip/Widgets/CallControlButton.swift b/Classes/Voip/Widgets/CallControlButton.swift deleted file mode 100644 index 03a8a4835..000000000 --- a/Classes/Voip/Widgets/CallControlButton.swift +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import Foundation -import UIKit -import SwiftUI - -class CallControlButton : ButtonWithStateBackgrounds { - - // Layout constants - static let default_size = 50 - static let hungup_width = 65 - - var showActivityIndicatorDataSource : MutableLiveData? = nil { - didSet { - if let showActivityIndicatorDataSource = self.showActivityIndicatorDataSource { - let spinner = UIActivityIndicatorView(style: .white) - spinner.color = VoipTheme.primary_color - self.addSubview(spinner) - spinner.matchParentDimmensions().center().done() - - showActivityIndicatorDataSource.readCurrentAndObserve { (show) in - if (show == true) { - spinner.startAnimating() - spinner.isHidden = false - self.isEnabled = false - } else { - spinner.stopAnimating() - spinner.isHidden = true - self.isEnabled = true - } - } - } - } - } - - var onClickAction : (()->Void)? = nil - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - init (width:Int = CallControlButton.default_size, height:Int = CallControlButton.default_size, imageInset:UIEdgeInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2), buttonTheme: ButtonTheme, onClickAction : (()->Void)? = nil ) { - super.init(backgroundStateColors: buttonTheme.backgroundStateColors) - - layer.cornerRadius = CGFloat(height/2) - clipsToBounds = true - contentMode = .scaleAspectFit - - applyTintedIcons(tintedIcons: buttonTheme.tintableStateIcons) - - imageView?.contentMode = .scaleAspectFit - - imageEdgeInsets = imageInset - - size(w: CGFloat(width), h: CGFloat(height)).done() - - self.onClickAction = onClickAction - onClick { - self.onClickAction?() - } - - } - - func applyTintedIcons(tintedIcons: [UInt: TintableIcon]) { - tintedIcons.keys.forEach { (stateRawValue) in - let tintedIcon = tintedIcons[stateRawValue]! - UIImage(named:tintedIcon.name).map { - setImage($0.tinted(with: tintedIcon.tintColor?.get()),for: UIButton.State(rawValue: stateRawValue)) - } - } - } - - -} diff --git a/Classes/Voip/Widgets/RotatingSpinner.swift b/Classes/Voip/Widgets/RotatingSpinner.swift deleted file mode 100644 index a03f12671..000000000 --- a/Classes/Voip/Widgets/RotatingSpinner.swift +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation - -class RotatingSpinner : UIImageView { - - init () { - super.init(frame: .zero) - self.image = UIImage(named: "voip_spinner") - self.tint(UIColor.white) - self.contentMode = .scaleAspectFit - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - func startRotation() { - let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") - rotation.toValue = NSNumber(value: Double.pi * 2) - rotation.duration = 2.2 - rotation.isCumulative = true - rotation.repeatCount = Float.greatestFiniteMagnitude - self.layer.add(rotation, forKey: "rotationAnimation") - } - - func stopRotation() { - self.layer.removeAllAnimations() - } -} - diff --git a/Classes/Voip/Widgets/StyledLabel.swift b/Classes/Voip/Widgets/StyledLabel.swift deleted file mode 100644 index 29c15da3e..000000000 --- a/Classes/Voip/Widgets/StyledLabel.swift +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation - -class StyledLabel: UILabel { - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - init (_ style:TextStyle, _ text:String? = nil) { - super.init(frame: .zero) - self.text = text - applyStyle(style) - } - -} diff --git a/Classes/Voip/Widgets/UICallTimer.swift b/Classes/Voip/Widgets/UICallTimer.swift deleted file mode 100644 index 1eaf13ef9..000000000 --- a/Classes/Voip/Widgets/UICallTimer.swift +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import Foundation -import linphonesw - -class CallTimer : StyledLabel { - - let min_width = 50.0 - - let formatter = DateComponentsFormatter() - var call:Call? = nil { - didSet { - if (self.call != nil) { - self.format() - } - } - } - - var conference:Conference? = nil { - didSet { - if (self.call != nil) { - self.format() - } - } - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - init (_ text:String?, _ style:TextStyle, _ call:Call? = nil) { - super.init(style,text) - self.call = call - formatter.unitsStyle = .positional - formatter.allowedUnits = [.minute, .second ] - formatter.zeroFormattingBehavior = [ .pad ] - Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in - self.format() - } - minWidth(min_width).done() - - } - - func format() { - guard let duration = self.call != nil ? self.call!.duration : self.conference != nil ? self.conference!.duration: nil else { - return - } - formatter.string(from: TimeInterval(duration)).map { - self.text = $0.hasPrefix("0:") ? "0" + $0 : $0 - } - } - -} diff --git a/Classes/Voip/Widgets/VoipExtraButton.swift b/Classes/Voip/Widgets/VoipExtraButton.swift deleted file mode 100644 index 67fce96c1..000000000 --- a/Classes/Voip/Widgets/VoipExtraButton.swift +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import Foundation -import UIKit -import SwiftUI - -class VoipExtraButton : UIButton { - - // Layout constants - let width = 60.0 - let image_size = 50.0 - let bouncing_label_size = 17.0 - - var boucingCounter : BouncingCounter? = nil - - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - init ( text:String, buttonTheme: ButtonTheme, withbBoucinCounterDataSource:MutableLiveData? = nil, onClickAction : @escaping ()->Void ) { - super.init(frame: .zero) - - - contentMode = .scaleToFill - - buttonTheme.tintableStateIcons.keys.forEach { (stateRawValue) in - let tintedIcon = buttonTheme.tintableStateIcons[stateRawValue]! - UIImage(named:tintedIcon.name).map { - setImage($0.tinted(with: tintedIcon.tintColor?.get()),for: UIButton.State(rawValue: stateRawValue)) - } - setTitleColor(tintedIcon.tintColor?.get(), for: UIButton.State(rawValue: stateRawValue)) - } - imageView?.contentMode = .scaleAspectFit - imageView?.size(w: image_size,h: image_size).centerX().alignParentTop().done() - titleLabel?.alignUnder(view: imageView!).centerX().done() - - - size(w: width,h: image_size).done() - setTitle(text, for: .normal) - applyTitleStyle(VoipTheme.voip_extra_button) - - onClick { - ControlsViewModel.shared.hideExtraButtons.value = true - onClickAction() - } - - if (withbBoucinCounterDataSource != nil) { - boucingCounter = BouncingCounter(inButton:self) - addSubview(boucingCounter!) - boucingCounter?.dataSource = withbBoucinCounterDataSource - } - - } - - -} diff --git a/Classes/ar.lproj/CallIncomingView.strings b/Classes/ar.lproj/CallIncomingView.strings new file mode 100644 index 000000000..c5adc5123 Binary files /dev/null and b/Classes/ar.lproj/CallIncomingView.strings differ diff --git a/Classes/ar.lproj/CallView.strings b/Classes/ar.lproj/CallView.strings new file mode 100644 index 000000000..6544e6570 Binary files /dev/null and b/Classes/ar.lproj/CallView.strings differ diff --git a/Classes/fr.lproj/CallIncomingView.strings b/Classes/fr.lproj/CallIncomingView.strings new file mode 100644 index 000000000..b59db541e Binary files /dev/null and b/Classes/fr.lproj/CallIncomingView.strings differ diff --git a/Classes/fr.lproj/CallOutgoingView.strings b/Classes/fr.lproj/CallOutgoingView.strings new file mode 100644 index 000000000..f507fda06 Binary files /dev/null and b/Classes/fr.lproj/CallOutgoingView.strings differ diff --git a/Classes/fr.lproj/CallView.strings b/Classes/fr.lproj/CallView.strings new file mode 100644 index 000000000..8303fcfed Binary files /dev/null and b/Classes/fr.lproj/CallView.strings differ diff --git a/Classes/fr.lproj/CallView~ipad.strings b/Classes/fr.lproj/CallView~ipad.strings new file mode 100644 index 000000000..b4c093b13 Binary files /dev/null and b/Classes/fr.lproj/CallView~ipad.strings differ diff --git a/Classes/hu.lproj/CallIncomingView.strings b/Classes/hu.lproj/CallIncomingView.strings new file mode 100644 index 000000000..de84a65e8 Binary files /dev/null and b/Classes/hu.lproj/CallIncomingView.strings differ diff --git a/Classes/hu.lproj/CallOutgoingView.strings b/Classes/hu.lproj/CallOutgoingView.strings new file mode 100644 index 000000000..912463c42 Binary files /dev/null and b/Classes/hu.lproj/CallOutgoingView.strings differ diff --git a/Classes/hu.lproj/CallView.strings b/Classes/hu.lproj/CallView.strings new file mode 100644 index 000000000..95effba3d Binary files /dev/null and b/Classes/hu.lproj/CallView.strings differ diff --git a/Classes/hu.lproj/CallView~ipad.strings b/Classes/hu.lproj/CallView~ipad.strings new file mode 100644 index 000000000..3bd40d4d4 Binary files /dev/null and b/Classes/hu.lproj/CallView~ipad.strings differ diff --git a/Classes/linphone-Bridging-Header.h b/Classes/linphone-Bridging-Header.h index c09603899..a520acc8e 100644 --- a/Classes/linphone-Bridging-Header.h +++ b/Classes/linphone-Bridging-Header.h @@ -7,8 +7,5 @@ #import #import "FastAddressBook.h" #import "Log.h" -#import "LinphoneUI/UICompositeView.h" -#import "Contact.h" -#import "StatusBarView.h" -#import "LinphoneUI/UIBouncingView.h" -#import "PhoneMainView.h" +#import "AudioHelper.h" + diff --git a/Classes/ru.lproj/CallIncomingView.strings b/Classes/ru.lproj/CallIncomingView.strings new file mode 100644 index 000000000..f433ea682 Binary files /dev/null and b/Classes/ru.lproj/CallIncomingView.strings differ diff --git a/Classes/ru.lproj/CallView.strings b/Classes/ru.lproj/CallView.strings new file mode 100644 index 000000000..c3217f4ee Binary files /dev/null and b/Classes/ru.lproj/CallView.strings differ diff --git a/Podfile b/Podfile index 4bdf972fb..d6a747f18 100644 --- a/Podfile +++ b/Podfile @@ -26,7 +26,6 @@ target 'linphone' do # Pods for linphone pod 'SVProgressHUD' - pod 'SnapKit' all_pods end diff --git a/Resources/fonts/Roboto-Bold.ttf b/Resources/fonts/Roboto-Bold.ttf deleted file mode 100644 index 8d6cf0551..000000000 Binary files a/Resources/fonts/Roboto-Bold.ttf and /dev/null differ diff --git a/Resources/fonts/Roboto-Italic.ttf b/Resources/fonts/Roboto-Italic.ttf deleted file mode 100644 index 737244bc0..000000000 Binary files a/Resources/fonts/Roboto-Italic.ttf and /dev/null differ diff --git a/Resources/fonts/Roboto-Regular.ttf b/Resources/fonts/Roboto-Regular.ttf deleted file mode 100644 index 3a4973c78..000000000 Binary files a/Resources/fonts/Roboto-Regular.ttf and /dev/null differ diff --git a/Resources/images/voip_audio_routes.png b/Resources/images/voip_audio_routes.png deleted file mode 100644 index fae4e84e3..000000000 Binary files a/Resources/images/voip_audio_routes.png and /dev/null differ diff --git a/Resources/images/voip_bluetooth.png b/Resources/images/voip_bluetooth.png deleted file mode 100644 index 3010fb418..000000000 Binary files a/Resources/images/voip_bluetooth.png and /dev/null differ diff --git a/Resources/images/voip_call.png b/Resources/images/voip_call.png deleted file mode 100644 index 1a95c052e..000000000 Binary files a/Resources/images/voip_call.png and /dev/null differ diff --git a/Resources/images/voip_call_add.png b/Resources/images/voip_call_add.png deleted file mode 100644 index 8237f3305..000000000 Binary files a/Resources/images/voip_call_add.png and /dev/null differ diff --git a/Resources/images/voip_call_chat.png b/Resources/images/voip_call_chat.png deleted file mode 100644 index 4ff01de6f..000000000 Binary files a/Resources/images/voip_call_chat.png and /dev/null differ diff --git a/Resources/images/voip_call_forward.png b/Resources/images/voip_call_forward.png deleted file mode 100644 index cc61de482..000000000 Binary files a/Resources/images/voip_call_forward.png and /dev/null differ diff --git a/Resources/images/voip_call_header_active.png b/Resources/images/voip_call_header_active.png deleted file mode 100644 index 3ef0106bc..000000000 Binary files a/Resources/images/voip_call_header_active.png and /dev/null differ diff --git a/Resources/images/voip_call_header_incoming.png b/Resources/images/voip_call_header_incoming.png deleted file mode 100644 index 7a8d458ad..000000000 Binary files a/Resources/images/voip_call_header_incoming.png and /dev/null differ diff --git a/Resources/images/voip_call_header_outgoing.png b/Resources/images/voip_call_header_outgoing.png deleted file mode 100644 index 474abe754..000000000 Binary files a/Resources/images/voip_call_header_outgoing.png and /dev/null differ diff --git a/Resources/images/voip_call_header_paused.png b/Resources/images/voip_call_header_paused.png deleted file mode 100644 index fdcfaf5d2..000000000 Binary files a/Resources/images/voip_call_header_paused.png and /dev/null differ diff --git a/Resources/images/voip_call_list_menu.png b/Resources/images/voip_call_list_menu.png deleted file mode 100644 index fdd82bea6..000000000 Binary files a/Resources/images/voip_call_list_menu.png and /dev/null differ diff --git a/Resources/images/voip_call_more.png b/Resources/images/voip_call_more.png deleted file mode 100644 index 73bb13b36..000000000 Binary files a/Resources/images/voip_call_more.png and /dev/null differ diff --git a/Resources/images/voip_call_numpad.png b/Resources/images/voip_call_numpad.png deleted file mode 100644 index a0fd33835..000000000 Binary files a/Resources/images/voip_call_numpad.png and /dev/null differ diff --git a/Resources/images/voip_call_participants.png b/Resources/images/voip_call_participants.png deleted file mode 100644 index b2b766b14..000000000 Binary files a/Resources/images/voip_call_participants.png and /dev/null differ diff --git a/Resources/images/voip_call_record.png b/Resources/images/voip_call_record.png deleted file mode 100644 index 9c392dc47..000000000 Binary files a/Resources/images/voip_call_record.png and /dev/null differ diff --git a/Resources/images/voip_call_stats.png b/Resources/images/voip_call_stats.png deleted file mode 100644 index 3dd39d43b..000000000 Binary files a/Resources/images/voip_call_stats.png and /dev/null differ diff --git a/Resources/images/voip_calls_list.png b/Resources/images/voip_calls_list.png deleted file mode 100644 index a3d69b84e..000000000 Binary files a/Resources/images/voip_calls_list.png and /dev/null differ diff --git a/Resources/images/voip_camera_off.png b/Resources/images/voip_camera_off.png deleted file mode 100644 index dd41c338b..000000000 Binary files a/Resources/images/voip_camera_off.png and /dev/null differ diff --git a/Resources/images/voip_camera_on.png b/Resources/images/voip_camera_on.png deleted file mode 100644 index 7109c577d..000000000 Binary files a/Resources/images/voip_camera_on.png and /dev/null differ diff --git a/Resources/images/voip_cancel.png b/Resources/images/voip_cancel.png deleted file mode 100644 index 493b35e79..000000000 Binary files a/Resources/images/voip_cancel.png and /dev/null differ diff --git a/Resources/images/voip_change_camera.png b/Resources/images/voip_change_camera.png deleted file mode 100644 index d6dc15cb8..000000000 Binary files a/Resources/images/voip_change_camera.png and /dev/null differ diff --git a/Resources/images/voip_chat_rooms_list.png b/Resources/images/voip_chat_rooms_list.png deleted file mode 100644 index edf722c7e..000000000 Binary files a/Resources/images/voip_chat_rooms_list.png and /dev/null differ diff --git a/Resources/images/voip_conference_active_speaker.png b/Resources/images/voip_conference_active_speaker.png deleted file mode 100644 index 18f21106a..000000000 Binary files a/Resources/images/voip_conference_active_speaker.png and /dev/null differ diff --git a/Resources/images/voip_conference_mosaic.png b/Resources/images/voip_conference_mosaic.png deleted file mode 100644 index 8fa0137b7..000000000 Binary files a/Resources/images/voip_conference_mosaic.png and /dev/null differ diff --git a/Resources/images/voip_conference_new.png b/Resources/images/voip_conference_new.png deleted file mode 100644 index 8985782ae..000000000 Binary files a/Resources/images/voip_conference_new.png and /dev/null differ diff --git a/Resources/images/voip_conference_paused_big.png b/Resources/images/voip_conference_paused_big.png deleted file mode 100644 index 745f17220..000000000 Binary files a/Resources/images/voip_conference_paused_big.png and /dev/null differ diff --git a/Resources/images/voip_conference_play_big.png b/Resources/images/voip_conference_play_big.png deleted file mode 100644 index 303d05faa..000000000 Binary files a/Resources/images/voip_conference_play_big.png and /dev/null differ diff --git a/Resources/images/voip_copy.png b/Resources/images/voip_copy.png deleted file mode 100644 index 43639693e..000000000 Binary files a/Resources/images/voip_copy.png and /dev/null differ diff --git a/Resources/images/voip_delete.png b/Resources/images/voip_delete.png deleted file mode 100644 index 3022d156d..000000000 Binary files a/Resources/images/voip_delete.png and /dev/null differ diff --git a/Resources/images/voip_dropdown.png b/Resources/images/voip_dropdown.png deleted file mode 100644 index d9fccac91..000000000 Binary files a/Resources/images/voip_dropdown.png and /dev/null differ diff --git a/Resources/images/voip_earpiece.png b/Resources/images/voip_earpiece.png deleted file mode 100644 index e95a30801..000000000 Binary files a/Resources/images/voip_earpiece.png and /dev/null differ diff --git a/Resources/images/voip_edit.png b/Resources/images/voip_edit.png deleted file mode 100644 index c24930212..000000000 Binary files a/Resources/images/voip_edit.png and /dev/null differ diff --git a/Resources/images/voip_export.png b/Resources/images/voip_export.png deleted file mode 100644 index 3fdfa078a..000000000 Binary files a/Resources/images/voip_export.png and /dev/null differ diff --git a/Resources/images/voip_hangup.png b/Resources/images/voip_hangup.png deleted file mode 100644 index a2ceab5d8..000000000 Binary files a/Resources/images/voip_hangup.png and /dev/null differ diff --git a/Resources/images/voip_info.png b/Resources/images/voip_info.png deleted file mode 100644 index ae8dd86f8..000000000 Binary files a/Resources/images/voip_info.png and /dev/null differ diff --git a/Resources/images/voip_mandatory.png b/Resources/images/voip_mandatory.png deleted file mode 100644 index 4be37f7e4..000000000 Binary files a/Resources/images/voip_mandatory.png and /dev/null differ diff --git a/Resources/images/voip_menu_more.png b/Resources/images/voip_menu_more.png deleted file mode 100644 index 7f7f7d8fd..000000000 Binary files a/Resources/images/voip_menu_more.png and /dev/null differ diff --git a/Resources/images/voip_merge_calls.png b/Resources/images/voip_merge_calls.png deleted file mode 100644 index 6c4da5988..000000000 Binary files a/Resources/images/voip_merge_calls.png and /dev/null differ diff --git a/Resources/images/voip_micro_off.png b/Resources/images/voip_micro_off.png deleted file mode 100644 index 57569b4f2..000000000 Binary files a/Resources/images/voip_micro_off.png and /dev/null differ diff --git a/Resources/images/voip_micro_on.png b/Resources/images/voip_micro_on.png deleted file mode 100644 index 6552d35d5..000000000 Binary files a/Resources/images/voip_micro_on.png and /dev/null differ diff --git a/Resources/images/voip_multiple_contacts_avatar.png b/Resources/images/voip_multiple_contacts_avatar.png deleted file mode 100644 index 78b10f11b..000000000 Binary files a/Resources/images/voip_multiple_contacts_avatar.png and /dev/null differ diff --git a/Resources/images/voip_numpad_0.png b/Resources/images/voip_numpad_0.png deleted file mode 100644 index 115bdb17d..000000000 Binary files a/Resources/images/voip_numpad_0.png and /dev/null differ diff --git a/Resources/images/voip_numpad_1.png b/Resources/images/voip_numpad_1.png deleted file mode 100644 index 4d8b7f5cc..000000000 Binary files a/Resources/images/voip_numpad_1.png and /dev/null differ diff --git a/Resources/images/voip_numpad_2.png b/Resources/images/voip_numpad_2.png deleted file mode 100644 index 6b561c468..000000000 Binary files a/Resources/images/voip_numpad_2.png and /dev/null differ diff --git a/Resources/images/voip_numpad_3.png b/Resources/images/voip_numpad_3.png deleted file mode 100644 index 386715586..000000000 Binary files a/Resources/images/voip_numpad_3.png and /dev/null differ diff --git a/Resources/images/voip_numpad_4.png b/Resources/images/voip_numpad_4.png deleted file mode 100644 index e3dfdcc51..000000000 Binary files a/Resources/images/voip_numpad_4.png and /dev/null differ diff --git a/Resources/images/voip_numpad_5.png b/Resources/images/voip_numpad_5.png deleted file mode 100644 index a18af28e5..000000000 Binary files a/Resources/images/voip_numpad_5.png and /dev/null differ diff --git a/Resources/images/voip_numpad_6.png b/Resources/images/voip_numpad_6.png deleted file mode 100644 index 79279cb99..000000000 Binary files a/Resources/images/voip_numpad_6.png and /dev/null differ diff --git a/Resources/images/voip_numpad_7.png b/Resources/images/voip_numpad_7.png deleted file mode 100644 index c68656fd3..000000000 Binary files a/Resources/images/voip_numpad_7.png and /dev/null differ diff --git a/Resources/images/voip_numpad_8.png b/Resources/images/voip_numpad_8.png deleted file mode 100644 index 8d84c96ba..000000000 Binary files a/Resources/images/voip_numpad_8.png and /dev/null differ diff --git a/Resources/images/voip_numpad_9.png b/Resources/images/voip_numpad_9.png deleted file mode 100644 index af3e0e0bf..000000000 Binary files a/Resources/images/voip_numpad_9.png and /dev/null differ diff --git a/Resources/images/voip_numpad_hash.png b/Resources/images/voip_numpad_hash.png deleted file mode 100644 index 790e7d12e..000000000 Binary files a/Resources/images/voip_numpad_hash.png and /dev/null differ diff --git a/Resources/images/voip_numpad_star.png b/Resources/images/voip_numpad_star.png deleted file mode 100644 index 5a2649de4..000000000 Binary files a/Resources/images/voip_numpad_star.png and /dev/null differ diff --git a/Resources/images/voip_pause.png b/Resources/images/voip_pause.png deleted file mode 100644 index e888da937..000000000 Binary files a/Resources/images/voip_pause.png and /dev/null differ diff --git a/Resources/images/voip_radio_off.png b/Resources/images/voip_radio_off.png deleted file mode 100644 index b703dea80..000000000 Binary files a/Resources/images/voip_radio_off.png and /dev/null differ diff --git a/Resources/images/voip_radio_on.png b/Resources/images/voip_radio_on.png deleted file mode 100644 index feaf00e11..000000000 Binary files a/Resources/images/voip_radio_on.png and /dev/null differ diff --git a/Resources/images/voip_remote_recording.png b/Resources/images/voip_remote_recording.png deleted file mode 100644 index 3e4e94009..000000000 Binary files a/Resources/images/voip_remote_recording.png and /dev/null differ diff --git a/Resources/images/voip_single_contact_avatar.png b/Resources/images/voip_single_contact_avatar.png deleted file mode 100644 index 5d158fa49..000000000 Binary files a/Resources/images/voip_single_contact_avatar.png and /dev/null differ diff --git a/Resources/images/voip_speaker_off.png b/Resources/images/voip_speaker_off.png deleted file mode 100644 index c018c9899..000000000 Binary files a/Resources/images/voip_speaker_off.png and /dev/null differ diff --git a/Resources/images/voip_speaker_on.png b/Resources/images/voip_speaker_on.png deleted file mode 100644 index 07f13c9b6..000000000 Binary files a/Resources/images/voip_speaker_on.png and /dev/null differ diff --git a/Resources/images/voip_spinner.png b/Resources/images/voip_spinner.png deleted file mode 100644 index 8238de56b..000000000 Binary files a/Resources/images/voip_spinner.png and /dev/null differ diff --git a/linphone-Info.plist b/linphone-Info.plist index b9d24c1fb..8bd93f866 100644 --- a/linphone-Info.plist +++ b/linphone-Info.plist @@ -102,8 +102,6 @@ Share photos with your friends and customize avatars NSContactsUsageDescription Make calls with your friends - NSLocalNetworkUsageDescription - Stream audio and video through the local network NSLocationWhenInUseUsageDescription Linphone will not use, store or communicate your location. The authorization allows us to detect Wifi connection changes NSMicrophoneUsageDescription @@ -112,6 +110,8 @@ Add tranfered files to your library NSPhotoLibraryUsageDescription Share photos with your friends and customize avatars + NSLocalNetworkUsageDescription + Stream audio and video through the local network NSUbiquitousContainers iCloud.org.linphone.phone @@ -126,12 +126,6 @@ NSVoIPUsageDescription Make audio/video calls - UIAppFonts - - Roboto-Regular.ttf - Roboto-Bold.ttf - Roboto-Italic.ttf - UIApplicationShortcutItems diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 907c0c136..fbe3126e2 100644 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -7,13 +7,13 @@ objects = { /* Begin PBXBuildFile section */ - 017AC1D70F142AE8EAC13BDB /* Pods_msgNotificationContent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A164BAF39B3A5B9F905917A7 /* Pods_msgNotificationContent.framework */; }; 152F22361B15E889008C0621 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 152F22351B15E889008C0621 /* libxml2.dylib */; }; 1D3623260D0F684500981E51 /* LinphoneAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* LinphoneAppDelegate.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 2214EB7A12F846B1002A5394 /* UICallButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 2214EB7912F846B1002A5394 /* UICallButton.m */; }; + 2214EB8912F84EBB002A5394 /* UIHangUpButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 2214EB8812F84EBB002A5394 /* UIHangUpButton.m */; }; 2214EBF312F86360002A5394 /* UIMutedMicroButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 2214EBF212F86360002A5394 /* UIMutedMicroButton.m */; }; 22276E8913C73DC000210156 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22276E8813C73DC000210156 /* CoreMedia.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 22405EEE1600B4E400B92522 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22405EED1600B4E400B92522 /* AssetsLibrary.framework */; }; @@ -25,6 +25,8 @@ 2274401A106F31BD006EC466 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22744019106F31BD006EC466 /* CoreAudio.framework */; }; 2274402F106F335E006EC466 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2274402E106F335E006EC466 /* AudioToolbox.framework */; }; 228697C411AC29B800E9E0CA /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 228697C311AC29B800E9E0CA /* CFNetwork.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 22968A5F12F875C600588287 /* UISpeakerButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 22968A5E12F875C600588287 /* UISpeakerButton.m */; }; + 22AA8B0113D83F6300B30535 /* UICamSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 22AA8B0013D83F6300B30535 /* UICamSwitch.m */; }; 22C755601317E59C007BC101 /* UIBluetoothButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 22C7555F1317E59C007BC101 /* UIBluetoothButton.m */; }; 22D1B68112A3E0BE001AE361 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 22D1B68012A3E0BE001AE361 /* libresolv.dylib */; }; 22E0A822111C44E100B04932 /* AboutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22E0A81C111C44E100B04932 /* AboutView.m */; }; @@ -51,8 +53,10 @@ 24E1C7C01F9A235600D3F981 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1C7B91F9A235500D3F981 /* Contacts.framework */; }; 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; 340751971506459A00B89C47 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 340751961506459A00B89C47 /* CoreTelephony.framework */; }; + 340751E7150F38FD00B89C47 /* UIVideoButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 340751E6150F38FD00B89C47 /* UIVideoButton.m */; }; 34216F401547EBCD00EA9777 /* VideoZoomHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 34216F3F1547EBCD00EA9777 /* VideoZoomHandler.m */; }; 344ABDF114850AE9007420B6 /* libc++.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 344ABDEF14850AE9007420B6 /* libc++.1.dylib */; settings = {ATTRIBUTES = (Weak, ); }; }; + 369CCF81C921CD7C4E49A637 /* Pods_msgNotificationContent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82E9DEDA2A78C6DBBD1A54DB /* Pods_msgNotificationContent.framework */; }; 570742581D5A0691004B9C84 /* ShopView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 570742561D5A0691004B9C84 /* ShopView.xib */; }; 570742611D5A09B8004B9C84 /* ShopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5707425F1D5A09B8004B9C84 /* ShopView.m */; }; 570742671D5A63DB004B9C84 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 570742661D5A63DB004B9C84 /* StoreKit.framework */; }; @@ -105,6 +109,7 @@ 61AE364F20C00B370089D9D3 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AE364E20C00B370089D9D3 /* ShareViewController.m */; }; 61AE365220C00B370089D9D3 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61AE365020C00B370089D9D3 /* MainInterface.storyboard */; }; 61AE365620C00B370089D9D3 /* linphoneExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 61AEBEA321906AFC00F35E7F /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; 61AEBEBD2191990A00F35E7F /* DevicesListView.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AEBEBC2191990A00F35E7F /* DevicesListView.m */; }; 61AEBEBF2191991F00F35E7F /* DevicesListView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 61AEBEBE2191991F00F35E7F /* DevicesListView.xib */; }; 61AEBEC62191E47500F35E7F /* chevron_list_close.png in Resources */ = {isa = PBXBuildFile; fileRef = 61AEBEC52191E47500F35E7F /* chevron_list_close.png */; }; @@ -558,7 +563,11 @@ 6341807C1BBC103100F71761 /* ChatConversationCreateTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6341807B1BBC103100F71761 /* ChatConversationCreateTableView.m */; }; 63423C0A1C4501D000D9A050 /* Contact.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423C091C4501D000D9A050 /* Contact.m */; }; 634610061B61330300548952 /* UILabel+Boldify.m in Sources */ = {isa = PBXBuildFile; fileRef = 634610051B61330300548952 /* UILabel+Boldify.m */; }; + 6346100F1B61409800548952 /* CallOutgoingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6346100E1B61409800548952 /* CallOutgoingView.m */; }; + 634610121B6140A500548952 /* CallOutgoingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 634610101B6140A500548952 /* CallOutgoingView.xib */; }; 635173F91BA082A40095EB0A /* UIChatBubblePhotoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 635173F81BA082A40095EB0A /* UIChatBubblePhotoCell.m */; }; + 6352A5751BE0D4B800594C1C /* CallSideMenuView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6352A5731BE0D4B800594C1C /* CallSideMenuView.m */; }; + 6352A5761BE0D4B800594C1C /* CallSideMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6352A5741BE0D4B800594C1C /* CallSideMenuView.xib */; }; 635775251B6673EC00C8B704 /* HistoryDetailsTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 635775241B6673EC00C8B704 /* HistoryDetailsTableView.m */; }; 636316D11A1DEBCB0009B839 /* AboutView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D31A1DEBCB0009B839 /* AboutView.xib */; }; 636316D41A1DEC650009B839 /* SettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D61A1DEC650009B839 /* SettingsView.xib */; }; @@ -568,6 +577,7 @@ 6377AC801BDE4069007F7625 /* UIBackToCallButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 6377AC7F1BDE4069007F7625 /* UIBackToCallButton.m */; }; 6381DA7D1C1AD5EA00DF3BBD /* UIBouncingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6381DA7C1C1AD5EA00DF3BBD /* UIBouncingView.m */; }; 638F1A621C2021B2004B8E02 /* DialerView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 638F1A601C2021B2004B8E02 /* DialerView~ipad.xib */; }; + 638F1A881C2167C2004B8E02 /* CallView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 638F1A861C2167C2004B8E02 /* CallView~ipad.xib */; }; 638F1A911C21993D004B8E02 /* UICompositeView~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 638F1A8F1C21993D004B8E02 /* UICompositeView~ipad.xib */; }; 639CEAFD1A1DF4D9004DE38F /* StatusBarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEAFF1A1DF4D9004DE38F /* StatusBarView.xib */; }; 639CEB001A1DF4E4004DE38F /* UIHistoryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB021A1DF4E4004DE38F /* UIHistoryCell.xib */; }; @@ -575,6 +585,7 @@ 639CEB091A1DF4FA004DE38F /* UIChatCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB0B1A1DF4FA004DE38F /* UIChatCell.xib */; }; 639E9C801C0DB13D00019A75 /* UICheckBoxTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 639E9C7F1C0DB13D00019A75 /* UICheckBoxTableView.m */; }; 639E9C931C0DB7BE00019A75 /* FirstLoginView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639E9C951C0DB7BE00019A75 /* FirstLoginView.xib */; }; + 639E9C9D1C0DB7DF00019A75 /* UICallPausedCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639E9C9F1C0DB7DF00019A75 /* UICallPausedCell.xib */; }; 639E9CA01C0DB7E500019A75 /* UIChatBubblePhotoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639E9CA21C0DB7E500019A75 /* UIChatBubblePhotoCell.xib */; }; 639E9CA31C0DB7EA00019A75 /* UIChatBubbleTextCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639E9CA51C0DB7EA00019A75 /* UIChatBubbleTextCell.xib */; }; 639E9CA61C0DB7F200019A75 /* UIChatCreateCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639E9CA81C0DB7F200019A75 /* UIChatCreateCell.xib */; }; @@ -598,6 +609,7 @@ 63B81A101B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B81A0B1B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m */; }; 63B8D68C1BCBE65600C12B09 /* ChatConversationCreateView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63B8D68E1BCBE65600C12B09 /* ChatConversationCreateView.xib */; }; 63B8D6A21BCBF43100C12B09 /* UIChatCreateCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B8D6A01BCBF43100C12B09 /* UIChatCreateCell.m */; }; + 63BC49E21BA2CDFC004EC273 /* UICallPausedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 63BC49E11BA2CDFC004EC273 /* UICallPausedCell.m */; }; 63BE7A781D75BDF6000990EF /* ShopTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63BE7A771D75BDF6000990EF /* ShopTableView.m */; }; 63C441C31BBC23ED0053DC5E /* UIAssistantTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 63C441C21BBC23ED0053DC5E /* UIAssistantTextField.m */; }; 63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CD4B4E1A5AAC8C00B84282 /* DTAlertView.m */; }; @@ -610,12 +622,16 @@ 63E27A321C4FECD000D332AE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63E27A311C4FECD000D332AE /* LaunchScreen.xib */; }; 63E27A521C50EDB000D332AE /* hold.mkv in Resources */ = {isa = PBXBuildFile; fileRef = 63E27A511C50EB2700D332AE /* hold.mkv */; }; 63E59A3F1ADE70D900646FB3 /* InAppProductsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E59A3E1ADE70D900646FB3 /* InAppProductsManager.m */; }; - 63E802DB1C625AEF000D5509 /* (null) in Resources */ = {isa = PBXBuildFile; }; + 63E802DB1C625AEF000D5509 /* BuildFile in Resources */ = {isa = PBXBuildFile; }; 63EC8D391D7438660066547B /* AssistantLinkView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63EC8D3B1D7438660066547B /* AssistantLinkView.xib */; }; 63F1DF441BCE618E00EDED90 /* UIAddressTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF431BCE618E00EDED90 /* UIAddressTextField.m */; }; + 63F1DF4B1BCE983200EDED90 /* CallConferenceTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF4A1BCE983200EDED90 /* CallConferenceTableView.m */; }; + 63F1DF4F1BCE985F00EDED90 /* UICallConferenceCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF4D1BCE985F00EDED90 /* UICallConferenceCell.m */; }; + 63F1DF511BCE986A00EDED90 /* UICallConferenceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63F1DF531BCE986A00EDED90 /* UICallConferenceCell.xib */; }; 63FB30351A680E73008CA393 /* UIRoundedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63FB30341A680E73008CA393 /* UIRoundedImageView.m */; }; 70E542F313E147E3002BA2C0 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70E542F213E147E3002BA2C0 /* OpenGLES.framework */; }; 70E542F513E147EB002BA2C0 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70E542F413E147EB002BA2C0 /* QuartzCore.framework */; }; + 8C1B67061E671826001EA2FE /* AudioHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C1B67051E671826001EA2FE /* AudioHelper.m */; }; 8C2595DF1DEDCC8E007A6424 /* CallKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C2595DE1DEDCC8E007A6424 /* CallKit.framework */; }; 8C2A81951F87B8000012A66B /* chat_group_avatar@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8C2A81931F87B7FF0012A66B /* chat_group_avatar@2x.png */; }; 8C2A81961F87B8000012A66B /* chat_group_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 8C2A81941F87B8000012A66B /* chat_group_avatar.png */; }; @@ -654,11 +670,8 @@ 8CF25D961F9F336100BEA0C1 /* check_unselected.png in Resources */ = {isa = PBXBuildFile; fileRef = 8CF25D941F9F336100BEA0C1 /* check_unselected.png */; }; 8CF25D9D1F9F76BD00BEA0C1 /* chat_group_informations.png in Resources */ = {isa = PBXBuildFile; fileRef = 8CF25D9B1F9F76BC00BEA0C1 /* chat_group_informations.png */; }; 8CF25D9E1F9F76BD00BEA0C1 /* chat_group_informations@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8CF25D9C1F9F76BD00BEA0C1 /* chat_group_informations@2x.png */; }; - 9C0B30F54D61774AFD1473CE /* Pods_linphone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B464E44A606CB50A65A96FE2 /* Pods_linphone.framework */; }; - C60B66682721AFFA0026AC7D /* CallStatisticsData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60B66672721AFFA0026AC7D /* CallStatisticsData.swift */; }; - C60D265627299C94006238BB /* ControlsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60D265527299C94006238BB /* ControlsViewModel.swift */; }; - C60D265827299F70006238BB /* CoreExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60D265727299F6F006238BB /* CoreExtensions.swift */; }; - C60D265C272AA0BD006238BB /* UIImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60D265B272AA0BD006238BB /* UIImageExtensions.swift */; }; + 93566413F75DA69D2811A716 /* Pods_msgNotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F30EA7BEA39DA427CE0754E /* Pods_msgNotificationService.framework */; }; + A634ABAFCB39B6AAE4CA991D /* Pods_linphone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CEDD144CABFAA70A29AF27 /* Pods_linphone.framework */; }; C61B1BF22667D075001A4E4A /* menu_security_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF12667D075001A4E4A /* menu_security_default.png */; }; C61B1BF42667D202001A4E4A /* more_menu_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF32667D202001A4E4A /* more_menu_default.png */; }; C61B1BF72667EC6B001A4E4A /* ephemeral_messages_color_A.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */; }; @@ -668,105 +681,14 @@ C622E3F226A81290004F5434 /* vr_off.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EC26A8128F004F5434 /* vr_off.png */; }; C622E3F326A81290004F5434 /* vr_pause.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3ED26A8128F004F5434 /* vr_pause.png */; }; C622E3F426A81290004F5434 /* vr_play.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EE26A81290004F5434 /* vr_play.png */; }; - C6277DA8274BF1CE00406FB9 /* voip_radio_on.png in Resources */ = {isa = PBXBuildFile; fileRef = C6277DA6274BF1CD00406FB9 /* voip_radio_on.png */; }; - C6277DA9274BF1CE00406FB9 /* voip_radio_off.png in Resources */ = {isa = PBXBuildFile; fileRef = C6277DA7274BF1CD00406FB9 /* voip_radio_off.png */; }; - C6278497273C21E1002FAA29 /* LocalVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6278496273C21E1002FAA29 /* LocalVideoView.swift */; }; C64A854E2667B67200252AD2 /* EphemeralSettingsView.m in Sources */ = {isa = PBXBuildFile; fileRef = C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */; }; C64A85502667B67A00252AD2 /* EphemeralSettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */; }; C64A85522667B74100252AD2 /* ephemeral_messages_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C64A85512667B74100252AD2 /* ephemeral_messages_default.png */; }; - C6586149273E595700A0DBFC /* VoipExtraButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6586148273E595700A0DBFC /* VoipExtraButtonsView.swift */; }; - C658614C273E5B5E00A0DBFC /* VoipExtraButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C658614B273E5B5E00A0DBFC /* VoipExtraButton.swift */; }; - C65A5D3027216B86005BA038 /* ActiveCallOrConferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65A5D2F27216B86005BA038 /* ActiveCallOrConferenceView.swift */; }; - C65A5D3B27216CC0005BA038 /* MutableLiveData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65A5D3727216CC0005BA038 /* MutableLiveData.swift */; }; - C65A5D3F27216E3A005BA038 /* CallData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65A5D3E27216E3A005BA038 /* CallData.swift */; }; - C65A5D45272196AE005BA038 /* OptionalExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65A5D44272196AE005BA038 /* OptionalExtensions.swift */; }; C666756F264C925800A0273C /* VFSUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA657B261C950C0020CB43 /* VFSUtil.swift */; }; C6667571264C925B00A0273C /* VFSUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA657B261C950C0020CB43 /* VFSUtil.swift */; }; C66B03BB26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C66B03BD26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib */; }; C66B040A26EFDA55009B5EDC /* reply_cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = C66B040926EFDA54009B5EDC /* reply_cancel.png */; }; C66B040E26F095D1009B5EDC /* cancel_forward.png in Resources */ = {isa = PBXBuildFile; fileRef = C66B040D26F095CE009B5EDC /* cancel_forward.png */; }; - C6710F4F2722903200ED888F /* RotatingSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710F4E2722903200ED888F /* RotatingSpinner.swift */; }; - C6710F512722932600ED888F /* UIImageViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710F502722932600ED888F /* UIImageViewExtensions.swift */; }; - C6710F53272297C400ED888F /* VoipTexts.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710F52272297C400ED888F /* VoipTexts.swift */; }; - C6710F5527229D5900ED888F /* LightDarkColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710F5427229D5900ED888F /* LightDarkColor.swift */; }; - C6710F5727229DEE00ED888F /* TextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710F5627229DEE00ED888F /* TextStyle.swift */; }; - C6710F592722A9B800ED888F /* StyledLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710F582722A9B800ED888F /* StyledLabel.swift */; }; - C6710F5C2722AAED00ED888F /* UIDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710F5B2722AAED00ED888F /* UIDeviceExtensions.swift */; }; - C6710F612722AECB00ED888F /* Roboto-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C6710F5E2722AECB00ED888F /* Roboto-Italic.ttf */; }; - C6710F622722AECB00ED888F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C6710F5F2722AECB00ED888F /* Roboto-Bold.ttf */; }; - C6710F632722AECB00ED888F /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C6710F602722AECB00ED888F /* Roboto-Regular.ttf */; }; - C6710F652722B13000ED888F /* voip_spinner.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F642722B13000ED888F /* voip_spinner.png */; }; - C6710F9F2722B20000ED888F /* voip_numpad_1.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F662722B1EF00ED888F /* voip_numpad_1.png */; }; - C6710FA02722B20000ED888F /* voip_numpad_0.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F672722B1EF00ED888F /* voip_numpad_0.png */; }; - C6710FA12722B20000ED888F /* voip_copy.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F682722B1EF00ED888F /* voip_copy.png */; }; - C6710FA22722B20000ED888F /* voip_merge_calls.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F692722B1EF00ED888F /* voip_merge_calls.png */; }; - C6710FA32722B20000ED888F /* voip_call_numpad.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F6A2722B1EF00ED888F /* voip_call_numpad.png */; }; - C6710FA42722B20000ED888F /* voip_single_contact_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F6B2722B1F000ED888F /* voip_single_contact_avatar.png */; }; - C6710FA52722B20000ED888F /* voip_mandatory.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F6C2722B1F000ED888F /* voip_mandatory.png */; }; - C6710FA62722B20000ED888F /* voip_bluetooth.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F6D2722B1F000ED888F /* voip_bluetooth.png */; }; - C6710FA72722B20000ED888F /* voip_call_more.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F6E2722B1F000ED888F /* voip_call_more.png */; }; - C6710FA82722B20000ED888F /* voip_multiple_contacts_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F6F2722B1F100ED888F /* voip_multiple_contacts_avatar.png */; }; - C6710FA92722B20000ED888F /* voip_call_stats.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F702722B1F100ED888F /* voip_call_stats.png */; }; - C6710FAA2722B20000ED888F /* voip_conference_active_speaker.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F712722B1F100ED888F /* voip_conference_active_speaker.png */; }; - C6710FAB2722B20000ED888F /* voip_edit.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F722722B1F200ED888F /* voip_edit.png */; }; - C6710FAC2722B20000ED888F /* voip_call_chat.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F732722B1F200ED888F /* voip_call_chat.png */; }; - C6710FAD2722B20000ED888F /* voip_numpad_5.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F742722B1F200ED888F /* voip_numpad_5.png */; }; - C6710FAE2722B20000ED888F /* voip_hangup.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F752722B1F300ED888F /* voip_hangup.png */; }; - C6710FAF2722B20000ED888F /* voip_conference_new.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F762722B1F300ED888F /* voip_conference_new.png */; }; - C6710FB02722B20000ED888F /* voip_chat_rooms_list.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F772722B1F300ED888F /* voip_chat_rooms_list.png */; }; - C6710FB12722B20000ED888F /* voip_micro_on.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F782722B1F300ED888F /* voip_micro_on.png */; }; - C6710FB22722B20000ED888F /* voip_calls_list.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F792722B1F400ED888F /* voip_calls_list.png */; }; - C6710FB32722B20000ED888F /* voip_pause.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F7A2722B1F400ED888F /* voip_pause.png */; }; - C6710FB42722B20000ED888F /* voip_conference_mosaic.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F7B2722B1F500ED888F /* voip_conference_mosaic.png */; }; - C6710FB52722B20000ED888F /* voip_delete.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F7C2722B1F500ED888F /* voip_delete.png */; }; - C6710FB62722B20000ED888F /* voip_audio_routes.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F7D2722B1F500ED888F /* voip_audio_routes.png */; }; - C6710FB72722B20000ED888F /* voip_numpad_6.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F7E2722B1F600ED888F /* voip_numpad_6.png */; }; - C6710FB82722B20000ED888F /* voip_numpad_3.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F7F2722B1F600ED888F /* voip_numpad_3.png */; }; - C6710FB92722B20000ED888F /* voip_call_add.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F802722B1F600ED888F /* voip_call_add.png */; }; - C6710FBA2722B20000ED888F /* voip_numpad_9.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F812722B1F700ED888F /* voip_numpad_9.png */; }; - C6710FBB2722B20000ED888F /* voip_call.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F822722B1F700ED888F /* voip_call.png */; }; - C6710FBC2722B20000ED888F /* voip_change_camera.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F832722B1F700ED888F /* voip_change_camera.png */; }; - C6710FBD2722B20000ED888F /* voip_call_header_paused.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F842722B1F800ED888F /* voip_call_header_paused.png */; }; - C6710FBE2722B20000ED888F /* voip_export.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F852722B1F800ED888F /* voip_export.png */; }; - C6710FBF2722B20000ED888F /* voip_earpiece.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F862722B1F800ED888F /* voip_earpiece.png */; }; - C6710FC02722B20000ED888F /* voip_numpad_hash.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F872722B1F800ED888F /* voip_numpad_hash.png */; }; - C6710FC12722B20000ED888F /* voip_micro_off.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F882722B1F900ED888F /* voip_micro_off.png */; }; - C6710FC22722B20000ED888F /* voip_numpad_2.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F892722B1F900ED888F /* voip_numpad_2.png */; }; - C6710FC32722B20000ED888F /* voip_cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F8A2722B1F900ED888F /* voip_cancel.png */; }; - C6710FC42722B20000ED888F /* voip_numpad_star.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F8B2722B1FA00ED888F /* voip_numpad_star.png */; }; - C6710FC52722B20000ED888F /* voip_camera_off.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F8C2722B1FA00ED888F /* voip_camera_off.png */; }; - C6710FC62722B20000ED888F /* voip_menu_more.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F8D2722B1FA00ED888F /* voip_menu_more.png */; }; - C6710FC72722B20000ED888F /* voip_numpad_4.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F8E2722B1FB00ED888F /* voip_numpad_4.png */; }; - C6710FC82722B20000ED888F /* voip_numpad_7.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F8F2722B1FB00ED888F /* voip_numpad_7.png */; }; - C6710FC92722B20000ED888F /* voip_speaker_on.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F902722B1FB00ED888F /* voip_speaker_on.png */; }; - C6710FCA2722B20000ED888F /* voip_call_header_incoming.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F912722B1FC00ED888F /* voip_call_header_incoming.png */; }; - C6710FCB2722B20000ED888F /* voip_remote_recording.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F922722B1FC00ED888F /* voip_remote_recording.png */; }; - C6710FCC2722B20000ED888F /* voip_call_list_menu.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F932722B1FC00ED888F /* voip_call_list_menu.png */; }; - C6710FCD2722B20000ED888F /* voip_call_participants.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F942722B1FD00ED888F /* voip_call_participants.png */; }; - C6710FCE2722B20000ED888F /* voip_speaker_off.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F952722B1FD00ED888F /* voip_speaker_off.png */; }; - C6710FCF2722B20000ED888F /* voip_numpad_8.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F962722B1FD00ED888F /* voip_numpad_8.png */; }; - C6710FD02722B20000ED888F /* voip_call_header_active.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F972722B1FE00ED888F /* voip_call_header_active.png */; }; - C6710FD12722B20000ED888F /* voip_dropdown.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F982722B1FE00ED888F /* voip_dropdown.png */; }; - C6710FD22722B20000ED888F /* voip_call_record.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F992722B1FE00ED888F /* voip_call_record.png */; }; - C6710FD32722B20000ED888F /* voip_conference_paused_big.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F9A2722B1FE00ED888F /* voip_conference_paused_big.png */; }; - C6710FD42722B20000ED888F /* voip_camera_on.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F9B2722B1FF00ED888F /* voip_camera_on.png */; }; - C6710FD52722B20000ED888F /* voip_call_header_outgoing.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F9C2722B1FF00ED888F /* voip_call_header_outgoing.png */; }; - C6710FD62722B20000ED888F /* voip_conference_play_big.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F9D2722B20000ED888F /* voip_conference_play_big.png */; }; - C6710FD72722B20000ED888F /* voip_info.png in Resources */ = {isa = PBXBuildFile; fileRef = C6710F9E2722B20000ED888F /* voip_info.png */; }; - C6710FD92722BD0100ED888F /* UICallTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FD82722BD0100ED888F /* UICallTimer.swift */; }; - C6710FDC2722C3BB00ED888F /* UIVIewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FDB2722C3BB00ED888F /* UIVIewExtensions.swift */; }; - C6710FDE2722D44B00ED888F /* IncomingOuntgoingCommonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FDD2722D44A00ED888F /* IncomingOuntgoingCommonView.swift */; }; - C6710FE12722F0E400ED888F /* Avatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FE02722F0E400ED888F /* Avatar.swift */; }; - C6710FE527230B5800ED888F /* AddressExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FE427230B5800ED888F /* AddressExtensions.swift */; }; - C6710FE72723234400ED888F /* OutgoingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FE62723234400ED888F /* OutgoingCallView.swift */; }; - C6710FE92723DD7D00ED888F /* CallControlButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FE82723DD7D00ED888F /* CallControlButton.swift */; }; - C6710FEB2726874D00ED888F /* ButtonTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6710FEA2726874D00ED888F /* ButtonTheme.swift */; }; - C67C97B1274FB4C10074A0D8 /* VoipConferenceDisplayModeSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67C97B0274FB4C10074A0D8 /* VoipConferenceDisplayModeSelectionView.swift */; }; - C67C97B4274FC5EF0074A0D8 /* AudioRoutesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67C97B3274FC5EE0074A0D8 /* AudioRoutesView.swift */; }; - C67C97B8274FD76B0074A0D8 /* AudioRouteUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67C97B7274FD76B0074A0D8 /* AudioRouteUtils.swift */; }; - C6824FBA27219D890043D4FC /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6824FB927219D890043D4FC /* IncomingCallView.swift */; }; - C683B20E2722702300D4E15C /* VoipTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = C683B20D2722702300D4E15C /* VoipTheme.swift */; }; - C683B213272276CF00D4E15C /* UIColorExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C683B212272276CF00D4E15C /* UIColorExtensions.swift */; }; C6A1BB3526E8815400540D50 /* menu_info.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3126E8815300540D50 /* menu_info.png */; }; C6A1BB3626E8815400540D50 /* menu_forward_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3226E8815400540D50 /* menu_forward_default.png */; }; C6A1BB3726E8815400540D50 /* menu_copy_text_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3326E8815400540D50 /* menu_copy_text_default.png */; }; @@ -776,46 +698,13 @@ C6A1BB4126E889AD00540D50 /* forward_message_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB4026E889AD00540D50 /* forward_message_default.png */; }; C6A1BB4326E88F7C00540D50 /* menu_resend_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB4226E88F7C00540D50 /* menu_resend_default.png */; }; C6A1BB4526E890BD00540D50 /* file_voice_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB4426E890BD00540D50 /* file_voice_default.png */; }; - C6B04D61274B954500F70559 /* ParticipantsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B04D60274B954500F70559 /* ParticipantsListView.swift */; }; - C6B04D63274B95D500F70559 /* VoipParticipantCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B04D62274B95D400F70559 /* VoipParticipantCell.swift */; }; - C6B04D67274BD61300F70559 /* VoipConferenceActiveSpeakerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B04D66274BD61200F70559 /* VoipConferenceActiveSpeakerView.swift */; }; - C6B04D69274BD6A100F70559 /* VoipActiveSpeakerParticipantCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B04D68274BD6A100F70559 /* VoipActiveSpeakerParticipantCell.swift */; }; C6B4444226AAD0980076C517 /* file_video_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4443D26AAD0970076C517 /* file_video_default.png */; }; C6B4444326AAD0980076C517 /* file_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4443E26AAD0970076C517 /* file_default.png */; }; C6B4444426AAD0980076C517 /* file_picture_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4443F26AAD0970076C517 /* file_picture_default.png */; }; C6B4444526AAD0980076C517 /* file_audio_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4444026AAD0970076C517 /* file_audio_default.png */; }; C6B4444626AAD0980076C517 /* file_pdf_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4444126AAD0970076C517 /* file_pdf_default.png */; }; C6B4444826AADA530076C517 /* SwiftUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B4444726AADA530076C517 /* SwiftUtil.swift */; }; - C6C65E89272723DC00E48FC6 /* UIVIewControllerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C65E88272723DC00E48FC6 /* UIVIewControllerExtensions.swift */; }; - C6C65E8B2727274A00E48FC6 /* NumpadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C65E8A2727274A00E48FC6 /* NumpadView.swift */; }; - C6C98CCE27438A3F00059B55 /* DismissableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CCD27438A3F00059B55 /* DismissableView.swift */; }; - C6C98CD027439A7F00059B55 /* VoipCallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CCF27439A7F00059B55 /* VoipCallCell.swift */; }; - C6C98CD22743FD0B00059B55 /* VoipCallContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CD12743FD0B00059B55 /* VoipCallContextMenu.swift */; }; - C6C98CD527453ED900059B55 /* ConferenceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CD427453ED700059B55 /* ConferenceViewModel.swift */; }; - C6C98CD727453F9600059B55 /* ConferenceParticipantData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CD627453F9600059B55 /* ConferenceParticipantData.swift */; }; - C6C98CDB274541E400059B55 /* ConferenceParticipantDeviceData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CDA274541E400059B55 /* ConferenceParticipantDeviceData.swift */; }; - C6C98CDD274547C500059B55 /* ParticipantExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CDC274547C500059B55 /* ParticipantExtensions.swift */; }; - C6C98CDF2745590500059B55 /* ConferenceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CDE2745590400059B55 /* ConferenceExtensions.swift */; }; - C6C98CE1274568F800059B55 /* VoipConferenceGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C98CE0274568F700059B55 /* VoipConferenceGridView.swift */; }; - C6D09F3D273EE467003C2173 /* BouncingCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D09F3C273EE467003C2173 /* BouncingCounter.swift */; }; - C6D09F3F274273FB003C2173 /* CallStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D09F3E274273FB003C2173 /* CallStatsView.swift */; }; - C6D09F4127428626003C2173 /* IceState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D09F4027428626003C2173 /* IceState.swift */; }; - C6D09F43274288D4003C2173 /* PayloadType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D09F42274288D4003C2173 /* PayloadType.swift */; }; - C6D09F4B27438707003C2173 /* CallsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D09F4A27438706003C2173 /* CallsListView.swift */; }; - C6D1EC4A274D212B0091881C /* UICamSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = C6D1EC49274D212B0091881C /* UICamSwitch.m */; }; - C6D52B45274648E500904660 /* VoipGridParticipantCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D52B44274648E500904660 /* VoipGridParticipantCell.swift */; }; C6DA657C261C950C0020CB43 /* VFSUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA657B261C950C0020CB43 /* VFSUtil.swift */; }; - C6EA2F4827514D09008E60F8 /* voip_call_forward.png in Resources */ = {isa = PBXBuildFile; fileRef = C6EA2F4727514D08008E60F8 /* voip_call_forward.png */; }; - C6F2D4EF27392D970071BA52 /* CallsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D4EE27392D960071BA52 /* CallsViewModel.swift */; }; - C6F2D4F1273935860071BA52 /* CallExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D4F0273935860071BA52 /* CallExtensions.swift */; }; - C6F2D4F32739475C0071BA52 /* ActiveCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D4F22739475C0071BA52 /* ActiveCallView.swift */; }; - C6F2D4F72739861F0071BA52 /* RemotelyRecording.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D4F62739861F0071BA52 /* RemotelyRecording.swift */; }; - C6F2D4F9273A4CD70071BA52 /* SharedLayoutConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D4F8273A4CD60071BA52 /* SharedLayoutConstants.swift */; }; - C6F2D4FD273A85A90071BA52 /* PausedCallOrConferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D4FC273A85A90071BA52 /* PausedCallOrConferenceView.swift */; }; - C6F2D4FF273AF01A0071BA52 /* ControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D4FE273AF01A0071BA52 /* ControlsView.swift */; }; - C6F2D501273B0EFC0071BA52 /* VoipDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D500273B0EFC0071BA52 /* VoipDialog.swift */; }; - C6F2D503273BAC030071BA52 /* ButtonWithStateBackgrounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D502273BAC030071BA52 /* ButtonWithStateBackgrounds.swift */; }; - C6F2D505273BB3BB0071BA52 /* UIApplication+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F2D504273BB3BB0071BA52 /* UIApplication+Extension.swift */; }; C90FAA7915AF54E6002091CB /* HistoryDetailsView.m in Sources */ = {isa = PBXBuildFile; fileRef = C90FAA7715AF54E6002091CB /* HistoryDetailsView.m */; }; CF15F21E20E4F9A3008B1DE6 /* UIImageViewDeletable.m in Sources */ = {isa = PBXBuildFile; fileRef = CF15F21C20E4F9A3008B1DE6 /* UIImageViewDeletable.m */; }; CF15F21F20E4F9A3008B1DE6 /* UIImageViewDeletable.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF15F21D20E4F9A3008B1DE6 /* UIImageViewDeletable.xib */; }; @@ -832,6 +721,7 @@ CFBD7A2A20E504AE007C5286 /* delete_img.png in Resources */ = {isa = PBXBuildFile; fileRef = CFBD7A2320E504AD007C5286 /* delete_img.png */; }; D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = D306459D1611EC2900BB571E /* UILoadingImageView.m */; }; D3128FE115AABC7E00A2147A /* ContactDetailsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3128FDF15AABC7E00A2147A /* ContactDetailsView.m */; }; + D31AAF5E159B3919002C6B02 /* CallPausedTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = D31AAF5D159B3919002C6B02 /* CallPausedTableView.m */; }; D31B4B21159876C0002E6C72 /* UICompositeView.m in Sources */ = {isa = PBXBuildFile; fileRef = D31B4B1F159876C0002E6C72 /* UICompositeView.m */; }; D31C9C98158A1CDF00756B45 /* UIHistoryCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D31C9C97158A1CDE00756B45 /* UIHistoryCell.m */; }; D326483815887D5200930C67 /* OrderedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = D326483715887D5200930C67 /* OrderedDictionary.m */; }; @@ -846,6 +736,7 @@ D35860D615B549B500513429 /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = D35860D515B549B500513429 /* Utils.m */; }; D35E7597159460580066B1C1 /* ChatsListView.m in Sources */ = {isa = PBXBuildFile; fileRef = D35E7595159460560066B1C1 /* ChatsListView.m */; }; D35E759F159460B70066B1C1 /* SettingsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D35E759D159460B50066B1C1 /* SettingsView.m */; }; + D36FB2D51589EF7C0036F6F2 /* UIPauseButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D36FB2D41589EF7C0036F6F2 /* UIPauseButton.m */; }; D378AB2A15DCDB4A0098505D /* ImagePickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = D378AB2915DCDB490098505D /* ImagePickerView.m */; }; D37C639B15AADEF6009D0BAC /* ContactDetailsTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = D37C639A15AADEF5009D0BAC /* ContactDetailsTableView.m */; }; D37DC6C11594AE1800B2A5EB /* LinphoneCoreSettingsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = D37DC6C01594AE1800B2A5EB /* LinphoneCoreSettingsStore.m */; }; @@ -878,8 +769,10 @@ D38187C115FE345B00C3EDCA /* DialerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D38187C415FE345B00C3EDCA /* DialerView.xib */; }; D38187CD15FE346700C3EDCA /* HistoryDetailsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D38187D015FE346700C3EDCA /* HistoryDetailsView.xib */; }; D38187D115FE346B00C3EDCA /* HistoryListView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D38187D415FE346B00C3EDCA /* HistoryListView.xib */; }; + D38187D915FE347700C3EDCA /* CallIncomingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D38187DC15FE347700C3EDCA /* CallIncomingView.xib */; }; D38187DD15FE348A00C3EDCA /* AssistantView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D38187E015FE348A00C3EDCA /* AssistantView.xib */; }; D38187F815FE355D00C3EDCA /* TabBarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D38187FB15FE355D00C3EDCA /* TabBarView.xib */; }; + D381881915FE3FCA00C3EDCA /* CallView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D381881C15FE3FCA00C3EDCA /* CallView.xib */; }; D3A55FBC15877E5E003FD403 /* UIContactCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D3A55FBB15877E5E003FD403 /* UIContactCell.m */; }; D3A8BB7015A6C7D500F96BE5 /* UIChatBubbleTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D3A8BB6F15A6C7D500F96BE5 /* UIChatBubbleTextCell.m */; }; D3C6526715AC1A8F0092A874 /* UIContactDetailsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D3C6526615AC1A8F0092A874 /* UIContactDetailsCell.m */; }; @@ -890,10 +783,11 @@ D3ED3E871586291E006C0DE4 /* TabBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED3E851586291B006C0DE4 /* TabBarView.m */; }; D3ED3EA71587334E006C0DE4 /* HistoryListTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED3EA51587334C006C0DE4 /* HistoryListTableView.m */; }; D3ED3EB81587392C006C0DE4 /* HistoryListView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED3EB615873929006C0DE4 /* HistoryListView.m */; }; + D3F26BF115986B73005F9CAB /* CallIncomingView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F26BEF15986B71005F9CAB /* CallIncomingView.m */; }; D3F795D615A582810077328B /* ChatConversationView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F795D415A582800077328B /* ChatConversationView.m */; }; D3F7998115BD32370018C273 /* TPMultiLayoutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F7998015BD32370018C273 /* TPMultiLayoutViewController.m */; }; + D3F83EEC1582021700336684 /* CallView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F83EEA1582021700336684 /* CallView.m */; }; D3F83F8E15822ABE00336684 /* PhoneMainView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F83F8D15822ABD00336684 /* PhoneMainView.m */; }; - E42B8736B8196388DDF2771A /* Pods_msgNotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B39681098B0AF5B59B3A61 /* Pods_msgNotificationService.framework */; }; EA0007A62356008F003CC6BF /* msgNotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = EA5F25D9232BD3E200475F2E /* msgNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; EA3650DB2330D2E30001148A /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5F25DB232BD3E200475F2E /* NotificationService.swift */; }; EA88A405242A6216007FEC61 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 63AADBC41B6A0FF200AA16FD /* Localizable.strings */; }; @@ -965,10 +859,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 02DBDD5A09F46796AEC2485B /* Pods-msgNotificationContent.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.release.xcconfig"; path = "Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.release.xcconfig"; sourceTree = ""; }; - 063D57B2E4769739DC5DA5C0 /* Pods-msgNotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.release.xcconfig"; path = "Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.release.xcconfig"; sourceTree = ""; }; - 0DF941C97B75E7BA39A90600 /* Pods-linphone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.release.xcconfig"; path = "Target Support Files/Pods-linphone/Pods-linphone.release.xcconfig"; sourceTree = ""; }; - 1060E68152C51FCE5ACBF779 /* Pods-msgNotificationContent.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.debug.xcconfig"; path = "Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.debug.xcconfig"; sourceTree = ""; }; + 046DEFE77AD0675DA9932C4C /* Pods-liblinphoneTesterTests.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTesterTests.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTesterTests/Pods-liblinphoneTesterTests.distributionadhoc.xcconfig"; sourceTree = ""; }; + 13B1BD646346F33BF57412F2 /* Pods-messagesNotification.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-messagesNotification.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-messagesNotification/Pods-messagesNotification.distribution.xcconfig"; sourceTree = ""; }; 152F22351B15E889008C0621 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; }; 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 1D3623240D0F684500981E51 /* LinphoneAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinphoneAppDelegate.h; sourceTree = ""; }; @@ -977,6 +869,8 @@ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 2214EB7812F846B1002A5394 /* UICallButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICallButton.h; sourceTree = ""; }; 2214EB7912F846B1002A5394 /* UICallButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICallButton.m; sourceTree = ""; }; + 2214EB8712F84EBB002A5394 /* UIHangUpButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIHangUpButton.h; sourceTree = ""; }; + 2214EB8812F84EBB002A5394 /* UIHangUpButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIHangUpButton.m; sourceTree = ""; }; 2214EBF112F86360002A5394 /* UIMutedMicroButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIMutedMicroButton.h; sourceTree = ""; }; 2214EBF212F86360002A5394 /* UIMutedMicroButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIMutedMicroButton.m; sourceTree = ""; }; 22276E8613C73D8A00210156 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; @@ -994,12 +888,15 @@ 22744043106F33FC006EC466 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 22744056106F9BC9006EC466 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 228697C311AC29B800E9E0CA /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; + 22968A5D12F875C600588287 /* UISpeakerButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UISpeakerButton.h; sourceTree = ""; }; + 22968A5E12F875C600588287 /* UISpeakerButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UISpeakerButton.m; sourceTree = ""; }; + 22AA8AFF13D83F6300B30535 /* UICamSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICamSwitch.h; sourceTree = ""; }; + 22AA8B0013D83F6300B30535 /* UICamSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICamSwitch.m; sourceTree = ""; }; 22B5EFA210CE50BD00777D97 /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; 22B5F03410CE6B2F00777D97 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; 22C7555E1317E59C007BC101 /* UIBluetoothButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIBluetoothButton.h; sourceTree = ""; }; 22C7555F1317E59C007BC101 /* UIBluetoothButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIBluetoothButton.m; sourceTree = ""; }; 22D1B68012A3E0BE001AE361 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = usr/lib/libresolv.dylib; sourceTree = SDKROOT; }; - 22D3BF4C45858F6B07F4D2A4 /* Pods-linphone.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.distributionadhoc.xcconfig"; path = "Target Support Files/Pods-linphone/Pods-linphone.distributionadhoc.xcconfig"; sourceTree = ""; }; 22E0A81C111C44E100B04932 /* AboutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutView.m; sourceTree = ""; }; 22E0A81D111C44E100B04932 /* AboutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutView.h; sourceTree = ""; }; 22F2508B107141E100AC9B3F /* DialerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DialerView.h; sourceTree = ""; }; @@ -1008,6 +905,8 @@ 244523AD1E8266CC0037A187 /* chat_error.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chat_error.png; sourceTree = ""; }; 244523AE1E8266CC0037A187 /* chat_read.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chat_read.png; sourceTree = ""; }; 244523BC1E8D3A6C0037A187 /* chat_unsecure.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chat_unsecure.png; sourceTree = ""; }; + 24585CBE78DA4F005C7F9D71 /* Pods-liblinphoneTester.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTester.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTester/Pods-liblinphoneTester.distribution.xcconfig"; sourceTree = ""; }; + 248C326F4AD75E654C1CB37A /* Pods-liblinphoneTesterTests.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTesterTests.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTesterTests/Pods-liblinphoneTesterTests.distribution.xcconfig"; sourceTree = ""; }; 249660941FD6A359001D55AA /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; 24A3459D1D95797700881A5C /* UIShopTableCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UIShopTableCell.xib; sourceTree = ""; }; 24A345A51D95798A00881A5C /* UIShopTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIShopTableCell.m; sourceTree = ""; }; @@ -1028,14 +927,16 @@ 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* linphone_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linphone_Prefix.pch; sourceTree = ""; }; + 34027665305514025971F85C /* Pods-msgNotificationContent.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.release.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.release.xcconfig"; sourceTree = ""; }; 340751961506459A00B89C47 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; - 3411568BE5527EB500F75EBB /* Pods-msgNotificationService.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.distributionadhoc.xcconfig"; path = "Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.distributionadhoc.xcconfig"; sourceTree = ""; }; + 340751E5150F38FC00B89C47 /* UIVideoButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIVideoButton.h; sourceTree = ""; }; + 340751E6150F38FD00B89C47 /* UIVideoButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIVideoButton.m; sourceTree = ""; }; 34216F3E1547EBCD00EA9777 /* VideoZoomHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VideoZoomHandler.h; path = LinphoneUI/VideoZoomHandler.h; sourceTree = ""; }; 34216F3F1547EBCD00EA9777 /* VideoZoomHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VideoZoomHandler.m; path = LinphoneUI/VideoZoomHandler.m; sourceTree = ""; }; 344ABDEF14850AE9007420B6 /* libc++.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libc++.1.dylib"; path = "usr/lib/libc++.1.dylib"; sourceTree = SDKROOT; }; 344ABDF014850AE9007420B6 /* libstdc++.6.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.6.dylib"; path = "usr/lib/libstdc++.6.dylib"; sourceTree = SDKROOT; }; - 507103607396F28FF4427108 /* Pods-msgNotificationContent.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.distribution.xcconfig"; path = "Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.distribution.xcconfig"; sourceTree = ""; }; - 53432234870660E9876CBCA8 /* Pods-linphone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.debug.xcconfig"; path = "Target Support Files/Pods-linphone/Pods-linphone.debug.xcconfig"; sourceTree = ""; }; + 38A3AE51B9E09ABF29222E5F /* Pods-liblinphoneTester.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTester.release.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTester/Pods-liblinphoneTester.release.xcconfig"; sourceTree = ""; }; + 38DF35D11A7C0F45E990C83A /* Pods-linphone.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-linphone/Pods-linphone.distribution.xcconfig"; sourceTree = ""; }; 570742571D5A0691004B9C84 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ShopView.xib; sourceTree = ""; }; 5707425F1D5A09B8004B9C84 /* ShopView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShopView.m; sourceTree = ""; }; 570742601D5A09B8004B9C84 /* ShopView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShopView.h; sourceTree = ""; }; @@ -1055,7 +956,6 @@ 614C087723D1A35F00217F80 /* ProviderDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = ""; }; 614C087923D1A37400217F80 /* CallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallManager.swift; sourceTree = ""; }; 614D09CD21E74D5400C43EDF /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 6150F32455334A0A7B3D46C8 /* Pods-msgNotificationContent.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.distributionadhoc.xcconfig"; path = "Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.distributionadhoc.xcconfig"; sourceTree = ""; }; 61586B7A217A16EE0038AC45 /* menu_about.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_about.png; sourceTree = ""; }; 61586B82217A16FD0038AC45 /* menu_about@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_about@2x.png"; sourceTree = ""; }; 61586B84217A17070038AC45 /* menu_assistant.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_assistant.png; sourceTree = ""; }; @@ -1100,6 +1000,10 @@ 6187B1B624B3271500D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/AssistantLinkView.strings; sourceTree = ""; }; 6187B1B724B3271600D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/AssistantView.strings; sourceTree = ""; }; 6187B1B824B3271600D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/AssistantViewScreens.strings; sourceTree = ""; }; + 6187B1B924B3271700D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/CallIncomingView.strings; sourceTree = ""; }; + 6187B1BA24B3271700D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/CallOutgoingView.strings; sourceTree = ""; }; + 6187B1BB24B3271700D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/CallView.strings; sourceTree = ""; }; + 6187B1BC24B3271800D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = "hu.lproj/CallView~ipad.strings"; sourceTree = ""; }; 6187B1BD24B3271800D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/ChatConversationCreateView.strings; sourceTree = ""; }; 6187B1BE24B3271900D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/ChatConversationImdnView.strings; sourceTree = ""; }; 6187B1BF24B3271900D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/ChatConversationInfoView.strings; sourceTree = ""; }; @@ -1114,6 +1018,8 @@ 6187B1C824B3271D00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/HistoryDetailsView.strings; sourceTree = ""; }; 6187B1C924B3271D00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/HistoryListView.strings; sourceTree = ""; }; 6187B1CA24B3271E00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/ImageView.strings; sourceTree = ""; }; + 6187B1CB24B3271E00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/UICallConferenceCell.strings; sourceTree = ""; }; + 6187B1CC24B3271E00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/UICallPausedCell.strings; sourceTree = ""; }; 6187B1CD24B3271F00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/UIChatBubblePhotoCell.strings; sourceTree = ""; }; 6187B1CE24B3271F00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/UIChatBubbleTextCell.strings; sourceTree = ""; }; 6187B1CF24B3271F00D580FB /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/UIChatCell.strings; sourceTree = ""; }; @@ -1613,8 +1519,14 @@ 63423C091C4501D000D9A050 /* Contact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Contact.m; sourceTree = ""; }; 634610041B61330300548952 /* UILabel+Boldify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UILabel+Boldify.h"; sourceTree = ""; }; 634610051B61330300548952 /* UILabel+Boldify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UILabel+Boldify.m"; sourceTree = ""; }; + 6346100D1B61409800548952 /* CallOutgoingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallOutgoingView.h; sourceTree = ""; }; + 6346100E1B61409800548952 /* CallOutgoingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallOutgoingView.m; sourceTree = ""; }; + 634610111B6140A500548952 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/CallOutgoingView.xib; sourceTree = ""; }; 635173F71BA082A40095EB0A /* UIChatBubblePhotoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIChatBubblePhotoCell.h; sourceTree = ""; }; 635173F81BA082A40095EB0A /* UIChatBubblePhotoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIChatBubblePhotoCell.m; sourceTree = ""; }; + 6352A5721BE0D4B800594C1C /* CallSideMenuView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallSideMenuView.h; sourceTree = ""; }; + 6352A5731BE0D4B800594C1C /* CallSideMenuView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallSideMenuView.m; sourceTree = ""; }; + 6352A5741BE0D4B800594C1C /* CallSideMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CallSideMenuView.xib; sourceTree = ""; }; 635775231B6673EC00C8B704 /* HistoryDetailsTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryDetailsTableView.h; sourceTree = ""; }; 635775241B6673EC00C8B704 /* HistoryDetailsTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryDetailsTableView.m; sourceTree = ""; }; 636316D21A1DEBCB0009B839 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AboutView.xib; sourceTree = ""; }; @@ -1631,6 +1543,7 @@ 6381DA7B1C1AD5EA00DF3BBD /* UIBouncingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIBouncingView.h; sourceTree = ""; }; 6381DA7C1C1AD5EA00DF3BBD /* UIBouncingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIBouncingView.m; sourceTree = ""; }; 638F1A611C2021B2004B8E02 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Base.lproj/DialerView~ipad.xib"; sourceTree = ""; }; + 638F1A871C2167C2004B8E02 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Base.lproj/CallView~ipad.xib"; sourceTree = ""; }; 638F1A901C21993D004B8E02 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Base.lproj/UICompositeView~ipad.xib"; sourceTree = ""; }; 639CEAFE1A1DF4D9004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/StatusBarView.xib; sourceTree = ""; }; 639CEB011A1DF4E4004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIHistoryCell.xib; sourceTree = ""; }; @@ -1639,6 +1552,7 @@ 639E9C7E1C0DB13D00019A75 /* UICheckBoxTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICheckBoxTableView.h; sourceTree = ""; }; 639E9C7F1C0DB13D00019A75 /* UICheckBoxTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICheckBoxTableView.m; sourceTree = ""; }; 639E9C941C0DB7BE00019A75 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/FirstLoginView.xib; sourceTree = ""; }; + 639E9C9E1C0DB7DF00019A75 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UICallPausedCell.xib; sourceTree = ""; }; 639E9CA11C0DB7E500019A75 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIChatBubblePhotoCell.xib; sourceTree = ""; }; 639E9CA41C0DB7EA00019A75 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIChatBubbleTextCell.xib; sourceTree = ""; }; 639E9CA71C0DB7F200019A75 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIChatCreateCell.xib; sourceTree = ""; }; @@ -1672,6 +1586,8 @@ 63B8D68D1BCBE65600C12B09 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ChatConversationCreateView.xib; sourceTree = ""; }; 63B8D69F1BCBF43100C12B09 /* UIChatCreateCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIChatCreateCell.h; sourceTree = ""; }; 63B8D6A01BCBF43100C12B09 /* UIChatCreateCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIChatCreateCell.m; sourceTree = ""; }; + 63BC49E01BA2CDFC004EC273 /* UICallPausedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICallPausedCell.h; sourceTree = ""; }; + 63BC49E11BA2CDFC004EC273 /* UICallPausedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICallPausedCell.m; sourceTree = ""; }; 63BE7A761D75BDF6000990EF /* ShopTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShopTableView.h; sourceTree = ""; }; 63BE7A771D75BDF6000990EF /* ShopTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShopTableView.m; sourceTree = ""; }; 63C441C11BBC23ED0053DC5E /* UIAssistantTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAssistantTextField.h; sourceTree = ""; }; @@ -1695,13 +1611,30 @@ 63EEE40D1BBA9B250087D3AF /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; 63F1DF421BCE618E00EDED90 /* UIAddressTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAddressTextField.h; sourceTree = ""; }; 63F1DF431BCE618E00EDED90 /* UIAddressTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAddressTextField.m; sourceTree = ""; }; + 63F1DF491BCE983100EDED90 /* CallConferenceTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallConferenceTableView.h; sourceTree = ""; }; + 63F1DF4A1BCE983200EDED90 /* CallConferenceTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallConferenceTableView.m; sourceTree = ""; }; + 63F1DF4C1BCE985F00EDED90 /* UICallConferenceCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICallConferenceCell.h; sourceTree = ""; }; + 63F1DF4D1BCE985F00EDED90 /* UICallConferenceCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICallConferenceCell.m; sourceTree = ""; }; + 63F1DF521BCE986A00EDED90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UICallConferenceCell.xib; sourceTree = ""; }; 63FB30331A680E73008CA393 /* UIRoundedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIRoundedImageView.h; sourceTree = ""; }; 63FB30341A680E73008CA393 /* UIRoundedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIRoundedImageView.m; sourceTree = ""; }; + 65CEDD144CABFAA70A29AF27 /* Pods_linphone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_linphone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 68D9EC27FCECD5DE2E19CD3C /* Pods-liblinphoneTester.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTester.debug.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTester/Pods-liblinphoneTester.debug.xcconfig"; sourceTree = ""; }; + 6E1BC45342F5201DABD7FE55 /* Pods_latestCallsWidget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_latestCallsWidget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6F30EA7BEA39DA427CE0754E /* Pods_msgNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_msgNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 70E542F213E147E3002BA2C0 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 70E542F413E147EB002BA2C0 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - 72B39681098B0AF5B59B3A61 /* Pods_msgNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_msgNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 79B41078A602EFB886981917 /* Pods-linphone.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.distribution.xcconfig"; path = "Target Support Files/Pods-linphone/Pods-linphone.distribution.xcconfig"; sourceTree = ""; }; + 7513CBF7F2BA0A9F99977C2B /* Pods_richNotifications.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_richNotifications.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 791017662FE117B9B12E8938 /* Pods-messagesNotification.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-messagesNotification.debug.xcconfig"; path = "Pods/Target Support Files/Pods-messagesNotification/Pods-messagesNotification.debug.xcconfig"; sourceTree = ""; }; + 799BA1104845EB01ACE764D8 /* Pods-linphone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.debug.xcconfig"; path = "Pods/Target Support Files/Pods-linphone/Pods-linphone.debug.xcconfig"; sourceTree = ""; }; + 7D8CCFE176C634813E3A2593 /* Pods-liblinphoneTesterTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTesterTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTesterTests/Pods-liblinphoneTesterTests.debug.xcconfig"; sourceTree = ""; }; + 82E9DEDA2A78C6DBBD1A54DB /* Pods_msgNotificationContent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_msgNotificationContent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 85FB19B6A8124D942C8471F1 /* Pods-linphoneTests.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphoneTests.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-linphoneTests/Pods-linphoneTests.distribution.xcconfig"; sourceTree = ""; }; + 8B488C393394746F9D630789 /* Pods_latestChatroomsWidget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_latestChatroomsWidget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8B4C43A28E90775F6FCA2CEE /* Pods-msgNotificationContent.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.debug.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.debug.xcconfig"; sourceTree = ""; }; 8C1A1F7C1FA331D40064BE00 /* libsoci_sqlite3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsoci_sqlite3.a; path = "liblinphone-sdk/apple-darwin/lib/libsoci_sqlite3.a"; sourceTree = ""; }; + 8C1B67051E671826001EA2FE /* AudioHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioHelper.m; sourceTree = ""; }; + 8C1B67081E6718BC001EA2FE /* AudioHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioHelper.h; path = Utils/AudioHelper.h; sourceTree = ""; }; 8C23BCB71D82AAC3005F19BB /* linphone.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = linphone.entitlements; sourceTree = ""; }; 8C2595DE1DEDCC8E007A6424 /* CallKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CallKit.framework; path = System/Library/Frameworks/CallKit.framework; sourceTree = SDKROOT; }; 8C2A81931F87B7FF0012A66B /* chat_group_avatar@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_group_avatar@2x.png"; sourceTree = ""; }; @@ -1738,6 +1671,10 @@ 8CBD7BAD20B6B82F00E5DCC0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIChatCreateCollectionViewCell.xib; sourceTree = ""; }; 8CBD7BB120B6B86900E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AssistantView.strings; sourceTree = ""; }; 8CBD7BB220B6B86A00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AssistantViewScreens.strings; sourceTree = ""; }; + 8CBD7BB320B6B86B00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/CallIncomingView.strings; sourceTree = ""; }; + 8CBD7BB420B6B86B00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/CallOutgoingView.strings; sourceTree = ""; }; + 8CBD7BB520B6B86C00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/CallView.strings; sourceTree = ""; }; + 8CBD7BB620B6B86D00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = "fr.lproj/CallView~ipad.strings"; sourceTree = ""; }; 8CBD7BB720B6B86E00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/ChatConversationInfoView.strings; sourceTree = ""; }; 8CBD7BB820B6B86F00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/ChatConversationImdnView.strings; sourceTree = ""; }; 8CBD7BB920B6B87000E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/ChatConversationCreateView.strings; sourceTree = ""; }; @@ -1752,6 +1689,8 @@ 8CBD7BC220B6B87600E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/HistoryDetailsView.strings; sourceTree = ""; }; 8CBD7BC320B6B87700E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/HistoryListView.strings; sourceTree = ""; }; 8CBD7BC420B6B87800E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/ImageView.strings; sourceTree = ""; }; + 8CBD7BC520B6B87800E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UICallConferenceCell.strings; sourceTree = ""; }; + 8CBD7BC620B6B87900E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UICallPausedCell.strings; sourceTree = ""; }; 8CBD7BC720B6B87A00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UIChatBubblePhotoCell.strings; sourceTree = ""; }; 8CBD7BC820B6B87B00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UIChatBubbleTextCell.strings; sourceTree = ""; }; 8CBD7BC920B6B87B00E5DCC0 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UIChatCell.strings; sourceTree = ""; }; @@ -1789,14 +1728,13 @@ 8CF25D941F9F336100BEA0C1 /* check_unselected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = check_unselected.png; sourceTree = ""; }; 8CF25D9B1F9F76BC00BEA0C1 /* chat_group_informations.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chat_group_informations.png; sourceTree = ""; }; 8CF25D9C1F9F76BD00BEA0C1 /* chat_group_informations@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_group_informations@2x.png"; sourceTree = ""; }; - A164BAF39B3A5B9F905917A7 /* Pods_msgNotificationContent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_msgNotificationContent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - B464E44A606CB50A65A96FE2 /* Pods_linphone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_linphone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - B9F41097CE0124A05554DB9C /* Pods-msgNotificationService.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.distribution.xcconfig"; path = "Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.distribution.xcconfig"; sourceTree = ""; }; - C589627B9D9D2A4F9C816051 /* Pods-msgNotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.debug.xcconfig"; path = "Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.debug.xcconfig"; sourceTree = ""; }; - C60B66672721AFFA0026AC7D /* CallStatisticsData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallStatisticsData.swift; sourceTree = ""; }; - C60D265527299C94006238BB /* ControlsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlsViewModel.swift; sourceTree = ""; }; - C60D265727299F6F006238BB /* CoreExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreExtensions.swift; sourceTree = ""; }; - C60D265B272AA0BD006238BB /* UIImageExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtensions.swift; sourceTree = ""; }; + 8FD0D10102F0A8922703B8A4 /* Pods-msgNotificationService.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.distributionadhoc.xcconfig"; sourceTree = ""; }; + 904C1EC75CB9E03374AAA802 /* Pods-msgNotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.release.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.release.xcconfig"; sourceTree = ""; }; + 9CBD6E980619195CB7EE32AC /* Pods_liblinphoneTester.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_liblinphoneTester.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + ABB887316C42EE876A3051A9 /* Pods-linphoneTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphoneTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-linphoneTests/Pods-linphoneTests.debug.xcconfig"; sourceTree = ""; }; + ADCA571A7CF61077747BFE53 /* Pods-msgNotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.debug.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.debug.xcconfig"; sourceTree = ""; }; + BAD0A9494E833034EB559687 /* Pods-msgNotificationContent.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.distributionadhoc.xcconfig"; sourceTree = ""; }; + BE06BDE664323B2A53469696 /* Pods-liblinphoneTesterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTesterTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTesterTests/Pods-liblinphoneTesterTests.release.xcconfig"; sourceTree = ""; }; C61B1BF12667D075001A4E4A /* menu_security_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_security_default.png; sourceTree = ""; }; C61B1BF32667D202001A4E4A /* more_menu_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = more_menu_default.png; sourceTree = ""; }; C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ephemeral_messages_color_A.png; sourceTree = ""; }; @@ -1806,106 +1744,15 @@ C622E3EC26A8128F004F5434 /* vr_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_off.png; sourceTree = ""; }; C622E3ED26A8128F004F5434 /* vr_pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_pause.png; sourceTree = ""; }; C622E3EE26A81290004F5434 /* vr_play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_play.png; sourceTree = ""; }; - C6277DA6274BF1CD00406FB9 /* voip_radio_on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_radio_on.png; sourceTree = ""; }; - C6277DA7274BF1CD00406FB9 /* voip_radio_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_radio_off.png; sourceTree = ""; }; - C6278496273C21E1002FAA29 /* LocalVideoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalVideoView.swift; sourceTree = ""; }; C64A854C2667B66900252AD2 /* EphemeralSettingsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EphemeralSettingsView.h; sourceTree = ""; }; C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EphemeralSettingsView.m; sourceTree = ""; }; C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EphemeralSettingsView.xib; sourceTree = ""; }; C64A85512667B74100252AD2 /* ephemeral_messages_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ephemeral_messages_default.png; sourceTree = ""; }; - C6586148273E595700A0DBFC /* VoipExtraButtonsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipExtraButtonsView.swift; sourceTree = ""; }; - C658614B273E5B5E00A0DBFC /* VoipExtraButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipExtraButton.swift; sourceTree = ""; }; - C65A5D2F27216B86005BA038 /* ActiveCallOrConferenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveCallOrConferenceView.swift; sourceTree = ""; }; - C65A5D3727216CC0005BA038 /* MutableLiveData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MutableLiveData.swift; sourceTree = ""; }; - C65A5D3E27216E3A005BA038 /* CallData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallData.swift; sourceTree = ""; }; - C65A5D44272196AE005BA038 /* OptionalExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalExtensions.swift; sourceTree = ""; }; C66B03BC26E8EB1A009B5EDC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIChatReplyBubbleView.xib; sourceTree = ""; }; C66B03C126E8EB82009B5EDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/UIChatReplyBubbleView.strings; sourceTree = ""; }; C66B03C326E8EB87009B5EDC /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UIChatReplyBubbleView.strings; sourceTree = ""; }; C66B040926EFDA54009B5EDC /* reply_cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = reply_cancel.png; sourceTree = ""; }; C66B040D26F095CE009B5EDC /* cancel_forward.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cancel_forward.png; sourceTree = ""; }; - C6710F4E2722903200ED888F /* RotatingSpinner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotatingSpinner.swift; sourceTree = ""; }; - C6710F502722932600ED888F /* UIImageViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageViewExtensions.swift; sourceTree = ""; }; - C6710F52272297C400ED888F /* VoipTexts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipTexts.swift; sourceTree = ""; }; - C6710F5427229D5900ED888F /* LightDarkColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightDarkColor.swift; sourceTree = ""; }; - C6710F5627229DEE00ED888F /* TextStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextStyle.swift; sourceTree = ""; }; - C6710F582722A9B800ED888F /* StyledLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StyledLabel.swift; sourceTree = ""; }; - C6710F5B2722AAED00ED888F /* UIDeviceExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIDeviceExtensions.swift; sourceTree = ""; }; - C6710F5E2722AECB00ED888F /* Roboto-Italic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Italic.ttf"; sourceTree = ""; }; - C6710F5F2722AECB00ED888F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = ""; }; - C6710F602722AECB00ED888F /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = ""; }; - C6710F642722B13000ED888F /* voip_spinner.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_spinner.png; sourceTree = ""; }; - C6710F662722B1EF00ED888F /* voip_numpad_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_1.png; sourceTree = ""; }; - C6710F672722B1EF00ED888F /* voip_numpad_0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_0.png; sourceTree = ""; }; - C6710F682722B1EF00ED888F /* voip_copy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_copy.png; sourceTree = ""; }; - C6710F692722B1EF00ED888F /* voip_merge_calls.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_merge_calls.png; sourceTree = ""; }; - C6710F6A2722B1EF00ED888F /* voip_call_numpad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_numpad.png; sourceTree = ""; }; - C6710F6B2722B1F000ED888F /* voip_single_contact_avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_single_contact_avatar.png; sourceTree = ""; }; - C6710F6C2722B1F000ED888F /* voip_mandatory.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_mandatory.png; sourceTree = ""; }; - C6710F6D2722B1F000ED888F /* voip_bluetooth.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_bluetooth.png; sourceTree = ""; }; - C6710F6E2722B1F000ED888F /* voip_call_more.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_more.png; sourceTree = ""; }; - C6710F6F2722B1F100ED888F /* voip_multiple_contacts_avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_multiple_contacts_avatar.png; sourceTree = ""; }; - C6710F702722B1F100ED888F /* voip_call_stats.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_stats.png; sourceTree = ""; }; - C6710F712722B1F100ED888F /* voip_conference_active_speaker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_conference_active_speaker.png; sourceTree = ""; }; - C6710F722722B1F200ED888F /* voip_edit.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_edit.png; sourceTree = ""; }; - C6710F732722B1F200ED888F /* voip_call_chat.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_chat.png; sourceTree = ""; }; - C6710F742722B1F200ED888F /* voip_numpad_5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_5.png; sourceTree = ""; }; - C6710F752722B1F300ED888F /* voip_hangup.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_hangup.png; sourceTree = ""; }; - C6710F762722B1F300ED888F /* voip_conference_new.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_conference_new.png; sourceTree = ""; }; - C6710F772722B1F300ED888F /* voip_chat_rooms_list.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_chat_rooms_list.png; sourceTree = ""; }; - C6710F782722B1F300ED888F /* voip_micro_on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_micro_on.png; sourceTree = ""; }; - C6710F792722B1F400ED888F /* voip_calls_list.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_calls_list.png; sourceTree = ""; }; - C6710F7A2722B1F400ED888F /* voip_pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_pause.png; sourceTree = ""; }; - C6710F7B2722B1F500ED888F /* voip_conference_mosaic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_conference_mosaic.png; sourceTree = ""; }; - C6710F7C2722B1F500ED888F /* voip_delete.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_delete.png; sourceTree = ""; }; - C6710F7D2722B1F500ED888F /* voip_audio_routes.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_audio_routes.png; sourceTree = ""; }; - C6710F7E2722B1F600ED888F /* voip_numpad_6.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_6.png; sourceTree = ""; }; - C6710F7F2722B1F600ED888F /* voip_numpad_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_3.png; sourceTree = ""; }; - C6710F802722B1F600ED888F /* voip_call_add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_add.png; sourceTree = ""; }; - C6710F812722B1F700ED888F /* voip_numpad_9.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_9.png; sourceTree = ""; }; - C6710F822722B1F700ED888F /* voip_call.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call.png; sourceTree = ""; }; - C6710F832722B1F700ED888F /* voip_change_camera.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_change_camera.png; sourceTree = ""; }; - C6710F842722B1F800ED888F /* voip_call_header_paused.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_header_paused.png; sourceTree = ""; }; - C6710F852722B1F800ED888F /* voip_export.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_export.png; sourceTree = ""; }; - C6710F862722B1F800ED888F /* voip_earpiece.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_earpiece.png; sourceTree = ""; }; - C6710F872722B1F800ED888F /* voip_numpad_hash.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_hash.png; sourceTree = ""; }; - C6710F882722B1F900ED888F /* voip_micro_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_micro_off.png; sourceTree = ""; }; - C6710F892722B1F900ED888F /* voip_numpad_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_2.png; sourceTree = ""; }; - C6710F8A2722B1F900ED888F /* voip_cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_cancel.png; sourceTree = ""; }; - C6710F8B2722B1FA00ED888F /* voip_numpad_star.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_star.png; sourceTree = ""; }; - C6710F8C2722B1FA00ED888F /* voip_camera_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_camera_off.png; sourceTree = ""; }; - C6710F8D2722B1FA00ED888F /* voip_menu_more.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_menu_more.png; sourceTree = ""; }; - C6710F8E2722B1FB00ED888F /* voip_numpad_4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_4.png; sourceTree = ""; }; - C6710F8F2722B1FB00ED888F /* voip_numpad_7.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_7.png; sourceTree = ""; }; - C6710F902722B1FB00ED888F /* voip_speaker_on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_speaker_on.png; sourceTree = ""; }; - C6710F912722B1FC00ED888F /* voip_call_header_incoming.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_header_incoming.png; sourceTree = ""; }; - C6710F922722B1FC00ED888F /* voip_remote_recording.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_remote_recording.png; sourceTree = ""; }; - C6710F932722B1FC00ED888F /* voip_call_list_menu.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_list_menu.png; sourceTree = ""; }; - C6710F942722B1FD00ED888F /* voip_call_participants.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_participants.png; sourceTree = ""; }; - C6710F952722B1FD00ED888F /* voip_speaker_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_speaker_off.png; sourceTree = ""; }; - C6710F962722B1FD00ED888F /* voip_numpad_8.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_numpad_8.png; sourceTree = ""; }; - C6710F972722B1FE00ED888F /* voip_call_header_active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_header_active.png; sourceTree = ""; }; - C6710F982722B1FE00ED888F /* voip_dropdown.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_dropdown.png; sourceTree = ""; }; - C6710F992722B1FE00ED888F /* voip_call_record.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_record.png; sourceTree = ""; }; - C6710F9A2722B1FE00ED888F /* voip_conference_paused_big.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_conference_paused_big.png; sourceTree = ""; }; - C6710F9B2722B1FF00ED888F /* voip_camera_on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_camera_on.png; sourceTree = ""; }; - C6710F9C2722B1FF00ED888F /* voip_call_header_outgoing.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_header_outgoing.png; sourceTree = ""; }; - C6710F9D2722B20000ED888F /* voip_conference_play_big.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_conference_play_big.png; sourceTree = ""; }; - C6710F9E2722B20000ED888F /* voip_info.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_info.png; sourceTree = ""; }; - C6710FD82722BD0100ED888F /* UICallTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICallTimer.swift; sourceTree = ""; }; - C6710FDB2722C3BB00ED888F /* UIVIewExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIVIewExtensions.swift; sourceTree = ""; }; - C6710FDD2722D44A00ED888F /* IncomingOuntgoingCommonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IncomingOuntgoingCommonView.swift; sourceTree = ""; }; - C6710FE02722F0E400ED888F /* Avatar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Avatar.swift; sourceTree = ""; }; - C6710FE427230B5800ED888F /* AddressExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressExtensions.swift; sourceTree = ""; }; - C6710FE62723234400ED888F /* OutgoingCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingCallView.swift; sourceTree = ""; }; - C6710FE82723DD7D00ED888F /* CallControlButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallControlButton.swift; sourceTree = ""; }; - C6710FEA2726874D00ED888F /* ButtonTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonTheme.swift; sourceTree = ""; }; - C67C97B0274FB4C10074A0D8 /* VoipConferenceDisplayModeSelectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipConferenceDisplayModeSelectionView.swift; sourceTree = ""; }; - C67C97B3274FC5EE0074A0D8 /* AudioRoutesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioRoutesView.swift; sourceTree = ""; }; - C67C97B7274FD76B0074A0D8 /* AudioRouteUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioRouteUtils.swift; sourceTree = ""; }; - C6824FB927219D890043D4FC /* IncomingCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallView.swift; sourceTree = ""; }; - C683B20D2722702300D4E15C /* VoipTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipTheme.swift; sourceTree = ""; }; - C683B212272276CF00D4E15C /* UIColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorExtensions.swift; sourceTree = ""; }; C6A1BB3126E8815300540D50 /* menu_info.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_info.png; sourceTree = ""; }; C6A1BB3226E8815400540D50 /* menu_forward_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_forward_default.png; sourceTree = ""; }; C6A1BB3326E8815400540D50 /* menu_copy_text_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_copy_text_default.png; sourceTree = ""; }; @@ -1916,50 +1763,18 @@ C6A1BB4026E889AD00540D50 /* forward_message_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = forward_message_default.png; sourceTree = ""; }; C6A1BB4226E88F7C00540D50 /* menu_resend_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_resend_default.png; sourceTree = ""; }; C6A1BB4426E890BD00540D50 /* file_voice_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_voice_default.png; sourceTree = ""; }; - C6B04D60274B954500F70559 /* ParticipantsListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParticipantsListView.swift; sourceTree = ""; }; - C6B04D62274B95D400F70559 /* VoipParticipantCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipParticipantCell.swift; sourceTree = ""; }; - C6B04D66274BD61200F70559 /* VoipConferenceActiveSpeakerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipConferenceActiveSpeakerView.swift; sourceTree = ""; }; - C6B04D68274BD6A100F70559 /* VoipActiveSpeakerParticipantCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipActiveSpeakerParticipantCell.swift; sourceTree = ""; }; C6B4443D26AAD0970076C517 /* file_video_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_video_default.png; sourceTree = ""; }; C6B4443E26AAD0970076C517 /* file_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_default.png; sourceTree = ""; }; C6B4443F26AAD0970076C517 /* file_picture_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_picture_default.png; sourceTree = ""; }; C6B4444026AAD0970076C517 /* file_audio_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_audio_default.png; sourceTree = ""; }; C6B4444126AAD0970076C517 /* file_pdf_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_pdf_default.png; sourceTree = ""; }; C6B4444726AADA530076C517 /* SwiftUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUtil.swift; sourceTree = ""; }; - C6C65E88272723DC00E48FC6 /* UIVIewControllerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIVIewControllerExtensions.swift; sourceTree = ""; }; - C6C65E8A2727274A00E48FC6 /* NumpadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumpadView.swift; sourceTree = ""; }; - C6C98CCD27438A3F00059B55 /* DismissableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DismissableView.swift; sourceTree = ""; }; - C6C98CCF27439A7F00059B55 /* VoipCallCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipCallCell.swift; sourceTree = ""; }; - C6C98CD12743FD0B00059B55 /* VoipCallContextMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipCallContextMenu.swift; sourceTree = ""; }; - C6C98CD427453ED700059B55 /* ConferenceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConferenceViewModel.swift; sourceTree = ""; }; - C6C98CD627453F9600059B55 /* ConferenceParticipantData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConferenceParticipantData.swift; sourceTree = ""; }; - C6C98CDA274541E400059B55 /* ConferenceParticipantDeviceData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConferenceParticipantDeviceData.swift; sourceTree = ""; }; - C6C98CDC274547C500059B55 /* ParticipantExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParticipantExtensions.swift; sourceTree = ""; }; - C6C98CDE2745590400059B55 /* ConferenceExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConferenceExtensions.swift; sourceTree = ""; }; - C6C98CE0274568F700059B55 /* VoipConferenceGridView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipConferenceGridView.swift; sourceTree = ""; }; - C6D09F3C273EE467003C2173 /* BouncingCounter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BouncingCounter.swift; sourceTree = ""; }; - C6D09F3E274273FB003C2173 /* CallStatsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallStatsView.swift; sourceTree = ""; }; - C6D09F4027428626003C2173 /* IceState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IceState.swift; sourceTree = ""; }; - C6D09F42274288D4003C2173 /* PayloadType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayloadType.swift; sourceTree = ""; }; - C6D09F4A27438706003C2173 /* CallsListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallsListView.swift; sourceTree = ""; }; - C6D1EC48274D212A0091881C /* UICamSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICamSwitch.h; sourceTree = ""; }; - C6D1EC49274D212B0091881C /* UICamSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICamSwitch.m; sourceTree = ""; }; - C6D52B44274648E500904660 /* VoipGridParticipantCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipGridParticipantCell.swift; sourceTree = ""; }; C6DA657B261C950C0020CB43 /* VFSUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VFSUtil.swift; sourceTree = ""; }; - C6EA2F4727514D08008E60F8 /* voip_call_forward.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voip_call_forward.png; sourceTree = ""; }; - C6F2D4EE27392D960071BA52 /* CallsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallsViewModel.swift; sourceTree = ""; }; - C6F2D4F0273935860071BA52 /* CallExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallExtensions.swift; sourceTree = ""; }; - C6F2D4F22739475C0071BA52 /* ActiveCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveCallView.swift; sourceTree = ""; }; - C6F2D4F62739861F0071BA52 /* RemotelyRecording.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemotelyRecording.swift; sourceTree = ""; }; - C6F2D4F8273A4CD60071BA52 /* SharedLayoutConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedLayoutConstants.swift; sourceTree = ""; }; - C6F2D4FC273A85A90071BA52 /* PausedCallOrConferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PausedCallOrConferenceView.swift; sourceTree = ""; }; - C6F2D4FE273AF01A0071BA52 /* ControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlsView.swift; sourceTree = ""; }; - C6F2D500273B0EFC0071BA52 /* VoipDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipDialog.swift; sourceTree = ""; }; - C6F2D502273BAC030071BA52 /* ButtonWithStateBackgrounds.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonWithStateBackgrounds.swift; sourceTree = ""; }; - C6F2D504273BB3BB0071BA52 /* UIApplication+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Extension.swift"; sourceTree = ""; }; C90FAA7615AF54E6002091CB /* HistoryDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryDetailsView.h; sourceTree = ""; }; C90FAA7715AF54E6002091CB /* HistoryDetailsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryDetailsView.m; sourceTree = ""; }; C9B3A6FD15B485DB006F52EE /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = Utils/Utils.h; sourceTree = ""; }; + CC6F924A8B1B1698914A3BB2 /* Pods-messagesNotification.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-messagesNotification.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-messagesNotification/Pods-messagesNotification.distributionadhoc.xcconfig"; sourceTree = ""; }; + CE119C214B6B8B2740622BBD /* Pods-linphoneTests.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphoneTests.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-linphoneTests/Pods-linphoneTests.distributionadhoc.xcconfig"; sourceTree = ""; }; CF15F21B20E4F9A3008B1DE6 /* UIImageViewDeletable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIImageViewDeletable.h; sourceTree = ""; }; CF15F21C20E4F9A3008B1DE6 /* UIImageViewDeletable.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIImageViewDeletable.m; sourceTree = ""; }; CF15F21D20E4F9A3008B1DE6 /* UIImageViewDeletable.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UIImageViewDeletable.xib; sourceTree = ""; }; @@ -1978,10 +1793,13 @@ CF7602F3210898C600749F76 /* rec_off_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = rec_off_default.png; sourceTree = ""; }; CF7602F4210898C800749F76 /* rec_on_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = rec_on_default.png; sourceTree = ""; }; CFBD7A2320E504AD007C5286 /* delete_img.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = delete_img.png; sourceTree = ""; }; + D252FEC7DD06DD5695A320A1 /* Pods_liblinphoneTesterTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_liblinphoneTesterTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D306459C1611EC2900BB571E /* UILoadingImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UILoadingImageView.h; sourceTree = ""; }; D306459D1611EC2900BB571E /* UILoadingImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UILoadingImageView.m; sourceTree = ""; }; D3128FDE15AABC7E00A2147A /* ContactDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsView.h; sourceTree = ""; }; D3128FDF15AABC7E00A2147A /* ContactDetailsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactDetailsView.m; sourceTree = ""; }; + D31AAF5C159B3919002C6B02 /* CallPausedTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallPausedTableView.h; sourceTree = ""; }; + D31AAF5D159B3919002C6B02 /* CallPausedTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallPausedTableView.m; sourceTree = ""; }; D31B4B1E159876C0002E6C72 /* UICompositeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICompositeView.h; sourceTree = ""; }; D31B4B1F159876C0002E6C72 /* UICompositeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICompositeView.m; sourceTree = ""; }; D31C9C96158A1CDE00756B45 /* UIHistoryCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIHistoryCell.h; sourceTree = ""; }; @@ -2009,6 +1827,8 @@ D35E7595159460560066B1C1 /* ChatsListView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatsListView.m; sourceTree = ""; }; D35E759C159460B50066B1C1 /* SettingsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsView.h; sourceTree = ""; }; D35E759D159460B50066B1C1 /* SettingsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsView.m; sourceTree = ""; }; + D36FB2D31589EF7C0036F6F2 /* UIPauseButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIPauseButton.h; sourceTree = ""; }; + D36FB2D41589EF7C0036F6F2 /* UIPauseButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIPauseButton.m; sourceTree = ""; }; D378AB2815DCDB480098505D /* ImagePickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImagePickerView.h; sourceTree = ""; }; D378AB2915DCDB490098505D /* ImagePickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImagePickerView.m; sourceTree = ""; }; D37C639915AADEF4009D0BAC /* ContactDetailsTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsTableView.h; sourceTree = ""; }; @@ -2075,12 +1895,17 @@ D3ED3EA51587334C006C0DE4 /* HistoryListTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = HistoryListTableView.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; D3ED3EB515873928006C0DE4 /* HistoryListView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryListView.h; sourceTree = ""; }; D3ED3EB615873929006C0DE4 /* HistoryListView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = HistoryListView.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + D3F26BEE15986B71005F9CAB /* CallIncomingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallIncomingView.h; sourceTree = ""; }; + D3F26BEF15986B71005F9CAB /* CallIncomingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallIncomingView.m; sourceTree = ""; }; D3F795D315A582800077328B /* ChatConversationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatConversationView.h; sourceTree = ""; }; D3F795D415A582800077328B /* ChatConversationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatConversationView.m; sourceTree = ""; }; D3F7997F15BD32370018C273 /* TPMultiLayoutViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPMultiLayoutViewController.h; path = Utils/TPMultiLayoutViewController/TPMultiLayoutViewController.h; sourceTree = ""; }; D3F7998015BD32370018C273 /* TPMultiLayoutViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPMultiLayoutViewController.m; path = Utils/TPMultiLayoutViewController/TPMultiLayoutViewController.m; sourceTree = ""; }; + D3F83EE91582021700336684 /* CallView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallView.h; sourceTree = ""; }; + D3F83EEA1582021700336684 /* CallView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallView.m; sourceTree = ""; }; D3F83F8C158229C500336684 /* PhoneMainView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhoneMainView.h; sourceTree = ""; }; D3F83F8D15822ABD00336684 /* PhoneMainView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhoneMainView.m; sourceTree = ""; }; + E40C9A7D22675584396C0A3D /* Pods-msgNotificationContent.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.distribution.xcconfig"; sourceTree = ""; }; EA5F25D9232BD3E200475F2E /* msgNotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = msgNotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; EA5F25DB232BD3E200475F2E /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; EA5F25DD232BD3E200475F2E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -2091,6 +1916,7 @@ EA8CB83F239FD41400C330CC /* msgNotificationContent.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = msgNotificationContent.entitlements; sourceTree = ""; }; EAB783CF232F8E4D0076B1A0 /* msgNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = msgNotificationService.entitlements; sourceTree = ""; }; EAE6C88323FABF690076A018 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = msgNotification/Utils.swift; sourceTree = SOURCE_ROOT; }; + EE807919DDB0B4B46AD1D439 /* Pods-messagesNotification.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-messagesNotification.release.xcconfig"; path = "Pods/Target Support Files/Pods-messagesNotification/Pods-messagesNotification.release.xcconfig"; sourceTree = ""; }; F0181B6B18BF7B1200A9A357 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; F03A9B9418C0DAE100C4D7FE /* libstdc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.dylib"; path = "usr/lib/libstdc++.dylib"; sourceTree = SDKROOT; }; F03A9B9718C0DB6F00C4D7FE /* libc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libc++.dylib"; path = "usr/lib/libc++.dylib"; sourceTree = SDKROOT; }; @@ -2109,6 +1935,8 @@ F09548201883F15400E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/HistoryDetailsView.xib; sourceTree = ""; }; F09548211883F15400E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/HistoryListView.xib; sourceTree = ""; }; F09548221883F15400E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ImageView.xib; sourceTree = ""; }; + F09548231883F15400E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/CallView.xib; sourceTree = ""; }; + F09548241883F15400E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/CallIncomingView.xib; sourceTree = ""; }; F095482C1883F15400E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/TabBarView.xib; sourceTree = ""; }; F095482E1883F15500E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AssistantView.xib; sourceTree = ""; }; F09548301883F15500E8A69B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AssistantViewScreens.xib; sourceTree = ""; }; @@ -2119,6 +1947,8 @@ F095483C1883F2E300E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/DialerView.strings; sourceTree = ""; }; F09548421883F51B00E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/HistoryListView.strings; sourceTree = ""; }; F09548441883F52900E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/ImageView.strings; sourceTree = ""; }; + F09548461883F54200E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/CallView.strings; sourceTree = ""; }; + F09548481883F55800E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/CallIncomingView.strings; sourceTree = ""; }; F09548561883F61600E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/TabBarView.strings; sourceTree = ""; }; F095485A1883F67B00E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/AssistantView.strings; sourceTree = ""; }; F095485E1883F6EA00E8A69B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/AssistantViewScreens.strings; sourceTree = ""; }; @@ -2130,6 +1960,8 @@ F0AF06F91A24BA760086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/HistoryDetailsView.strings; sourceTree = ""; }; F0AF06FA1A24BA770086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/HistoryListView.strings; sourceTree = ""; }; F0AF06FB1A24BA770086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/ImageView.strings; sourceTree = ""; }; + F0AF06FC1A24BA770086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/CallView.strings; sourceTree = ""; }; + F0AF06FD1A24BA770086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/CallIncomingView.strings; sourceTree = ""; }; F0AF07021A24BA770086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/UIChatCell.strings; sourceTree = ""; }; F0AF07041A24BA770086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/UICompositeView.strings; sourceTree = ""; }; F0AF07061A24BA770086C9C1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/UIContactCell.strings; sourceTree = ""; }; @@ -2145,6 +1977,12 @@ F0BB8C34193624C800974404 /* libresolv.9.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.9.dylib; path = usr/lib/libresolv.9.dylib; sourceTree = SDKROOT; }; F0BB8C4A193631B300974404 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; F0FF66AA1ACAEEB0008A4486 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = ../../../../Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + F325590DD6CD7F6CC8F60C03 /* Pods_linphoneTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_linphoneTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F4BE1A2318FC69D799C34F0A /* Pods-msgNotificationService.distribution.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.distribution.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.distribution.xcconfig"; sourceTree = ""; }; + F6373F9231918DECD2B3004D /* Pods-linphoneTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphoneTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-linphoneTests/Pods-linphoneTests.release.xcconfig"; sourceTree = ""; }; + FD22CA9E3EFBFEFFF1B80BA2 /* Pods-liblinphoneTester.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTester.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTester/Pods-liblinphoneTester.distributionadhoc.xcconfig"; sourceTree = ""; }; + FE7D89A821FDC1BCA9BB9F8F /* Pods-linphone.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-linphone/Pods-linphone.distributionadhoc.xcconfig"; sourceTree = ""; }; + FEAFB5AD0E3AA409BBD1136E /* Pods-linphone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linphone.release.xcconfig"; path = "Pods/Target Support Files/Pods-linphone/Pods-linphone.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -2154,7 +1992,7 @@ files = ( EA88F3AC241BD05200E66528 /* UserNotificationsUI.framework in Frameworks */, EA88F3AB241BD05200E66528 /* UserNotifications.framework in Frameworks */, - 017AC1D70F142AE8EAC13BDB /* Pods_msgNotificationContent.framework in Frameworks */, + 369CCF81C921CD7C4E49A637 /* Pods_msgNotificationContent.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2164,6 +2002,7 @@ files = ( 61DD7E1F2372E88F001BDD01 /* CoreLocation.framework in Frameworks */, 6180D6FE21EE41A800AD9CB6 /* QuickLook.framework in Frameworks */, + 61AEBEA321906AFC00F35E7F /* BuildFile in Frameworks */, D37DC7181594AF3400B2A5EB /* MessageUI.framework in Frameworks */, 61F1997520C6B1D5006B069A /* AVKit.framework in Frameworks */, 249660951FD6A35F001D55AA /* Photos.framework in Frameworks */, @@ -2195,7 +2034,7 @@ F05BAA621A5D594E00411815 /* libz.dylib in Frameworks */, 344ABDF114850AE9007420B6 /* libc++.1.dylib in Frameworks */, 22D1B68112A3E0BE001AE361 /* libresolv.dylib in Frameworks */, - 9C0B30F54D61774AFD1473CE /* Pods_linphone.framework in Frameworks */, + A634ABAFCB39B6AAE4CA991D /* Pods_linphone.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2203,7 +2042,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E42B8736B8196388DDF2771A /* Pods_msgNotificationService.framework in Frameworks */, + 93566413F75DA69D2811A716 /* Pods_msgNotificationService.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2220,8 +2059,6 @@ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( - C65A5D41272184CE005BA038 /* SwiftUtil */, - C65A5D2D2721683B005BA038 /* Voip */, 22E0A81D111C44E100B04932 /* AboutView.h */, 22E0A81C111C44E100B04932 /* AboutView.m */, 636316D31A1DEBCB0009B839 /* AboutView.xib */, @@ -2232,6 +2069,23 @@ D350F20C15A43BB100149E54 /* AssistantView.m */, D38187E015FE348A00C3EDCA /* AssistantView.xib */, D3D5126A160B3A8E00946DF8 /* AssistantViewScreens.xib */, + 63F1DF491BCE983100EDED90 /* CallConferenceTableView.h */, + 63F1DF4A1BCE983200EDED90 /* CallConferenceTableView.m */, + D3F26BEE15986B71005F9CAB /* CallIncomingView.h */, + D3F26BEF15986B71005F9CAB /* CallIncomingView.m */, + D38187DC15FE347700C3EDCA /* CallIncomingView.xib */, + 6346100D1B61409800548952 /* CallOutgoingView.h */, + 6346100E1B61409800548952 /* CallOutgoingView.m */, + 634610101B6140A500548952 /* CallOutgoingView.xib */, + D31AAF5C159B3919002C6B02 /* CallPausedTableView.h */, + D31AAF5D159B3919002C6B02 /* CallPausedTableView.m */, + 6352A5721BE0D4B800594C1C /* CallSideMenuView.h */, + 6352A5731BE0D4B800594C1C /* CallSideMenuView.m */, + 6352A5741BE0D4B800594C1C /* CallSideMenuView.xib */, + D3F83EE91582021700336684 /* CallView.h */, + D3F83EEA1582021700336684 /* CallView.m */, + D381881C15FE3FCA00C3EDCA /* CallView.xib */, + 638F1A861C2167C2004B8E02 /* CallView~ipad.xib */, 8C9C5E0B1F83B2EF006987FA /* ChatConversationCreateCollectionViewController.h */, 8C9C5E0C1F83B2EF006987FA /* ChatConversationCreateCollectionViewController.m */, 6341807A1BBC103100F71761 /* ChatConversationCreateTableView.h */, @@ -2363,8 +2217,6 @@ 2214EB7012F84668002A5394 /* LinphoneUI */ = { isa = PBXGroup; children = ( - C6D1EC48274D212A0091881C /* UICamSwitch.h */, - C6D1EC49274D212B0091881C /* UICamSwitch.m */, C6A1BB3B26E882D000540D50 /* UIChatReplyBubbleView.h */, C6A1BB3C26E882D000540D50 /* UIChatReplyBubbleView.m */, C66B03BD26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib */, @@ -2382,6 +2234,14 @@ 6381DA7C1C1AD5EA00DF3BBD /* UIBouncingView.m */, 2214EB7812F846B1002A5394 /* UICallButton.h */, 2214EB7912F846B1002A5394 /* UICallButton.m */, + 63F1DF4C1BCE985F00EDED90 /* UICallConferenceCell.h */, + 63F1DF4D1BCE985F00EDED90 /* UICallConferenceCell.m */, + 63F1DF531BCE986A00EDED90 /* UICallConferenceCell.xib */, + 63BC49E01BA2CDFC004EC273 /* UICallPausedCell.h */, + 63BC49E11BA2CDFC004EC273 /* UICallPausedCell.m */, + 639E9C9F1C0DB7DF00019A75 /* UICallPausedCell.xib */, + 22AA8AFF13D83F6300B30535 /* UICamSwitch.h */, + 22AA8B0013D83F6300B30535 /* UICamSwitch.m */, 635173F71BA082A40095EB0A /* UIChatBubblePhotoCell.h */, 635173F81BA082A40095EB0A /* UIChatBubblePhotoCell.m */, 639E9CA21C0DB7E500019A75 /* UIChatBubblePhotoCell.xib */, @@ -2428,6 +2288,8 @@ 61CCC3D721933B380060EDEA /* UIDeviceCell.h */, 61CCC3DE21933B580060EDEA /* UIDeviceCell.m */, 61CCC3E021933B660060EDEA /* UIDeviceCell.xib */, + 2214EB8712F84EBB002A5394 /* UIHangUpButton.h */, + 2214EB8812F84EBB002A5394 /* UIHangUpButton.m */, D31C9C96158A1CDE00756B45 /* UIHistoryCell.h */, D31C9C97158A1CDE00756B45 /* UIHistoryCell.m */, 639CEB021A1DF4E4004DE38F /* UIHistoryCell.xib */, @@ -2449,6 +2311,8 @@ D306459D1611EC2900BB571E /* UILoadingImageView.m */, 2214EBF112F86360002A5394 /* UIMutedMicroButton.h */, 2214EBF212F86360002A5394 /* UIMutedMicroButton.m */, + D36FB2D31589EF7C0036F6F2 /* UIPauseButton.h */, + D36FB2D41589EF7C0036F6F2 /* UIPauseButton.m */, CF7602E42108759A00749F76 /* UIRecordingCell.h */, CF7602E52108759A00749F76 /* UIRecordingCell.m */, CF7602E62108759A00749F76 /* UIRecordingCell.xib */, @@ -2459,19 +2323,23 @@ 8C5D1B991D9BC48100DC6539 /* UIShopTableCell.h */, 8C5D1B9B1D9BC48100DC6539 /* UIShopTableCell.xib */, 24A345A71D95799900881A5C /* UIShopTableCell.h */, + 22968A5D12F875C600588287 /* UISpeakerButton.h */, + 22968A5E12F875C600588287 /* UISpeakerButton.m */, 630CF5551AF7CE1500539F7A /* UITextField+DoneButton.h */, 630CF5561AF7CE1500539F7A /* UITextField+DoneButton.m */, F03CA84118C72F1A0008889D /* UITextViewNoDefine.h */, F03CA84218C72F1A0008889D /* UITextViewNoDefine.m */, D32648421588F6FA00930C67 /* UIToggleButton.h */, D32648431588F6FB00930C67 /* UIToggleButton.m */, + 340751E5150F38FC00B89C47 /* UIVideoButton.h */, + 340751E6150F38FD00B89C47 /* UIVideoButton.m */, 24A345A51D95798A00881A5C /* UIShopTableCell.m */, 24A3459D1D95797700881A5C /* UIShopTableCell.xib */, ); path = LinphoneUI; sourceTree = ""; }; - 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + 29B97314FDCFA39411CA2CEA = { isa = PBXGroup; children = ( 8C23BCB71D82AAC3005F19BB /* linphone.entitlements */, @@ -2487,7 +2355,7 @@ 633E388219FFB0F400936D1C /* README.md */, 63AADBC31B6A0FF200AA16FD /* Resources */, D398D3031594B0FB00FD553C /* Settings */, - 5BCEB53D544D440FA098AEE3 /* Pods */, + 561D0FD932DE3595BE512375 /* Pods */, ); name = CustomTemplate; sourceTree = ""; @@ -2558,30 +2426,52 @@ 8C73477B1D9BA3A00022EE8C /* UserNotifications.framework */, 5E58962520DCE5700030868C /* UserNotificationsUI.framework */, 63CE583F1C85EBF400304800 /* VideoToolbox.framework */, - B464E44A606CB50A65A96FE2 /* Pods_linphone.framework */, - A164BAF39B3A5B9F905917A7 /* Pods_msgNotificationContent.framework */, - 72B39681098B0AF5B59B3A61 /* Pods_msgNotificationService.framework */, + 6E1BC45342F5201DABD7FE55 /* Pods_latestCallsWidget.framework */, + 8B488C393394746F9D630789 /* Pods_latestChatroomsWidget.framework */, + 9CBD6E980619195CB7EE32AC /* Pods_liblinphoneTester.framework */, + D252FEC7DD06DD5695A320A1 /* Pods_liblinphoneTesterTests.framework */, + 65CEDD144CABFAA70A29AF27 /* Pods_linphone.framework */, + F325590DD6CD7F6CC8F60C03 /* Pods_linphoneTests.framework */, + 7513CBF7F2BA0A9F99977C2B /* Pods_richNotifications.framework */, + 82E9DEDA2A78C6DBBD1A54DB /* Pods_msgNotificationContent.framework */, + 6F30EA7BEA39DA427CE0754E /* Pods_msgNotificationService.framework */, ); name = Frameworks; sourceTree = ""; }; - 5BCEB53D544D440FA098AEE3 /* Pods */ = { + 561D0FD932DE3595BE512375 /* Pods */ = { isa = PBXGroup; children = ( - 53432234870660E9876CBCA8 /* Pods-linphone.debug.xcconfig */, - 0DF941C97B75E7BA39A90600 /* Pods-linphone.release.xcconfig */, - 79B41078A602EFB886981917 /* Pods-linphone.distribution.xcconfig */, - 22D3BF4C45858F6B07F4D2A4 /* Pods-linphone.distributionadhoc.xcconfig */, - 1060E68152C51FCE5ACBF779 /* Pods-msgNotificationContent.debug.xcconfig */, - 02DBDD5A09F46796AEC2485B /* Pods-msgNotificationContent.release.xcconfig */, - 507103607396F28FF4427108 /* Pods-msgNotificationContent.distribution.xcconfig */, - 6150F32455334A0A7B3D46C8 /* Pods-msgNotificationContent.distributionadhoc.xcconfig */, - C589627B9D9D2A4F9C816051 /* Pods-msgNotificationService.debug.xcconfig */, - 063D57B2E4769739DC5DA5C0 /* Pods-msgNotificationService.release.xcconfig */, - B9F41097CE0124A05554DB9C /* Pods-msgNotificationService.distribution.xcconfig */, - 3411568BE5527EB500F75EBB /* Pods-msgNotificationService.distributionadhoc.xcconfig */, + 68D9EC27FCECD5DE2E19CD3C /* Pods-liblinphoneTester.debug.xcconfig */, + 38A3AE51B9E09ABF29222E5F /* Pods-liblinphoneTester.release.xcconfig */, + 24585CBE78DA4F005C7F9D71 /* Pods-liblinphoneTester.distribution.xcconfig */, + FD22CA9E3EFBFEFFF1B80BA2 /* Pods-liblinphoneTester.distributionadhoc.xcconfig */, + 7D8CCFE176C634813E3A2593 /* Pods-liblinphoneTesterTests.debug.xcconfig */, + BE06BDE664323B2A53469696 /* Pods-liblinphoneTesterTests.release.xcconfig */, + 248C326F4AD75E654C1CB37A /* Pods-liblinphoneTesterTests.distribution.xcconfig */, + 046DEFE77AD0675DA9932C4C /* Pods-liblinphoneTesterTests.distributionadhoc.xcconfig */, + 799BA1104845EB01ACE764D8 /* Pods-linphone.debug.xcconfig */, + FEAFB5AD0E3AA409BBD1136E /* Pods-linphone.release.xcconfig */, + 38DF35D11A7C0F45E990C83A /* Pods-linphone.distribution.xcconfig */, + FE7D89A821FDC1BCA9BB9F8F /* Pods-linphone.distributionadhoc.xcconfig */, + ABB887316C42EE876A3051A9 /* Pods-linphoneTests.debug.xcconfig */, + F6373F9231918DECD2B3004D /* Pods-linphoneTests.release.xcconfig */, + 85FB19B6A8124D942C8471F1 /* Pods-linphoneTests.distribution.xcconfig */, + CE119C214B6B8B2740622BBD /* Pods-linphoneTests.distributionadhoc.xcconfig */, + 791017662FE117B9B12E8938 /* Pods-messagesNotification.debug.xcconfig */, + EE807919DDB0B4B46AD1D439 /* Pods-messagesNotification.release.xcconfig */, + 13B1BD646346F33BF57412F2 /* Pods-messagesNotification.distribution.xcconfig */, + CC6F924A8B1B1698914A3BB2 /* Pods-messagesNotification.distributionadhoc.xcconfig */, + 8B4C43A28E90775F6FCA2CEE /* Pods-msgNotificationContent.debug.xcconfig */, + 34027665305514025971F85C /* Pods-msgNotificationContent.release.xcconfig */, + E40C9A7D22675584396C0A3D /* Pods-msgNotificationContent.distribution.xcconfig */, + BAD0A9494E833034EB559687 /* Pods-msgNotificationContent.distributionadhoc.xcconfig */, + ADCA571A7CF61077747BFE53 /* Pods-msgNotificationService.debug.xcconfig */, + 904C1EC75CB9E03374AAA802 /* Pods-msgNotificationService.release.xcconfig */, + F4BE1A2318FC69D799C34F0A /* Pods-msgNotificationService.distribution.xcconfig */, + 8FD0D10102F0A8922703B8A4 /* Pods-msgNotificationService.distributionadhoc.xcconfig */, ); - path = Pods; + name = Pods; sourceTree = ""; }; 61AE364C20C00B370089D9D3 /* linphoneExtension */ = { @@ -2611,67 +2501,6 @@ 633FEBE11D3CD5570014B822 /* images */ = { isa = PBXGroup; children = ( - C6EA2F4727514D08008E60F8 /* voip_call_forward.png */, - C6277DA7274BF1CD00406FB9 /* voip_radio_off.png */, - C6277DA6274BF1CD00406FB9 /* voip_radio_on.png */, - C6710F7D2722B1F500ED888F /* voip_audio_routes.png */, - C6710F6D2722B1F000ED888F /* voip_bluetooth.png */, - C6710F802722B1F600ED888F /* voip_call_add.png */, - C6710F732722B1F200ED888F /* voip_call_chat.png */, - C6710F972722B1FE00ED888F /* voip_call_header_active.png */, - C6710F912722B1FC00ED888F /* voip_call_header_incoming.png */, - C6710F9C2722B1FF00ED888F /* voip_call_header_outgoing.png */, - C6710F842722B1F800ED888F /* voip_call_header_paused.png */, - C6710F932722B1FC00ED888F /* voip_call_list_menu.png */, - C6710F6E2722B1F000ED888F /* voip_call_more.png */, - C6710F6A2722B1EF00ED888F /* voip_call_numpad.png */, - C6710F942722B1FD00ED888F /* voip_call_participants.png */, - C6710F992722B1FE00ED888F /* voip_call_record.png */, - C6710F702722B1F100ED888F /* voip_call_stats.png */, - C6710F822722B1F700ED888F /* voip_call.png */, - C6710F792722B1F400ED888F /* voip_calls_list.png */, - C6710F8C2722B1FA00ED888F /* voip_camera_off.png */, - C6710F9B2722B1FF00ED888F /* voip_camera_on.png */, - C6710F8A2722B1F900ED888F /* voip_cancel.png */, - C6710F832722B1F700ED888F /* voip_change_camera.png */, - C6710F772722B1F300ED888F /* voip_chat_rooms_list.png */, - C6710F712722B1F100ED888F /* voip_conference_active_speaker.png */, - C6710F7B2722B1F500ED888F /* voip_conference_mosaic.png */, - C6710F762722B1F300ED888F /* voip_conference_new.png */, - C6710F9A2722B1FE00ED888F /* voip_conference_paused_big.png */, - C6710F9D2722B20000ED888F /* voip_conference_play_big.png */, - C6710F682722B1EF00ED888F /* voip_copy.png */, - C6710F7C2722B1F500ED888F /* voip_delete.png */, - C6710F982722B1FE00ED888F /* voip_dropdown.png */, - C6710F862722B1F800ED888F /* voip_earpiece.png */, - C6710F722722B1F200ED888F /* voip_edit.png */, - C6710F852722B1F800ED888F /* voip_export.png */, - C6710F752722B1F300ED888F /* voip_hangup.png */, - C6710F9E2722B20000ED888F /* voip_info.png */, - C6710F6C2722B1F000ED888F /* voip_mandatory.png */, - C6710F8D2722B1FA00ED888F /* voip_menu_more.png */, - C6710F692722B1EF00ED888F /* voip_merge_calls.png */, - C6710F882722B1F900ED888F /* voip_micro_off.png */, - C6710F782722B1F300ED888F /* voip_micro_on.png */, - C6710F6F2722B1F100ED888F /* voip_multiple_contacts_avatar.png */, - C6710F672722B1EF00ED888F /* voip_numpad_0.png */, - C6710F662722B1EF00ED888F /* voip_numpad_1.png */, - C6710F892722B1F900ED888F /* voip_numpad_2.png */, - C6710F7F2722B1F600ED888F /* voip_numpad_3.png */, - C6710F8E2722B1FB00ED888F /* voip_numpad_4.png */, - C6710F742722B1F200ED888F /* voip_numpad_5.png */, - C6710F7E2722B1F600ED888F /* voip_numpad_6.png */, - C6710F8F2722B1FB00ED888F /* voip_numpad_7.png */, - C6710F962722B1FD00ED888F /* voip_numpad_8.png */, - C6710F812722B1F700ED888F /* voip_numpad_9.png */, - C6710F872722B1F800ED888F /* voip_numpad_hash.png */, - C6710F8B2722B1FA00ED888F /* voip_numpad_star.png */, - C6710F7A2722B1F400ED888F /* voip_pause.png */, - C6710F922722B1FC00ED888F /* voip_remote_recording.png */, - C6710F6B2722B1F000ED888F /* voip_single_contact_avatar.png */, - C6710F952722B1FD00ED888F /* voip_speaker_off.png */, - C6710F902722B1FB00ED888F /* voip_speaker_on.png */, - C6710F642722B13000ED888F /* voip_spinner.png */, C66B040D26F095CE009B5EDC /* cancel_forward.png */, C66B040926EFDA54009B5EDC /* reply_cancel.png */, C6A1BB4426E890BD00540D50 /* file_voice_default.png */, @@ -3209,7 +3038,6 @@ 63AADBC31B6A0FF200AA16FD /* Resources */ = { isa = PBXGroup; children = ( - C6710F5D2722AE8900ED888F /* fonts */, 63AADBE31B6A0FF200AA16FD /* assistant_external_sip.rc */, 63AADBE41B6A0FF200AA16FD /* assistant_linphone_create.rc */, 63AADBE51B6A0FF200AA16FD /* assistant_linphone_existing.rc */, @@ -3262,205 +3090,6 @@ path = ringtones; sourceTree = ""; }; - C658614A273E59A300A0DBFC /* CompositeViewControllers */ = { - isa = PBXGroup; - children = ( - C65A5D2F27216B86005BA038 /* ActiveCallOrConferenceView.swift */, - C6824FB927219D890043D4FC /* IncomingCallView.swift */, - C6710FE62723234400ED888F /* OutgoingCallView.swift */, - ); - path = CompositeViewControllers; - sourceTree = ""; - }; - C65A5D2D2721683B005BA038 /* Voip */ = { - isa = PBXGroup; - children = ( - C6F2D500273B0EFC0071BA52 /* VoipDialog.swift */, - C67C97B7274FD76B0074A0D8 /* AudioRouteUtils.swift */, - C6710F5A2722A9FB00ED888F /* Theme */, - C6710F4D2722900A00ED888F /* Widgets */, - C65A5D3127216C3E005BA038 /* Models */, - C65A5D2E27216B4C005BA038 /* Views */, - ); - path = Voip; - sourceTree = ""; - }; - C65A5D2E27216B4C005BA038 /* Views */ = { - isa = PBXGroup; - children = ( - C6F2D4F8273A4CD60071BA52 /* SharedLayoutConstants.swift */, - C6710FDF2722D47E00ED888F /* Fragments */, - C658614A273E59A300A0DBFC /* CompositeViewControllers */, - ); - path = Views; - sourceTree = ""; - }; - C65A5D3127216C3E005BA038 /* Models */ = { - isa = PBXGroup; - children = ( - C65A5D3E27216E3A005BA038 /* CallData.swift */, - C6C98CD627453F9600059B55 /* ConferenceParticipantData.swift */, - C6C98CDA274541E400059B55 /* ConferenceParticipantDeviceData.swift */, - C60B66672721AFFA0026AC7D /* CallStatisticsData.swift */, - C60D265527299C94006238BB /* ControlsViewModel.swift */, - C6F2D4EE27392D960071BA52 /* CallsViewModel.swift */, - C6C98CD427453ED700059B55 /* ConferenceViewModel.swift */, - ); - path = Models; - sourceTree = ""; - }; - C65A5D3427216CAB005BA038 /* ViewModel */ = { - isa = PBXGroup; - children = ( - C65A5D3727216CC0005BA038 /* MutableLiveData.swift */, - ); - path = ViewModel; - sourceTree = ""; - }; - C65A5D41272184CE005BA038 /* SwiftUtil */ = { - isa = PBXGroup; - children = ( - C683B211272276C100D4E15C /* Extensions */, - C65A5D3427216CAB005BA038 /* ViewModel */, - ); - path = SwiftUtil; - sourceTree = ""; - }; - C6710F4D2722900A00ED888F /* Widgets */ = { - isa = PBXGroup; - children = ( - C6710F582722A9B800ED888F /* StyledLabel.swift */, - C6710FD82722BD0100ED888F /* UICallTimer.swift */, - C6710F4E2722903200ED888F /* RotatingSpinner.swift */, - C6710FE02722F0E400ED888F /* Avatar.swift */, - C6710FE82723DD7D00ED888F /* CallControlButton.swift */, - C658614B273E5B5E00A0DBFC /* VoipExtraButton.swift */, - C6D09F3C273EE467003C2173 /* BouncingCounter.swift */, - C6F2D502273BAC030071BA52 /* ButtonWithStateBackgrounds.swift */, - ); - path = Widgets; - sourceTree = ""; - }; - C6710F5A2722A9FB00ED888F /* Theme */ = { - isa = PBXGroup; - children = ( - C6710F5427229D5900ED888F /* LightDarkColor.swift */, - C6710F5627229DEE00ED888F /* TextStyle.swift */, - C683B20D2722702300D4E15C /* VoipTheme.swift */, - C6710F52272297C400ED888F /* VoipTexts.swift */, - C6710FEA2726874D00ED888F /* ButtonTheme.swift */, - ); - path = Theme; - sourceTree = ""; - }; - C6710F5D2722AE8900ED888F /* fonts */ = { - isa = PBXGroup; - children = ( - C6710F5F2722AECB00ED888F /* Roboto-Bold.ttf */, - C6710F5E2722AECB00ED888F /* Roboto-Italic.ttf */, - C6710F602722AECB00ED888F /* Roboto-Regular.ttf */, - ); - path = fonts; - sourceTree = ""; - }; - C6710FDF2722D47E00ED888F /* Fragments */ = { - isa = PBXGroup; - children = ( - C67C97AF274FB3620074A0D8 /* ParticipantsList */, - C67C97AE274FB3370074A0D8 /* CallsList */, - C67C97AC274FB2DA0074A0D8 /* ActiveCall */, - C6D52B4727481D3F00904660 /* Conference */, - C6F2D4FE273AF01A0071BA52 /* ControlsView.swift */, - C67C97B3274FC5EE0074A0D8 /* AudioRoutesView.swift */, - C6F2D4F62739861F0071BA52 /* RemotelyRecording.swift */, - C6278496273C21E1002FAA29 /* LocalVideoView.swift */, - C6586148273E595700A0DBFC /* VoipExtraButtonsView.swift */, - C6F2D4FC273A85A90071BA52 /* PausedCallOrConferenceView.swift */, - C6710FDD2722D44A00ED888F /* IncomingOuntgoingCommonView.swift */, - C6C65E8A2727274A00E48FC6 /* NumpadView.swift */, - C6D09F3E274273FB003C2173 /* CallStatsView.swift */, - C6C98CCD27438A3F00059B55 /* DismissableView.swift */, - ); - path = Fragments; - sourceTree = ""; - }; - C6710FE227230B2300ED888F /* IOS */ = { - isa = PBXGroup; - children = ( - C6F2D504273BB3BB0071BA52 /* UIApplication+Extension.swift */, - C6710F5B2722AAED00ED888F /* UIDeviceExtensions.swift */, - C65A5D44272196AE005BA038 /* OptionalExtensions.swift */, - C683B212272276CF00D4E15C /* UIColorExtensions.swift */, - C6710F502722932600ED888F /* UIImageViewExtensions.swift */, - C60D265B272AA0BD006238BB /* UIImageExtensions.swift */, - C6710FDB2722C3BB00ED888F /* UIVIewExtensions.swift */, - C6C65E88272723DC00E48FC6 /* UIVIewControllerExtensions.swift */, - ); - path = IOS; - sourceTree = ""; - }; - C6710FE327230B2D00ED888F /* LinphoneCore */ = { - isa = PBXGroup; - children = ( - C6710FE427230B5800ED888F /* AddressExtensions.swift */, - C60D265727299F6F006238BB /* CoreExtensions.swift */, - C6F2D4F0273935860071BA52 /* CallExtensions.swift */, - C6C98CDC274547C500059B55 /* ParticipantExtensions.swift */, - C6C98CDE2745590400059B55 /* ConferenceExtensions.swift */, - C6D09F4027428626003C2173 /* IceState.swift */, - C6D09F42274288D4003C2173 /* PayloadType.swift */, - ); - path = LinphoneCore; - sourceTree = ""; - }; - C67C97AC274FB2DA0074A0D8 /* ActiveCall */ = { - isa = PBXGroup; - children = ( - C6F2D4F22739475C0071BA52 /* ActiveCallView.swift */, - ); - path = ActiveCall; - sourceTree = ""; - }; - C67C97AE274FB3370074A0D8 /* CallsList */ = { - isa = PBXGroup; - children = ( - C6D09F4A27438706003C2173 /* CallsListView.swift */, - C6C98CCF27439A7F00059B55 /* VoipCallCell.swift */, - C6C98CD12743FD0B00059B55 /* VoipCallContextMenu.swift */, - ); - path = CallsList; - sourceTree = ""; - }; - C67C97AF274FB3620074A0D8 /* ParticipantsList */ = { - isa = PBXGroup; - children = ( - C6B04D62274B95D400F70559 /* VoipParticipantCell.swift */, - C6B04D60274B954500F70559 /* ParticipantsListView.swift */, - ); - path = ParticipantsList; - sourceTree = ""; - }; - C683B211272276C100D4E15C /* Extensions */ = { - isa = PBXGroup; - children = ( - C6710FE327230B2D00ED888F /* LinphoneCore */, - C6710FE227230B2300ED888F /* IOS */, - ); - path = Extensions; - sourceTree = ""; - }; - C6D52B4727481D3F00904660 /* Conference */ = { - isa = PBXGroup; - children = ( - C6C98CE0274568F700059B55 /* VoipConferenceGridView.swift */, - C6D52B44274648E500904660 /* VoipGridParticipantCell.swift */, - C6B04D66274BD61200F70559 /* VoipConferenceActiveSpeakerView.swift */, - C6B04D68274BD6A100F70559 /* VoipActiveSpeakerParticipantCell.swift */, - C67C97B0274FB4C10074A0D8 /* VoipConferenceDisplayModeSelectionView.swift */, - ); - path = Conference; - sourceTree = ""; - }; D326483415887D4400930C67 /* Utils */ = { isa = PBXGroup; children = ( @@ -3487,6 +3116,8 @@ 63D11C541C3D503A00E8FCEE /* Log.h */, 63423C081C4501D000D9A050 /* Contact.h */, 63423C091C4501D000D9A050 /* Contact.m */, + 8C1B67081E6718BC001EA2FE /* AudioHelper.h */, + 8C1B67051E671826001EA2FE /* AudioHelper.m */, C6B4444726AADA530076C517 /* SwiftUtil.swift */, ); name = Utils; @@ -3638,15 +3269,15 @@ isa = PBXNativeTarget; buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "linphone" */; buildPhases = ( - 068EB8CED53992A5D7A733DF /* [CP] Check Pods Manifest.lock */, + 20EEEF6D60A7B77C2EFF85DB /* [CP] Check Pods Manifest.lock */, 1D60588D0D05DD3D006BFB54 /* Resources */, 63DCC71D1A07B08E00916627 /* Run Script */, 1D60588E0D05DD3D006BFB54 /* Sources */, 1D60588F0D05DD3D006BFB54 /* Frameworks */, 8CDC89061EAF89A8006B5652 /* Embed Frameworks */, 5EF0C35020C806A5005081B0 /* Embed App Extensions */, + 4D22DCAAC0231865D78AC1E6 /* [CP] Embed Pods Frameworks */, 614D0A1821E77F5300C43EDF /* ShellScript */, - D7A9CDC06B7BB5D324EA10C9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -3681,7 +3312,7 @@ isa = PBXNativeTarget; buildConfigurationList = EA5F25E1232BD3E300475F2E /* Build configuration list for PBXNativeTarget "msgNotificationService" */; buildPhases = ( - 1E9EBAB02A694F2487E6099B /* [CP] Check Pods Manifest.lock */, + CD5CF0B3FE8B6052CD8219CE /* [CP] Check Pods Manifest.lock */, EA5F25D5232BD3E200475F2E /* Sources */, 203E6292C3E84CD13778F720 /* Frameworks */, EA88A406242A6224007FEC61 /* Resources */, @@ -3700,7 +3331,7 @@ isa = PBXNativeTarget; buildConfigurationList = EA8CB834239F96CA00C330CC /* Build configuration list for PBXNativeTarget "msgNotificationContent" */; buildPhases = ( - 2E68C0F1B7E1F6C3000F700C /* [CP] Check Pods Manifest.lock */, + B0A561F0290F0342EACE9005 /* [CP] Check Pods Manifest.lock */, EA8CB823239F96CA00C330CC /* Sources */, 143EFEE2501CB14E6BB244EF /* Frameworks */, EA88F3AE241BD1ED00E66528 /* Resources */, @@ -3802,7 +3433,7 @@ fr, hu, ); - mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + mainGroup = 29B97314FDCFA39411CA2CEA; productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */; projectDirPath = ""; projectRoot = ""; @@ -3834,7 +3465,6 @@ 633FEE2B1D3CD5590014B822 /* color_C.png in Resources */, 633FEE871D3CD5590014B822 /* led_inprogress@2x.png in Resources */, 633FEEC61D3CD55A0014B822 /* numpad_5_over@2x.png in Resources */, - C6710FC02722B20000ED888F /* voip_numpad_hash.png in Resources */, 633FEF021D3CD55A0014B822 /* options_disabled.png in Resources */, 633FEDC81D3CD5590014B822 /* call_missed.png in Resources */, 8CB2B8FA1F86229E0015CEE2 /* next_disabled.png in Resources */, @@ -3854,7 +3484,6 @@ 638F1A621C2021B2004B8E02 /* DialerView~ipad.xib in Resources */, 615A2817217F280C0060F920 /* chat_list_indicator.png in Resources */, 633FEEFF1D3CD55A0014B822 /* options_add_call_disabled@2x.png in Resources */, - C6710FB92722B20000ED888F /* voip_call_add.png in Resources */, 633FEF091D3CD55A0014B822 /* options_start_conference_disabled@2x.png in Resources */, C622E3F326A81290004F5434 /* vr_pause.png in Resources */, 633FEE051D3CD5590014B822 /* cancel_edit_disabled@2x.png in Resources */, @@ -3866,28 +3495,23 @@ 633FEE0B1D3CD5590014B822 /* chat_attachment_default@2x.png in Resources */, 633FEED41D3CD55A0014B822 /* numpad_7_default@2x.png in Resources */, 633FEEE01D3CD55A0014B822 /* numpad_8_over~ipad@2x.png in Resources */, - C6710FA42722B20000ED888F /* voip_single_contact_avatar.png in Resources */, 633FEDDC1D3CD5590014B822 /* call_start_body_disabled~ipad.png in Resources */, - 63E802DB1C625AEF000D5509 /* (null) in Resources */, + 63E802DB1C625AEF000D5509 /* BuildFile in Resources */, 633FEE2E1D3CD5590014B822 /* color_F.png in Resources */, - C6710FA72722B20000ED888F /* voip_call_more.png in Resources */, 633FEDC51D3CD5590014B822 /* call_hangup_disabled@2x.png in Resources */, 633FEEDF1D3CD55A0014B822 /* numpad_8_over~ipad.png in Resources */, - C6710FB62722B20000ED888F /* voip_audio_routes.png in Resources */, - C6710FB02722B20000ED888F /* voip_chat_rooms_list.png in Resources */, 8CD99A372090A824008A7CDA /* splashscreen@2x.png in Resources */, 24BFAAA9209B0630004F47A7 /* linphone_logo@2x.png in Resources */, 633FEE071D3CD5590014B822 /* chat_add_default@2x.png in Resources */, - C6710FBB2722B20000ED888F /* voip_call.png in Resources */, 633FEF551D3CD55A0014B822 /* waiting_time@2x.png in Resources */, 633FEEAC1D3CD55A0014B822 /* numpad_2_default@2x.png in Resources */, - C6710FD22722B20000ED888F /* voip_call_record.png in Resources */, 633FEE541D3CD5590014B822 /* dialer_back_default.png in Resources */, 633FEF0B1D3CD55A0014B822 /* options_transfer_call_default@2x.png in Resources */, 633FEDE81D3CD5590014B822 /* call_status_missed~ipad.png in Resources */, 63AADBFF1B6A0FF200AA16FD /* assistant_external_sip.rc in Resources */, 61CCC3E121933B660060EDEA /* UIDeviceCell.xib in Resources */, 633FEE9E1D3CD55A0014B822 /* numpad_0_over@2x.png in Resources */, + 634610121B6140A500548952 /* CallOutgoingView.xib in Resources */, 8CE24F581F8268850077AC0A /* conference_delete@2x.png in Resources */, 633FEDC21D3CD5590014B822 /* call_hangup_default.png in Resources */, 633FEEB41D3CD55A0014B822 /* numpad_3_default@2x.png in Resources */, @@ -3909,10 +3533,8 @@ 633FEE401D3CD5590014B822 /* contacts_all_selected.png in Resources */, 633FEE0C1D3CD5590014B822 /* chat_attachment_disabled.png in Resources */, C622E3EF26A81290004F5434 /* vr_stop.png in Resources */, - C6710FD12722B20000ED888F /* voip_dropdown.png in Resources */, 633FEF001D3CD55A0014B822 /* options_default.png in Resources */, CF15F21F20E4F9A3008B1DE6 /* UIImageViewDeletable.xib in Resources */, - C6710FBF2722B20000ED888F /* voip_earpiece.png in Resources */, 633FEE951D3CD55A0014B822 /* micro_default@2x.png in Resources */, 633FEE6A1D3CD5590014B822 /* footer_dialer_default.png in Resources */, 633FEEC91D3CD55A0014B822 /* numpad_5~ipad.png in Resources */, @@ -3936,20 +3558,18 @@ 633FEE7A1D3CD5590014B822 /* history_missed_default.png in Resources */, 633FEF121D3CD55A0014B822 /* pause_big_over_selected.png in Resources */, 633FED9D1D3CD5590014B822 /* add_field_default@2x.png in Resources */, - C6710FA32722B20000ED888F /* voip_call_numpad.png in Resources */, C622E3F426A81290004F5434 /* vr_play.png in Resources */, 639E9CB01C0DB83000019A75 /* SideMenuView.xib in Resources */, 633FEDBB1D3CD5590014B822 /* call_audio_start_default@2x.png in Resources */, 633FEF1A1D3CD55A0014B822 /* presence_away.png in Resources */, 639E9CB51C0DB88200019A75 /* PhoneMainView.xib in Resources */, - C6710F652722B13000ED888F /* voip_spinner.png in Resources */, 633FEDB61D3CD5590014B822 /* call_alt_start_default.png in Resources */, + 6352A5761BE0D4B800594C1C /* CallSideMenuView.xib in Resources */, 633FEF0D1D3CD55A0014B822 /* options_transfer_call_disabled@2x.png in Resources */, 633FEDEF1D3CD5590014B822 /* call_transfer_default@2x.png in Resources */, 633FEF391D3CD55A0014B822 /* routes_selected@2x.png in Resources */, 633FEE491D3CD5590014B822 /* delete_default@2x.png in Resources */, 633FEF291D3CD55A0014B822 /* route_earpiece_default@2x.png in Resources */, - C6710FAF2722B20000ED888F /* voip_conference_new.png in Resources */, 633FEE271D3CD5590014B822 /* checkbox_checked@2x.png in Resources */, 61586B85217A17070038AC45 /* menu_assistant.png in Resources */, 633FEDCC1D3CD5590014B822 /* call_quality_indicator_0.png in Resources */, @@ -3974,7 +3594,6 @@ 633FEEEF1D3CD55A0014B822 /* numpad_hash_over~ipad.png in Resources */, 633FEEE21D3CD55A0014B822 /* numpad_8~ipad@2x.png in Resources */, 633FEEED1D3CD55A0014B822 /* numpad_hash_over.png in Resources */, - C6710FC42722B20000ED888F /* voip_numpad_star.png in Resources */, 633FEE1F1D3CD5590014B822 /* chat_start_body_disabled@2x.png in Resources */, 633FEEF81D3CD55A0014B822 /* numpad_star_over~ipad.png in Resources */, C6A1BB3826E8815400540D50 /* menu_reply_default.png in Resources */, @@ -3982,7 +3601,6 @@ 639CEAFD1A1DF4D9004DE38F /* StatusBarView.xib in Resources */, 633FEDE91D3CD5590014B822 /* call_status_missed~ipad@2x.png in Resources */, 8CE24F4C1F8234A30077AC0A /* next_default@2x.png in Resources */, - C6710FB12722B20000ED888F /* voip_micro_on.png in Resources */, 244523B11E8266CC0037A187 /* chat_read.png in Resources */, 61AEBEC62191E47500F35E7F /* chevron_list_close.png in Resources */, 617B4A60260A2B7800A87337 /* RecordingsListView.xib in Resources */, @@ -3991,19 +3609,15 @@ 8CF25D951F9F336100BEA0C1 /* check_unselected@2x.png in Resources */, F088488A19FF8C41007FFCF3 /* UIContactCell.xib in Resources */, 633FEE381D3CD5590014B822 /* contact_add_default.png in Resources */, - C6710FC22722B20000ED888F /* voip_numpad_2.png in Resources */, 633FEE6F1D3CD5590014B822 /* footer_history_default@2x.png in Resources */, - C6710FD52722B20000ED888F /* voip_call_header_outgoing.png in Resources */, 633FEF201D3CD55A0014B822 /* presence_unregistered.png in Resources */, 61586B8D217A173F0038AC45 /* menu_options.png in Resources */, 61AEBEC82191E48400F35E7F /* chevron_list_close@2x.png in Resources */, 633FEF341D3CD55A0014B822 /* routes_default.png in Resources */, - C6710FC82722B20000ED888F /* voip_numpad_7.png in Resources */, 633FEE061D3CD5590014B822 /* chat_add_default.png in Resources */, 633FEDF21D3CD5590014B822 /* call_video_start_default.png in Resources */, 633FEF491D3CD55A0014B822 /* speaker_selected@2x.png in Resources */, 633FEF541D3CD55A0014B822 /* waiting_time.png in Resources */, - C6277DA8274BF1CE00406FB9 /* voip_radio_on.png in Resources */, 633FEE861D3CD5590014B822 /* led_inprogress.png in Resources */, 633FEDFC1D3CD5590014B822 /* camera_switch_default.png in Resources */, 24BFAA9F209B0630004F47A7 /* linphone_user.png in Resources */, @@ -4020,13 +3634,11 @@ 633FEE281D3CD5590014B822 /* checkbox_unchecked.png in Resources */, 633FEE9D1D3CD55A0014B822 /* numpad_0_over.png in Resources */, 633FEEC21D3CD55A0014B822 /* numpad_4~ipad@2x.png in Resources */, - C6710FCA2722B20000ED888F /* voip_call_header_incoming.png in Resources */, 633FEDFE1D3CD5590014B822 /* camera_switch_disabled.png in Resources */, 633FEE7F1D3CD5590014B822 /* history_missed_selected@2x.png in Resources */, 633FEDC01D3CD5590014B822 /* call_back_disabled.png in Resources */, 633FEED31D3CD55A0014B822 /* numpad_7_default.png in Resources */, 63130FB21C1ED06900371918 /* SideMenuView~ipad.xib in Resources */, - C6710FB82722B20000ED888F /* voip_numpad_3.png in Resources */, 633FEEE71D3CD55A0014B822 /* numpad_9_over~ipad.png in Resources */, 633FEEEA1D3CD55A0014B822 /* numpad_9~ipad@2x.png in Resources */, 633FEEC31D3CD55A0014B822 /* numpad_5_default.png in Resources */, @@ -4035,8 +3647,6 @@ 633FEEC01D3CD55A0014B822 /* numpad_4_over~ipad@2x.png in Resources */, 61586B8B217A17320038AC45 /* menu_link_account@2x.png in Resources */, 63CDC4661C3BDE370085F529 /* shortring.caf in Resources */, - C6710FB42722B20000ED888F /* voip_conference_mosaic.png in Resources */, - C6710FC92722B20000ED888F /* voip_speaker_on.png in Resources */, C6A1BB4126E889AD00540D50 /* forward_message_default.png in Resources */, 633FEDD51D3CD5590014B822 /* call_quality_indicator_4@2x.png in Resources */, 633FEDE71D3CD5590014B822 /* call_status_missed@2x.png in Resources */, @@ -4049,10 +3659,8 @@ 633FEEBB1D3CD55A0014B822 /* numpad_4_default.png in Resources */, 633FEF2B1D3CD55A0014B822 /* route_earpiece_disabled@2x.png in Resources */, 639E9CA31C0DB7EA00019A75 /* UIChatBubbleTextCell.xib in Resources */, - C6710FA62722B20000ED888F /* voip_bluetooth.png in Resources */, 633FEDD21D3CD5590014B822 /* call_quality_indicator_3.png in Resources */, 633FEDAF1D3CD5590014B822 /* call_add_default@2x.png in Resources */, - C6710FA82722B20000ED888F /* voip_multiple_contacts_avatar.png in Resources */, 633FEE931D3CD55A0014B822 /* menu@2x.png in Resources */, 633FEF3D1D3CD55A0014B822 /* security_ok@2x.png in Resources */, 633FEF161D3CD55A0014B822 /* pause_small_disabled.png in Resources */, @@ -4065,8 +3673,8 @@ 615A280F217F1FD50060F920 /* chat_add_group.png in Resources */, 633FEEC41D3CD55A0014B822 /* numpad_5_default@2x.png in Resources */, 633FEDAC1D3CD5590014B822 /* backspace_over.png in Resources */, + 639E9C9D1C0DB7DF00019A75 /* UICallPausedCell.xib in Resources */, 633FEE1B1D3CD5590014B822 /* chat_start_body_default@2x.png in Resources */, - C6710FB22722B20000ED888F /* voip_calls_list.png in Resources */, 633FEE021D3CD5590014B822 /* cancel_edit_default.png in Resources */, 633FEEE31D3CD55A0014B822 /* numpad_9_default.png in Resources */, 633FEE651D3CD5590014B822 /* footer_chat_disabled@2x.png in Resources */, @@ -4098,7 +3706,6 @@ 633FEDD11D3CD5590014B822 /* call_quality_indicator_2@2x.png in Resources */, 633FEDBC1D3CD5590014B822 /* call_audio_start_disabled.png in Resources */, 24BFAA9E209B0630004F47A7 /* dialer_background.png in Resources */, - C6710FD72722B20000ED888F /* voip_info.png in Resources */, 633FEE481D3CD5590014B822 /* delete_default.png in Resources */, 633FEEB01D3CD55A0014B822 /* numpad_2_over~ipad@2x.png in Resources */, 633FEE2A1D3CD5590014B822 /* color_A.png in Resources */, @@ -4106,8 +3713,6 @@ 63E27A321C4FECD000D332AE /* LaunchScreen.xib in Resources */, 633FEED11D3CD55A0014B822 /* numpad_6~ipad.png in Resources */, CF7602E82108759A00749F76 /* UIRecordingCell.xib in Resources */, - C6710FC62722B20000ED888F /* voip_menu_more.png in Resources */, - C6710FC12722B20000ED888F /* voip_micro_off.png in Resources */, C6B4444626AAD0980076C517 /* file_pdf_default.png in Resources */, 633FEED21D3CD55A0014B822 /* numpad_6~ipad@2x.png in Resources */, 633FEDCD1D3CD5590014B822 /* call_quality_indicator_0@2x.png in Resources */, @@ -4138,14 +3743,13 @@ D34F6F9E1594D3FB0095705B /* InAppSettings.bundle in Resources */, 633FEE4D1D3CD5590014B822 /* delete_field_default@2x.png in Resources */, 615A28362180720D0060F920 /* security_toogle_background_grey@2x.png in Resources */, - C6710F612722AECB00ED888F /* Roboto-Italic.ttf in Resources */, 639CEB091A1DF4FA004DE38F /* UIChatCell.xib in Resources */, 633FEE961D3CD55A0014B822 /* micro_disabled.png in Resources */, 63AADBF61B6A0FF200AA16FD /* linphonerc-factory in Resources */, - C6710FA92722B20000ED888F /* voip_call_stats.png in Resources */, 633FEE671D3CD5590014B822 /* footer_contacts_default@2x.png in Resources */, 615A2830218071E80060F920 /* security_toogle_background_green.png in Resources */, 63B8D68C1BCBE65600C12B09 /* ChatConversationCreateView.xib in Resources */, + D38187D915FE347700C3EDCA /* CallIncomingView.xib in Resources */, 63CDC45F1C3BDE370085F529 /* ringback.wav in Resources */, 8CD99A1C20908C27008A7CDA /* callkit_logo@2x.png in Resources */, 633FEE251D3CD5590014B822 /* chat_start_body_over~ipad@2x.png in Resources */, @@ -4178,16 +3782,13 @@ 633FEF3A1D3CD55A0014B822 /* security_ko.png in Resources */, 615A283A2180788E0060F920 /* security_toogle_button.png in Resources */, 633FEDA01D3CD5590014B822 /* avatar.png in Resources */, - C6710FA02722B20000ED888F /* voip_numpad_0.png in Resources */, 633FEEBC1D3CD55A0014B822 /* numpad_4_default@2x.png in Resources */, - C6710FAD2722B20000ED888F /* voip_numpad_5.png in Resources */, 633FEEA91D3CD55A0014B822 /* numpad_1~ipad.png in Resources */, 615A28402180A2620060F920 /* invite_linphone@2x.png in Resources */, C61B1BF42667D202001A4E4A /* more_menu_default.png in Resources */, 633FEDF71D3CD5590014B822 /* camera_default@2x.png in Resources */, C64A85522667B74100252AD2 /* ephemeral_messages_default.png in Resources */, 633FEDB31D3CD5590014B822 /* call_alt_back_default@2x.png in Resources */, - C6710FB52722B20000ED888F /* voip_delete.png in Resources */, 633FEDCF1D3CD5590014B822 /* call_quality_indicator_1@2x.png in Resources */, 633FEF131D3CD55A0014B822 /* pause_big_over_selected@2x.png in Resources */, 8CDC61951F84D89B0087CF7F /* check_selected.png in Resources */, @@ -4201,28 +3802,22 @@ 633FEDB21D3CD5590014B822 /* call_alt_back_default.png in Resources */, 633FEE3D1D3CD5590014B822 /* contacts_all_default@2x.png in Resources */, 633FEF251D3CD55A0014B822 /* route_bluetooth_disabled@2x.png in Resources */, - C6710FCF2722B20000ED888F /* voip_numpad_8.png in Resources */, 633FEDD81D3CD5590014B822 /* call_start_body_default~ipad.png in Resources */, 61586B83217A16FD0038AC45 /* menu_about@2x.png in Resources */, 633FEED81D3CD55A0014B822 /* numpad_7_over~ipad@2x.png in Resources */, - C6710FBE2722B20000ED888F /* voip_export.png in Resources */, 633FEDD71D3CD5590014B822 /* call_start_body_default@2x.png in Resources */, - C6710FC32722B20000ED888F /* voip_cancel.png in Resources */, 633FEE571D3CD5590014B822 /* dialer_back_disabled@2x.png in Resources */, 63CDC45E1C3BDE370085F529 /* msg.caf in Resources */, 633FEE6D1D3CD5590014B822 /* footer_dialer_disabled@2x.png in Resources */, 633FEF171D3CD55A0014B822 /* pause_small_disabled@2x.png in Resources */, - C6710FCE2722B20000ED888F /* voip_speaker_off.png in Resources */, C6A1BB3626E8815400540D50 /* menu_forward_default.png in Resources */, D38187DD15FE348A00C3EDCA /* AssistantView.xib in Resources */, 633FEDA61D3CD5590014B822 /* back_disabled.png in Resources */, 633FEED61D3CD55A0014B822 /* numpad_7_over@2x.png in Resources */, - C6710FD02722B20000ED888F /* voip_call_header_active.png in Resources */, - C6710FBA2722B20000ED888F /* voip_numpad_9.png in Resources */, + 638F1A881C2167C2004B8E02 /* CallView~ipad.xib in Resources */, 633FEDA11D3CD5590014B822 /* avatar@2x.png in Resources */, 633FED9E1D3CD5590014B822 /* add_field_over.png in Resources */, 633FEE0A1D3CD5590014B822 /* chat_attachment_default.png in Resources */, - C6710FC72722B20000ED888F /* voip_numpad_4.png in Resources */, 633FEE201D3CD5590014B822 /* chat_start_body_disabled~ipad.png in Resources */, 633FEE5B1D3CD5590014B822 /* edit_default@2x.png in Resources */, 633FEDE11D3CD5590014B822 /* call_start_body_over~ipad@2x.png in Resources */, @@ -4237,11 +3832,8 @@ C622E3F126A81290004F5434 /* vr_on.png in Resources */, 633FEF401D3CD55A0014B822 /* select_all_default.png in Resources */, C6B4444426AAD0980076C517 /* file_picture_default.png in Resources */, - C6EA2F4827514D09008E60F8 /* voip_call_forward.png in Resources */, 633FEDF01D3CD5590014B822 /* call_transfer_disabled.png in Resources */, 633FEE351D3CD5590014B822 /* conference_exit_default@2x.png in Resources */, - C6710FCB2722B20000ED888F /* voip_remote_recording.png in Resources */, - C6710FAA2722B20000ED888F /* voip_conference_active_speaker.png in Resources */, 633FEECF1D3CD55A0014B822 /* numpad_6_over~ipad.png in Resources */, 61586B87217A17160038AC45 /* menu_assistant@2x.png in Resources */, 633FEE9A1D3CD55A0014B822 /* nowebcamCIF.jpg in Resources */, @@ -4250,10 +3842,8 @@ 633FEEDB1D3CD55A0014B822 /* numpad_8_default.png in Resources */, 633FEE5C1D3CD5590014B822 /* edit_disabled.png in Resources */, 8CF25D9E1F9F76BD00BEA0C1 /* chat_group_informations@2x.png in Resources */, - C6710FD62722B20000ED888F /* voip_conference_play_big.png in Resources */, 633FEDCA1D3CD5590014B822 /* call_outgoing.png in Resources */, 633FEDF81D3CD5590014B822 /* camera_disabled.png in Resources */, - C6710FBD2722B20000ED888F /* voip_call_header_paused.png in Resources */, 8CB2B8FB1F86229E0015CEE2 /* next_disabled@2x.png in Resources */, 633FEEE91D3CD55A0014B822 /* numpad_9~ipad.png in Resources */, 633FEE331D3CD5590014B822 /* color_M.png in Resources */, @@ -4263,9 +3853,7 @@ 633FEF411D3CD55A0014B822 /* select_all_default@2x.png in Resources */, 633FEEFD1D3CD55A0014B822 /* options_add_call_default@2x.png in Resources */, 633FEEA81D3CD55A0014B822 /* numpad_1_over~ipad@2x.png in Resources */, - C6710FA12722B20000ED888F /* voip_copy.png in Resources */, D38187AD15FE340100C3EDCA /* ChatConversationView.xib in Resources */, - C6710FB72722B20000ED888F /* voip_numpad_6.png in Resources */, 633FEE7C1D3CD5590014B822 /* history_missed_disabled.png in Resources */, CF1DE92E210A0F5D00A0A97E /* UILinphoneAudioPlayer.xib in Resources */, 633FEDF11D3CD5590014B822 /* call_transfer_disabled@2x.png in Resources */, @@ -4289,7 +3877,6 @@ 633FEF471D3CD55A0014B822 /* speaker_disabled@2x.png in Resources */, 633FEEFE1D3CD55A0014B822 /* options_add_call_disabled.png in Resources */, 633FEE291D3CD5590014B822 /* checkbox_unchecked@2x.png in Resources */, - C6710FCD2722B20000ED888F /* voip_call_participants.png in Resources */, 63AADC001B6A0FF200AA16FD /* assistant_linphone_create.rc in Resources */, 633FEF1C1D3CD55A0014B822 /* presence_offline.png in Resources */, 633FEE901D3CD55A0014B822 /* list_details_over.png in Resources */, @@ -4299,14 +3886,12 @@ 63EC8D391D7438660066547B /* AssistantLinkView.xib in Resources */, 633FEE971D3CD55A0014B822 /* micro_disabled@2x.png in Resources */, D38187CD15FE346700C3EDCA /* HistoryDetailsView.xib in Resources */, - C6710FC52722B20000ED888F /* voip_camera_off.png in Resources */, 633FEEA21D3CD55A0014B822 /* numpad_0~ipad@2x.png in Resources */, 633FEE991D3CD55A0014B822 /* micro_selected@2x.png in Resources */, 633FEE621D3CD5590014B822 /* footer_chat_default.png in Resources */, 24BFAAA3209B0630004F47A7 /* contacts_sip_selected.png in Resources */, 633FEE0D1D3CD5590014B822 /* chat_attachment_disabled@2x.png in Resources */, 639E9CA61C0DB7F200019A75 /* UIChatCreateCell.xib in Resources */, - C6710FAE2722B20000ED888F /* voip_hangup.png in Resources */, 8CBD7BAC20B6B82F00E5DCC0 /* UIChatCreateCollectionViewCell.xib in Resources */, 633FEEA31D3CD55A0014B822 /* numpad_1_default.png in Resources */, 633FEEA51D3CD55A0014B822 /* numpad_1_over.png in Resources */, @@ -4323,7 +3908,6 @@ 633FEE691D3CD5590014B822 /* footer_contacts_disabled@2x.png in Resources */, 8CBD7BA020B6B7FD00E5DCC0 /* ChatConversationInfoView.xib in Resources */, 633FEF071D3CD55A0014B822 /* options_start_conference_default@2x.png in Resources */, - C6710FD32722B20000ED888F /* voip_conference_paused_big.png in Resources */, 633FEE151D3CD5590014B822 /* chat_send_default@2x.png in Resources */, 633FEDC31D3CD5590014B822 /* call_hangup_default@2x.png in Resources */, 633FEF061D3CD55A0014B822 /* options_start_conference_default.png in Resources */, @@ -4345,10 +3929,10 @@ C66B040E26F095D1009B5EDC /* cancel_forward.png in Resources */, CF7602F6210898CC00749F76 /* rec_on_default@2x.png in Resources */, 633FEF081D3CD55A0014B822 /* options_start_conference_disabled.png in Resources */, + 63F1DF511BCE986A00EDED90 /* UICallConferenceCell.xib in Resources */, 633FEE301D3CD5590014B822 /* color_H.png in Resources */, 633FEE7D1D3CD5590014B822 /* history_missed_disabled@2x.png in Resources */, 633FEE941D3CD55A0014B822 /* micro_default.png in Resources */, - C6710FB32722B20000ED888F /* voip_pause.png in Resources */, 633FEE611D3CD5590014B822 /* edit_list_disabled@2x.png in Resources */, 633FEE761D3CD5590014B822 /* history_all_selected.png in Resources */, 8C300D9B1E40E0CC00728EF3 /* lime_ko@2x.png in Resources */, @@ -4387,7 +3971,6 @@ 633FEF3B1D3CD55A0014B822 /* security_ko@2x.png in Resources */, 633FEE4A1D3CD5590014B822 /* delete_disabled.png in Resources */, 614D09CE21E74D5400C43EDF /* GoogleService-Info.plist in Resources */, - C6710F632722AECB00ED888F /* Roboto-Regular.ttf in Resources */, C6B4444526AAD0980076C517 /* file_audio_default.png in Resources */, C6A1BB3526E8815400540D50 /* menu_info.png in Resources */, C61B1BF72667EC6B001A4E4A /* ephemeral_messages_color_A.png in Resources */, @@ -4401,9 +3984,8 @@ 633FEE011D3CD5590014B822 /* camera_switch_over@2x.png in Resources */, 633FEEA01D3CD55A0014B822 /* numpad_0_over~ipad@2x.png in Resources */, 633FEF3E1D3CD55A0014B822 /* security_pending.png in Resources */, - C6710FBC2722B20000ED888F /* voip_change_camera.png in Resources */, + D381881915FE3FCA00C3EDCA /* CallView.xib in Resources */, 633FEE7E1D3CD5590014B822 /* history_missed_selected.png in Resources */, - C6277DA9274BF1CE00406FB9 /* voip_radio_off.png in Resources */, 633FEE261D3CD5590014B822 /* checkbox_checked.png in Resources */, 633FEF531D3CD55A0014B822 /* voicemail@2x.png in Resources */, 633FEF2C1D3CD55A0014B822 /* route_earpiece_selected.png in Resources */, @@ -4414,7 +3996,6 @@ 633FEECB1D3CD55A0014B822 /* numpad_6_default.png in Resources */, 633FEDC71D3CD5590014B822 /* call_incoming@2x.png in Resources */, 633FEDB81D3CD5590014B822 /* call_alt_start_disabled.png in Resources */, - C6710FCC2722B20000ED888F /* voip_call_list_menu.png in Resources */, 615A281D217F6FA80060F920 /* security_2_indicator@2x.png in Resources */, 633FEF3C1D3CD55A0014B822 /* security_ok.png in Resources */, 633FEEAF1D3CD55A0014B822 /* numpad_2_over~ipad.png in Resources */, @@ -4441,7 +4022,6 @@ 633FEDF31D3CD5590014B822 /* call_video_start_default@2x.png in Resources */, 24BFAAA2209B0630004F47A7 /* linphone_user~ipad@2x.png in Resources */, 633FEDBA1D3CD5590014B822 /* call_audio_start_default.png in Resources */, - C6710FA52722B20000ED888F /* voip_mandatory.png in Resources */, 61586B8F217A174F0038AC45 /* menu_options@2x.png in Resources */, 633FEE131D3CD5590014B822 /* chat_message_not_delivered@2x.png in Resources */, 615A282A21805B4C0060F920 /* security_toogle_icon_grey@2x.png in Resources */, @@ -4452,8 +4032,6 @@ 633FEDCE1D3CD5590014B822 /* call_quality_indicator_1.png in Resources */, 8CB2B8F91F86229E0015CEE2 /* chat_secure.png in Resources */, 633FEF4E1D3CD55A0014B822 /* valid_default.png in Resources */, - C6710FA22722B20000ED888F /* voip_merge_calls.png in Resources */, - C6710FAC2722B20000ED888F /* voip_call_chat.png in Resources */, 570742581D5A0691004B9C84 /* ShopView.xib in Resources */, 633FEE361D3CD5590014B822 /* conference_exit_over.png in Resources */, 633FEDAA1D3CD5590014B822 /* backspace_disabled.png in Resources */, @@ -4469,18 +4047,14 @@ 633FEDDD1D3CD5590014B822 /* call_start_body_disabled~ipad@2x.png in Resources */, 633FEEBD1D3CD55A0014B822 /* numpad_4_over.png in Resources */, 8CA70AD41F9E285C00A3D2EB /* chat_group_add@2x.png in Resources */, - C6710FAB2722B20000ED888F /* voip_edit.png in Resources */, C66B040A26EFDA55009B5EDC /* reply_cancel.png in Resources */, 633FEEF11D3CD55A0014B822 /* numpad_hash~ipad.png in Resources */, 633FEE781D3CD5590014B822 /* history_chat_indicator.png in Resources */, 633FEF431D3CD55A0014B822 /* select_all_disabled@2x.png in Resources */, - C6710F622722AECB00ED888F /* Roboto-Bold.ttf in Resources */, 633FEE771D3CD5590014B822 /* history_all_selected@2x.png in Resources */, - C6710F9F2722B20000ED888F /* voip_numpad_1.png in Resources */, 633FEF031D3CD55A0014B822 /* options_disabled@2x.png in Resources */, 633FEDA21D3CD5590014B822 /* avatar~ipad.png in Resources */, 24BFAAA1209B0630004F47A7 /* linphone_user@2x.png in Resources */, - C6710FD42722B20000ED888F /* voip_camera_on.png in Resources */, 633FEF211D3CD55A0014B822 /* presence_unregistered@2x.png in Resources */, 633FEEA71D3CD55A0014B822 /* numpad_1_over~ipad.png in Resources */, ); @@ -4516,20 +4090,16 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 068EB8CED53992A5D7A733DF /* [CP] Check Pods Manifest.lock */ = { + 20EEEF6D60A7B77C2EFF85DB /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-linphone-checkManifestLockResult.txt", ); @@ -4538,48 +4108,60 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 1E9EBAB02A694F2487E6099B /* [CP] Check Pods Manifest.lock */ = { + 4D22DCAAC0231865D78AC1E6 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-linphone/Pods-linphone-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/bctoolbox-ios.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/bctoolbox-tester.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/bctoolbox.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/belcard.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/belle-sip.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/belr.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/lime.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/limetester.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/linphone.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/linphonetester.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/mediastreamer2.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/msamr.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/mscodec2.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/msopenh264.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/mssilk.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/mswebrtc.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/msx264.framework", + "${PODS_ROOT}/linphone-sdk/linphone-sdk/apple-darwin/Frameworks/ortp.framework", + "${BUILT_PRODUCTS_DIR}/linphone-sdk/linphonesw.framework", ); + name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-msgNotificationService-checkManifestLockResult.txt", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SVProgressHUD.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/bctoolbox-ios.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/bctoolbox-tester.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/bctoolbox.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/belcard.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/belle-sip.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/belr.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/lime.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/limetester.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/linphone.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/linphonetester.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mediastreamer2.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msamr.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mscodec2.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msopenh264.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mssilk.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mswebrtc.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msx264.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ortp.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/linphonesw.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 2E68C0F1B7E1F6C3000F700C /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-msgNotificationContent-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-linphone/Pods-linphone-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 6112A019243B2C8400DBD5F5 /* ShellScript */ = { @@ -4654,58 +4236,48 @@ shellPath = /bin/sh; shellScript = "$SRCROOT/Tools/git_version.sh\n"; }; - D7A9CDC06B7BB5D324EA10C9 /* [CP] Embed Pods Frameworks */ = { + B0A561F0290F0342EACE9005 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-linphone/Pods-linphone-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework", - "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/bctoolbox-ios.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/bctoolbox.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/belcard.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/belle-sip.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/belr.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/lime.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/linphone.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/linphonetester.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/mediastreamer2.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/msamr.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/mscodec2.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/msopenh264.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/mssilk.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/mswebrtc.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/msx264.framework", - "${PODS_ROOT}/../../../../../../../Volumes/dada/bc/linphone-sdk/ios/linphone-sdk/apple-darwin/Frameworks/ortp.framework", - "${BUILT_PRODUCTS_DIR}/linphone-sdk/linphonesw.framework", + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SVProgressHUD.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/bctoolbox-ios.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/bctoolbox.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/belcard.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/belle-sip.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/belr.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/lime.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/linphone.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/linphonetester.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mediastreamer2.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msamr.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mscodec2.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msopenh264.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mssilk.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/mswebrtc.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msx264.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ortp.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/linphonesw.framework", + "$(DERIVED_FILE_DIR)/Pods-msgNotificationContent-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-linphone/Pods-linphone-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + CD5CF0B3FE8B6052CD8219CE /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-msgNotificationService-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -4717,27 +4289,15 @@ files = ( 63B81A0F1B57DA33009604A6 /* TPKeyboardAvoidingTableView.m in Sources */, CF1DE92D210A0F5D00A0A97E /* UILinphoneAudioPlayer.m in Sources */, - C6D1EC4A274D212B0091881C /* UICamSwitch.m in Sources */, 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 6135761C240E81BB005304D4 /* UIInterfaceStyleButton.m in Sources */, 8CD99A3C2090B9FA008A7CDA /* ChatConversationImdnView.m in Sources */, 1D3623260D0F684500981E51 /* LinphoneAppDelegate.m in Sources */, - C6F2D503273BAC030071BA52 /* ButtonWithStateBackgrounds.swift in Sources */, - C6C98CD027439A7F00059B55 /* VoipCallCell.swift in Sources */, - C60B66682721AFFA0026AC7D /* CallStatisticsData.swift in Sources */, C6B4444826AADA530076C517 /* SwiftUtil.swift in Sources */, 614C087A23D1A37400217F80 /* CallManager.swift in Sources */, CF15F21E20E4F9A3008B1DE6 /* UIImageViewDeletable.m in Sources */, - C6F2D4FD273A85A90071BA52 /* PausedCallOrConferenceView.swift in Sources */, - C6F2D4FF273AF01A0071BA52 /* ControlsView.swift in Sources */, - C6710F5527229D5900ED888F /* LightDarkColor.swift in Sources */, - C6F2D4F9273A4CD70071BA52 /* SharedLayoutConstants.swift in Sources */, - C6D09F3F274273FB003C2173 /* CallStatsView.swift in Sources */, 22F2508E107141E100AC9B3F /* DialerView.m in Sources */, 633756451B67D2B200E21BAD /* SideMenuView.m in Sources */, - C6F2D4F1273935860071BA52 /* CallExtensions.swift in Sources */, - C6710F5C2722AAED00ED888F /* UIDeviceExtensions.swift in Sources */, - C65A5D3027216B86005BA038 /* ActiveCallOrConferenceView.swift in Sources */, 8CD99A422090CE6F008A7CDA /* UIChatConversationImdnTableViewCell.m in Sources */, 22E0A822111C44E100B04932 /* AboutView.m in Sources */, 633671611BCBAAD200BFCBDE /* ChatConversationCreateView.m in Sources */, @@ -4745,38 +4305,37 @@ 2248E90E12F7E4CF00220D9C /* UIDigitButton.m in Sources */, 6134812F2407B35200695B41 /* AppManager.swift in Sources */, 633756391B67BAF400E21BAD /* SideMenuTableView.m in Sources */, - C6B04D63274B95D500F70559 /* VoipParticipantCell.swift in Sources */, 2214EB7A12F846B1002A5394 /* UICallButton.m in Sources */, - C683B213272276CF00D4E15C /* UIColorExtensions.swift in Sources */, - C6710F512722932600ED888F /* UIImageViewExtensions.swift in Sources */, + 6352A5751BE0D4B800594C1C /* CallSideMenuView.m in Sources */, + 2214EB8912F84EBB002A5394 /* UIHangUpButton.m in Sources */, 630CF5571AF7CE1500539F7A /* UITextField+DoneButton.m in Sources */, 2214EBF312F86360002A5394 /* UIMutedMicroButton.m in Sources */, - C6D09F4127428626003C2173 /* IceState.swift in Sources */, - C658614C273E5B5E00A0DBFC /* VoipExtraButton.swift in Sources */, 8C9C5E111F83BD97006987FA /* UIChatCreateCollectionViewCell.m in Sources */, + 22968A5F12F875C600588287 /* UISpeakerButton.m in Sources */, 63701DDF1BA32039006A9AE3 /* UIConfirmationDialog.m in Sources */, 6134812D2406CECC00695B41 /* ConfigManager.swift in Sources */, 22C755601317E59C007BC101 /* UIBluetoothButton.m in Sources */, + 22AA8B0113D83F6300B30535 /* UICamSwitch.m in Sources */, 63B8D6A21BCBF43100C12B09 /* UIChatCreateCell.m in Sources */, 636BC9971B5F921B00C754CE /* UIIconButton.m in Sources */, 63423C0A1C4501D000D9A050 /* Contact.m in Sources */, - C6710FE12722F0E400ED888F /* Avatar.swift in Sources */, + 340751E7150F38FD00B89C47 /* UIVideoButton.m in Sources */, 34216F401547EBCD00EA9777 /* VideoZoomHandler.m in Sources */, 614C087823D1A35F00217F80 /* ProviderDelegate.swift in Sources */, + D3F83EEC1582021700336684 /* CallView.m in Sources */, CF7602D7210867E800749F76 /* RecordingsListView.m in Sources */, + 63F1DF4B1BCE983200EDED90 /* CallConferenceTableView.m in Sources */, D3F83F8E15822ABE00336684 /* PhoneMainView.m in Sources */, C6A1BB3E26E882D000540D50 /* UIChatReplyBubbleView.m in Sources */, 6377AC801BDE4069007F7625 /* UIBackToCallButton.m in Sources */, - C6D09F43274288D4003C2173 /* PayloadType.swift in Sources */, 6308F9C51BF0DD6600D1234B /* XMLRPCHelper.m in Sources */, - C6F2D4F72739861F0071BA52 /* RemotelyRecording.swift in Sources */, D3ED3E871586291E006C0DE4 /* TabBarView.m in Sources */, 617C242A263022690042FB4A /* UIChatContentView.m in Sources */, D3ED3EA71587334E006C0DE4 /* HistoryListTableView.m in Sources */, 61AEBEBD2191990A00F35E7F /* DevicesListView.m in Sources */, D3ED3EB81587392C006C0DE4 /* HistoryListView.m in Sources */, - C6710FE72723234400ED888F /* OutgoingCallView.swift in Sources */, 24A345A61D95798A00881A5C /* UIShopTableCell.m in Sources */, + 8C1B67061E671826001EA2FE /* AudioHelper.m in Sources */, D35497FE15875372000081D8 /* ContactsListView.m in Sources */, 635173F91BA082A40095EB0A /* UIChatBubblePhotoCell.m in Sources */, D3549816158761D0000081D8 /* ContactsListTableView.m in Sources */, @@ -4786,99 +4345,71 @@ 6341807C1BBC103100F71761 /* ChatConversationCreateTableView.m in Sources */, 63BE7A781D75BDF6000990EF /* ShopTableView.m in Sources */, D326483815887D5200930C67 /* OrderedDictionary.m in Sources */, - C6710F4F2722903200ED888F /* RotatingSpinner.swift in Sources */, D32648441588F6FC00930C67 /* UIToggleButton.m in Sources */, - C6C98CDF2745590500059B55 /* ConferenceExtensions.swift in Sources */, - C67C97B4274FC5EF0074A0D8 /* AudioRoutesView.swift in Sources */, - C6824FBA27219D890043D4FC /* IncomingCallView.swift in Sources */, - C6C98CD527453ED900059B55 /* ConferenceViewModel.swift in Sources */, + D36FB2D51589EF7C0036F6F2 /* UIPauseButton.m in Sources */, D31C9C98158A1CDF00756B45 /* UIHistoryCell.m in Sources */, D35E7597159460580066B1C1 /* ChatsListView.m in Sources */, D35E759F159460B70066B1C1 /* SettingsView.m in Sources */, 63B81A101B57DA33009604A6 /* UIScrollView+TPKeyboardAvoidingAdditions.m in Sources */, F03CA84318C72F1A0008889D /* UITextViewNoDefine.m in Sources */, 63B81A0D1B57DA33009604A6 /* TPKeyboardAvoidingCollectionView.m in Sources */, - C6710FD92722BD0100ED888F /* UICallTimer.swift in Sources */, 570742611D5A09B8004B9C84 /* ShopView.m in Sources */, - C65A5D3B27216CC0005BA038 /* MutableLiveData.swift in Sources */, - C6C98CCE27438A3F00059B55 /* DismissableView.swift in Sources */, + 63F1DF4F1BCE985F00EDED90 /* UICallConferenceCell.m in Sources */, D37DC6C11594AE1800B2A5EB /* LinphoneCoreSettingsStore.m in Sources */, 63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */, D3EA53FD159850E80037DC6B /* LinphoneManager.m in Sources */, - C60D265C272AA0BD006238BB /* UIImageExtensions.swift in Sources */, - C6D09F3D273EE467003C2173 /* BouncingCounter.swift in Sources */, C6DA657C261C950C0020CB43 /* VFSUtil.swift in Sources */, 63B81A0E1B57DA33009604A6 /* TPKeyboardAvoidingScrollView.m in Sources */, 633888451BFB2C49001D5E7B /* HPGrowingTextView.m in Sources */, 63F1DF441BCE618E00EDED90 /* UIAddressTextField.m in Sources */, D3EA540D1598528B0037DC6B /* ChatsListTableView.m in Sources */, D3EA5411159853750037DC6B /* UIChatCell.m in Sources */, + D3F26BF115986B73005F9CAB /* CallIncomingView.m in Sources */, D31B4B21159876C0002E6C72 /* UICompositeView.m in Sources */, + D31AAF5E159B3919002C6B02 /* CallPausedTableView.m in Sources */, 8C9C5E0D1F83B2EF006987FA /* ChatConversationCreateCollectionViewController.m in Sources */, 631098491D4660580041F2B3 /* CountryListView.m in Sources */, D32B9DFC15A2F131000B6DEC /* FastAddressBook.m in Sources */, D350F20E15A43BB100149E54 /* AssistantView.m in Sources */, D3F795D615A582810077328B /* ChatConversationView.m in Sources */, - C60D265627299C94006238BB /* ControlsViewModel.swift in Sources */, D32B6E2915A5BC440033019F /* ChatConversationTableView.m in Sources */, - C6D09F4B27438707003C2173 /* CallsListView.swift in Sources */, D3A8BB7015A6C7D500F96BE5 /* UIChatBubbleTextCell.m in Sources */, - C683B20E2722702300D4E15C /* VoipTheme.swift in Sources */, - C6278497273C21E1002FAA29 /* LocalVideoView.swift in Sources */, 63D11C531C3D501200E8FCEE /* Log.m in Sources */, D3128FE115AABC7E00A2147A /* ContactDetailsView.m in Sources */, 6135761F240E81D0005304D4 /* UIInterfaceStyleToggleButton.m in Sources */, - C6B04D67274BD61300F70559 /* VoipConferenceActiveSpeakerView.swift in Sources */, D37C639B15AADEF6009D0BAC /* ContactDetailsTableView.m in Sources */, 63E59A3F1ADE70D900646FB3 /* InAppProductsManager.m in Sources */, - C67C97B8274FD76B0074A0D8 /* AudioRouteUtils.swift in Sources */, - C6C98CE1274568F800059B55 /* VoipConferenceGridView.swift in Sources */, D3C6526715AC1A8F0092A874 /* UIContactDetailsCell.m in Sources */, 631348301B6F7B6600C6BDCB /* UIRoundBorderedButton.m in Sources */, C90FAA7915AF54E6002091CB /* HistoryDetailsView.m in Sources */, 63FB30351A680E73008CA393 /* UIRoundedImageView.m in Sources */, 635775251B6673EC00C8B704 /* HistoryDetailsTableView.m in Sources */, - C6C98CD727453F9600059B55 /* ConferenceParticipantData.swift in Sources */, 63C441C31BBC23ED0053DC5E /* UIAssistantTextField.m in Sources */, - C6B04D69274BD6A100F70559 /* VoipActiveSpeakerParticipantCell.swift in Sources */, - C65A5D45272196AE005BA038 /* OptionalExtensions.swift in Sources */, + 6346100F1B61409800548952 /* CallOutgoingView.m in Sources */, D35860D615B549B500513429 /* Utils.m in Sources */, D3F7998115BD32370018C273 /* TPMultiLayoutViewController.m in Sources */, D3807FBF15C28940005BE9BC /* DCRoundSwitch.m in Sources */, D3807FC115C28940005BE9BC /* DCRoundSwitchKnobLayer.m in Sources */, - C6B04D61274B954500F70559 /* ParticipantsListView.swift in Sources */, 61CCC3DF21933B580060EDEA /* UIDeviceCell.m in Sources */, 6306440E1BECB08500134C72 /* FirstLoginView.m in Sources */, D3807FC315C28940005BE9BC /* DCRoundSwitchOutlineLayer.m in Sources */, CF7602E221086EB200749F76 /* RecordingsListTableView.m in Sources */, D3807FC515C28940005BE9BC /* DCRoundSwitchToggleLayer.m in Sources */, - C6586149273E595700A0DBFC /* VoipExtraButtonsView.swift in Sources */, 633E41821D74259000320475 /* AssistantLinkView.m in Sources */, - C6710F5727229DEE00ED888F /* TextStyle.swift in Sources */, D3807FE815C2894A005BE9BC /* IASKAppSettingsViewController.m in Sources */, D3807FEC15C2894A005BE9BC /* IASKSpecifierValuesViewController.m in Sources */, 8CA70AE41F9E39E400A3D2EB /* UIChatConversationInfoTableViewCell.m in Sources */, D3807FEE15C2894A005BE9BC /* IASKSettingsReader.m in Sources */, - C6C65E8B2727274A00E48FC6 /* NumpadView.swift in Sources */, - C6F2D501273B0EFC0071BA52 /* VoipDialog.swift in Sources */, - C6710F53272297C400ED888F /* VoipTexts.swift in Sources */, D3807FF015C2894A005BE9BC /* IASKSettingsStore.m in Sources */, - C6710FEB2726874D00ED888F /* ButtonTheme.swift in Sources */, 8CA70AD11F9E0AE100A3D2EB /* ChatConversationInfoView.m in Sources */, D3807FF215C2894A005BE9BC /* IASKSettingsStoreFile.m in Sources */, D3807FF415C2894A005BE9BC /* IASKSettingsStoreUserDefaults.m in Sources */, - C6710FDC2722C3BB00ED888F /* UIVIewExtensions.swift in Sources */, - C6F2D4F32739475C0071BA52 /* ActiveCallView.swift in Sources */, 639E9C801C0DB13D00019A75 /* UICheckBoxTableView.m in Sources */, CF7602E72108759A00749F76 /* UIRecordingCell.m in Sources */, - C6C98CD22743FD0B00059B55 /* VoipCallContextMenu.swift in Sources */, D3807FF615C2894A005BE9BC /* IASKSpecifier.m in Sources */, - C6710FE92723DD7D00ED888F /* CallControlButton.swift in Sources */, D3807FF815C2894A005BE9BC /* IASKPSSliderSpecifierViewCell.m in Sources */, D3807FFA15C2894A005BE9BC /* IASKPSTextFieldSpecifierViewCell.m in Sources */, D3807FFC15C2894A005BE9BC /* IASKPSTitleValueSpecifierViewCell.m in Sources */, - C6F2D4EF27392D970071BA52 /* CallsViewModel.swift in Sources */, - C6C65E89272723DC00E48FC6 /* UIVIewControllerExtensions.swift in Sources */, D3807FFE15C2894A005BE9BC /* IASKSlider.m in Sources */, D380800015C2894A005BE9BC /* IASKSwitch.m in Sources */, D380800215C2894A005BE9BC /* IASKTextField.m in Sources */, @@ -4886,23 +4417,14 @@ C64A854E2667B67200252AD2 /* EphemeralSettingsView.m in Sources */, 8C92ABF31FA773E50006FB5D /* UIChatNotifiedEventCell.m in Sources */, 633FEF581D3CD5E00014B822 /* UIAvatarPresence.m in Sources */, - C6C98CDB274541E400059B55 /* ConferenceParticipantDeviceData.swift in Sources */, 637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */, - C6710FDE2722D44B00ED888F /* IncomingOuntgoingCommonView.swift in Sources */, D378AB2A15DCDB4A0098505D /* ImagePickerView.m in Sources */, - C6710F592722A9B800ED888F /* StyledLabel.swift in Sources */, 22405F001601C19200B92522 /* ImageView.m in Sources */, - C60D265827299F70006238BB /* CoreExtensions.swift in Sources */, - C6710FE527230B5800ED888F /* AddressExtensions.swift in Sources */, + 63BC49E21BA2CDFC004EC273 /* UICallPausedCell.m in Sources */, D37EE162160377D7003608A6 /* DTActionSheet.m in Sources */, - C67C97B1274FB4C10074A0D8 /* VoipConferenceDisplayModeSelectionView.swift in Sources */, - C6D52B45274648E500904660 /* VoipGridParticipantCell.swift in Sources */, D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */, 6381DA7D1C1AD5EA00DF3BBD /* UIBouncingView.m in Sources */, - C6C98CDD274547C500059B55 /* ParticipantExtensions.swift in Sources */, D37E3ECD1619C27A0087659A /* CAAnimation+Blocks.m in Sources */, - C6F2D505273BB3BB0071BA52 /* UIApplication+Extension.swift in Sources */, - C65A5D3F27216E3A005BA038 /* CallData.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5003,6 +4525,16 @@ name = "SideMenuView~ipad.xib"; sourceTree = ""; }; + 634610101B6140A500548952 /* CallOutgoingView.xib */ = { + isa = PBXVariantGroup; + children = ( + 634610111B6140A500548952 /* Base */, + 8CBD7BB420B6B86B00E5DCC0 /* fr */, + 6187B1BA24B3271700D580FB /* hu */, + ); + name = CallOutgoingView.xib; + sourceTree = ""; + }; 636316D31A1DEBCB0009B839 /* AboutView.xib */ = { isa = PBXVariantGroup; children = ( @@ -5035,6 +4567,16 @@ name = "DialerView~ipad.xib"; sourceTree = ""; }; + 638F1A861C2167C2004B8E02 /* CallView~ipad.xib */ = { + isa = PBXVariantGroup; + children = ( + 638F1A871C2167C2004B8E02 /* Base */, + 8CBD7BB620B6B86D00E5DCC0 /* fr */, + 6187B1BC24B3271800D580FB /* hu */, + ); + name = "CallView~ipad.xib"; + sourceTree = ""; + }; 638F1A8F1C21993D004B8E02 /* UICompositeView~ipad.xib */ = { isa = PBXVariantGroup; children = ( @@ -5100,6 +4642,16 @@ name = FirstLoginView.xib; sourceTree = ""; }; + 639E9C9F1C0DB7DF00019A75 /* UICallPausedCell.xib */ = { + isa = PBXVariantGroup; + children = ( + 639E9C9E1C0DB7DF00019A75 /* Base */, + 8CBD7BC620B6B87900E5DCC0 /* fr */, + 6187B1CC24B3271E00D580FB /* hu */, + ); + name = UICallPausedCell.xib; + sourceTree = ""; + }; 639E9CA21C0DB7E500019A75 /* UIChatBubblePhotoCell.xib */ = { isa = PBXVariantGroup; children = ( @@ -5204,6 +4756,16 @@ name = AssistantLinkView.xib; sourceTree = ""; }; + 63F1DF531BCE986A00EDED90 /* UICallConferenceCell.xib */ = { + isa = PBXVariantGroup; + children = ( + 63F1DF521BCE986A00EDED90 /* Base */, + 8CBD7BC520B6B87800E5DCC0 /* fr */, + 6187B1CB24B3271E00D580FB /* hu */, + ); + name = UICallConferenceCell.xib; + sourceTree = ""; + }; 8CBD7BA220B6B7FD00E5DCC0 /* ChatConversationInfoView.xib */ = { isa = PBXVariantGroup; children = ( @@ -5360,6 +4922,18 @@ name = HistoryListView.xib; sourceTree = ""; }; + D38187DC15FE347700C3EDCA /* CallIncomingView.xib */ = { + isa = PBXVariantGroup; + children = ( + F09548241883F15400E8A69B /* Base */, + F09548481883F55800E8A69B /* ru */, + F0AF06FD1A24BA770086C9C1 /* ar */, + 8CBD7BB320B6B86B00E5DCC0 /* fr */, + 6187B1B924B3271700D580FB /* hu */, + ); + name = CallIncomingView.xib; + sourceTree = ""; + }; D38187E015FE348A00C3EDCA /* AssistantView.xib */ = { isa = PBXVariantGroup; children = ( @@ -5385,6 +4959,18 @@ path = LinphoneUI; sourceTree = ""; }; + D381881C15FE3FCA00C3EDCA /* CallView.xib */ = { + isa = PBXVariantGroup; + children = ( + F09548231883F15400E8A69B /* Base */, + F09548461883F54200E8A69B /* ru */, + F0AF06FC1A24BA770086C9C1 /* ar */, + 8CBD7BB520B6B86C00E5DCC0 /* fr */, + 6187B1BB24B3271700D580FB /* hu */, + ); + name = CallView.xib; + sourceTree = ""; + }; D3D5126A160B3A8E00946DF8 /* AssistantViewScreens.xib */ = { isa = PBXVariantGroup; children = ( @@ -5421,7 +5007,7 @@ /* Begin XCBuildConfiguration section */ 1D6058940D05DD3E006BFB54 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 53432234870660E9876CBCA8 /* Pods-linphone.debug.xcconfig */; + baseConfigurationReference = 799BA1104845EB01ACE764D8 /* Pods-linphone.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; ALWAYS_SEARCH_USER_PATHS = NO; @@ -5464,10 +5050,7 @@ INFOPLIST_FILE = "linphone-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(inherited)", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; MARKETING_VERSION = 4.4.0; OTHER_CFLAGS = ( @@ -5476,7 +5059,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.20+3cffbc5\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; @@ -5489,7 +5072,6 @@ SWIFT_OBJC_BRIDGING_HEADER = "Classes/linphone-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "linphoneapp-Swift.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_PRECOMPILE_BRIDGING_HEADER = YES; SWIFT_VERSION = 5.0; WARNING_CFLAGS = ( "-Werror=objc-method-access", @@ -5551,7 +5133,7 @@ }; 228B19A71302902F00F154D3 /* DistributionAdhoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 22D3BF4C45858F6B07F4D2A4 /* Pods-linphone.distributionadhoc.xcconfig */; + baseConfigurationReference = FE7D89A821FDC1BCA9BB9F8F /* Pods-linphone.distributionadhoc.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; ALWAYS_SEARCH_USER_PATHS = NO; @@ -5591,10 +5173,7 @@ INFOPLIST_FILE = "linphone-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(inherited)", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; MARKETING_VERSION = 4.4.0; OTHER_CFLAGS = ( @@ -5603,7 +5182,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.20+3cffbc5\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; @@ -5615,7 +5194,6 @@ STRIP_SWIFT_SYMBOLS = NO; SWIFT_OBJC_BRIDGING_HEADER = "Classes/linphone-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "linphoneapp-Swift.h"; - SWIFT_PRECOMPILE_BRIDGING_HEADER = YES; SWIFT_VERSION = 5.0; WARNING_CFLAGS = ( "-Werror=objc-method-access", @@ -5677,7 +5255,7 @@ }; 22F3D55613CC3C9100A0DA02 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0DF941C97B75E7BA39A90600 /* Pods-linphone.release.xcconfig */; + baseConfigurationReference = FEAFB5AD0E3AA409BBD1136E /* Pods-linphone.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; ALWAYS_SEARCH_USER_PATHS = NO; @@ -5717,10 +5295,7 @@ INFOPLIST_FILE = "linphone-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(inherited)", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; MARKETING_VERSION = 4.4.0; OTHER_CFLAGS = ( @@ -5729,7 +5304,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.20+3cffbc5\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; @@ -5741,7 +5316,6 @@ STRIP_SWIFT_SYMBOLS = NO; SWIFT_OBJC_BRIDGING_HEADER = "Classes/linphone-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "linphoneapp-Swift.h"; - SWIFT_PRECOMPILE_BRIDGING_HEADER = YES; SWIFT_VERSION = 5.0; WARNING_CFLAGS = ( "-Werror=objc-method-access", @@ -5802,7 +5376,7 @@ }; 22F51EE8107FA53D00F98953 /* Distribution */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 79B41078A602EFB886981917 /* Pods-linphone.distribution.xcconfig */; + baseConfigurationReference = 38DF35D11A7C0F45E990C83A /* Pods-linphone.distribution.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; ALWAYS_SEARCH_USER_PATHS = NO; @@ -5842,10 +5416,7 @@ INFOPLIST_FILE = "linphone-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(inherited)", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; MARKETING_VERSION = 4.4.0; OTHER_CFLAGS = ( @@ -5854,7 +5425,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.20+3cffbc5\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; @@ -5866,7 +5437,6 @@ STRIP_SWIFT_SYMBOLS = NO; SWIFT_OBJC_BRIDGING_HEADER = "Classes/linphone-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "linphoneapp-Swift.h"; - SWIFT_PRECOMPILE_BRIDGING_HEADER = YES; SWIFT_VERSION = 5.0; WARNING_CFLAGS = ( "-Werror=objc-method-access", @@ -6096,7 +5666,7 @@ }; EA5F25E2232BD3E300475F2E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C589627B9D9D2A4F9C816051 /* Pods-msgNotificationService.debug.xcconfig */; + baseConfigurationReference = ADCA571A7CF61077747BFE53 /* Pods-msgNotificationService.debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -6152,7 +5722,7 @@ }; EA5F25E3232BD3E300475F2E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 063D57B2E4769739DC5DA5C0 /* Pods-msgNotificationService.release.xcconfig */; + baseConfigurationReference = 904C1EC75CB9E03374AAA802 /* Pods-msgNotificationService.release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -6204,7 +5774,7 @@ }; EA5F25E4232BD3E300475F2E /* Distribution */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B9F41097CE0124A05554DB9C /* Pods-msgNotificationService.distribution.xcconfig */; + baseConfigurationReference = F4BE1A2318FC69D799C34F0A /* Pods-msgNotificationService.distribution.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -6256,7 +5826,7 @@ }; EA5F25E5232BD3E300475F2E /* DistributionAdhoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3411568BE5527EB500F75EBB /* Pods-msgNotificationService.distributionadhoc.xcconfig */; + baseConfigurationReference = 8FD0D10102F0A8922703B8A4 /* Pods-msgNotificationService.distributionadhoc.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -6308,7 +5878,7 @@ }; EA8CB835239F96CA00C330CC /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1060E68152C51FCE5ACBF779 /* Pods-msgNotificationContent.debug.xcconfig */; + baseConfigurationReference = 8B4C43A28E90775F6FCA2CEE /* Pods-msgNotificationContent.debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -6364,7 +5934,7 @@ }; EA8CB836239F96CA00C330CC /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 02DBDD5A09F46796AEC2485B /* Pods-msgNotificationContent.release.xcconfig */; + baseConfigurationReference = 34027665305514025971F85C /* Pods-msgNotificationContent.release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -6416,7 +5986,7 @@ }; EA8CB837239F96CA00C330CC /* Distribution */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 507103607396F28FF4427108 /* Pods-msgNotificationContent.distribution.xcconfig */; + baseConfigurationReference = E40C9A7D22675584396C0A3D /* Pods-msgNotificationContent.distribution.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -6468,7 +6038,7 @@ }; EA8CB838239F96CA00C330CC /* DistributionAdhoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6150F32455334A0A7B3D46C8 /* Pods-msgNotificationContent.distributionadhoc.xcconfig */; + baseConfigurationReference = BAD0A9494E833034EB559687 /* Pods-msgNotificationContent.distributionadhoc.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; diff --git a/linphone_Prefix.pch b/linphone_Prefix.pch index 389c6e7d3..6f87a986f 100644 --- a/linphone_Prefix.pch +++ b/linphone_Prefix.pch @@ -12,6 +12,7 @@ #import "Contact.h" #import "UIToggleButton.h" +#import "UISpeakerButton.h" #import "UIBluetoothButton.h" #import "UIMutedMicroButton.h"