forked from mirrors/linphone-iphone
Compare commits
246 commits
master
...
release/5.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f4a80500e | ||
|
|
0913df3ac8 | ||
|
|
b82f8bb84e | ||
|
|
470ec60d99 | ||
|
|
211714167a | ||
|
|
590ebdbd66 | ||
|
|
a1dfc7c6c3 | ||
|
|
8315ac543e | ||
|
|
bac9d2b98e | ||
|
|
8cbeac0e54 | ||
|
|
45c596dcec | ||
|
|
eca3dbe9d9 | ||
|
|
79cb76ac75 | ||
|
|
d34ba5df7c | ||
|
|
8d873e496d | ||
|
|
aefe5e1ad0 | ||
|
|
5fe2af9d50 | ||
|
|
fd627b4c4a | ||
|
|
4c93d335ff | ||
|
|
c47a50f5d1 | ||
|
|
ac4397cbbe | ||
|
|
64c0e84cfa | ||
|
|
29bcbf64c0 | ||
|
|
b99327dbe5 | ||
|
|
952b27c94f | ||
|
|
5407a18b57 | ||
|
|
9e52922fff | ||
|
|
4ade9f2c60 | ||
|
|
abf598b654 | ||
|
|
0a05baea1e | ||
|
|
4cd9da44de | ||
|
|
a341bb6aec | ||
|
|
ff5bafb7c0 | ||
|
|
9ba95b024c | ||
|
|
05b905a3f1 | ||
|
|
e8c2e92fc9 | ||
|
|
82289f4523 | ||
|
|
6365c66d55 | ||
|
|
61e645c238 | ||
|
|
9d5836b991 | ||
|
|
b78b4a1e6b | ||
|
|
6850282208 | ||
|
|
9803678d6a | ||
|
|
f2b36ed7f8 | ||
|
|
d39fb0661b | ||
|
|
b378682d0c | ||
|
|
7da10d500f | ||
|
|
4b5eaa3bc5 | ||
|
|
78c21a5c2b | ||
|
|
fecbb85a81 | ||
|
|
8582d93555 | ||
|
|
a74d042a6a | ||
|
|
ad9163320c | ||
|
|
5ab6a7ce1b | ||
|
|
7ccdcbebcf | ||
|
|
0fe94354d7 | ||
|
|
3dc7d4fb15 | ||
|
|
a98aa42ca4 | ||
|
|
84a817783d | ||
|
|
6e846f092c | ||
|
|
fd9afd66fa | ||
|
|
e5505a836c | ||
|
|
781a9b07d1 | ||
|
|
6a4ef41ab5 | ||
|
|
c09519bcc1 | ||
|
|
9ab5a0f106 | ||
|
|
eff9964b12 | ||
|
|
0202c7aa6b | ||
|
|
4cb99a62a0 | ||
|
|
fc3f48363f | ||
|
|
3800aafd1f | ||
|
|
3a3c04bb23 | ||
|
|
8607469f68 | ||
|
|
987ea21e05 | ||
|
|
b6ff317551 | ||
|
|
9977644872 | ||
|
|
d447158a25 | ||
|
|
c3746801ac | ||
|
|
dbd56b5c38 | ||
|
|
c49013aa2b | ||
|
|
fc9c9b9508 | ||
|
|
6cb4ea55f6 | ||
|
|
54fb56d93c | ||
|
|
ac49ee5d56 | ||
|
|
03af1afac1 | ||
|
|
233865747e | ||
|
|
1291e7dee4 | ||
|
|
61ec8a37dd | ||
|
|
bd42b8855c | ||
|
|
7a78a14bbf | ||
|
|
236a8ee52f | ||
|
|
62f7d8a620 | ||
|
|
8a47583130 | ||
|
|
59098c6db0 | ||
|
|
3043fc5c7a | ||
|
|
3e6bffd723 | ||
|
|
0cd72844b6 | ||
|
|
d5a6a233af | ||
|
|
65573ba1be | ||
|
|
669851065a | ||
|
|
6fa24fff6d | ||
|
|
670dabaf77 | ||
|
|
93eecbc304 | ||
|
|
e02580bade | ||
|
|
581d2dbf50 | ||
|
|
f7ad67390a | ||
|
|
c72d8913b8 | ||
|
|
490f9e96db | ||
|
|
5fb42ce09f | ||
|
|
736059f699 | ||
|
|
b63779b65e | ||
|
|
0fc1f024d3 | ||
|
|
8b5668e8ce | ||
|
|
8909ae7279 | ||
|
|
be5e303b09 | ||
|
|
82704471ac | ||
|
|
988840d9a9 | ||
|
|
a120a067c9 | ||
|
|
555428d62d | ||
|
|
d326b7f56e | ||
|
|
59c90fe65a | ||
|
|
3edcfb4222 | ||
|
|
77c4fb1747 | ||
|
|
50f656d1ee | ||
|
|
06cbe9fa1d | ||
|
|
f3bc7add35 | ||
|
|
9fcfe2b8de | ||
|
|
d04f961559 | ||
|
|
1e1c0fd3d3 | ||
|
|
7ddfff9c32 | ||
|
|
ecdb22dc5d | ||
|
|
d340db5680 | ||
|
|
960046b87e | ||
|
|
79a2235368 | ||
|
|
df53cc73e9 | ||
|
|
44cf121007 | ||
|
|
14ddbaa58a | ||
|
|
0c687d1dce | ||
|
|
f00daf1997 | ||
|
|
c80ad228ef | ||
|
|
70b2671f19 | ||
|
|
3c8af14495 | ||
|
|
51f23e91bb | ||
|
|
cd7951e590 | ||
|
|
a6638d3c9b | ||
|
|
0e947803ce | ||
|
|
666b2c7f48 | ||
|
|
ac32d80b51 | ||
|
|
e2dc5d4ad3 | ||
|
|
eda3fa114a | ||
|
|
fd3afda60c | ||
|
|
670ad21770 | ||
|
|
0353180bd0 | ||
|
|
b402f08006 | ||
|
|
b495e4b8bb | ||
|
|
a0a1e1a417 | ||
|
|
821f2e30b7 | ||
|
|
d0f83d6d1d | ||
|
|
f705e14664 | ||
|
|
35c772db3a | ||
|
|
a57da3d499 | ||
|
|
b9ef7a83b5 | ||
|
|
559a9d8bc3 | ||
|
|
f8d3a196f5 | ||
|
|
298778e20d | ||
|
|
b4103d2f4f | ||
|
|
4c75c4222d | ||
|
|
d8163fb55b | ||
|
|
68597369ed | ||
|
|
388e3482a9 | ||
|
|
811a859430 | ||
|
|
96543cdaca | ||
|
|
23633d1ea4 | ||
|
|
cf78ae8ff9 | ||
|
|
2b252a04ff | ||
|
|
d54c9ef5a9 | ||
|
|
aaea844c4c | ||
|
|
507060fb31 | ||
|
|
863731f775 | ||
|
|
6a8c5a4440 | ||
|
|
360c88b764 | ||
|
|
a4bfa37454 | ||
|
|
68bece526b | ||
|
|
8efce6e446 | ||
|
|
4333e97932 | ||
|
|
77b9287195 | ||
|
|
a4bc64f2b3 | ||
|
|
2a54eae049 | ||
|
|
2279a23db1 | ||
|
|
8743a01b88 | ||
|
|
8ed7ba7bee | ||
|
|
240d28e234 | ||
|
|
d352034e5e | ||
|
|
3c12854dc6 | ||
|
|
47b7820b58 | ||
|
|
ed56de2527 | ||
|
|
57399ec722 | ||
|
|
57b676c775 | ||
|
|
07e0f0ca80 | ||
|
|
981a7c5a60 | ||
|
|
8ba4230c19 | ||
|
|
12f9de3384 | ||
|
|
6af2602639 | ||
|
|
81964daa0c | ||
|
|
7cdcdd4a4d | ||
|
|
be1e726a0c | ||
|
|
8d3fead61d | ||
|
|
5dda082a75 | ||
|
|
a77d6bb1b6 | ||
|
|
dcc832436e | ||
|
|
1559bf46c7 | ||
|
|
4ec4723fbb | ||
|
|
d25cbbf609 | ||
|
|
90c367ccca | ||
|
|
3e22ea3a80 | ||
|
|
49bee7c6a0 | ||
|
|
907cc94fc6 | ||
|
|
b04a306443 | ||
|
|
ffe795bf02 | ||
|
|
5ee6695cdc | ||
|
|
d14a0d3c10 | ||
|
|
9612e21162 | ||
|
|
81688b416b | ||
|
|
da08af7e3f | ||
|
|
9ab70c60fe | ||
|
|
e3ed160c54 | ||
|
|
7d71bd500e | ||
|
|
6ca276b718 | ||
|
|
0d0c0225f1 | ||
|
|
6adeb43fdc | ||
|
|
761a47ad87 | ||
|
|
343a30d93b | ||
|
|
54071f9d15 | ||
|
|
924b499496 | ||
|
|
10b28cd6cf | ||
|
|
33b07703ca | ||
|
|
74c69b3779 | ||
|
|
ef8e1baa92 | ||
|
|
6e93601508 | ||
|
|
0e31b555c1 | ||
|
|
930dd74c89 | ||
|
|
f847d8cfe3 | ||
|
|
263b460372 | ||
|
|
4c690f9274 | ||
|
|
ff14c18f1c | ||
|
|
97708e9096 |
192 changed files with 4660 additions and 2183 deletions
|
|
@ -7,11 +7,12 @@ variables:
|
|||
job-ios:
|
||||
|
||||
stage: build
|
||||
tags: [ "macmini-m1-xcode13" ]
|
||||
tags: [ "macos-xcode13" ]
|
||||
|
||||
script:
|
||||
- pod install --repo-update
|
||||
- pwd
|
||||
- sed 's/fileprivate let tableView =/public let tableView =/g' ./Pods/DropDown/DropDown/src/DropDown.swift > tmp.swift && mv -f tmp.swift ./Pods/DropDown/DropDown/src/DropDown.swift
|
||||
- xcodebuild archive -scheme $archive_scheme -archivePath ./$archive_path -configuration Release -workspace ./linphone.xcworkspace -UseModernBuildSystem=YES -destination 'generic/platform=iOS'
|
||||
- xcodebuild -exportArchive -archivePath ./$archive_path -exportPath ./$export_path -exportOptionsPlist ./$export_options_plist -allowProvisioningUpdates -UseModernBuildSystem=YES -destination 'generic/platform=iOS'
|
||||
|
||||
|
|
|
|||
56
CHANGELOG.md
56
CHANGELOG.md
|
|
@ -10,15 +10,61 @@ Group changes to describe their impact on the project, as follows:
|
|||
Fixed for any bug fixes.
|
||||
Security to invite users to upgrade in case of vulnerabilities.
|
||||
|
||||
## [5.0.2] - 2023-16-03
|
||||
|
||||
### Changed
|
||||
- Update linphone SDK to 5.2.32
|
||||
|
||||
### Fixed
|
||||
- Performance issue causing a global slowing of the app, especially at launch
|
||||
- Fix several memory leaks and crashes
|
||||
|
||||
## [5.0.1] - 2023-10-01
|
||||
|
||||
### Changed
|
||||
- Update linphone SDK to 5.2.11
|
||||
|
||||
### Fixed
|
||||
- Makes sure sip.linphone.org accounts have a LIME X3DH server URL for E2E chat messages encryption
|
||||
- Fix potential crash when displaying images received in a chatroom
|
||||
- Fix bug that would cause the previous call to be terminated when resuming another call that was paused
|
||||
- Fix participant video display in conferences when a second participant joined with video enabled
|
||||
|
||||
## [5.0.0] - 2022-12-06
|
||||
|
||||
### Added
|
||||
- Post Quantum encryption when using ZRTP
|
||||
- Conference creation with scheduling, video, different layouts, showing who is speaking and who is muted, etc...
|
||||
- Group calls directly from group chat rooms
|
||||
- Chat rooms can be individually muted (no notification when receiving a chat message)
|
||||
- Outgoing call video in early-media if requested by callee
|
||||
- Call recordings can be exported
|
||||
- Setting to prevent international prefix from account to be applied to call & chat
|
||||
- Add a "Never ask again" option to the "Link my account" pop-up when starting the app
|
||||
|
||||
### Changed
|
||||
- In-call views have been re-designed
|
||||
- Improved how contact avatars are generated
|
||||
- 3-dots menu even for basic chat rooms with more options
|
||||
- Update linphone SDK to 5.2.0
|
||||
|
||||
### Fixed
|
||||
- Chatroom appearing as empty when being logged on multiple accounts
|
||||
- Chatroom appearing as empty after playing a video file inside it
|
||||
- Fix potential crash when entering a chatroom
|
||||
- Fix potential crash when accessing to the delivery infos of a message in a group chat.
|
||||
- IMDN logo not properly displayed when transfering or replying to a message with media (voice message, photo...)
|
||||
- Clarified view when sending an image from the galery
|
||||
- Various audio route fixes for CallKit and IOS 16
|
||||
|
||||
## [4.6.4] - 2021-08-06
|
||||
## [4.6.4] - 2022-08-06
|
||||
### Changed
|
||||
- Update linphone SDK to 5.1.42
|
||||
|
||||
### Fixed
|
||||
- Prevent possible application freeze and crash when creating a new chatroom, depending on the phone's contacts.
|
||||
|
||||
## [4.6.3] - 2021-02-06
|
||||
## [4.6.3] - 2022-02-06
|
||||
|
||||
### Added
|
||||
- New "Contacts" menu in the settings, which allows the use of LDAP configurations
|
||||
|
|
@ -33,7 +79,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
- Display bug when changing audio device
|
||||
|
||||
|
||||
## [4.6.2] - 2021-07-03
|
||||
## [4.6.2] - 2022-07-03
|
||||
|
||||
### Fixed
|
||||
- Bug preventing the activation of the phone speaker during calls
|
||||
|
|
@ -41,7 +87,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
- Bug causing IMDNs to be missing in some chatrooms
|
||||
- Update linphone SDK to 5.1.7
|
||||
|
||||
## [4.6.1] - 2021-04-03
|
||||
## [4.6.1] - 2022-04-03
|
||||
|
||||
### Fixed
|
||||
- Crash in chatroom info view after entering background and re-entering foreground
|
||||
|
|
@ -49,7 +95,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
- Hard to see text (written in black) on dark mode
|
||||
- Removed duplicate push authorization request pop up on install
|
||||
|
||||
## [4.6.0] - 2021-31-02
|
||||
## [4.6.0] - 2022-31-02
|
||||
|
||||
### Added
|
||||
- Reply to chat message feature (with original message preview)
|
||||
|
|
|
|||
|
|
@ -127,7 +127,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
if (!mustRestoreView) {
|
||||
new_account = NULL;
|
||||
number_of_accounts_before = bctbx_list_size(linphone_core_get_account_list(LC));
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
number_of_accounts_before = bctbx_list_size(accounts);
|
||||
bctbx_free(accounts);
|
||||
[self resetTextFields];
|
||||
[self changeView:_welcomeView back:FALSE animation:FALSE];
|
||||
}
|
||||
|
|
@ -519,6 +521,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
#endif
|
||||
linphone_push_notification_config_set_provider(pushConfig, PROVIDER_NAME);
|
||||
|
||||
if (strcmp(creatorDomain, "sip.linphone.org")==0) {
|
||||
linphone_core_set_media_encryption(LC, LinphoneMediaEncryptionSRTP);
|
||||
}
|
||||
|
||||
new_account = linphone_core_create_account(LC, accountParams);
|
||||
linphone_account_params_unref(accountParams);
|
||||
|
||||
|
|
@ -705,7 +711,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
LinphoneAccount *default_account = linphone_core_create_account(LC, default_account_params);
|
||||
const char *identity = linphone_account_params_get_identity(linphone_account_get_params(default_account));
|
||||
if (identity) {
|
||||
LinphoneAddress *default_addr = linphone_core_interpret_url(LC, identity);
|
||||
LinphoneAddress *default_addr = linphone_core_interpret_url_2(LC, identity, false);
|
||||
if (default_addr) {
|
||||
const char *domain = linphone_address_get_domain(default_addr);
|
||||
const char *username = linphone_address_get_username(default_addr);
|
||||
|
|
@ -1011,10 +1017,13 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[LinphoneManager.instance lpConfigSetInt:[NSDate new].timeIntervalSince1970
|
||||
forKey:@"must_link_account_time"];
|
||||
[LinphoneManager.instance configurePushProviderForAccounts];
|
||||
if (number_of_accounts_before < bctbx_list_size(linphone_core_get_account_list(LC))) {
|
||||
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
if (number_of_accounts_before < bctbx_list_size(accounts)) {
|
||||
LOGI(@"A proxy config was set up with the remote provisioning, skip assistant");
|
||||
[self onDialerClick:nil];
|
||||
}
|
||||
bctbx_free(accounts);
|
||||
|
||||
_waitView.hidden = true;
|
||||
if (nextView == nil) {
|
||||
|
|
@ -1149,7 +1158,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_outgoingView = DialerView.compositeViewDescription;
|
||||
[self configureAccount];
|
||||
} else if (status == LinphoneAccountCreatorStatusAccountExist) {
|
||||
_outgoingView = AssistantLinkView.compositeViewDescription;
|
||||
if([LinphoneManager.instance lpConfigIntForKey:@"hide_link_phone_number"]){
|
||||
_outgoingView = DialerView.compositeViewDescription;
|
||||
}else{
|
||||
_outgoingView = AssistantLinkView.compositeViewDescription;
|
||||
}
|
||||
[self configureAccount];
|
||||
} else {
|
||||
if (resp) {
|
||||
|
|
@ -1584,10 +1597,11 @@ UIColor *previousColor = (UIColor*)[sender backgroundColor]; \
|
|||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[self presentViewController:errView animated:YES completion:nil];
|
||||
_waitView.hidden = TRUE;
|
||||
} else {
|
||||
linphone_core_set_provisioning_uri(LC, [self addSchemeToProvisiionninUriIMissing:[self findTextField:ViewElement_URL].text].UTF8String);
|
||||
[self resetLiblinphone:TRUE];
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -175,13 +175,13 @@
|
|||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KRQ-Fm-3cQ" userLabel="addedContacts" customClass="UICollectionView">
|
||||
<rect key="frame" x="8" y="110" width="398" height="70"/>
|
||||
<rect key="frame" x="8" y="110" width="398" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<accessibility key="accessibilityConfiguration" label="addedContacts"/>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" allowsSelectionDuringEditing="YES" allowsMultipleSelectionDuringEditing="YES" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="6">
|
||||
<rect key="frame" x="5" y="178" width="403" height="610"/>
|
||||
<rect key="frame" x="5" y="158" width="403" height="610"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<color key="separatorColor" red="0.67030966281890869" green="0.71867996454238892" blue="0.75078284740447998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XSI-9T-NtW" userLabel="addButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="382" y="4" width="24" height="21"/>
|
||||
<rect key="frame" x="382" y="2" width="24" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -218,7 +218,7 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="15" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="%@ is composing..." lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="fpY-Fv-ht2" userLabel="composeLabel">
|
||||
<rect key="frame" x="0.0" y="1" width="414" height="22"/>
|
||||
<rect key="frame" x="10" y="-5" width="406" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label=""/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
@ -364,7 +364,7 @@
|
|||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tjL-Vc-5gN" userLabel="encryptedButton">
|
||||
<rect key="frame" x="359" y="10" width="34" height="40"/>
|
||||
<rect key="frame" x="372" y="8" width="34" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="security_1_indicator.png"/>
|
||||
<connections>
|
||||
|
|
@ -608,7 +608,6 @@
|
|||
</state>
|
||||
<state key="selected" image="vr_on.png"/>
|
||||
<connections>
|
||||
<action selector="onPictureClick:" destination="-1" eventType="touchUpInside" id="qhP-B0-dkG"/>
|
||||
<action selector="onVrStart:" destination="-1" eventType="touchUpInside" id="yWJ-st-yz2"/>
|
||||
</connections>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
<connections>
|
||||
<outlet property="addButton" destination="6" id="91"/>
|
||||
<outlet property="allButton" destination="4" id="27"/>
|
||||
<outlet property="ldapMoreResultsLabel" destination="cDH-mL-cHP" id="3d9-gp-Hog"/>
|
||||
<outlet property="linphoneButton" destination="5" id="31"/>
|
||||
<outlet property="loadingLabel" destination="qSa-Ba-dq9" id="CPa-pO-OQD"/>
|
||||
<outlet property="loadingView" destination="CM2-Aq-Q3g" id="uie-SJ-TKf"/>
|
||||
|
|
@ -179,6 +180,14 @@
|
|||
<outlet property="delegate" destination="TJG-JZ-YRR" id="V1N-gI-U4J"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="More results are available, refine search to see them" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cDH-mL-cHP" userLabel="ldapMoreResultsLabel">
|
||||
<rect key="frame" x="8" y="110" width="359" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="No contact found in your address book" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JR3-k7-gVP" userLabel="emptyTableLabel">
|
||||
<rect key="frame" x="0.0" y="110" width="375" height="449"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
|
|
@ -187,7 +196,7 @@
|
|||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view hidden="YES" contentMode="scaleToFill" id="CM2-Aq-Q3g">
|
||||
<view hidden="YES" alpha="0.80000000000000004" contentMode="scaleToFill" id="CM2-Aq-Q3g">
|
||||
<rect key="frame" x="0.0" y="110" width="375" height="449"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
|
|
@ -209,7 +218,7 @@
|
|||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<point key="canvasLocation" x="6.5217391304347831" y="142.29910714285714"/>
|
||||
<point key="canvasLocation" x="5.7971014492753632" y="141.96428571428569"/>
|
||||
</view>
|
||||
<tableViewController id="TJG-JZ-YRR" userLabel="tableController" customClass="ContactsListTableView">
|
||||
<connections>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_0" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -11,6 +14,7 @@
|
|||
<outlet property="addressLabel" destination="EoB-ux-sD7" id="Ajw-2s-M6X"/>
|
||||
<outlet property="avatarImage" destination="23" id="43"/>
|
||||
<outlet property="backButton" destination="9" id="Pqj-y9-hqc"/>
|
||||
<outlet property="chatButton" destination="obZ-W7-q8P" id="96n-Oe-Gm0"/>
|
||||
<outlet property="contactLabel" destination="25" id="rTL-Ut-42o"/>
|
||||
<outlet property="emptyLabel" destination="hvz-CS-NME" id="Qws-r1-XMh"/>
|
||||
<outlet property="encryptedChatView" destination="JU4-bf-tVI" id="j6f-qz-VKd"/>
|
||||
|
|
@ -26,19 +30,19 @@
|
|||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="HKr-sq-hGv" userLabel="iphone6MetricsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4">
|
||||
<rect key="frame" x="0.0" y="42" width="667" height="267"/>
|
||||
<rect key="frame" x="-1" y="41" width="389" height="735"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view alpha="0.90000000000000002" tag="2" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6" userLabel="topBar">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="389" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" tag="4" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9" userLabel="backButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="128" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="74" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -50,7 +54,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="5" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="50" userLabel="addButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="539" y="0.0" width="128" height="66"/>
|
||||
<rect key="frame" x="314" y="0.0" width="75" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Add to contact"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -62,14 +66,14 @@
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||
</view>
|
||||
<view tag="7" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="33" userLabel="headerView">
|
||||
<rect key="frame" x="0.0" y="66" width="667" height="250"/>
|
||||
<rect key="frame" x="0.0" y="66" width="389" height="250"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" tag="8" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="23" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<rect key="frame" x="244" y="8" width="178" height="100"/>
|
||||
<rect key="frame" x="141" y="8" width="104" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact avatar">
|
||||
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
|
||||
|
|
@ -77,7 +81,7 @@
|
|||
</accessibility>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="9" contentMode="left" fixedFrame="YES" text="John Doe" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="25" userLabel="contactLabel">
|
||||
<rect key="frame" x="0.0" y="110" width="667" height="40"/>
|
||||
<rect key="frame" x="0.0" y="110" width="389" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="33"/>
|
||||
|
|
@ -85,7 +89,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" tag="10" contentMode="scaleAspectFit" fixedFrame="YES" image="linphone_user.png" translatesAutoresizingMaskIntoConstraints="NO" id="mfN-Ai-9RX" userLabel="linphoneImage" customClass="UIRoundedImageView">
|
||||
<rect key="frame" x="642" y="124" width="15" height="15"/>
|
||||
<rect key="frame" x="363" y="124" width="16" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact avatar">
|
||||
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
|
||||
|
|
@ -93,7 +97,7 @@
|
|||
</accessibility>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="11" contentMode="left" fixedFrame="YES" text="johndoe@sip.linphone.org" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="EoB-ux-sD7" userLabel="addressLabel">
|
||||
<rect key="frame" x="0.0" y="158" width="667" height="23"/>
|
||||
<rect key="frame" x="0.0" y="158" width="389" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
|
|
@ -101,11 +105,11 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="k0D-99-OKO" userLabel="optionsView">
|
||||
<rect key="frame" x="0.0" y="189" width="667" height="44"/>
|
||||
<rect key="frame" x="0.0" y="189" width="389" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" tag="13" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5eX-W0-T4B" userLabel="callButton">
|
||||
<rect key="frame" x="179" y="0.0" width="51" height="51"/>
|
||||
<rect key="frame" x="98" y="0.0" width="51" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="call_start_body_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -117,7 +121,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="12" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="obZ-W7-q8P" userLabel="chatButton">
|
||||
<rect key="frame" x="317" y="0.0" width="50" height="51"/>
|
||||
<rect key="frame" x="174" y="0.0" width="50" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="chat_start_body_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -129,11 +133,11 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JU4-bf-tVI" userLabel="encryptedChatView">
|
||||
<rect key="frame" x="456" y="-1" width="50" height="51"/>
|
||||
<rect key="frame" x="251" y="-2" width="49" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="E2n-mF-saI" userLabel="encryptedChatButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="-1" y="0.0" width="51" height="51"/>
|
||||
<rect key="frame" x="0.0" y="-2" width="51" height="53"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Chat"/>
|
||||
<state key="normal" image="chat_start_body_default.png">
|
||||
|
|
@ -154,35 +158,35 @@
|
|||
</subviews>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" tag="6" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="30" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="k6N-Av-eOu">
|
||||
<rect key="frame" x="0.0" y="316" width="667" height="0.0"/>
|
||||
<rect key="frame" x="0.0" y="316" width="389" height="419"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="baU-d4-eu3" id="p7o-Mx-Kmc"/>
|
||||
<outlet property="delegate" destination="baU-d4-eu3" id="iS5-xg-0C2"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" tag="40" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="No log selected" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hvz-CS-NME" userLabel="emptyLabel">
|
||||
<rect key="frame" x="0.0" y="66" width="667" height="201"/>
|
||||
<rect key="frame" x="0.0" y="65" width="389" height="670"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view hidden="YES" tag="8" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dEJ-xc-518" userLabel="waitView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="267"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="389" height="735"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" tag="9" contentMode="scaleToFill" fixedFrame="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="NK3-ME-9jd" userLabel="activityIndicatorView">
|
||||
<rect key="frame" x="326" y="122" width="20" height="20"/>
|
||||
<rect key="frame" x="186" y="352" width="20" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<gestureRecognizers/>
|
||||
</view>
|
||||
</subviews>
|
||||
|
|
@ -193,23 +197,23 @@
|
|||
<point key="canvasLocation" x="-3.2000000000000002" y="22.488755622188908"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="LBc-mh-ozk" userLabel="iphone6MetricsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NHC-7w-48z">
|
||||
<rect key="frame" x="0.0" y="42" width="667" height="333"/>
|
||||
<rect key="frame" x="-2" y="42" width="391" height="800"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view tag="2" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rtv-hu-bCz" userLabel="topBar">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="391" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" tag="3" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="imageView:JOe-5t-C7f:image" translatesAutoresizingMaskIntoConstraints="NO" id="JOe-5t-C7f" userLabel="backgroundColor">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="391" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<button opaque="NO" tag="4" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NJl-Lb-CU6" userLabel="backButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="71" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="41" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -221,7 +225,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="5" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="O7r-6t-b7w" userLabel="addButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="594" y="0.0" width="73" height="66"/>
|
||||
<rect key="frame" x="346" y="0.0" width="45" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Add to contact"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -235,7 +239,7 @@
|
|||
</subviews>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" tag="6" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="30" sectionHeaderHeight="44" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="2jK-gw-ULv">
|
||||
<rect key="frame" x="0.0" y="168" width="667" height="165"/>
|
||||
<rect key="frame" x="0.0" y="167" width="391" height="633"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
|
|
@ -244,11 +248,11 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<view tag="7" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Mwp-y3-g1b" userLabel="headerView">
|
||||
<rect key="frame" x="0.0" y="66" width="667" height="102"/>
|
||||
<rect key="frame" x="0.0" y="66" width="391" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" tag="8" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="d9m-G0-1u3" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<rect key="frame" x="28" y="8" width="88" height="86"/>
|
||||
<rect key="frame" x="16" y="8" width="51" height="86"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact avatar">
|
||||
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
|
||||
|
|
@ -256,7 +260,7 @@
|
|||
</accessibility>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="9" contentMode="left" fixedFrame="YES" text="John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Qbg-hm-bd7" userLabel="contactLabel">
|
||||
<rect key="frame" x="160" y="8" width="356" height="50"/>
|
||||
<rect key="frame" x="94" y="8" width="207" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="33"/>
|
||||
|
|
@ -264,7 +268,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="11" contentMode="left" fixedFrame="YES" text="johndoe@sip.linphone.org" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="XJa-f6-K0y" userLabel="addressLabel">
|
||||
<rect key="frame" x="160" y="56" width="356" height="38"/>
|
||||
<rect key="frame" x="94" y="54" width="207" height="39"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||
|
|
@ -272,11 +276,11 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="teU-AB-8hO" userLabel="optionsView">
|
||||
<rect key="frame" x="0.0" y="29" width="667" height="44"/>
|
||||
<rect key="frame" x="0.0" y="29" width="391" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" tag="13" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pBo-Oo-bAW" userLabel="callButton">
|
||||
<rect key="frame" x="491" y="0.0" width="51" height="51"/>
|
||||
<rect key="frame" x="271" y="0.0" width="51" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="call_start_body_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -288,7 +292,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="12" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iDG-Mn-jm2" userLabel="chatButton">
|
||||
<rect key="frame" x="551" y="0.0" width="51" height="51"/>
|
||||
<rect key="frame" x="303" y="0.0" width="51" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="chat_start_body_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -300,11 +304,11 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="m90-u6-x3J" userLabel="encryptedChatView">
|
||||
<rect key="frame" x="611" y="0.0" width="51" height="51"/>
|
||||
<rect key="frame" x="336" y="-1" width="51" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8fY-hz-ECC" userLabel="encryptedChatButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="51" height="51"/>
|
||||
<rect key="frame" x="0.0" y="-2" width="51" height="53"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Chat"/>
|
||||
<state key="normal" image="chat_start_body_default.png">
|
||||
|
|
@ -325,7 +329,7 @@
|
|||
</subviews>
|
||||
</view>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" tag="10" contentMode="scaleAspectFit" fixedFrame="YES" image="linphone_user.png" translatesAutoresizingMaskIntoConstraints="NO" id="G2O-Yh-fZA" userLabel="linphoneImage">
|
||||
<rect key="frame" x="123" y="8" width="30" height="25"/>
|
||||
<rect key="frame" x="71" y="8" width="19" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact avatar">
|
||||
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
|
||||
|
|
@ -336,7 +340,7 @@
|
|||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" tag="40" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="No log selected" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IHY-Yg-pkN" userLabel="emptyLabel">
|
||||
<rect key="frame" x="0.0" y="66" width="667" height="267"/>
|
||||
<rect key="frame" x="0.0" y="65" width="391" height="735"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
@ -344,11 +348,11 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view hidden="YES" tag="8" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="X29-vB-VIz" userLabel="waitView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="333"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="391" height="800"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" tag="9" contentMode="scaleToFill" fixedFrame="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="7l5-ZU-CbW" userLabel="activityIndicatorView">
|
||||
<rect key="frame" x="326" y="155" width="20" height="20"/>
|
||||
<rect key="frame" x="185" y="385" width="21" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
|
|
@ -384,106 +388,113 @@
|
|||
<image name="contact_add_disabled.png" width="55.200000762939453" height="47.200000762939453"/>
|
||||
<image name="imageView:JOe-5t-C7f:image" width="2" height="2">
|
||||
<mutableData key="keyedArchiveRepresentation">
|
||||
YnBsaXN0MDDUAQIDBAUGUlNYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK8QEQcI
|
||||
ERYbHCAhKCsuOEBESExPVSRudWxs1AkKCwwNDg8QViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05T
|
||||
Q29sb3KAEBIAwAAAgAKACtISCRMVWk5TLm9iamVjdHOhFIADgAnSEgkXGqIYGYAEgAWACBAA0h0JHh9f
|
||||
EBROU1RJRkZSZXByZXNlbnRhdGlvboAGgAdPEQI+TU0AKgAAAAzh4eHhAA8BAAADAAAAAQACAAABAQAD
|
||||
AAAAAQACAAABAgADAAAAAQAIAAABAwADAAAAAQABAAABBgADAAAAAQABAAABCgADAAAAAQABAAABEQAE
|
||||
AAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQABAAABFgADAAAAAQACAAABFwAEAAAAAQAAAAQBHAAD
|
||||
AAAAAQABAAABKAADAAAAAQACAAABUwADAAAAAQABAACHcwAHAAABeAAAAMYAAAAAAAABeGFwcGwCEAAA
|
||||
bW50ckdSQVlYWVogB9UABwABAAAAAAAAYWNzcEFQUEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPbW
|
||||
AAEAAAAA0y1hcHBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE
|
||||
ZGVzYwAAALQAAAB1Y3BydAAAASwAAAAnd3RwdAAAAVQAAAAUa1RSQwAAAWgAAAAOZGVzYwAAAAAAAAAb
|
||||
Q2FsaWJyYXRlZCBHcmF5IENvbG9yc3BhY2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdGV4dAAAAABDb3B5
|
||||
cmlnaHQgQXBwbGUgQ29tcHV0ZXIsIEluYy4AAFhZWiAAAAAAAADzUQABAAAAARbMY3VydgAAAAAAAAAB
|
||||
AjMAANIiIyQlWiRjbGFzc25hbWVYJGNsYXNzZXNfEBBOU0JpdG1hcEltYWdlUmVwoyQmJ1pOU0ltYWdl
|
||||
UmVwWE5TT2JqZWN00iIjKSpXTlNBcnJheaIpJ9IiIywtXk5TTXV0YWJsZUFycmF5oywpJ9UvMDEyCTM0
|
||||
NTY3V05TV2hpdGVcTlNDb21wb25lbnRzXE5TQ29sb3JTcGFjZV8QEk5TQ3VzdG9tQ29sb3JTcGFjZUQw
|
||||
IDAAQzAgMBADgAuAD9Q5OjsJPD0+P1ROU0lEVU5TSUNDV05TTW9kZWwQCYAMEACADtJBCUJDV05TLmRh
|
||||
dGFPERFoAAARaGFwcGwCAAAAbW50ckdSQVlYWVogB9wACAAXAA8ALgAPYWNzcEFQUEwAAAAAbm9uZQAA
|
||||
AAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAFZGVzYwAAAMAAAAB5ZHNjbQAAATwAAAfoY3BydAAACSQAAAAjd3RwdAAA
|
||||
CUgAAAAUa1RSQwAACVwAAAgMZGVzYwAAAAAAAAAfR2VuZXJpYyBHcmF5IEdhbW1hIDIuMiBQcm9maWxl
|
||||
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05T
|
||||
S2V5ZWRBcmNoaXZlctEICVRyb290gAGvEBALDBccEyEmJy4xND5GR0tOVSRudWxs1Q0ODxAREhMUFRZW
|
||||
JGNsYXNzXk5TUmVzaXppbmdNb2RlXE5TSW1hZ2VGbGFnc1ZOU1JlcHNXTlNDb2xvcoAPEAASAMAAAIAC
|
||||
gArSGA0ZG1pOUy5vYmplY3RzoRqAA4AJ0hgNHSCiHh+ABIAFgAjTDSIjJCUTXxAUTlNUSUZGUmVwcmVz
|
||||
ZW50YXRpb25fEBlOU0ludGVybmFsTGF5b3V0RGlyZWN0aW9ugAeABk8RAj5NTQAqAAAADOHh4eEADwEA
|
||||
AAMAAAABAAIAAAEBAAMAAAABAAIAAAECAAMAAAABAAgAAAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAEK
|
||||
AAMAAAABAAEAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAEAAAEWAAMAAAABAAIAAAEX
|
||||
AAQAAAABAAAABAEcAAMAAAABAAEAAAEoAAMAAAABAAIAAAFTAAMAAAABAAEAAIdzAAcAAAF4AAAAxgAA
|
||||
AAAAAAF4YXBwbAIQAABtbnRyR1JBWVhZWiAH1QAHAAEAAAAAAABhY3NwQVBQTAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAARkZXNjAAAAtAAAAHVjcHJ0AAABLAAAACd3dHB0AAABVAAAABRrVFJDAAABaAAA
|
||||
AA5kZXNjAAAAAAAAABtDYWxpYnJhdGVkIEdyYXkgQ29sb3JzcGFjZQAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1sdWMAAAAAAAAAHwAAAAxza1NLAAAALgAAAYRkYURLAAAAOAAA
|
||||
AbJjYUVTAAAAOAAAAep2aVZOAAAAQAAAAiJwdEJSAAAASgAAAmJ1a1VBAAAALAAAAqxmckZVAAAAPgAA
|
||||
AthodUhVAAAANAAAAxZ6aFRXAAAAHgAAA0puYk5PAAAAOgAAA2hjc0NaAAAAKAAAA6JoZUlMAAAAJAAA
|
||||
A8ppdElUAAAATgAAA+5yb1JPAAAAKgAABDxkZURFAAAATgAABGZrb0tSAAAAIgAABLRzdlNFAAAAOAAA
|
||||
AbJ6aENOAAAAHgAABNZqYUpQAAAAJgAABPRlbEdSAAAAKgAABRpwdFBPAAAAUgAABURubE5MAAAAQAAA
|
||||
BZZlc0VTAAAATAAABdZ0aFRIAAAAMgAABiJ0clRSAAAAJAAABlRmaUZJAAAARgAABnhockhSAAAAPgAA
|
||||
Br5wbFBMAAAASgAABvxydVJVAAAAOgAAB0ZlblVTAAAAPAAAB4BhckVHAAAALAAAB7wAVgFhAGUAbwBi
|
||||
AGUAYwBuAOEAIABzAGkAdgDhACAAZwBhAG0AYQAgADIALAAyAEcAZQBuAGUAcgBpAHMAawAgAGcAcgDl
|
||||
ACAAMgAsADIAIABnAGEAbQBtAGEAcAByAG8AZgBpAGwARwBhAG0AbQBhACAAZABlACAAZwByAGkAcwBv
|
||||
AHMAIABnAGUAbgDoAHIAaQBjAGEAIAAyAC4AMgBDHqUAdQAgAGgA7ABuAGgAIABNAOAAdQAgAHgA4QBt
|
||||
ACAAQwBoAHUAbgBnACAARwBhAG0AbQBhACAAMgAuADIAUABlAHIAZgBpAGwAIABHAGUAbgDpAHIAaQBj
|
||||
AG8AIABkAGEAIABHAGEAbQBhACAAZABlACAAQwBpAG4AegBhAHMAIAAyACwAMgQXBDAEMwQwBDsETAQ9
|
||||
BDAAIABHAHIAYQB5AC0EMwQwBDwEMAAgADIALgAyAFAAcgBvAGYAaQBsACAAZwDpAG4A6QByAGkAcQB1
|
||||
AGUAIABnAHIAaQBzACAAZwBhAG0AbQBhACAAMgAsADIAwQBsAHQAYQBsAOEAbgBvAHMAIABzAHoA/ABy
|
||||
AGsAZQAgAGcAYQBtAG0AYQAgADIALgAykBp1KHBwlo5RSV6mACAAMgAuADIAIIJyX2ljz4/wAEcAZQBu
|
||||
AGUAcgBpAHMAawAgAGcAcgDlACAAZwBhAG0AbQBhACAAMgAsADIALQBwAHIAbwBmAGkAbABPAGIAZQBj
|
||||
AG4A4QAgAWEAZQBkAOEAIABnAGEAbQBhACAAMgAuADIF0gXQBd4F1AAgBdAF5AXVBegAIAXbBdwF3AXZ
|
||||
ACAAMgAuADIAUAByAG8AZgBpAGwAbwAgAGcAcgBpAGcAaQBvACAAZwBlAG4AZQByAGkAYwBvACAAZABl
|
||||
AGwAbABhACAAZwBhAG0AbQBhACAAMgAsADIARwBhAG0AYQAgAGcAcgBpACAAZwBlAG4AZQByAGkAYwED
|
||||
ACAAMgAsADIAQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQAdQBmAGUAbgAtAFAAcgBv
|
||||
AGYAaQBsACAARwBhAG0AbQBhACAAMgAsADLHfLwYACDWjMDJACCsELnIACAAMgAuADIAINUEuFzTDMd8
|
||||
Zm6QGnBwXqZ8+2VwACAAMgAuADIAIGPPj/Blh072TgCCLDCwMOwwpDCsMPMw3gAgADIALgAyACAw1zDt
|
||||
MNUwoTCkMOsDkwO1A70DuQO6A8wAIAOTA7oDwQO5ACADkwOsA7wDvAOxACAAMgAuADIAUABlAHIAZgBp
|
||||
AGwAIABnAGUAbgDpAHIAaQBjAG8AIABkAGUAIABjAGkAbgB6AGUAbgB0AG8AcwAgAGQAYQAgAEcAYQBt
|
||||
AG0AYQAgADIALAAyAEEAbABnAGUAbQBlAGUAbgAgAGcAcgBpAGoAcwAgAGcAYQBtAG0AYQAgADIALAAy
|
||||
AC0AcAByAG8AZgBpAGUAbABQAGUAcgBmAGkAbAAgAGcAZQBuAOkAcgBpAGMAbwAgAGQAZQAgAGcAYQBt
|
||||
AG0AYQAgAGQAZQAgAGcAcgBpAHMAZQBzACAAMgAsADIOIw4xDgcOKg41DkEOAQ4hDiEOMg5ADgEOIw4i
|
||||
DkwOFw4xDkgOJw5EDhsAIAAyAC4AMgBHAGUAbgBlAGwAIABHAHIAaQAgAEcAYQBtAGEAIAAyACwAMgBZ
|
||||
AGwAZQBpAG4AZQBuACAAaABhAHIAbQBhAGEAbgAgAGcAYQBtAG0AYQAgADIALAAyACAALQBwAHIAbwBm
|
||||
AGkAaQBsAGkARwBlAG4AZQByAGkBDQBrAGkAIABHAHIAYQB5ACAARwBhAG0AbQBhACAAMgAuADIAIABw
|
||||
AHIAbwBmAGkAbABVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBmAGkAbAAgAHMAegBhAHIAbwFb
|
||||
AGMAaQAgAGcAYQBtAG0AYQAgADIALAAyBB4EMQRJBDAETwAgBEEENQRABDAETwAgBDMEMAQ8BDwEMAAg
|
||||
ADIALAAyAC0EPwRABD4ERAQ4BDsETABHAGUAbgBlAHIAaQBjACAARwByAGEAeQAgAEcAYQBtAG0AYQAg
|
||||
ADIALgAyACAAUAByAG8AZgBpAGwAZQY6BicGRQYnACAAMgAuADIAIAZEBkgGRgAgBjEGRQYnBi8GSgAg
|
||||
BjkGJwZFdGV4dAAAAABDb3B5cmlnaHQgQXBwbGUgSW5jLiwgMjAxMgAAWFlaIAAAAAAAAPNRAAEAAAAB
|
||||
FsxjdXJ2AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABt
|
||||
AHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEH
|
||||
AQ0BEwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZ
|
||||
AeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1
|
||||
AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7BEgEVQRj
|
||||
BHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYn
|
||||
BjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgLCB8IMghG
|
||||
CFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrF
|
||||
CtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2p
|
||||
DcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1
|
||||
ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixSt
|
||||
FM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjV
|
||||
GPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1w
|
||||
HZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKC
|
||||
Iq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgN
|
||||
KD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4W
|
||||
Lkwugi63Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSe
|
||||
NNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuq
|
||||
O+g8JzxlPKQ84z0iPWE9oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6
|
||||
Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtT
|
||||
S5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2
|
||||
VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0n
|
||||
XXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmbo
|
||||
Zz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6
|
||||
cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwh
|
||||
fIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZyhteHO4ef
|
||||
iASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2
|
||||
lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBp
|
||||
oNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24
|
||||
ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7Lrun
|
||||
vCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4
|
||||
yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls
|
||||
2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG
|
||||
6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH
|
||||
+lf65/t3/Af8mP0p/br+S/7c/23//4AN0iIjRUZdTlNNdXRhYmxlRGF0YaNFRydWTlNEYXRh0iIjSUpc
|
||||
TlNDb2xvclNwYWNloksnXE5TQ29sb3JTcGFjZdIiI01OV05TQ29sb3KiTSfSIiNQUVdOU0ltYWdlolAn
|
||||
XxAPTlNLZXllZEFyY2hpdmVy0VRVVHJvb3SAAQAIABEAGgAjAC0AMgA3AEsAUQBaAGEAbgB1AH0AfwCE
|
||||
AIYAiACNAJgAmgCcAJ4AowCmAKgAqgCsAK4AswDKAMwAzgMQAxUDIAMpAzwDQANLA1QDWQNhA2QDaQN4
|
||||
A3wDhwOPA5wDqQO+A8MDxwPJA8sDzQPWA9sD4QPpA+sD7QPvA/ED9gP+FWoVbBVxFX8VgxWKFY8VnBWf
|
||||
FawVsRW5FbwVwRXJFcwV3hXhFeYAAAAAAAACAQAAAAAAAABWAAAAAAAAAAAAAAAAAAAV6A
|
||||
AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLgAAWFlaIAAAAAAAAPNRAAEAAAAB
|
||||
FsxjdXJ2AAAAAAAAAAECMwAA0igpKitaJGNsYXNzbmFtZVgkY2xhc3Nlc18QEE5TQml0bWFwSW1hZ2VS
|
||||
ZXCjKiwtWk5TSW1hZ2VSZXBYTlNPYmplY3TSKCkvMFdOU0FycmF5oi8t0igpMjNeTlNNdXRhYmxlQXJy
|
||||
YXmjMi8t1TU2NzgNOTo7PD1XTlNXaGl0ZVxOU0NvbXBvbmVudHNcTlNDb2xvclNwYWNlXxASTlNDdXN0
|
||||
b21Db2xvclNwYWNlRDAgMABDMCAwEAOAC4AO1D9AQQ1CQ0RFVE5TSURVTlNJQ0NXTlNNb2RlbBAJgAwQ
|
||||
AIANTxERnAAAEZxhcHBsAgAAAG1udHJHUkFZWFlaIAfcAAgAFwAPAC4AD2Fjc3BBUFBMAAAAAG5vbmUA
|
||||
AAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMtYXBwbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAABWRlc2MAAADAAAAAeWRzY20AAAE8AAAIGmNwcnQAAAlYAAAAI3d0cHQA
|
||||
AAl8AAAAFGtUUkMAAAmQAAAIDGRlc2MAAAAAAAAAH0dlbmVyaWMgR3JheSBHYW1tYSAyLjIgUHJvZmls
|
||||
ZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAB8AAAAMc2tTSwAAAC4AAAGEZGFESwAAADoA
|
||||
AAGyY2FFUwAAADgAAAHsdmlWTgAAAEAAAAIkcHRCUgAAAEoAAAJkdWtVQQAAACwAAAKuZnJGVQAAAD4A
|
||||
AALaaHVIVQAAADQAAAMYemhUVwAAABoAAANMa29LUgAAACIAAANmbmJOTwAAADoAAAOIY3NDWgAAACgA
|
||||
AAPCaGVJTAAAACQAAAPqcm9STwAAACoAAAQOZGVERQAAAE4AAAQ4aXRJVAAAAE4AAASGc3ZTRQAAADgA
|
||||
AATUemhDTgAAABoAAAUMamFKUAAAACYAAAUmZWxHUgAAACoAAAVMcHRQTwAAAFIAAAV2bmxOTAAAAEAA
|
||||
AAXIZXNFUwAAAEwAAAYIdGhUSAAAADIAAAZUdHJUUgAAACQAAAaGZmlGSQAAAEYAAAaqaHJIUgAAAD4A
|
||||
AAbwcGxQTAAAAEoAAAcuYXJFRwAAACwAAAd4cnVSVQAAADoAAAekZW5VUwAAADwAAAfeAFYBYQBlAG8A
|
||||
YgBlAGMAbgDhACAAcwBpAHYA4QAgAGcAYQBtAGEAIAAyACwAMgBHAGUAbgBlAHIAaQBzAGsAIABnAHIA
|
||||
5QAgADIALAAyACAAZwBhAG0AbQBhAC0AcAByAG8AZgBpAGwARwBhAG0AbQBhACAAZABlACAAZwByAGkA
|
||||
cwBvAHMAIABnAGUAbgDoAHIAaQBjAGEAIAAyAC4AMgBDHqUAdQAgAGgA7ABuAGgAIABNAOAAdQAgAHgA
|
||||
4QBtACAAQwBoAHUAbgBnACAARwBhAG0AbQBhACAAMgAuADIAUABlAHIAZgBpAGwAIABHAGUAbgDpAHIA
|
||||
aQBjAG8AIABkAGEAIABHAGEAbQBhACAAZABlACAAQwBpAG4AegBhAHMAIAAyACwAMgQXBDAEMwQwBDsE
|
||||
TAQ9BDAAIABHAHIAYQB5AC0EMwQwBDwEMAAgADIALgAyAFAAcgBvAGYAaQBsACAAZwDpAG4A6QByAGkA
|
||||
cQB1AGUAIABnAHIAaQBzACAAZwBhAG0AbQBhACAAMgAsADIAwQBsAHQAYQBsAOEAbgBvAHMAIABzAHoA
|
||||
/AByAGsAZQAgAGcAYQBtAG0AYQAgADIALgAykBp1KHBwlo5RSV6mADIALgAygnJfaWPPj/DHfLwYACDW
|
||||
jMDJACCsELnIACAAMgAuADIAINUEuFzTDMd8AEcAZQBuAGUAcgBpAHMAawAgAGcAcgDlACAAZwBhAG0A
|
||||
bQBhACAAMgAsADIALQBwAHIAbwBmAGkAbABPAGIAZQBjAG4A4QAgAWEAZQBkAOEAIABnAGEAbQBhACAA
|
||||
MgAuADIF0gXQBd4F1AAgBdAF5AXVBegAIAXbBdwF3AXZACAAMgAuADIARwBhAG0AYQAgAGcAcgBpACAA
|
||||
ZwBlAG4AZQByAGkAYwEDACAAMgAsADIAQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQA
|
||||
dQBmAGUAbgAtAFAAcgBvAGYAaQBsACAARwBhAG0AbQBhACAAMgAsADIAUAByAG8AZgBpAGwAbwAgAGcA
|
||||
cgBpAGcAaQBvACAAZwBlAG4AZQByAGkAYwBvACAAZABlAGwAbABhACAAZwBhAG0AbQBhACAAMgAsADIA
|
||||
RwBlAG4AZQByAGkAcwBrACAAZwByAOUAIAAyACwAMgAgAGcAYQBtAG0AYQBwAHIAbwBmAGkAbGZukBpw
|
||||
cF6mfPtlcAAyAC4AMmPPj/Blh072TgCCLDCwMOwwpDCsMPMw3gAgADIALgAyACAw1zDtMNUwoTCkMOsD
|
||||
kwO1A70DuQO6A8wAIAOTA7oDwQO5ACADkwOsA7wDvAOxACAAMgAuADIAUABlAHIAZgBpAGwAIABnAGUA
|
||||
bgDpAHIAaQBjAG8AIABkAGUAIABjAGkAbgB6AGUAbgB0AG8AcwAgAGQAYQAgAEcAYQBtAG0AYQAgADIA
|
||||
LAAyAEEAbABnAGUAbQBlAGUAbgAgAGcAcgBpAGoAcwAgAGcAYQBtAG0AYQAgADIALAAyAC0AcAByAG8A
|
||||
ZgBpAGUAbABQAGUAcgBmAGkAbAAgAGcAZQBuAOkAcgBpAGMAbwAgAGQAZQAgAGcAYQBtAG0AYQAgAGQA
|
||||
ZQAgAGcAcgBpAHMAZQBzACAAMgAsADIOIw4xDgcOKg41DkEOAQ4hDiEOMg5ADgEOIw4iDkwOFw4xDkgO
|
||||
Jw5EDhsAIAAyAC4AMgBHAGUAbgBlAGwAIABHAHIAaQAgAEcAYQBtAGEAIAAyACwAMgBZAGwAZQBpAG4A
|
||||
ZQBuACAAaABhAHIAbQBhAGEAbgAgAGcAYQBtAG0AYQAgADIALAAyACAALQBwAHIAbwBmAGkAaQBsAGkA
|
||||
RwBlAG4AZQByAGkBDQBrAGkAIABHAHIAYQB5ACAARwBhAG0AbQBhACAAMgAuADIAIABwAHIAbwBmAGkA
|
||||
bABVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBmAGkAbAAgAHMAegBhAHIAbwFbAGMAaQAgAGcA
|
||||
YQBtAG0AYQAgADIALAAyBjoGJwZFBicAIAAyAC4AMgAgBkQGSAZGACAGMQZFBicGLwZKACAGOQYnBkUE
|
||||
HgQxBEkEMARPACAEQQQ1BEAEMARPACAEMwQwBDwEPAQwACAAMgAsADIALQQ/BEAEPgREBDgEOwRMAEcA
|
||||
ZQBuAGUAcgBpAGMAIABHAHIAYQB5ACAARwBhAG0AbQBhACAAMgAuADIAIABQAHIAbwBmAGkAbABlAAB0
|
||||
ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDEyAABYWVogAAAAAAAA81EAAQAAAAEWzGN1cnYA
|
||||
AAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwA
|
||||
gQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkB
|
||||
HwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB
|
||||
+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYD
|
||||
IQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwE
|
||||
mgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkG
|
||||
agZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIII
|
||||
lgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsL
|
||||
Igs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgO
|
||||
Ew4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8R
|
||||
bRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIV
|
||||
NBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZ
|
||||
axmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHewe
|
||||
Fh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwoj
|
||||
OCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo
|
||||
1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu
|
||||
7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01
|
||||
hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8
|
||||
pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANE
|
||||
R0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpM
|
||||
cky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtV
|
||||
KFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpe
|
||||
bF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+lo
|
||||
P2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwckty
|
||||
pnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9
|
||||
oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6J
|
||||
M4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSV
|
||||
X5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobai
|
||||
JqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxav
|
||||
i7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9
|
||||
j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bM
|
||||
Ncy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvb
|
||||
gNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXr
|
||||
cOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8
|
||||
B/yY/Sn9uv5L/tz/bf//0igpSElcTlNDb2xvclNwYWNlokotXE5TQ29sb3JTcGFjZdIoKUxNV05TQ29s
|
||||
b3KiTC3SKClPUFdOU0ltYWdlok8tAAgAEQAaACQAKQAyADcASQBMAFEAUwBmAGwAdwB+AI0AmgChAKkA
|
||||
qwCtALIAtAC2ALsAxgDIAMoAzADRANQA1gDYANoA4QD4ARQBFgEYA1oDXwNqA3MDhgOKA5UDngOjA6sD
|
||||
rgOzA8IDxgPRA9kD5gPzBAgEDQQRBBMEFQQXBCAEJQQrBDMENQQ3BDkEOxXbFeAV7RXwFf0WAhYKFg0W
|
||||
EhYaAAAAAAAAAgEAAAAAAAAAUQAAAAAAAAAAAAAAAAAAFh0
|
||||
</mutableData>
|
||||
</image>
|
||||
<image name="linphone_user.png" width="41.599998474121094" height="42.400001525878906"/>
|
||||
<image name="security_toogle_icon_green.png" width="33.599998474121094" height="38.400001525878906"/>
|
||||
<systemColor name="secondarySystemBackgroundColor">
|
||||
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -29,15 +29,15 @@
|
|||
@property(nonatomic, strong) NSMutableArray *addresses;
|
||||
@property(nonatomic, strong) NSMutableArray *phoneOrAddr;
|
||||
@property(nonatomic, strong) NSMutableArray *addressesCached;
|
||||
@property(readonly, nonatomic) NSMutableDictionary *ldapContactAddressBookMap;
|
||||
@property(readonly, nonatomic) NSMutableDictionary *ldapAndProvisioningContactAddressBookMap;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ChatConversationCreateTableView
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
if (!_ldapContactAddressBookMap) {
|
||||
_ldapContactAddressBookMap = [NSMutableDictionary dictionary];
|
||||
if (!_ldapAndProvisioningContactAddressBookMap) {
|
||||
_ldapAndProvisioningContactAddressBookMap = [NSMutableDictionary dictionary];
|
||||
}
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
|
|
@ -57,7 +57,7 @@
|
|||
|
||||
_addresses = [[NSMutableArray alloc] initWithCapacity:LinphoneManager.instance.fastAddressBook.addressBookMap.allKeys.count];
|
||||
_phoneOrAddr = [[NSMutableArray alloc] initWithCapacity:LinphoneManager.instance.fastAddressBook.addressBookMap.allKeys.count];
|
||||
_addressesCached = [[NSMutableArray alloc] initWithCapacity:LinphoneManager.instance.fastAddressBook.addressBookMap.allKeys.count];
|
||||
_addressesCached = [[NSMutableArray alloc] initWithCapacity:LinphoneManager.instance.fastAddressBook.addressBookMap.allKeys.count];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
|
|
@ -97,64 +97,76 @@
|
|||
_loadingView.hidden = TRUE;
|
||||
}
|
||||
|
||||
-(BOOL) isSecureChatable:(const LinphoneFriend*)friend {
|
||||
if (!friend)
|
||||
return false;
|
||||
const LinphonePresenceModel *model = linphone_friend_get_presence_model(friend);
|
||||
return model && linphone_presence_model_has_capability(model, LinphoneFriendCapabilityLimeX3dh);
|
||||
}
|
||||
|
||||
- (void) buildChatContactTable {
|
||||
|
||||
bctbx_list_t *results = [MagicSearchSingleton.instance getLastSearchResults];
|
||||
while (results) {
|
||||
|
||||
LinphoneSearchResult *result = results->data;
|
||||
bctbx_list_t *result_list = [MagicSearchSingleton.instance getLastSearchResults];
|
||||
bctbx_list_t *it;
|
||||
LinphoneAccount *account = linphone_core_get_default_account(LC);
|
||||
|
||||
for (it = result_list; it != NULL; it = it->next) {
|
||||
LinphoneSearchResult *result = it->data;
|
||||
const LinphoneAddress *addr = linphone_search_result_get_address(result);
|
||||
const LinphoneFriend* friend = linphone_search_result_get_friend(result);
|
||||
const char *phoneNumber = linphone_search_result_get_phone_number(result);
|
||||
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"force_lime_chat_rooms"] && ![self isSecureChatable:friend]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *phoneNumber = NULL;
|
||||
Contact *contact = nil;
|
||||
char *uri = nil;
|
||||
NSString *address = nil;
|
||||
|
||||
if (addr) {
|
||||
uri = linphone_address_as_string_uri_only(addr);
|
||||
address = [NSString stringWithUTF8String:uri];
|
||||
contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:[FastAddressBook normalizeSipURI:address]];
|
||||
}
|
||||
|
||||
const LinphoneFriend* friend = linphone_search_result_get_friend(result);
|
||||
if (!addr || (!contact && friend)) {
|
||||
phoneNumber = linphone_search_result_get_phone_number(result);
|
||||
contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:[FastAddressBook normalizeSipURI:address use_prefix:[CallManager.instance applyInternationalPrefix]]];
|
||||
|
||||
if (!contact && friend) {
|
||||
contact = [[Contact alloc] initWithFriend:friend];
|
||||
[contact setCreatedFromLdapOrProvisioning:TRUE];
|
||||
[_ldapAndProvisioningContactAddressBookMap setObject:contact forKey:address];
|
||||
}
|
||||
} else if (friend){
|
||||
if (!phoneNumber) {
|
||||
results = results->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
LinphoneAccount *account = linphone_core_get_default_account(LC);
|
||||
if (account) {
|
||||
const char *normalizedPhoneNumber = linphone_account_normalize_phone_number(account, phoneNumber);
|
||||
char *normalizedPhoneNumber = linphone_account_normalize_phone_number(account, phoneNumber);
|
||||
if (!normalizedPhoneNumber) {
|
||||
// get invalid phone number, continue
|
||||
results = results->next;
|
||||
continue;
|
||||
}
|
||||
addr = linphone_account_normalize_sip_uri(account, normalizedPhoneNumber);
|
||||
bctbx_free(normalizedPhoneNumber);
|
||||
uri = linphone_address_as_string_uri_only(addr);
|
||||
address = [NSString stringWithUTF8String:uri];
|
||||
|
||||
contact = [[Contact alloc] initWithFriend:friend];
|
||||
[contact setCreatedFromLdap:TRUE];
|
||||
[_ldapContactAddressBookMap setObject:contact forKey:address];
|
||||
[contact setCreatedFromLdapOrProvisioning:TRUE];
|
||||
[_ldapAndProvisioningContactAddressBookMap setObject:contact forKey:address];
|
||||
linphone_address_unref(addr);
|
||||
}
|
||||
|
||||
}
|
||||
if (uri) ms_free(uri);
|
||||
|
||||
if (!addr) {
|
||||
results = results->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
ms_free(uri);
|
||||
|
||||
[_addresses addObject:address];
|
||||
[_phoneOrAddr addObject:phoneNumber ? [NSString stringWithUTF8String:phoneNumber] : address];
|
||||
[_addressesCached addObject:[NSString stringWithFormat:@"%d",linphone_search_result_get_capabilities(result)]];
|
||||
|
||||
results = results->next;
|
||||
}
|
||||
bctbx_list_free(result_list);
|
||||
[self.tableView reloadData];
|
||||
_reloadMagicSearch = FALSE;
|
||||
}
|
||||
|
|
@ -168,7 +180,7 @@
|
|||
[_addresses removeAllObjects];
|
||||
[_phoneOrAddr removeAllObjects];
|
||||
[_addressesCached removeAllObjects];
|
||||
[_ldapContactAddressBookMap removeAllObjects];
|
||||
[_ldapAndProvisioningContactAddressBookMap removeAllObjects];
|
||||
[self.tableView reloadData];
|
||||
|
||||
_reloadMagicSearch = _reloadMagicSearch || [filter length]==0 || ![[MagicSearchSingleton.instance currentFilter] isEqualToString:filter];
|
||||
|
|
@ -192,7 +204,7 @@
|
|||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
|
||||
return 60.0;
|
||||
return 60.0;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -203,12 +215,12 @@
|
|||
|
||||
NSString *key = [_addresses objectAtIndex:indexPath.row];
|
||||
NSString *phoneOrAddr = [_phoneOrAddr objectAtIndex:indexPath.row];
|
||||
Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:[FastAddressBook normalizeSipURI:key]];
|
||||
Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:[FastAddressBook normalizeSipURI:key use_prefix:[CallManager.instance applyInternationalPrefix]]];
|
||||
if (!contact) {
|
||||
contact = [_ldapContactAddressBookMap objectForKey:key];
|
||||
contact = [_ldapAndProvisioningContactAddressBookMap objectForKey:key];
|
||||
}
|
||||
|
||||
const LinphonePresenceModel *model = contact.friend ? linphone_friend_get_presence_model(contact.friend) : NULL;
|
||||
const LinphonePresenceModel *model = contact.friend ? linphone_friend_get_presence_model(contact.friend) : NULL;
|
||||
Boolean linphoneContact = [FastAddressBook contactHasValidSipDomain:contact]
|
||||
|| (model && linphone_presence_model_get_basic_status(model) == LinphonePresenceBasicStatusOpen);
|
||||
LinphoneAddress *addr = [LinphoneUtils normalizeSipOrPhoneAddress:key];
|
||||
|
|
@ -216,30 +228,32 @@
|
|||
return cell;
|
||||
|
||||
cell.linphoneImage.hidden = [LinphoneManager.instance lpConfigBoolForKey:@"hide_linphone_contacts" inSection:@"app"] || !linphoneContact;
|
||||
cell.securityImage.hidden = !(model && linphone_presence_model_has_capability(model, LinphoneFriendCapabilityLimeX3dh));
|
||||
int capabilities = [[_addressesCached objectAtIndex:indexPath.row] intValue];
|
||||
BOOL greyCellForEncryptedChat = _isEncrypted ? capabilities > 1 : TRUE;
|
||||
BOOL greyCellForGroupChat = _isGroupChat ? capabilities > 0 : TRUE;
|
||||
cell.userInteractionEnabled = cell.greyView.hidden = greyCellForEncryptedChat && greyCellForGroupChat;
|
||||
cell.displayNameLabel.text = [contact createdFromLdap] ? [contact displayName] : [FastAddressBook displayNameForAddress:addr];
|
||||
cell.securityImage.hidden = !(model && linphone_presence_model_has_capability(model, LinphoneFriendCapabilityLimeX3dh));
|
||||
int capabilities = [[_addressesCached objectAtIndex:indexPath.row] intValue];
|
||||
BOOL greyCellForEncryptedChat = _isEncrypted ? capabilities > 1 : TRUE;
|
||||
BOOL greyCellForGroupChat = _isGroupChat ? capabilities > 0 : TRUE;
|
||||
cell.userInteractionEnabled = cell.greyView.hidden = greyCellForEncryptedChat && greyCellForGroupChat;
|
||||
cell.displayNameLabel.text = [contact createdFromLdapOrProvisioning] ? [contact displayName] : [FastAddressBook displayNameForAddress:addr];
|
||||
char *str = linphone_address_as_string(addr);
|
||||
cell.addressLabel.text = linphoneContact ? [NSString stringWithUTF8String:str] : phoneOrAddr;
|
||||
ms_free(str);
|
||||
cell.selectedImage.hidden = ![_contactsGroup containsObject:cell.addressLabel.text];
|
||||
[cell.avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:NO withRoundedRadius:YES];
|
||||
[cell.avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:NO withRoundedRadius:YES];
|
||||
cell.contentView.userInteractionEnabled = false;
|
||||
cell.contentView.backgroundColor = UIColor.clearColor;
|
||||
cell.backgroundColor = UIColor.clearColor;
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIChatCreateCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
if (!cell.userInteractionEnabled)
|
||||
return;
|
||||
if (!cell.userInteractionEnabled)
|
||||
return;
|
||||
|
||||
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
|
||||
if (!(defaultAccount && linphone_account_params_get_conference_factory_uri(linphone_account_get_params(defaultAccount))) || !_isGroupChat) {
|
||||
LinphoneAddress *addr = linphone_address_new(cell.addressLabel.text.UTF8String);
|
||||
[PhoneMainView.instance getOrCreateOneToOneChatRoom:addr waitView:_waitView isEncrypted:_isEncrypted];
|
||||
[PhoneMainView.instance getOrCreateOneToOneChatRoom:addr waitView:_waitView isEncrypted:_isEncrypted];
|
||||
if (!addr) {
|
||||
LOGE(@"Chat room could not be created on server, because null address.");
|
||||
[ChatConversationInfoView displayCreationError];
|
||||
|
|
@ -251,8 +265,6 @@
|
|||
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
NSInteger index = 0;
|
||||
_searchBar.text = @"";
|
||||
[self searchBar:_searchBar textDidChange:@""];
|
||||
if(cell.selectedImage.hidden) {
|
||||
if(![_contactsGroup containsObject:cell.addressLabel.text]) {
|
||||
[_contactsGroup addObject:cell.addressLabel.text];
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@
|
|||
- (IBAction)onNextClick:(id)sender;
|
||||
- (IBAction)onChiffreClick:(id)sender;
|
||||
|
||||
-(void) unfragmentCompositeDescription;
|
||||
-(void) fragmentCompositeDescription;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* ChatConversationCreateView_h */
|
||||
|
|
|
|||
|
|
@ -45,6 +45,21 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
return self.class.compositeViewDescription;
|
||||
}
|
||||
|
||||
-(void) unfragmentCompositeDescription {
|
||||
if (!IPAD)
|
||||
return;
|
||||
compositeDescription.isLeftFragment = true;
|
||||
compositeDescription.otherFragment = nil;
|
||||
}
|
||||
|
||||
-(void) fragmentCompositeDescription {
|
||||
if (!IPAD)
|
||||
return;
|
||||
compositeDescription.otherFragment = IPAD ? NSStringFromClass(ChatsListView.class) : nil;
|
||||
compositeDescription.isLeftFragment = false;
|
||||
}
|
||||
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
|
||||
|
|
@ -54,7 +69,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[self.view addGestureRecognizer:tap];
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.itemSize = CGSizeMake(100.0 , 50.0);
|
||||
layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize;
|
||||
_collectionController.collectionView = _collectionView;
|
||||
_collectionController = (ChatConversationCreateCollectionViewController *)[[UICollectionViewController alloc] initWithCollectionViewLayout:layout];
|
||||
_collectionView.dataSource = self;
|
||||
|
|
@ -75,6 +90,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector:@selector(viewUpdateEvent:)
|
||||
name:kLinphoneChatCreateViewChange
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(displayModeChanged)
|
||||
name:kDisplayModeChanged
|
||||
object:nil];
|
||||
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
|
||||
_chiffreOptionView.hidden = !(defaultAccount && linphone_account_params_get_conference_factory_uri(linphone_account_get_params(defaultAccount)));
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"hide_linphone_contacts" inSection:@"app"]) {
|
||||
|
|
@ -83,8 +102,17 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
CGRect frame = _allButton.frame;
|
||||
frame.origin.x = _linphoneButton.frame.origin.x;
|
||||
_allButton.frame = frame;
|
||||
|
||||
}
|
||||
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"force_lime_chat_rooms"]) {
|
||||
_chiffreOptionView.hidden = true;
|
||||
_isEncrypted = true;
|
||||
_tableController.isEncrypted = true;
|
||||
_allButton.hidden = true;
|
||||
_linphoneButton.hidden = true;
|
||||
_selectedButtonImage.hidden = true;
|
||||
}
|
||||
|
||||
if (_isForVoipConference) {
|
||||
_switchView.hidden = true;
|
||||
|
|
@ -95,13 +123,28 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
} else {
|
||||
[_nextButton setImage:[UIImage imageNamed:@"next_default"] forState:UIControlStateNormal];
|
||||
}
|
||||
_topBar.backgroundColor = VoipTheme.toolbar_color;
|
||||
} else {
|
||||
_voipTitle.hidden = true;
|
||||
[_nextButton setImage:[UIImage imageNamed:@"next_default"] forState:UIControlStateNormal];
|
||||
_topBar.backgroundColor = UIColor.secondarySystemBackgroundColor;
|
||||
}
|
||||
|
||||
[self displayModeChanged];
|
||||
}
|
||||
|
||||
- (void)displayModeChanged{
|
||||
[self.tableController.tableView reloadData];
|
||||
if (_isForVoipConference) {
|
||||
_topBar.backgroundColor = [VoipTheme.voipToolbarBackgroundColor get];
|
||||
self.view.backgroundColor = [VoipTheme.voipBackgroundBWColor get];
|
||||
_tableController.tableView.backgroundColor = [VoipTheme.voipBackgroundBWColor get];
|
||||
_tableController.searchBar.backgroundColor = [VoipTheme.voipBackgroundBWColor get];
|
||||
_tableController.collectionView.backgroundColor = [VoipTheme.voipBackgroundBWColor get];
|
||||
} else {
|
||||
_topBar.backgroundColor = UIColor.secondarySystemBackgroundColor;
|
||||
self.view.backgroundColor = [VoipTheme.backgroundWhiteBlack get];
|
||||
_tableController.tableView.backgroundColor = [VoipTheme.backgroundWhiteBlack get];
|
||||
_tableController.searchBar.backgroundColor = [VoipTheme.backgroundWhiteBlack get];
|
||||
_tableController.collectionView.backgroundColor = [VoipTheme.backgroundWhiteBlack get];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewUpdateEvent:(NSNotification *)notif {
|
||||
|
|
@ -116,17 +159,17 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
frame.origin.x = self.view.frame.size.width * 0.192;
|
||||
}
|
||||
_chiffreOptionView.frame = frame;
|
||||
_isEncrypted = FALSE;
|
||||
_isEncrypted = [LinphoneManager.instance lpConfigBoolForKey:@"force_lime_chat_rooms"]; // false by default
|
||||
CGRect buttonFrame = _chiffreButton.frame;
|
||||
_tableController.isEncrypted = _isEncrypted;
|
||||
|
||||
// no encrypted by default
|
||||
buttonFrame.origin.x = 2;
|
||||
[_chiffreImage setImage:[UIImage imageNamed:@"security_toogle_background_grey.png"]];
|
||||
_chiffreButton.frame = buttonFrame;
|
||||
if (!_isEncrypted) {
|
||||
buttonFrame.origin.x = 2;
|
||||
[_chiffreImage setImage:[UIImage imageNamed:@"security_toogle_background_grey.png"]];
|
||||
_chiffreButton.frame = buttonFrame;
|
||||
}
|
||||
|
||||
_waitView.hidden = YES;
|
||||
_backButton.hidden = IPAD;
|
||||
_backButton.hidden = IPAD && !(_isForVoipConference||_isForOngoingVoipConference);
|
||||
if(_tableController.contactsGroup.count == 0) {
|
||||
if (!_isForEditing)
|
||||
_nextButton.enabled = FALSE;
|
||||
|
|
@ -149,9 +192,8 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
if (IPAD)
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
[super viewWillDisappear:animated];
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - Chat room functions
|
||||
|
|
@ -168,7 +210,12 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
- (IBAction)onBackClick:(id)sender {
|
||||
[_tableController.contactsGroup removeAllObjects];
|
||||
if (_isForVoipConference) {
|
||||
[PhoneMainView.instance popToView:ConferenceSchedulingView.compositeViewDescription];
|
||||
if (_isForOngoingVoipConference) {
|
||||
[PhoneMainView.instance popToView:VIEW(ConferenceCallView).compositeViewDescription];
|
||||
[ControlsViewModelBridge showParticipants];
|
||||
} else {
|
||||
[PhoneMainView.instance popToView:ConferenceSchedulingView.compositeViewDescription];
|
||||
}
|
||||
} else {
|
||||
if (_tableController.isForEditing)
|
||||
[PhoneMainView.instance popToView:ChatConversationInfoView.compositeViewDescription];
|
||||
|
|
@ -180,7 +227,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
- (IBAction)onNextClick:(id)sender {
|
||||
if (_isForVoipConference) {
|
||||
if (_isForOngoingVoipConference) {
|
||||
[PhoneMainView.instance changeCurrentView:VIEW(ActiveCallOrConferenceView).compositeViewDescription];
|
||||
[PhoneMainView.instance popToView:VIEW(ConferenceCallView).compositeViewDescription];
|
||||
[ConferenceViewModelBridge updateParticipantsListWithAddresses:_tableController.contactsGroup];
|
||||
} else {
|
||||
[PhoneMainView.instance changeCurrentView:VIEW(ConferenceSchedulingSummaryView).compositeViewDescription];
|
||||
|
|
@ -260,7 +307,7 @@ typedef enum { ContactsAll, ContactsLinphone, ContactsMAX } ContactsCategory;
|
|||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
#pragma mark - UICollectionViewDataSource & Delegate
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return _tableController.contactsGroup.count;
|
||||
}
|
||||
|
|
@ -282,9 +329,10 @@ typedef enum { ContactsAll, ContactsLinphone, ContactsMAX } ContactsCategory;
|
|||
ms_free(phone);
|
||||
} else
|
||||
addr = linphone_address_new(uri.UTF8String);
|
||||
cell = [cell initWithName:[FastAddressBook displayNameForAddress:addr]];
|
||||
[cell.nameLabel setText:[FastAddressBook displayNameForAddress:addr]];
|
||||
linphone_address_unref(addr);
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
NSString *messageText;
|
||||
}
|
||||
|
||||
@property(nonatomic) LinphoneChatMessage *msg;
|
||||
@property(nonatomic) LinphoneEventLog *event;
|
||||
@property(nonatomic) bctbx_list_t *displayedList;
|
||||
@property(nonatomic) bctbx_list_t *receivedList;
|
||||
@property(nonatomic) bctbx_list_t *notReceivedList;
|
||||
|
|
|
|||
|
|
@ -48,17 +48,12 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
_msg = NULL;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
int index = [VIEW(ChatConversationView).tableController indexOfMesssage:_msg];
|
||||
if (index < 0)
|
||||
[PhoneMainView.instance popToView:ChatConversationView.compositeViewDescription];
|
||||
|
||||
_cell = (UIChatBubbleTextCell *)[VIEW(ChatConversationView).tableController tableView:VIEW(ChatConversationView).tableController.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]];
|
||||
_cell = [VIEW(ChatConversationView).tableController buildMessageCell:_event];
|
||||
_cell.frame = CGRectMake(-10,0,_msgView.frame.size.width,_msgView.frame.size.height);
|
||||
_cell.isFirst = true;
|
||||
_cell.isLast = true;
|
||||
|
|
@ -90,18 +85,21 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (void)updateImdnList {
|
||||
if (_msg && linphone_chat_message_get_chat_room(_msg)) {
|
||||
_displayedList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateDisplayed);
|
||||
_receivedList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateDeliveredToUser);
|
||||
_notReceivedList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateDelivered);
|
||||
_errorList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateNotDelivered);
|
||||
|
||||
[_tableView reloadData];
|
||||
if (_event) {
|
||||
LinphoneChatMessage *_msg = linphone_event_log_get_chat_message(_event);
|
||||
if (_msg) {
|
||||
_displayedList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateDisplayed);
|
||||
_receivedList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateDeliveredToUser);
|
||||
_notReceivedList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateDelivered);
|
||||
_errorList = linphone_chat_message_get_participants_by_imdn_state(_msg, LinphoneChatMessageStateNotDelivered);
|
||||
|
||||
[_tableView reloadData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)fitContent {
|
||||
|
||||
LinphoneChatMessage *_msg = linphone_event_log_get_chat_message(_event);
|
||||
CGSize messageSize = [UIChatBubbleTextCell ViewHeightForMessage:_msg withWidth:self.view.frame.size.width];
|
||||
[_msgView setFrame:CGRectMake(_msgView.frame.origin.x,
|
||||
_msgView.frame.origin.y,
|
||||
|
|
@ -299,7 +297,8 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
f.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
|
||||
f.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
|
||||
|
||||
if (linphone_chat_message_is_ephemeral(_msg)) {
|
||||
LinphoneChatMessage *_msg = _event ? linphone_event_log_get_chat_message(_event) : nil;
|
||||
if (_msg && linphone_chat_message_is_ephemeral(_msg)) {
|
||||
long duration = linphone_chat_message_get_ephemeral_expire_time(_msg) == 0 ?
|
||||
linphone_chat_room_get_ephemeral_lifetime(linphone_chat_message_get_chat_room(_msg)) :
|
||||
linphone_chat_message_get_ephemeral_expire_time(_msg)-[NSDate date].timeIntervalSince1970;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
@property(nonatomic) LinphoneChatRoom *room;
|
||||
@property(nonatomic) LinphoneChatRoomCbs *chatRoomCbs;
|
||||
@property(nonatomic) const char *peerAddress;
|
||||
@property(nonatomic) const char *localAddress;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIIconButton *nextButton;
|
||||
@property (weak, nonatomic) IBOutlet UIRoundBorderedButton *quitButton;
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_room = NULL;
|
||||
_chatRoomCbs = NULL;
|
||||
_peerAddress = NULL;
|
||||
_localAddress = NULL;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
|
@ -153,10 +154,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)onLinphoneCoreReady:(NSNotification *)notif {
|
||||
if ((LinphoneGlobalState)[[[notif userInfo] valueForKey:@"state"] integerValue] == LinphoneGlobalOn) {
|
||||
if (!_create && _peerAddress) {
|
||||
if (!_create && _peerAddress && _localAddress) {
|
||||
LinphoneAddress *peerAddr = linphone_core_create_address([LinphoneManager getLc], _peerAddress);
|
||||
if (peerAddr) {
|
||||
_room = linphone_core_get_chat_room([LinphoneManager getLc], peerAddr);
|
||||
LinphoneAddress *localAddr = linphone_core_create_address([LinphoneManager getLc], _localAddress);
|
||||
if (peerAddr && localAddr) {
|
||||
_room = linphone_core_search_chat_room([LinphoneManager getLc], NULL, localAddr, peerAddr, NULL);
|
||||
}
|
||||
[self configure];
|
||||
}
|
||||
|
|
@ -270,6 +272,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
- (IBAction)onBackClick:(id)sender {
|
||||
if(_create) {
|
||||
ChatConversationCreateView *view = VIEW(ChatConversationCreateView);
|
||||
[view fragmentCompositeDescription];
|
||||
view.tableController.contactsGroup = [_contacts mutableCopy];
|
||||
view.tableController.notFirstTime = TRUE;
|
||||
view.isForEditing = FALSE;
|
||||
|
|
@ -296,6 +299,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
- (IBAction)onAddClick:(id)sender {
|
||||
if (_create || _imAdmin) {
|
||||
ChatConversationCreateView *view = VIEW(ChatConversationCreateView);
|
||||
[view fragmentCompositeDescription];
|
||||
view.tableController.notFirstTime = TRUE;
|
||||
view.isForEditing = !_create;
|
||||
view.isGroupChat = TRUE;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#import "UICheckBoxTableView.h"
|
||||
|
||||
|
||||
@interface FileContext : NSObject
|
||||
@property NSMutableArray <NSString *> *typesArray;
|
||||
@property NSMutableArray <NSData *> *datasArray;
|
||||
|
|
@ -70,5 +71,6 @@
|
|||
- (void) dismissMessagesPopups;
|
||||
- (void) scrollToMessage:(LinphoneChatMessage *)message;
|
||||
- (int) indexOfMesssage:(LinphoneChatMessage *)message;
|
||||
- (void *)buildMessageCell:(LinphoneEventLog *) event;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#import "LinphoneManager.h"
|
||||
#import "ChatConversationTableView.h"
|
||||
#import "ChatConversationImdnView.h"
|
||||
#import "UIChatBubbleTextCell.h"
|
||||
#import "UIChatBubblePhotoCell.h"
|
||||
#import "UIChatNotifiedEventCell.h"
|
||||
#import "PhoneMainView.h"
|
||||
|
|
@ -84,7 +83,6 @@
|
|||
LinphoneChatRoomCapabilitiesMask capabilities = linphone_chat_room_get_capabilities(_chatRoom);
|
||||
bool oneToOne = capabilities & LinphoneChatRoomCapabilitiesOneToOne;
|
||||
bctbx_list_t *chatRoomEvents = linphone_chat_room_get_history_events(_chatRoom, 0);
|
||||
|
||||
int unread_count = 0;
|
||||
|
||||
bctbx_list_t *head = chatRoomEvents;
|
||||
|
|
@ -142,12 +140,11 @@
|
|||
|
||||
- (void)addEventEntry:(LinphoneEventLog *)event {
|
||||
[eventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]];
|
||||
[totalEventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]];
|
||||
[totalEventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]];
|
||||
int pos = (int)eventList.count - 1;
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:pos inSection:0];
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
|
||||
[self.tableView reloadData];
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
|
|
@ -331,28 +328,32 @@ static const int BASIC_EVENT_LIST=15;
|
|||
}
|
||||
}
|
||||
|
||||
-(UIChatBubbleTextCell *)buildMessageCell:(LinphoneEventLog *) event {
|
||||
NSString *kCellId = nil;
|
||||
LinphoneChatMessage *chat = linphone_event_log_get_chat_message(event);
|
||||
BOOL isConferenceIcs = [ICSBubbleView isConferenceInvitationMessageWithCmessage:chat];
|
||||
if (!isConferenceIcs && (linphone_chat_message_get_file_transfer_information(chat) || linphone_chat_message_get_external_body_url(chat)))
|
||||
kCellId = NSStringFromClass(UIChatBubblePhotoCell.class);
|
||||
else
|
||||
kCellId = NSStringFromClass(UIChatBubbleTextCell.class);
|
||||
// To use less memory and to avoid overlapping. To be improved.
|
||||
UIChatBubbleTextCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kCellId];
|
||||
cell = [[NSClassFromString(kCellId) alloc] initWithIdentifier:kCellId];
|
||||
[cell setEvent:event];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSString *kCellId = nil;
|
||||
LinphoneEventLog *event = [[eventList objectAtIndex:indexPath.row] pointerValue];
|
||||
if (linphone_event_log_get_type(event) == LinphoneEventLogTypeConferenceChatMessage) {
|
||||
UIChatBubbleTextCell *cell = [self buildMessageCell:event];
|
||||
LinphoneChatMessage *chat = linphone_event_log_get_chat_message(event);
|
||||
BOOL isConferenceIcs = [ICSBubbleView isConferenceInvitationMessageWithCmessage:chat];
|
||||
if (!isConferenceIcs && (linphone_chat_message_get_file_transfer_information(chat) || linphone_chat_message_get_external_body_url(chat)))
|
||||
kCellId = NSStringFromClass(UIChatBubblePhotoCell.class);
|
||||
else
|
||||
kCellId = NSStringFromClass(UIChatBubbleTextCell.class);
|
||||
|
||||
// To use less memory and to avoid overlapping. To be improved.
|
||||
UIChatBubbleTextCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId];
|
||||
cell = [[NSClassFromString(kCellId) alloc] initWithIdentifier:kCellId];
|
||||
|
||||
[cell setEvent:event];
|
||||
if (chat) {
|
||||
cell.isFirst = [self isFirstIndexInTableView:indexPath chat:chat];
|
||||
cell.isLast = [self isLastIndexInTableView:indexPath chat:chat];
|
||||
[cell update];
|
||||
}
|
||||
|
||||
if (chat) {
|
||||
cell.isFirst = [self isFirstIndexInTableView:indexPath chat:chat];
|
||||
cell.isLast = [self isLastIndexInTableView:indexPath chat:chat];
|
||||
[cell update];
|
||||
}
|
||||
[cell setChatRoomDelegate:_chatRoomDelegate];
|
||||
[super accessoryForCell:cell atPath:indexPath];
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
|
|
@ -378,6 +379,13 @@ static const int BASIC_EVENT_LIST=15;
|
|||
[_chatRoomDelegate tableViewIsScrolling];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
|
||||
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
|
||||
[ChatConversationView markAsRead:_chatRoom];
|
||||
}
|
||||
}
|
||||
|
||||
static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f;
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -443,12 +451,11 @@ static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f;
|
|||
|
||||
LinphoneEventLog *event = [[eventList objectAtIndex:indexPath.row] pointerValue];
|
||||
UIContextualAction *imdnAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
|
||||
title:NSLocalizedString(@"Info", nil)
|
||||
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
|
||||
LinphoneChatMessage *msg = linphone_event_log_get_chat_message(event);
|
||||
ChatConversationImdnView *view = VIEW(ChatConversationImdnView);
|
||||
view.msg = msg;
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
title:NSLocalizedString(@"Info", nil)
|
||||
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
|
||||
ChatConversationImdnView *view = VIEW(ChatConversationImdnView);
|
||||
view.event = event;
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
}];
|
||||
|
||||
UISwipeActionsConfiguration *swipeActionConfig;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
@property(nonatomic) LinphoneChatRoomCbs *chatRoomCbs;
|
||||
@property(nonatomic) Boolean markAsRead;
|
||||
@property(nonatomic) const char *peerAddress;
|
||||
@property(nonatomic) const char *localAddress;
|
||||
|
||||
@property (strong, nonatomic) FileDataSource *FileDataSource;
|
||||
|
||||
|
|
@ -112,6 +113,7 @@
|
|||
@property LinphonePlayer *sharedVoicePlayer;
|
||||
@property BOOL showVoiceRecorderView;
|
||||
@property BOOL preservePendingActions;
|
||||
@property BOOL *sharingMedia;
|
||||
|
||||
// Reply
|
||||
@property (weak, nonatomic) IBOutlet UIView *replyView;
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (compositeDescription == nil) {
|
||||
compositeDescription = [[UICompositeViewDescription alloc] init:self.class
|
||||
statusBar:StatusBarView.class
|
||||
tabBar:nil
|
||||
tabBar:IPAD ? TabBarView.class :nil
|
||||
sideMenu:SideMenuView.class
|
||||
fullscreen:false
|
||||
isLeftFragment:NO
|
||||
|
|
@ -196,7 +196,8 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_vrInnerView.layer.masksToBounds = YES;
|
||||
_vrWaveMaskPlayer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"color_L"]]; // rgba(1,88,7,0.2);
|
||||
_showVoiceRecorderView = false;
|
||||
|
||||
_toggleMenuButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_toggleRecord.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
}
|
||||
|
||||
- (void)refreshData {
|
||||
|
|
@ -212,10 +213,17 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
if (!_chatRoom)
|
||||
[self onLinphoneCoreReady:nil];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(applicationWillEnterBackground)
|
||||
selector:@selector(applicationDidEnterBackground)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(applicationWillEnterForeground)
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(keyboardWillShow:)
|
||||
name:UIKeyboardWillShowNotification
|
||||
|
|
@ -232,10 +240,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector:@selector(callUpdateEvent:)
|
||||
name:kLinphoneCallUpdate
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(onLinphoneCoreReady:)
|
||||
name:kLinphoneGlobalStateUpdate
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(onLinphoneCoreReady:)
|
||||
name:kLinphoneGlobalStateUpdate
|
||||
object:nil];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(endVoicePlayingIfDoingSO:)
|
||||
|
|
@ -246,24 +254,23 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector:@selector(endVoicePlayingIfDoingSO:)
|
||||
name:kLinphoneVoiceMessagePlayerEOF
|
||||
object:nil];
|
||||
if ([_fileContext count] > 0) {
|
||||
[UIView animateWithDuration:0
|
||||
delay:0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{
|
||||
// resizing imagesView
|
||||
CGRect imagesFrame = [_imagesView frame];
|
||||
imagesFrame.origin.y = [_messageView frame].origin.y - 120;
|
||||
imagesFrame.size.height = 120;
|
||||
[_imagesView setFrame:imagesFrame];
|
||||
// resizing chatTable
|
||||
CGRect tableViewFrame = [_tableController.tableView frame];
|
||||
tableViewFrame.size.height -= 120;
|
||||
[_tableController.tableView setFrame:tableViewFrame];
|
||||
[self updateFramesInclRecordingAndReplyView];
|
||||
}
|
||||
completion:nil];
|
||||
}
|
||||
if ([_fileContext count] > 0) {
|
||||
[UIView animateWithDuration:0
|
||||
delay:0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{
|
||||
// resizing imagesView
|
||||
CGRect imagesFrame = [_imagesView frame];
|
||||
imagesFrame.origin.y = [_messageView frame].origin.y - 120;
|
||||
imagesFrame.size.height = 120;
|
||||
[_imagesView setFrame:imagesFrame];
|
||||
// resizing chatTable
|
||||
CGRect tableViewFrame = [_tableController.tableView frame];
|
||||
tableViewFrame.size.height -= 120;
|
||||
[_tableController.tableView setFrame:tableViewFrame];
|
||||
[self updateFramesInclRecordingAndReplyView];
|
||||
} completion:nil];
|
||||
}
|
||||
[self configureForRoom:self.editing];
|
||||
|
||||
// Resize the popup table depending on wether ephemeral messages are enabled or not.
|
||||
|
|
@ -273,12 +280,13 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
// Voice recording & Replies
|
||||
_vrView.hidden = true;
|
||||
_toggleRecord.enabled = linphone_core_get_calls_nb(LC) == 0;
|
||||
_toggleRecord.enabled = linphone_core_get_calls_nb(LC) == 0;
|
||||
_replyView.hidden = true;
|
||||
_preservePendingActions = false;
|
||||
|
||||
_toggleRecord.enabled = linphone_core_get_calls_nb(LC) == 0;
|
||||
|
||||
|
||||
[PhoneMainView.instance hideTabBar:!IPAD];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
|
@ -307,6 +315,8 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
PhoneMainView.instance.currentRoom = NULL;
|
||||
[[UIApplication sharedApplication] setIdleTimerDisabled:false];
|
||||
_chatRoom = NULL;
|
||||
_tableController.chatRoom = nil;
|
||||
}
|
||||
|
||||
- (void)removeCallBacks {
|
||||
|
|
@ -323,27 +333,33 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
return;
|
||||
}
|
||||
composingVisible = !composingVisible;
|
||||
[self setComposingVisible:!composingVisible withDelay:0];
|
||||
|
||||
// force offset recomputing
|
||||
[_messageField refreshHeight];
|
||||
LinphoneAddress *peerAddr = linphone_core_create_address([LinphoneManager getLc], _peerAddress);
|
||||
if (peerAddr) {
|
||||
_chatRoom = linphone_core_get_chat_room([LinphoneManager getLc], peerAddr);
|
||||
isOneToOne = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesOneToOne;
|
||||
isEncrypted = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesEncrypted;
|
||||
LinphoneAddress *localAddr = linphone_core_create_address([LinphoneManager getLc], _localAddress);
|
||||
if (peerAddr && localAddr) {
|
||||
_chatRoom = linphone_core_search_chat_room([LinphoneManager getLc], NULL, localAddr, peerAddr, NULL);
|
||||
if (_chatRoom) {
|
||||
isOneToOne = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesOneToOne;
|
||||
isEncrypted = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesEncrypted;
|
||||
[self setComposingVisible:!composingVisible withDelay:0];
|
||||
[self configureForRoom:true];
|
||||
[_tableController scrollToBottom:true];
|
||||
}
|
||||
}
|
||||
[self configureForRoom:true];
|
||||
_backButton.hidden = _tableController.isEditing;
|
||||
[_tableController scrollToBottom:true];
|
||||
[self refreshImageDrawer];
|
||||
[self stopAllPlays];
|
||||
if (peerAddr) linphone_address_unref(peerAddr);
|
||||
if (localAddr) linphone_address_unref(localAddr);
|
||||
|
||||
_backButton.hidden = _tableController.isEditing;
|
||||
[self refreshImageDrawer];
|
||||
[self stopAllPlays];
|
||||
[self keyboardWillHide:nil];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)applicationWillEnterBackground{
|
||||
- (void)applicationDidEnterBackground{
|
||||
if (!_preservePendingActions)
|
||||
[self cancelVoiceRecording];
|
||||
else if (_isVoiceRecording)
|
||||
|
|
@ -351,9 +367,18 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (!_preservePendingActions)
|
||||
[self closePendingReply];
|
||||
[self stopAllPlays];
|
||||
|
||||
_chatRoom = nil;
|
||||
[_messageField resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground{
|
||||
if (_chatRoom == nil) {
|
||||
if (linphone_core_get_calls_nb(LC) == 0)
|
||||
[SVProgressHUD show];
|
||||
else
|
||||
[self onLinphoneCoreReady:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)configureForRoom:(BOOL)editing {
|
||||
if (!_chatRoom) {
|
||||
|
|
@ -395,6 +420,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
LinphoneParticipant *firstParticipant = participants ? (LinphoneParticipant *)participants->data : NULL;
|
||||
const LinphoneAddress *addr = firstParticipant ? linphone_participant_get_address(firstParticipant) : linphone_chat_room_get_peer_address(_chatRoom);
|
||||
[ContactDisplay setDisplayNameLabel:_addressLabel forAddress:addr];
|
||||
bctbx_list_free(participants);
|
||||
} else
|
||||
_addressLabel.text = [NSString stringWithUTF8String:linphone_chat_room_get_subject(_chatRoom) ?: LINPHONE_DUMMY_SUBJECT];
|
||||
|
||||
|
|
@ -426,7 +452,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (!room)
|
||||
return true;
|
||||
LinphoneChatRoomCapabilitiesMask capabilities = linphone_chat_room_get_capabilities(room);
|
||||
return capabilities & LinphoneChatRoomCapabilitiesBasic;
|
||||
return capabilities & LinphoneChatRoomCapabilitiesEncrypted;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -466,7 +492,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
//file shared from photo lib
|
||||
NSString *fileName = dict[@"url"];
|
||||
[_messageField setText:dict[@"message"]];
|
||||
[self confirmShare:[self nsDataRead] url:nil fileName:fileName];
|
||||
[self confirmShare:[self nsDataRead] url:nil fileName:fileName];
|
||||
[defaults removeObjectForKey:@"photoData"];
|
||||
} else if (dictFile) {
|
||||
NSString *fileName = dictFile[@"url"];
|
||||
|
|
@ -483,23 +509,26 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
// reload the chatroom after the core starts
|
||||
- (void)onLinphoneCoreReady:(NSNotification *)notif {
|
||||
if ((LinphoneGlobalState)[[[notif userInfo] valueForKey:@"state"] integerValue] == LinphoneGlobalOn) {
|
||||
LinphoneAddress *peerAddr = linphone_core_create_address([LinphoneManager getLc], _peerAddress);
|
||||
if (peerAddr) {
|
||||
_chatRoom = linphone_core_get_chat_room([LinphoneManager getLc], peerAddr);
|
||||
isOneToOne = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesOneToOne;
|
||||
isEncrypted = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesEncrypted;
|
||||
}
|
||||
[self configureForRoom:self.editing];
|
||||
if (_chatRoom && _markAsRead) {
|
||||
if (IPAD) {
|
||||
[VIEW(ChatsListView).tableController loadData];
|
||||
if (linphone_core_get_global_state(LC) == LinphoneGlobalOn) {
|
||||
LinphoneAddress *peerAddr = linphone_core_create_address([LinphoneManager getLc], _peerAddress);
|
||||
LinphoneAddress *localAddr = linphone_core_create_address([LinphoneManager getLc], _localAddress);
|
||||
if (peerAddr && localAddr) {
|
||||
_chatRoom = linphone_core_search_chat_room([LinphoneManager getLc], NULL, localAddr, peerAddr, NULL);
|
||||
if (_chatRoom) {
|
||||
isOneToOne = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesOneToOne;
|
||||
isEncrypted = linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesEncrypted;
|
||||
[self configureForRoom:self.editing];
|
||||
if (_chatRoom && _markAsRead) {
|
||||
if (IPAD) {
|
||||
[VIEW(ChatsListView).tableController loadData];
|
||||
}
|
||||
[ChatConversationView markAsRead:_chatRoom];
|
||||
}
|
||||
_markAsRead = TRUE;
|
||||
}
|
||||
|
||||
[ChatConversationView markAsRead:_chatRoom];
|
||||
}
|
||||
_markAsRead = TRUE;
|
||||
}
|
||||
}
|
||||
[SVProgressHUD dismiss];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)callUpdateEvent:(NSNotification *)notif {
|
||||
|
|
@ -598,9 +627,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (void)confirmShare:(NSData *)data url:(NSString *)url fileName:(NSString *)fileName {
|
||||
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:@""];
|
||||
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Select or create a conversation to share the file(s)", nil)];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"send to this conversation", nil)
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"Send to this conversation", nil)
|
||||
block:^() {
|
||||
if (![[self.messageField text] isEqualToString:@""]) {
|
||||
[self sendMessageInMessageField:linphone_chat_room_create_empty_message(_chatRoom)];
|
||||
|
|
@ -657,6 +686,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
completion:^(BOOL finished) {
|
||||
_composeIndicatorView.hidden = !visible;
|
||||
}];
|
||||
if (visible) {
|
||||
if (_tableController.tableView.contentOffset.y + newComposingFrame.size.height >= (_tableController.tableView.contentSize.height - _tableController.tableView.frame.size.height - 1)) {
|
||||
[_tableController scrollToBottom:TRUE];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) groupCallAvailable {
|
||||
|
|
@ -771,9 +805,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
// if we're showing the compose message, update it position
|
||||
if (![_composeLabel isHidden]) {
|
||||
CGRect frame = [_composeLabel frame];
|
||||
CGRect frame = [_composeIndicatorView frame];
|
||||
frame.origin.y -= diff;
|
||||
[_composeLabel setFrame:frame];
|
||||
[_composeIndicatorView setFrame:frame];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -781,7 +815,15 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
#pragma mark - Action Functions
|
||||
|
||||
- (IBAction)onBackClick:(id)event {
|
||||
[PhoneMainView.instance popCurrentView];
|
||||
NSString *previousViewName = [PhoneMainView.instance getPreviousViewName];
|
||||
_sharingMedia = nil;
|
||||
if ([previousViewName isEqualToString:@"ContactDetailsView"]) {
|
||||
ContactDetailsView *view = VIEW(ContactDetailsView);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
} else {
|
||||
ChatsListView *view = VIEW(ChatsListView);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onEditClick:(id)event {
|
||||
|
|
@ -937,6 +979,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
view.oldSubject = [NSString stringWithUTF8String:linphone_chat_room_get_subject(_chatRoom) ?: LINPHONE_DUMMY_SUBJECT];
|
||||
view.room = _chatRoom;
|
||||
view.peerAddress = _peerAddress;
|
||||
view.localAddress = _localAddress;
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
}
|
||||
|
||||
|
|
@ -1049,84 +1092,86 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
+ (void)writeMediaToGallery:(NSString *)name fileType:(NSString *)fileType {
|
||||
NSString *filePath = [LinphoneManager validFilePath:name];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if ([fileManager fileExistsAtPath:filePath]) {
|
||||
NSData* data = [NSData dataWithContentsOfFile:filePath];
|
||||
if (![LinphoneManager.instance lpConfigBoolForKey:@"vfs_enabled_mode"]) {
|
||||
NSString *filePath = [LinphoneManager validFilePath:name];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if ([fileManager fileExistsAtPath:filePath]) {
|
||||
NSData* data = [NSData dataWithContentsOfFile:filePath];
|
||||
|
||||
// define a block , not called immediately. To avoid crash when saving photo before PHAuthorizationStatusNotDetermined.
|
||||
void (^block)(void)= ^ {
|
||||
if ([fileType isEqualToString:@"image"] ) {
|
||||
// we're finished, save the image and update the message
|
||||
UIImage *image = [UIImage imageWithData:data];
|
||||
if (!image) {
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
[view showFileDownloadError];
|
||||
return;
|
||||
// define a block , not called immediately. To avoid crash when saving photo before PHAuthorizationStatusNotDetermined.
|
||||
void (^block)(void)= ^ {
|
||||
if ([fileType isEqualToString:@"image"] ) {
|
||||
// we're finished, save the image and update the message
|
||||
UIImage *image = [UIImage imageWithData:data];
|
||||
if (!image) {
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
[view showFileDownloadError];
|
||||
return;
|
||||
}
|
||||
__block PHObjectPlaceholder *placeHolder;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromImage:image];
|
||||
placeHolder = [request placeholderForCreatedAsset];
|
||||
} completionHandler:^(BOOL success, NSError *error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
|
||||
message:NSLocalizedString(@"Cannot write image to photo library",nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
} else {
|
||||
LOGI(@"Image saved to [%@]", [placeHolder localIdentifier]);
|
||||
}
|
||||
});
|
||||
}];
|
||||
} else if([fileType isEqualToString:@"video"]) {
|
||||
__block PHObjectPlaceholder *placeHolder;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:filePath]];
|
||||
placeHolder = [request placeholderForCreatedAsset];
|
||||
} completionHandler:^(BOOL success, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
LOGE(@"Cannot save video data downloaded [%@]", [error localizedDescription]);
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
|
||||
message:NSLocalizedString(@"Cannot write video to photo library", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
} else {
|
||||
LOGI(@"video saved to [%@]", [placeHolder localIdentifier]);
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
__block PHObjectPlaceholder *placeHolder;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromImage:image];
|
||||
placeHolder = [request placeholderForCreatedAsset];
|
||||
} completionHandler:^(BOOL success, NSError *error) {
|
||||
};
|
||||
|
||||
// When you save an image or video to a photo library, make sure that it is allowed. Otherwise, there will be a backup error.
|
||||
if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) {
|
||||
block();
|
||||
} else {
|
||||
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
|
||||
message:NSLocalizedString(@"Cannot write image to photo library",nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) {
|
||||
block();
|
||||
} else {
|
||||
LOGI(@"Image saved to [%@]", [placeHolder localIdentifier]);
|
||||
}
|
||||
});
|
||||
}];
|
||||
} else if([fileType isEqualToString:@"video"]) {
|
||||
__block PHObjectPlaceholder *placeHolder;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:filePath]];
|
||||
placeHolder = [request placeholderForCreatedAsset];
|
||||
} completionHandler:^(BOOL success, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
LOGE(@"Cannot save video data downloaded [%@]", [error localizedDescription]);
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
|
||||
message:NSLocalizedString(@"Cannot write video to photo library", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
} else {
|
||||
LOGI(@"video saved to [%@]", [placeHolder localIdentifier]);
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
// When you save an image or video to a photo library, make sure that it is allowed. Otherwise, there will be a backup error.
|
||||
if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) {
|
||||
block();
|
||||
} else {
|
||||
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) {
|
||||
block();
|
||||
} else {
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1415,12 +1460,11 @@ void on_chat_room_chat_message_received(LinphoneChatRoom *cr, const LinphoneEven
|
|||
|
||||
bool isDisplayingBottomOfTable = [view.tableController.tableView indexPathsForVisibleRows].lastObject.row == [view.tableController totalNumberOfItems] - 1;
|
||||
[view.tableController addEventEntry:(LinphoneEventLog *)event_log];
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:view];
|
||||
|
||||
|
||||
if (isDisplayingBottomOfTable) {
|
||||
[view.tableController scrollToBottom:TRUE];
|
||||
} else {
|
||||
[[view.tableController scrollBadge] setHidden:FALSE];
|
||||
int unread_msg = linphone_chat_room_get_unread_messages_count(cr);
|
||||
[[view.tableController scrollBadge] setText:[NSString stringWithFormat:@"%d", unread_msg]];
|
||||
}
|
||||
|
|
@ -1721,13 +1765,6 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
}
|
||||
}
|
||||
|
||||
-(BOOL) isConversationMuted {
|
||||
return FALSE; // TODO
|
||||
}
|
||||
-(void) toggleMuteConversation {
|
||||
// TODO
|
||||
}
|
||||
|
||||
-(void) showAddressAndIdentityPopup {
|
||||
|
||||
char *localAddress = linphone_address_as_string(linphone_chat_room_get_local_address(_chatRoom));
|
||||
|
|
@ -1754,8 +1791,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
}
|
||||
|
||||
-(BOOL) canAdminEphemeral:(const LinphoneChatRoom *)cr {
|
||||
if (!cr) return FALSE;
|
||||
if ([ChatConversationView isBasicChatRoom:_chatRoom]) return FALSE;
|
||||
if (!cr || !isEncrypted) return FALSE;
|
||||
|
||||
// If ephemeral mode is DeviceManaged, then we don't need to check anything else
|
||||
return (linphone_chat_room_params_get_ephemeral_mode(linphone_chat_room_get_current_params(cr)) == LinphoneChatRoomEphemeralModeDeviceManaged)
|
||||
|
|
@ -1773,42 +1809,57 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
_popupMenu.layer.masksToBounds = false;
|
||||
_toggleMenuButton.hidden = false;
|
||||
_popupMenu.tableFooterView = [UIView new];
|
||||
_popupMenu.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
[_popupMenu reloadData];
|
||||
}
|
||||
|
||||
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[self onToggleMenu:nil];
|
||||
BOOL isEncrypted = ![ChatConversationView isBasicChatRoom:_chatRoom];
|
||||
|
||||
if (indexPath.row == 0) {
|
||||
int firstIndex = isOneToOne ? 0 : 1;
|
||||
|
||||
if (!isOneToOne && indexPath.row == 0) { //Schedule meeting
|
||||
[ConferenceViewModelBridge scheduleFromGroupChatWithCChatRoom:_chatRoom];
|
||||
[PhoneMainView.instance popToView:ConferenceSchedulingView.compositeViewDescription];
|
||||
}
|
||||
|
||||
if (indexPath.row == firstIndex) {
|
||||
if (isOneToOne) {
|
||||
[self addOrGoToContact:linphone_chat_room_get_peer_address(_chatRoom)];
|
||||
if (isEncrypted) {
|
||||
LinphoneAddress* contactAddress = linphone_address_clone(linphone_participant_get_address(bctbx_list_nth_data(linphone_chat_room_get_participants(_chatRoom), 0)));
|
||||
linphone_address_clean(contactAddress);
|
||||
[self addOrGoToContact:contactAddress];
|
||||
linphone_address_unref(contactAddress);
|
||||
} else {
|
||||
[self addOrGoToContact:linphone_chat_room_get_peer_address(_chatRoom)];
|
||||
}
|
||||
} else {
|
||||
[self displayGroupInfo];
|
||||
}
|
||||
}
|
||||
|
||||
if (isEncrypted && indexPath.row == 1) {
|
||||
if (isEncrypted && indexPath.row == 1+firstIndex) {
|
||||
[self goToDeviceListView];
|
||||
}
|
||||
|
||||
BOOL canEphemeral = [self canAdminEphemeral:_chatRoom];
|
||||
if (canEphemeral && indexPath.row == 2) {
|
||||
if (canEphemeral && indexPath.row == 2+firstIndex) {
|
||||
EphemeralSettingsView *view = VIEW(EphemeralSettingsView);
|
||||
view.room = _chatRoom;
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
if ((!isEncrypted && indexPath.row == 1) || (isEncrypted && indexPath.row == 3)) {
|
||||
[self toggleMuteConversation];
|
||||
if ((!isEncrypted && indexPath.row == 1+firstIndex) || (isEncrypted && indexPath.row == 3+firstIndex)) {
|
||||
[LinphoneManager setChatroomPushEnabled:_chatRoom withPushEnabled:![LinphoneManager getChatroomPushEnabled:_chatRoom]];
|
||||
[_popupMenu reloadData];
|
||||
}
|
||||
|
||||
if ((!isEncrypted && indexPath.row == 2) || (isEncrypted && indexPath.row == 4)) {
|
||||
if ((!isEncrypted && indexPath.row == 2+firstIndex) || (isEncrypted && indexPath.row == 4+firstIndex)) {
|
||||
[_tableController onEditClick:nil];
|
||||
[self onEditionChangeClick:nil];
|
||||
}
|
||||
|
||||
if ((isEncrypted && ((!canEphemeral && indexPath.row == 4)||(canEphemeral && indexPath.row == 5)))
|
||||
|| (!isEncrypted && indexPath.row == 3)) {
|
||||
if ((isEncrypted && ((!canEphemeral && indexPath.row == 4+firstIndex)||(canEphemeral && indexPath.row == 5+firstIndex)))
|
||||
|| (!isEncrypted && indexPath.row == 3+firstIndex)) {
|
||||
[self showAddressAndIdentityPopup];
|
||||
}
|
||||
}
|
||||
|
|
@ -1831,61 +1882,89 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
if ([self canAdminEphemeral:_chatRoom])
|
||||
++nbRows;
|
||||
|
||||
if (!isOneToOne) // schedule meeting
|
||||
++nbRows;
|
||||
|
||||
return nbRows;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [[UITableViewCell alloc] init];
|
||||
|
||||
if (indexPath.row == 0) {
|
||||
if (!_chatRoom) {
|
||||
// Workaround to avoid crash in background for release 4.7. This shouldn't happen though, so there may be a deeper issue not found yet
|
||||
return cell;
|
||||
}
|
||||
|
||||
int firstIndex = isOneToOne ? 0 : 1;
|
||||
|
||||
if (!isOneToOne && indexPath.row == 0) {
|
||||
cell.imageView.image = [UIImage imageNamed:@"menu_voip_meeting_schedule"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Schedule a meeting",nil);
|
||||
}
|
||||
|
||||
if (indexPath.row == firstIndex) {
|
||||
if (isOneToOne) {
|
||||
Contact *contact = [FastAddressBook getContactWithAddress:linphone_chat_room_get_peer_address(_chatRoom)];
|
||||
Contact *contact;
|
||||
if (isEncrypted) {
|
||||
LinphoneAddress * contactAddress = linphone_address_clone(linphone_participant_get_address(bctbx_list_nth_data(linphone_chat_room_get_participants(_chatRoom), 0)));
|
||||
linphone_address_clean(contactAddress);
|
||||
contact = [FastAddressBook getContactWithAddress:contactAddress];
|
||||
linphone_address_unref(contactAddress);
|
||||
} else {
|
||||
contact = [FastAddressBook getContactWithAddress:linphone_chat_room_get_peer_address(_chatRoom)];
|
||||
}
|
||||
if (contact == nil) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"contact_add_default.png"] newSize:CGSizeMake(20, 25)];
|
||||
cell.imageView.image = [UIImage imageNamed:@"contact_add_default.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Add to contacts",nil);
|
||||
} else {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"contacts_all_default.png"] newSize:CGSizeMake(20, 25)];
|
||||
cell.imageView.image = [UIImage imageNamed:@"contacts_all_default.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Go to contact",nil);
|
||||
}
|
||||
} else {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"chat_group_informations.png"] newSize:CGSizeMake(25, 25)];
|
||||
cell.imageView.image = [UIImage imageNamed:@"chat_group_informations.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Group infos",nil);
|
||||
}
|
||||
}
|
||||
|
||||
if (isEncrypted && indexPath.row == 1) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"menu_security_default.png"] newSize:CGSizeMake(20, 25)];
|
||||
if (isEncrypted && indexPath.row == 1+firstIndex) {
|
||||
cell.imageView.image = [UIImage imageNamed:@"menu_security_default.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Conversation's devices",nil);
|
||||
}
|
||||
|
||||
bool canEphemeral = [self canAdminEphemeral:_chatRoom];
|
||||
if (canEphemeral && indexPath.row == 2) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"ephemeral_messages_default.png"] newSize:CGSizeMake(20, 25)];
|
||||
if (canEphemeral && indexPath.row == 2+firstIndex) {
|
||||
cell.imageView.image = [UIImage imageNamed:@"ephemeral_messages_default.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Ephemeral messages",nil);
|
||||
}
|
||||
|
||||
if ((isEncrypted && indexPath.row == 3) || (!isEncrypted && indexPath.row == 1)) {
|
||||
if ([self isConversationMuted]) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"menu_notifications_off.png"] newSize:CGSizeMake(20, 25)];
|
||||
cell.textLabel.text = NSLocalizedString(@"NOT IMPLEMENTED",nil);
|
||||
if ((isEncrypted && indexPath.row == 3+firstIndex) || (!isEncrypted && indexPath.row == 1+firstIndex)) {
|
||||
if ([LinphoneManager getChatroomPushEnabled:_chatRoom]) {
|
||||
cell.imageView.image = [UIImage imageNamed:@"menu_notifications_off.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Mute notifications",nil);
|
||||
} else {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"menu_notifications_on.png"] newSize:CGSizeMake(20, 25)];
|
||||
cell.textLabel.text = NSLocalizedString(@"NOT IMPLEMENTED",nil);
|
||||
cell.imageView.image = [UIImage imageNamed:@"menu_notifications_on.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Un-mute notifications",nil);
|
||||
}
|
||||
}
|
||||
|
||||
if ((isEncrypted && indexPath.row == 4) || (!isEncrypted && indexPath.row == 2)) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"delete_default.png"] newSize:CGSizeMake(20, 25)];
|
||||
if ((isEncrypted && indexPath.row == 4+firstIndex) || (!isEncrypted && indexPath.row == 2+firstIndex)) {
|
||||
cell.imageView.image = [UIImage imageNamed:@"delete_default.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Delete messages",nil);
|
||||
}
|
||||
|
||||
if ((isEncrypted && ((!canEphemeral && indexPath.row == 4)||(canEphemeral && indexPath.row == 5)))
|
||||
|| (!isEncrypted && indexPath.row == 3)) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"chat_group_informations.png"] newSize:CGSizeMake(25, 25)];
|
||||
cell.textLabel.text = NSLocalizedString(@"Show address and identity",nil);
|
||||
if ((isEncrypted && ((!canEphemeral && indexPath.row == 4+firstIndex)||(canEphemeral && indexPath.row == 5+firstIndex)))
|
||||
|| (!isEncrypted && indexPath.row == 3+firstIndex)) {
|
||||
cell.imageView.image = [UIImage imageNamed:@"chat_group_informations.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Debug infos",nil);
|
||||
}
|
||||
|
||||
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
UIImageView * icon = [[UIImageView alloc] initWithFrame:CGRectMake(tableView.frame.size.width-37, 7, 30, 30)];
|
||||
icon.contentMode = UIViewContentModeScaleAspectFit;
|
||||
icon.image = cell.imageView.image;
|
||||
[cell.contentView addSubview:icon];
|
||||
cell.imageView.image = nil;
|
||||
|
||||
return cell;
|
||||
}
|
||||
- (IBAction)onToggleMenu:(id)sender {
|
||||
|
|
@ -2194,6 +2273,7 @@ void on_shared_player_eof_reached(LinphonePlayer *p) {
|
|||
_showReplyView = true;
|
||||
[self updateFramesInclRecordingAndReplyView];
|
||||
[self.tableController scrollToMessage:message];
|
||||
[self.messageField becomeFirstResponder];
|
||||
}
|
||||
|
||||
-(void) handlePendingTransferIfAny {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
bctbx_list_free(_data);
|
||||
}
|
||||
|
||||
#pragma mark - ViewController Functions
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
|
@ -125,6 +130,7 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
|
|||
[LinphoneManager.instance lpConfigSetBool:FALSE forKey:@"create_chat"];
|
||||
} else if (![self selectFirstRow]) {
|
||||
ChatConversationCreateView *view = VIEW(ChatConversationCreateView);
|
||||
[view fragmentCompositeDescription];
|
||||
view.tableController.notFirstTime = FALSE;
|
||||
view.isForVoipConference = FALSE;
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
|
|
@ -190,7 +196,7 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
|
|||
|
||||
void deletion_chat_room_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomState newState) {
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_current_callbacks(cr);
|
||||
ChatsListTableView *view = (__bridge ChatsListTableView *)linphone_chat_room_cbs_get_user_data(cbs) ?: NULL;
|
||||
ChatsListTableView *view =cbs ? ((__bridge ChatsListTableView *)linphone_chat_room_cbs_get_user_data(cbs) ?: NULL) : NULL;
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
|
|
@ -231,7 +237,9 @@ void deletion_chat_room_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomStat
|
|||
}
|
||||
}
|
||||
[ftdToDelete cancel];
|
||||
|
||||
|
||||
// Re-enable push notification after deleting the chatroom, in order to get the notification if we are re-invited, or for secure 1-to-1 chatrooms.
|
||||
[LinphoneManager setChatroomPushEnabled:chatRoom withPushEnabled:TRUE];
|
||||
linphone_core_delete_chat_room(LC, chatRoom);
|
||||
chatRooms = chatRooms->next;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,4 +43,6 @@
|
|||
- (IBAction)onEditionChangeClick:(id)sender;
|
||||
- (IBAction)onDeleteClick:(id)sender;
|
||||
|
||||
-(void) mediaSharing;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@
|
|||
selector:@selector(ephemeralDeleted:)
|
||||
name:kLinphoneEphemeralMessageDeletedInRoom
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(displayModeChanged)
|
||||
name:kDisplayModeChanged
|
||||
object:nil];
|
||||
[_backToCallButton update];
|
||||
self.tableController.waitView = _waitView;
|
||||
[self setEditing:NO];
|
||||
|
|
@ -54,20 +58,43 @@
|
|||
forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.view addSubview:button];*/
|
||||
|
||||
BOOL forwardMode = VIEW(ChatConversationView).pendingForwardMessage != nil;
|
||||
[self mediaSharing];
|
||||
|
||||
}
|
||||
|
||||
- (void)mediaSharing{
|
||||
BOOL forwardMode;
|
||||
|
||||
NSString* groupName = [NSString stringWithFormat:@"group.%@.linphoneExtension",[[NSBundle mainBundle] bundleIdentifier]];
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName];
|
||||
NSDictionary *dict = [defaults valueForKey:@"photoData"];
|
||||
NSDictionary *dictFile = [defaults valueForKey:@"icloudData"];
|
||||
NSDictionary *dictUrl = [defaults valueForKey:@"url"];
|
||||
if(dict||dictFile||dictUrl) VIEW(ChatConversationView).sharingMedia = TRUE;
|
||||
|
||||
if(VIEW(ChatConversationView).sharingMedia == nil){
|
||||
forwardMode = VIEW(ChatConversationView).pendingForwardMessage != nil;
|
||||
}else{
|
||||
forwardMode = VIEW(ChatConversationView).sharingMedia != nil;
|
||||
}
|
||||
_tableController.editButton.hidden = forwardMode;
|
||||
_forwardTitle.text = NSLocalizedString(@"Select a discussion or create a new one",nil);
|
||||
if(VIEW(ChatConversationView).sharingMedia == nil){
|
||||
_forwardTitle.text = NSLocalizedString(@"Select a discussion or create a new one",nil);
|
||||
}
|
||||
else{
|
||||
_forwardTitle.text = NSLocalizedString(@"Select or create a conversation to share the file(s)",nil);
|
||||
}
|
||||
_forwardTitle.hidden = !forwardMode;
|
||||
_cancelForwardButton.hidden = !forwardMode;
|
||||
|
||||
_tableController.tableView.frame = CGRectMake(0, 66 + (forwardMode ? _forwardTitle.frame.size.height : 0), _tableController.tableView.frame.size.width, self.view.frame.size.height - 66 - ( forwardMode ? _forwardTitle.frame.size.height : 0 ));
|
||||
_addButton.frame = CGRectMake(forwardMode ? 82 : 0 , _addButton.frame.origin.y, _addButton.frame.size.width, _addButton.frame.size.height);
|
||||
_addGroupChatButton.frame = CGRectMake(forwardMode ? 164 : 82 , _addGroupChatButton.frame.origin.y, _addGroupChatButton.frame.size.width, _addGroupChatButton.frame.size.height);
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void)displayModeChanged{
|
||||
[self.tableController.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)ephemeralDeleted:(NSNotification *)notif {
|
||||
//LinphoneChatRoom *r =[[notif.userInfo objectForKey:@"room"] intValue];
|
||||
|
|
@ -117,6 +144,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)newChatCreate:(BOOL)isGroup {
|
||||
ChatConversationCreateView *view = VIEW(ChatConversationCreateView);
|
||||
[view fragmentCompositeDescription];
|
||||
view.isForEditing = false;
|
||||
view.isGroupChat = isGroup;
|
||||
view.tableController.notFirstTime = FALSE;
|
||||
|
|
@ -172,8 +200,16 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (IBAction)onCancelForwardClicked:(id)sender {
|
||||
VIEW(ChatConversationView).sharingMedia = nil;
|
||||
VIEW(ChatConversationView).pendingForwardMessage = nil;
|
||||
NSString* groupName = [NSString stringWithFormat:@"group.%@.linphoneExtension",[[NSBundle mainBundle] bundleIdentifier]];
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName];
|
||||
[defaults removeObjectForKey:@"photoData"];
|
||||
[defaults removeObjectForKey:@"icloudData"];
|
||||
[defaults removeObjectForKey:@"url"];
|
||||
[PhoneMainView.instance popCurrentView];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
@property(nonatomic, strong) NSMutableArray *sipAddresses;
|
||||
@property(nonatomic, strong) NSMutableArray *emails;
|
||||
@property(nonatomic, strong) NSMutableArray *phones;
|
||||
@property BOOL createdFromLdap;
|
||||
@property BOOL createdFromLdapOrProvisioning;
|
||||
@property BOOL added;
|
||||
|
||||
- (void)setAvatar:(UIImage *)avatar;
|
||||
|
|
@ -58,4 +58,6 @@
|
|||
- (BOOL)removeSipAddressAtIndex:(NSInteger)index;
|
||||
- (BOOL)removePhoneNumberAtIndex:(NSInteger)index;
|
||||
- (BOOL)removeEmailAtIndex:(NSInteger)index;
|
||||
|
||||
- (NSMutableArray*)getSipAddressesWithoutDuplicatePhoneNumbers;
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
_person = acncontact;
|
||||
_friend = afriend ? linphone_friend_ref(afriend) : NULL;
|
||||
_added = FALSE;
|
||||
_createdFromLdap = FALSE;
|
||||
_createdFromLdapOrProvisioning = FALSE;
|
||||
_phones = [[NSMutableArray alloc] init];
|
||||
_sipAddresses = [[NSMutableArray alloc] init];
|
||||
_emails = [[NSMutableArray alloc] init];
|
||||
|
|
@ -64,13 +64,17 @@
|
|||
}
|
||||
const char *key = [NSString stringWithFormat:@"ab%@", acncontact.identifier].UTF8String;
|
||||
// try to find friend associated with that person
|
||||
if (_friend){
|
||||
linphone_friend_unref(_friend);
|
||||
_friend = nil;
|
||||
}
|
||||
_friend = linphone_friend_list_find_friend_by_ref_key(linphone_core_get_default_friend_list(LC), key);
|
||||
if (!_friend) {
|
||||
_friend = linphone_friend_ref(linphone_core_create_friend(LC));
|
||||
_friend = linphone_core_create_friend(LC);
|
||||
linphone_friend_set_ref_key(_friend, key);
|
||||
linphone_friend_set_name(_friend, [NSString stringWithFormat:@"%@%@", _firstName ? _firstName : @"", _lastName ? [_firstName ? @" " : @"" stringByAppendingString:_lastName] : @""] .UTF8String);
|
||||
for (NSString *sipAddr in _sipAddresses) {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, sipAddr.UTF8String);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, sipAddr.UTF8String, true);
|
||||
if (addr) {
|
||||
linphone_address_set_display_name(addr, [self displayName].UTF8String);
|
||||
linphone_friend_add_address(_friend, addr);
|
||||
|
|
@ -85,9 +89,7 @@
|
|||
linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny);
|
||||
linphone_core_add_friend(LC, _friend);
|
||||
}
|
||||
}
|
||||
linphone_friend_ref(_friend);
|
||||
|
||||
}else linphone_friend_ref(_friend);
|
||||
} else if (_friend) {
|
||||
[self loadFriend];
|
||||
} else {
|
||||
|
|
@ -287,7 +289,7 @@
|
|||
[_person setValue:tmpSipAddresses forKey:CNContactInstantMessageAddressesKey];
|
||||
ret = TRUE;
|
||||
} else {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, sip.UTF8String) ?: linphone_address_new(sip.UTF8String);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, sip.UTF8String, true) ?: linphone_address_new(sip.UTF8String);
|
||||
if (!addr)
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -370,7 +372,7 @@
|
|||
}
|
||||
ret = TRUE;
|
||||
} else {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, ((NSString *)_sipAddresses[index]).UTF8String);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, ((NSString *)_sipAddresses[index]).UTF8String, true);
|
||||
if (!addr)
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -461,11 +463,11 @@
|
|||
// try to find friend associated with that person
|
||||
_friend = linphone_friend_list_find_friend_by_ref_key(linphone_core_get_default_friend_list(LC), key);
|
||||
if (!_friend) {
|
||||
_friend = linphone_friend_ref(linphone_core_create_friend(LC));
|
||||
_friend = linphone_core_create_friend(LC);
|
||||
linphone_friend_set_ref_key(_friend, key);
|
||||
linphone_friend_set_name(_friend, [NSString stringWithFormat:@"%@%@", _firstName ? _firstName : @"", _lastName ? [_firstName ? @" " : @"" stringByAppendingString:_lastName] : @""] .UTF8String);
|
||||
for (NSString *sipAddr in _sipAddresses) {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, sipAddr.UTF8String);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, sipAddr.UTF8String, true);
|
||||
if (addr) {
|
||||
linphone_address_set_display_name(addr, [self displayName].UTF8String);
|
||||
linphone_friend_add_address(_friend, addr);
|
||||
|
|
@ -480,12 +482,31 @@
|
|||
linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny);
|
||||
linphone_core_add_friend(LC, _friend);
|
||||
}
|
||||
}
|
||||
linphone_friend_ref(_friend);
|
||||
} else linphone_friend_ref(_friend);
|
||||
}
|
||||
|
||||
- (void)clearFriend {
|
||||
if (_friend) linphone_friend_unref(_friend);
|
||||
_friend = NULL;
|
||||
}
|
||||
|
||||
- (NSMutableArray*)getSipAddressesWithoutDuplicatePhoneNumbers {
|
||||
NSMutableArray* resAdresses = [[NSMutableArray alloc] init];
|
||||
|
||||
for (NSString *address in _sipAddresses) {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, [address UTF8String], YES);
|
||||
bool isFoundInPhones = false;
|
||||
if (addr && linphone_address_get_username(addr)) {
|
||||
for (NSString *phoneNb in _phones) {
|
||||
if ([phoneNb isEqualToString:[NSString stringWithUTF8String:linphone_address_get_username(addr)]]) {
|
||||
isFoundInPhones = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isFoundInPhones) [resAdresses addObject:address];
|
||||
}
|
||||
|
||||
return resAdresses;
|
||||
}
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -160,15 +160,15 @@
|
|||
/*first and last name only when editting */
|
||||
return (self.tableView.isEditing) ? 1 : 0;
|
||||
} else if (section == ContactSections_Sip) {
|
||||
return _contact.createdFromLdap ? 0 : _contact.sipAddresses.count;
|
||||
return [_contact getSipAddressesWithoutDuplicatePhoneNumbers].count;
|
||||
} else if (section == ContactSections_Number) {
|
||||
return _contact.phones.count;
|
||||
} else if (section == ContactSections_Email) {
|
||||
BOOL showEmails = [LinphoneManager.instance
|
||||
lpConfigBoolForKey:@"show_contacts_emails_preference"];
|
||||
return showEmails ? _contact.emails.count : 0;
|
||||
}
|
||||
return 0;
|
||||
return _contact.phones.count;
|
||||
} else if (section == ContactSections_Email) {
|
||||
BOOL showEmails = [LinphoneManager.instance
|
||||
lpConfigBoolForKey:@"show_contacts_emails_preference"];
|
||||
return showEmails ? _contact.emails.count : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -200,7 +200,7 @@
|
|||
LinphoneAddress *addr = NULL;
|
||||
if ([LinphoneManager.instance
|
||||
lpConfigBoolForKey:@"contact_display_username_only"] &&
|
||||
(addr = linphone_core_interpret_url(LC, [value UTF8String]))) {
|
||||
(addr = linphone_core_interpret_url_2(LC, [value UTF8String], YES))) {
|
||||
value =
|
||||
[NSString stringWithCString:linphone_address_get_username(addr)
|
||||
encoding:[NSString defaultCStringEncoding]];
|
||||
|
|
@ -283,7 +283,7 @@
|
|||
if (section == ContactSections_Number) {
|
||||
text = NSLocalizedString(@"Phone numbers", nil);
|
||||
addEntryName = NSLocalizedString(@"Add new phone number", nil);
|
||||
} else if (section == ContactSections_Sip && !_contact.createdFromLdap) {
|
||||
} else if (section == ContactSections_Sip && !_contact.createdFromLdapOrProvisioning) {
|
||||
text = NSLocalizedString(@"SIP addresses", nil);
|
||||
addEntryName = NSLocalizedString(@"Add new SIP address", nil);
|
||||
} else if (section == ContactSections_Email &&
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@
|
|||
}
|
||||
|
||||
for (NSString *sipAddr in _contact.sipAddresses) {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, sipAddr.UTF8String);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, sipAddr.UTF8String, true);
|
||||
if (addr) {
|
||||
linphone_friend_add_address(_contact.friend, addr);
|
||||
linphone_address_destroy(addr);
|
||||
|
|
@ -119,8 +119,8 @@
|
|||
_contact = acontact;
|
||||
_emptyLabel.hidden = (_contact != NULL);
|
||||
_avatarImage.hidden = !_emptyLabel.hidden;
|
||||
_deleteButton.hidden = !_emptyLabel.hidden || [_contact createdFromLdap];
|
||||
_editButton.hidden = !_emptyLabel.hidden || [_contact createdFromLdap];
|
||||
_deleteButton.hidden = !_emptyLabel.hidden || [_contact createdFromLdapOrProvisioning];
|
||||
_editButton.hidden = !_emptyLabel.hidden || [_contact createdFromLdapOrProvisioning];
|
||||
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact] bordered:NO withRoundedRadius:YES];
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];
|
||||
|
|
@ -146,7 +146,7 @@
|
|||
}
|
||||
|
||||
- (void)addCurrentContactContactField:(NSString *)address {
|
||||
LinphoneAddress *linphoneAddress = linphone_core_interpret_url(LC, address.UTF8String);
|
||||
LinphoneAddress *linphoneAddress = linphone_core_interpret_url_2(LC, address.UTF8String, true);
|
||||
NSString *username =
|
||||
linphoneAddress ? [NSString stringWithUTF8String:linphone_address_get_username(linphoneAddress)] : address;
|
||||
|
||||
|
|
@ -284,6 +284,9 @@
|
|||
if (IPAD && self.contact == NULL) {
|
||||
_editButton.hidden = TRUE;
|
||||
_deleteButton.hidden = TRUE;
|
||||
} else if (self.contact != NULL && self.contact.createdFromLdapOrProvisioning) {
|
||||
_editButton.hidden = TRUE;
|
||||
_deleteButton.hidden = TRUE;
|
||||
}
|
||||
PhoneMainView.instance.currentName = _nameLabel.text;
|
||||
// Update presence for contact
|
||||
|
|
@ -296,6 +299,7 @@
|
|||
[_editButton setImage:[UIImage imageNamed:@"valid_default.png"] forState:UIControlStateSelected];
|
||||
|
||||
[self updateBackOrCancelButton];
|
||||
[self recomputeTableViewSize:FALSE];
|
||||
}
|
||||
|
||||
- (void)deviceOrientationDidChange:(NSNotification*)notif {
|
||||
|
|
@ -310,9 +314,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (self.contact != NULL && self.contact.createdFromLdapOrProvisioning) {
|
||||
_editButton.hidden = TRUE;
|
||||
_deleteButton.hidden = TRUE;
|
||||
}
|
||||
_nameLabel.hidden = self.tableController.isEditing;
|
||||
[self updateBackOrCancelButton];
|
||||
|
||||
[self recomputeTableViewSize:_editButton.hidden];
|
||||
[self recomputeTableViewSize:self.tableController.isEditing];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
|
@ -408,10 +416,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)recomputeTableViewSize:(BOOL)editing {
|
||||
CGRect frame = _tableController.tableView.frame;
|
||||
frame.origin.y = _avatarImage.frame.size.height + _avatarImage.frame.origin.y;
|
||||
if ([self viewIsCurrentlyPortrait] && !editing) {
|
||||
frame.origin.y += _nameLabel.frame.size.height;
|
||||
}
|
||||
frame.origin.y = _nameLabel.frame.origin.y + _nameLabel.frame.size.height;
|
||||
} else {
|
||||
frame.origin.y = _avatarImage.frame.size.height + _avatarImage.frame.origin.y;
|
||||
}
|
||||
|
||||
frame.size.height = _tableController.tableView.contentSize.height;
|
||||
_tableController.tableView.frame = frame;
|
||||
|
|
@ -514,11 +523,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
NSString* previous = [PhoneMainView.instance getPreviousViewName];
|
||||
if ([previous isEqualToString:@"ContactsListView"] || [previous isEqualToString:@"ImagePickerView"]) {
|
||||
ContactsListView *view = VIEW(ContactsListView);
|
||||
if ([previous isEqualToString:@"HistoryDetailsView"]) {
|
||||
HistoryDetailsView *view = VIEW(HistoryDetailsView);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
} else {
|
||||
HistoryDetailsView *view = VIEW(HistoryDetailsView);
|
||||
ContactsListView *view = VIEW(ContactsListView);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
}
|
||||
|
|
@ -588,7 +597,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[[store unifiedContactWithIdentifier:contactToCheck.identifier keysToFetch:keysToFetch error:nil] mutableCopy];
|
||||
if(mCNContact == NULL){
|
||||
for(NSString *address in contactToCheck.sipAddresses){
|
||||
NSString *name = [FastAddressBook normalizeSipURI:address];
|
||||
NSString *name = [FastAddressBook normalizeSipURI:address use_prefix:TRUE];
|
||||
if([LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:name]){
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ typedef enum _ContactSelectionMode { ContactSelectionModeNone, ContactSelectionM
|
|||
@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *toggleSelectionButton;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *loadingLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIView *loadingView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *ldapMoreResultsLabel;
|
||||
|
||||
- (IBAction)onAllClick:(id)event;
|
||||
- (IBAction)onLinphoneClick:(id)event;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,15 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector:@selector(onMagicSearchFinished:)
|
||||
name:kLinphoneMagicSearchFinished
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(onMagicSearchMoreAvailable:)
|
||||
name:kLinphoneMagicSearchMoreAvailable
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(displayModeChanged)
|
||||
name:kDisplayModeChanged
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)onMagicSearchStarted:(NSNotification *)k {
|
||||
|
|
@ -150,6 +159,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
- (void)onMagicSearchFinished:(NSNotification *)k {
|
||||
_loadingView.hidden = TRUE;
|
||||
}
|
||||
- (void)onMagicSearchMoreAvailable:(NSNotification *)k {
|
||||
_ldapMoreResultsLabel.hidden = FALSE;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
NSLog(@"Debuglog viewDidAppear");
|
||||
|
|
@ -225,7 +237,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (void)refreshButtons {
|
||||
[addButton setHidden:FALSE];
|
||||
[addButton setHidden:![LinphoneManager.instance lpConfigBoolForKey:@"enable_native_address_book"]];
|
||||
[self changeView:[ContactSelection getSipFilterEnabled] ? ContactsLinphone : ContactsAll];
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +262,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)displayModeChanged{
|
||||
[self.tableController.tableView reloadData];
|
||||
}
|
||||
|
||||
- (IBAction)onDeleteClick:(id)sender {
|
||||
NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"Do you want to delete selected contacts?\nThey will also be deleted from your phone's address book.", nil)];
|
||||
[LinphoneManager.instance setContactsUpdated:TRUE];
|
||||
|
|
@ -268,6 +284,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (IBAction)onEditionChangeClick:(id)sender {
|
||||
allButton.hidden = linphoneButton.hidden = _selectedButtonImage.hidden = addButton.hidden = self.tableController.isEditing;
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"enable_native_address_book"]) {
|
||||
addButton.hidden = self.tableController.isEditing;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
||||
|
|
@ -292,6 +311,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (searchText.length == 0) {
|
||||
[LinphoneManager.instance setContactsUpdated:TRUE];
|
||||
}
|
||||
_ldapMoreResultsLabel.hidden = TRUE;
|
||||
[tableController loadDataWithFilter:searchText];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,9 +145,17 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_videoCameraSwitch setHidden:FALSE];
|
||||
}
|
||||
}
|
||||
[_addContactButton setImage:[UIImage imageNamed:@"voip_conference_new"] forState:UIControlStateNormal];
|
||||
_addContactButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_addContactButton.enabled = true;
|
||||
|
||||
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
|
||||
if (!(defaultAccount && linphone_account_params_get_conference_factory_uri(linphone_account_get_params(defaultAccount)))){
|
||||
[_addContactButton setImage:[UIImage imageNamed:@"contact_add_default"] forState:UIControlStateNormal];
|
||||
_addContactButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_addContactButton.enabled = true;
|
||||
}else{
|
||||
[_addContactButton setImage:[UIImage imageNamed:@"voip_conference_new"] forState:UIControlStateNormal];
|
||||
_addContactButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_addContactButton.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||||
|
|
@ -175,10 +183,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_padView.hidden = !IPAD && UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
|
||||
if (linphone_core_get_calls_nb(LC)) {
|
||||
_backButton.hidden = FALSE;
|
||||
_addContactButton.hidden = TRUE;
|
||||
} else {
|
||||
_backButton.hidden = TRUE;
|
||||
_addContactButton.hidden = FALSE;
|
||||
}
|
||||
_addContactButton.hidden = FALSE;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
|
|
@ -392,19 +401,38 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
#pragma mark - Action Functions
|
||||
|
||||
- (IBAction)onAddContactClick:(id)event {
|
||||
ConferenceSchedulingView *view = VIEW(ConferenceSchedulingView);
|
||||
[view resetViewModel];
|
||||
[PhoneMainView.instance changeCurrentView:ConferenceSchedulingView.compositeViewDescription];
|
||||
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
|
||||
if (!(defaultAccount && linphone_account_params_get_conference_factory_uri(linphone_account_get_params(defaultAccount)))){
|
||||
[ContactSelection setSelectionMode:ContactSelectionModeEdit];
|
||||
[ContactSelection setAddAddress:[_addressField text]];
|
||||
[ContactSelection enableSipFilter:FALSE];
|
||||
[PhoneMainView.instance changeCurrentView:ContactsListView.compositeViewDescription];
|
||||
}else{
|
||||
ConferenceSchedulingView *view = VIEW(ConferenceSchedulingView);
|
||||
[view resetViewModel];
|
||||
[PhoneMainView.instance changeCurrentView:ConferenceSchedulingView.compositeViewDescription];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onBackClick:(id)event {
|
||||
[PhoneMainView.instance popToView:ActiveCallOrConferenceView.compositeViewDescription];
|
||||
[PhoneMainView.instance popToView:[CallsViewModelBridge callViewToDisplay]];
|
||||
}
|
||||
|
||||
- (IBAction)onAddressChange:(id)sender {
|
||||
if ([self displayDebugPopup:_addressField.text]) {
|
||||
_addressField.text = @"";
|
||||
}
|
||||
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
|
||||
if (!(defaultAccount && linphone_account_params_get_conference_factory_uri(linphone_account_get_params(defaultAccount)))){
|
||||
[_addContactButton setImage:[UIImage imageNamed:@"contact_add_default"] forState:UIControlStateNormal];
|
||||
_addContactButton.enabled = ([[_addressField text] length] > 0);
|
||||
if ([_addressField.text length] == 0) {
|
||||
[self.view endEditing:YES];
|
||||
}
|
||||
}else{
|
||||
[_addContactButton setImage:[UIImage imageNamed:@"voip_conference_new"] forState:UIControlStateNormal];
|
||||
_addContactButton.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onBackspaceClick:(id)sender {
|
||||
|
|
|
|||
|
|
@ -69,14 +69,15 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
object:nil];
|
||||
|
||||
// Update on show
|
||||
const MSList *list = linphone_core_get_account_list([LinphoneManager getLc]);
|
||||
MSList *list = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
if (list != NULL) {
|
||||
LinphoneAccount *account = (LinphoneAccount *)list->data;
|
||||
if (account) {
|
||||
[self registrationUpdate:linphone_account_get_state(account)];
|
||||
}
|
||||
}
|
||||
|
||||
bctbx_list_free(list);
|
||||
|
||||
if (account_creator) {
|
||||
linphone_account_creator_unref(account_creator);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
@property (weak, nonatomic) IBOutlet UIView *waitView;
|
||||
@property (weak, nonatomic) IBOutlet UIRoundedImageView *linphoneImage;
|
||||
@property (weak, nonatomic) IBOutlet UIView *optionsView;
|
||||
@property(weak, nonatomic) IBOutlet UIButton *chatButton;
|
||||
@property (weak, nonatomic) IBOutlet UIView *encryptedChatView;
|
||||
|
||||
- (IBAction)onBackClick:(id)event;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,12 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_headerView addGestureRecognizer:headerTapGesture];
|
||||
}
|
||||
|
||||
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
|
||||
_chatButton.hidden = [LinphoneManager.instance lpConfigBoolForKey:@"force_lime_chat_rooms"];
|
||||
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
|
||||
[self update];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
_waitView.hidden = YES;
|
||||
|
|
|
|||
|
|
@ -268,9 +268,13 @@
|
|||
} else {
|
||||
if (linphone_call_log_was_conference(callLog)) {
|
||||
LinphoneConferenceInfo *confInfo = linphone_call_log_get_conference_info(callLog);
|
||||
ConferenceWaitingRoomFragment *view = VIEW(ConferenceWaitingRoomFragment);
|
||||
if (linphone_conference_info_get_state(confInfo) == LinphoneConferenceInfoStateCancelled) {
|
||||
[ConferenceViewModelBridge showCancelledMeetingWithCConferenceInfo:confInfo];
|
||||
return;
|
||||
}
|
||||
ConferenceWaitingRoomView *view = VIEW(ConferenceWaitingRoomView);
|
||||
[view setDetailsWithSubject:[NSString stringWithUTF8String:linphone_conference_info_get_subject(confInfo)] url:[NSString stringWithUTF8String:linphone_address_as_string(linphone_conference_info_get_uri(confInfo))]];
|
||||
[PhoneMainView.instance changeCurrentView:ConferenceWaitingRoomFragment.compositeViewDescription];
|
||||
[PhoneMainView.instance changeCurrentView:ConferenceWaitingRoomView.compositeViewDescription];
|
||||
} else {
|
||||
const LinphoneAddress *addr = linphone_call_log_get_remote_address(callLog);
|
||||
[LinphoneManager.instance call:addr];
|
||||
|
|
|
|||
|
|
@ -67,10 +67,15 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
// Fake event
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self];
|
||||
[_toggleSelectionButton setImage:[UIImage imageNamed:@"select_all_default.png"] forState:UIControlStateSelected];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(displayModeChanged)
|
||||
name:kDisplayModeChanged
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void) viewWillDisappear:(BOOL)animated {
|
||||
self.view = NULL;
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
@ -100,6 +105,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_selectedButtonImage.frame = frame;
|
||||
}
|
||||
|
||||
- (void)displayModeChanged{
|
||||
[self.tableController.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma m ~ark - Action Functions
|
||||
|
||||
- (IBAction)onAllClick:(id)event {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#import <IntentsUI/IntentsUI.h>
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
#import "SVProgressHUD.h"
|
||||
|
||||
|
||||
#ifdef USE_CRASHLYTICS
|
||||
#include "FIRApp.h"
|
||||
|
|
@ -85,6 +87,7 @@
|
|||
[LinphoneManager.instance.fastAddressBook reloadFriends];
|
||||
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:nil];
|
||||
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
|
|
@ -137,7 +140,6 @@
|
|||
if ((floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max)) {
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"autoanswer_notif_preference"]) {
|
||||
linphone_call_accept(call);
|
||||
[PhoneMainView.instance changeCurrentView:ActiveCallOrConferenceView.compositeViewDescription];
|
||||
} else {
|
||||
[PhoneMainView.instance displayIncomingCall:call];
|
||||
}
|
||||
|
|
@ -156,7 +158,9 @@
|
|||
[self handleShortcut:_shortcutItem];
|
||||
_shortcutItem = nil;
|
||||
}
|
||||
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
#else
|
||||
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge)
|
||||
completionHandler:^(BOOL granted, NSError *_Nullable error) {
|
||||
if (error)
|
||||
|
|
@ -182,6 +186,16 @@
|
|||
}
|
||||
|
||||
}];
|
||||
#endif
|
||||
|
||||
|
||||
if ([UIDeviceBridge switchedDisplayMode]) {
|
||||
[AvatarBridge prepareIt];
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kDisplayModeChanged object:nil];
|
||||
[PhoneMainView.instance.mainViewController removeEntryFromCache:ChatConversationCreateView.compositeViewDescription.name];
|
||||
[PhoneMainView.instance.mainViewController changeView:PhoneMainView.instance.currentView];
|
||||
[UIDeviceBridge notifyDisplayModeSwitch];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -331,8 +345,9 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
[PhoneMainView.instance.mainViewController getCachedController:ActiveCallOrConferenceView.compositeViewDescription.name]; // This will create the single instance of the ActiveCallOrConferenceView including listeneres
|
||||
|
||||
[PhoneMainView.instance.mainViewController getCachedController:SingleCallView.compositeViewDescription.name]; // This will create the single instance of the SingleCallView including listeneres
|
||||
[PhoneMainView.instance.mainViewController getCachedController:ConferenceCallView.compositeViewDescription.name]; // This will create the single instance of the ConferenceCallView including listeneres
|
||||
[CallsViewModelBridge setupCallsViewNavigation];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
|
@ -352,6 +367,7 @@
|
|||
- (BOOL)handleShortcut:(UIApplicationShortcutItem *)shortcutItem {
|
||||
BOOL success = NO;
|
||||
if ([shortcutItem.type isEqualToString:@"linphone.phone.action.newMessage"]) {
|
||||
[VIEW(ChatConversationCreateView) fragmentCompositeDescription];
|
||||
[PhoneMainView.instance changeCurrentView:ChatConversationCreateView.compositeViewDescription];
|
||||
success = YES;
|
||||
}
|
||||
|
|
@ -388,7 +404,15 @@
|
|||
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
} else if([[url scheme] isEqualToString:@"message-linphone"]) {
|
||||
[PhoneMainView.instance popToView:ChatsListView.compositeViewDescription];
|
||||
if ([[PhoneMainView.instance currentView] equal:ChatsListView.compositeViewDescription]) {
|
||||
VIEW(ChatConversationView).sharingMedia = TRUE;
|
||||
ChatsListView *view = VIEW(ChatsListView);
|
||||
[view mediaSharing];
|
||||
}else{
|
||||
[SVProgressHUD dismiss];
|
||||
VIEW(ChatConversationView).sharingMedia = TRUE;
|
||||
[PhoneMainView.instance popToView:ChatsListView.compositeViewDescription];
|
||||
}
|
||||
} else if ([scheme isEqualToString:@"sip"]||[scheme isEqualToString:@"sips"]) {
|
||||
// remove "sip://" from the URI, and do it correctly by taking resourceSpecifier and removing leading and
|
||||
// trailing "/"
|
||||
|
|
@ -503,15 +527,15 @@
|
|||
|
||||
- (void) userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
|
||||
// If an app extension launch a user notif while app is in fg, it is catch by the app
|
||||
NSString *category = [[[notification request] content] categoryIdentifier];
|
||||
if (category && [category isEqualToString:@"app_active"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *category = [[[notification request] content] categoryIdentifier];
|
||||
if (category && [category isEqualToString:@"app_active"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (category && [category isEqualToString:@"msg_cat"] && [UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
|
||||
if ((PhoneMainView.instance.currentView == ChatsListView.compositeViewDescription))
|
||||
return;
|
||||
|
||||
|
||||
if (PhoneMainView.instance.currentView == ChatConversationView.compositeViewDescription) {
|
||||
NSDictionary *userInfo = [[[notification request] content] userInfo];
|
||||
NSString *peerAddress = userInfo[@"peer_addr"];
|
||||
|
|
@ -519,12 +543,12 @@
|
|||
if (peerAddress && localAddress) {
|
||||
LinphoneAddress *peer = linphone_core_create_address([LinphoneManager getLc], peerAddress.UTF8String);
|
||||
LinphoneAddress *local = linphone_core_create_address([LinphoneManager getLc], localAddress.UTF8String);
|
||||
LinphoneChatRoom *room = linphone_core_find_chat_room([LinphoneManager getLc], peer, local);
|
||||
LinphoneChatRoom *room = linphone_core_search_chat_room([LinphoneManager getLc], NULL, local, peer, NULL);
|
||||
if (room == PhoneMainView.instance.currentRoom) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
completionHandler(UNNotificationPresentationOptionAlert);
|
||||
}
|
||||
|
||||
|
|
@ -616,7 +640,6 @@
|
|||
}
|
||||
} else if ([response.notification.request.content.categoryIdentifier isEqual:@"video_request"]) {
|
||||
if (!call) return;
|
||||
[PhoneMainView.instance changeCurrentView:ActiveCallOrConferenceView.compositeViewDescription];
|
||||
NSTimer *videoDismissTimer = nil;
|
||||
UIConfirmationDialog *sheet = [UIConfirmationDialog ShowWithMessage:response.notification.request.content.body
|
||||
cancelMessage:nil
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
@implementation LinphoneCoreSettingsStore
|
||||
|
||||
- (id)init {
|
||||
|
|
@ -141,7 +142,9 @@
|
|||
}
|
||||
|
||||
- (void)transformAccountToKeys:(NSString *)username {
|
||||
const MSList *accountList = linphone_core_get_account_list(LC);
|
||||
//const MSList *accountList = linphone_core_get_account_list(LC);
|
||||
MSList *accountListToBeFreed = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
MSList *accountList = accountListToBeFreed;
|
||||
while (username && accountList &&
|
||||
strcmp(username.UTF8String,
|
||||
linphone_address_get_username(linphone_account_params_get_identity_address(linphone_account_get_params(accountList->data)))) != 0) {
|
||||
|
|
@ -168,6 +171,7 @@
|
|||
[self setInteger:-1 forKey:@"account_expire_preference"];
|
||||
[self setInteger:-1 forKey:@"current_proxy_config_preference"];
|
||||
[self setCString:"" forKey:@"account_prefix_preference"];
|
||||
[self setBool:YES forKey:@"apply_international_prefix_for_calls_and_chats"];
|
||||
[self setBool:NO forKey:@"account_substitute_+_by_00_preference"];
|
||||
[self setBool:NO forKey:@"account_ice_preference"];
|
||||
[self setCString:"" forKey:@"account_stun_preference"];
|
||||
|
|
@ -183,7 +187,7 @@
|
|||
|
||||
const LinphoneAddress *identity_addr = linphone_account_params_get_identity_address(accountParams);
|
||||
const char *server_addr = linphone_account_params_get_server_addr(accountParams);
|
||||
LinphoneAddress *proxy_addr = linphone_core_interpret_url(LC, server_addr);
|
||||
LinphoneAddress *proxy_addr = linphone_core_interpret_url_2(LC, server_addr, false);
|
||||
if (identity_addr && proxy_addr) {
|
||||
int port = linphone_address_get_port(proxy_addr);
|
||||
|
||||
|
|
@ -234,9 +238,11 @@
|
|||
[self setCString:linphone_auth_info_get_algorithm(ai) forKey:@"ha1_algo_preference"];
|
||||
}
|
||||
|
||||
MSList *accountsList = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
int idx = (int)bctbx_list_index(linphone_core_get_account_list(LC), account);
|
||||
[self setInteger:idx forKey:@"current_proxy_config_preference"];
|
||||
|
||||
bctbx_list_free(accountsList);
|
||||
|
||||
int expires = linphone_account_params_get_expires(accountParams);
|
||||
[self setInteger:expires forKey:@"account_expire_preference"];
|
||||
|
||||
|
|
@ -251,10 +257,13 @@
|
|||
{
|
||||
const char *dial_prefix = linphone_account_params_get_international_prefix(accountParams);
|
||||
[self setCString:dial_prefix forKey:@"account_prefix_preference"];
|
||||
BOOL apply_prefix = linphone_account_params_get_use_international_prefix_for_calls_and_chats(accountParams);
|
||||
[self setBool:apply_prefix forKey:@"apply_international_prefix_for_calls_and_chats"];
|
||||
BOOL dial_escape_plus = linphone_account_params_get_dial_escape_plus_enabled(accountParams);
|
||||
[self setBool:dial_escape_plus forKey:@"account_substitute_+_by_00_preference"];
|
||||
}
|
||||
}
|
||||
bctbx_list_free(accountListToBeFreed);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -343,15 +352,17 @@
|
|||
|
||||
// root section
|
||||
{
|
||||
const bctbx_list_t *accounts = linphone_core_get_account_list(LC);
|
||||
size_t count = bctbx_list_size(accounts);
|
||||
for (size_t i = 1; i <= count; i++, accounts = accounts->next) {
|
||||
MSList *accountsListToBeFreed = [lm createAccountsNotHiddenList];
|
||||
MSList *accountsList = accountsListToBeFreed;
|
||||
size_t count = bctbx_list_size(accountsList);
|
||||
for (size_t i = 1; i <= count; i++, accountsList = accountsList->next) {
|
||||
NSString *key = [NSString stringWithFormat:@"menu_account_%lu", i];
|
||||
LinphoneAccount *account = (LinphoneAccount *)accounts->data;
|
||||
LinphoneAccount *account = (LinphoneAccount *)accountsList->data;
|
||||
[self setCString:linphone_address_get_username(linphone_account_params_get_identity_address(linphone_account_get_params(account)))
|
||||
forKey:key];
|
||||
}
|
||||
|
||||
bctbx_free(accountsListToBeFreed);
|
||||
|
||||
[self setBool:linphone_core_video_display_enabled(LC) forKey:@"enable_video_preference"];
|
||||
[self setBool:[LinphoneManager.instance lpConfigBoolForKey:@"auto_answer"]
|
||||
forKey:@"enable_auto_answer_preference"];
|
||||
|
|
@ -431,10 +442,10 @@
|
|||
{
|
||||
[self setCString:linphone_core_get_file_transfer_server(LC) forKey:@"file_transfer_server_url_preference"];
|
||||
int maxSize = linphone_core_get_max_size_for_auto_download_incoming_files(LC);
|
||||
[self setObject:maxSize==0 ? @"Always" : (maxSize==-1 ? @"Nerver" : @"Customize") forKey:@"auto_download_mode"];
|
||||
[self setObject:maxSize==0 ? @"Always" : (maxSize==-1 ? @"Never" : @"Customize") forKey:@"auto_download_mode"];
|
||||
[self setInteger:maxSize forKey:@"auto_download_incoming_files_max_size"];
|
||||
[self setBool:[VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] forKey:@"vfs_enabled_mode"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"auto_write_to_gallery_preference" withDefault:YES] forKey:@"auto_write_to_gallery_mode"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"auto_write_to_gallery_preference" withDefault:NO] forKey:@"auto_write_to_gallery_mode"];
|
||||
}
|
||||
|
||||
// network section
|
||||
|
|
@ -486,7 +497,7 @@
|
|||
val = "None";
|
||||
break;
|
||||
}
|
||||
[self setCString:val forKey:@"media_encryption_preference"];
|
||||
[self setCString:val forKey:linphone_core_get_post_quantum_available() ? @"media_encryption_preference_pq_enabled" : @"media_encryption_preference"];
|
||||
[self setInteger:linphone_core_get_upload_bandwidth(LC) forKey:@"upload_bandwidth_preference"];
|
||||
[self setInteger:linphone_core_get_download_bandwidth(LC) forKey:@"download_bandwidth_preference"];
|
||||
[self setBool:linphone_core_adaptive_rate_control_enabled(LC) forKey:@"adaptive_rate_control_preference"];
|
||||
|
|
@ -604,6 +615,7 @@
|
|||
int expire = [self integerForKey:@"account_expire_preference"];
|
||||
BOOL pushnotification = [self boolForKey:@"account_pushnotification_preference"];
|
||||
NSString *prefix = [self stringForKey:@"account_prefix_preference"];
|
||||
BOOL use_prefix = [self boolForKey:@"apply_international_prefix_for_calls_and_chats"];
|
||||
NSString *proxyAddress = [self stringForKey:@"account_proxy_preference"];
|
||||
|
||||
if ((!proxyAddress || [proxyAddress length] < 1) && domain) {
|
||||
|
|
@ -614,7 +626,7 @@
|
|||
proxyAddress = [NSString stringWithFormat:@"sip:%@", proxyAddress];
|
||||
}
|
||||
|
||||
LinphoneAddress *proxy_addr = linphone_core_interpret_url(LC, proxyAddress.UTF8String);
|
||||
LinphoneAddress *proxy_addr = linphone_core_interpret_url_2(LC, proxyAddress.UTF8String, false);
|
||||
|
||||
if (proxy_addr) {
|
||||
LinphoneTransportType type = LinphoneTransportUdp;
|
||||
|
|
@ -625,9 +637,11 @@
|
|||
|
||||
linphone_address_set_transport(proxy_addr, type);
|
||||
}
|
||||
|
||||
account = bctbx_list_nth_data(linphone_core_get_account_list(LC),
|
||||
|
||||
MSList *accountList= [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
account = bctbx_list_nth_data(accountList,
|
||||
[self integerForKey:@"current_proxy_config_preference"]);
|
||||
bctbx_free(accountList);
|
||||
|
||||
// if account was deleted, it is not present anymore
|
||||
if (account == NULL)
|
||||
|
|
@ -670,10 +684,8 @@
|
|||
linphone_nat_policy_set_stun_server(policy, stun_preference.UTF8String);
|
||||
linphone_account_params_set_nat_policy(newAccountParams, policy);
|
||||
|
||||
if ([prefix length] > 0) {
|
||||
linphone_account_params_set_international_prefix(newAccountParams, [prefix UTF8String]);
|
||||
}
|
||||
|
||||
linphone_account_params_set_international_prefix(newAccountParams, [prefix UTF8String]);
|
||||
linphone_account_params_set_use_international_prefix_for_calls_and_chats(newAccountParams, use_prefix);
|
||||
if ([self objectForKey:@"account_substitute_+_by_00_preference"]) {
|
||||
bool substitute_plus_by_00 = [self boolForKey:@"account_substitute_+_by_00_preference"];
|
||||
linphone_account_params_set_dial_escape_plus_enabled(newAccountParams, substitute_plus_by_00);
|
||||
|
|
@ -713,7 +725,7 @@
|
|||
}
|
||||
|
||||
char *identity = linphone_address_as_string(linphoneAddress);
|
||||
LinphoneAddress *from = linphone_core_interpret_url(LC, identity);
|
||||
LinphoneAddress *from = linphone_core_interpret_url_2(LC, identity, false);
|
||||
ms_free(identity);
|
||||
if (from) {
|
||||
const char *userid_str = (userID != nil) ? [userID UTF8String] : NULL;
|
||||
|
|
@ -805,7 +817,7 @@
|
|||
linphone_ldap_params_set_bind_dn(newLdapParams, [self stringForKey:@"ldap_bind_dn"].UTF8String);
|
||||
linphone_ldap_params_set_password(newLdapParams, [self stringForKey:@"ldap_password"].UTF8String);
|
||||
|
||||
LinphoneLdapAuthMethod authMethod = [[self stringForKey:@"ldap_verification_method"] isEqualToString:@"simple"] ? LinphoneLdapAuthMethodSimple : LinphoneLdapAuthMethodAnonymous;
|
||||
LinphoneLdapAuthMethod authMethod = [[self stringForKey:@"ldap_auth_method"] isEqualToString:@"simple"] ? LinphoneLdapAuthMethodSimple : LinphoneLdapAuthMethodAnonymous;
|
||||
linphone_ldap_params_set_auth_method(newLdapParams, authMethod);
|
||||
linphone_ldap_params_enable_tls(newLdapParams, [self boolForKey:@"ldap_tls_enabled"]);
|
||||
|
||||
|
|
@ -829,8 +841,8 @@
|
|||
|
||||
|
||||
// Analysis parameters
|
||||
linphone_ldap_params_set_name_attribute(newLdapParams, [self stringForKey:@"ldap_name_attributes"].UTF8String);
|
||||
linphone_ldap_params_set_sip_attribute(newLdapParams, [self stringForKey:@"ldap_sip_attributes"].UTF8String);
|
||||
linphone_ldap_params_set_name_attribute(newLdapParams, [self stringForKey:@"ldap_name_attribute"].UTF8String);
|
||||
linphone_ldap_params_set_sip_attribute(newLdapParams, [self stringForKey:@"ldap_sip_attribute"].UTF8String);
|
||||
linphone_ldap_params_set_sip_domain(newLdapParams, [self stringForKey:@"ldap_sip_domain"].UTF8String);
|
||||
|
||||
// Miscellaneous parameters
|
||||
|
|
@ -1020,7 +1032,7 @@
|
|||
[LinphoneCoreSettingsStore parsePortRange:video_port_preference minPort:&videoMinPort maxPort:&videoMaxPort];
|
||||
linphone_core_set_video_port_range(LC, videoMinPort, videoMaxPort);
|
||||
|
||||
NSString *menc = [self stringForKey:@"media_encryption_preference"];
|
||||
NSString *menc = [self stringForKey:linphone_core_get_post_quantum_available() ? @"media_encryption_preference_pq_enabled" : @"media_encryption_preference"];
|
||||
if (menc && [menc compare:@"SRTP"] == NSOrderedSame)
|
||||
linphone_core_set_media_encryption(LC, LinphoneMediaEncryptionSRTP);
|
||||
else if (menc && [menc compare:@"ZRTP"] == NSOrderedSame)
|
||||
|
|
@ -1096,7 +1108,9 @@
|
|||
NSString *rls_uri = [lm lpConfigStringForKey:@"rls_uri" inSection:@"sip" withDefault:@"sips:rls@sip.linphone.org"];
|
||||
LinphoneAddress *rls_addr = linphone_address_new(rls_uri.UTF8String);
|
||||
const char *rls_domain = linphone_address_get_domain(rls_addr);
|
||||
const MSList *accounts = linphone_core_get_account_list(LC);
|
||||
|
||||
MSList *accountListToBeFreed = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
const MSList *accounts = accountListToBeFreed;
|
||||
if (!accounts) // Enable it if no proxy config for first launch of app
|
||||
[self setInteger:1 forKey:@"use_rls_presence"];
|
||||
else {
|
||||
|
|
@ -1110,6 +1124,7 @@
|
|||
}
|
||||
}
|
||||
linphone_address_unref(rls_addr);
|
||||
bctbx_free(accountListToBeFreed);
|
||||
}
|
||||
|
||||
[lm lpConfigSetInt:[self integerForKey:@"use_rls_presence"] forKey:@"use_rls_presence"];
|
||||
|
|
@ -1151,9 +1166,12 @@
|
|||
}
|
||||
|
||||
- (void)removeAccount {
|
||||
LinphoneAccount *account = bctbx_list_nth_data(linphone_core_get_account_list(LC),
|
||||
|
||||
MSList *accountList = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
LinphoneAccount *account = bctbx_list_nth_data(accountList,
|
||||
[self integerForKey:@"current_proxy_config_preference"]);
|
||||
|
||||
|
||||
const MSList *lists = linphone_core_get_friends_lists(LC);
|
||||
while (lists) {
|
||||
linphone_friend_list_enable_subscriptions(lists->data, FALSE);
|
||||
|
|
@ -1174,11 +1192,12 @@
|
|||
|
||||
if (isDefault) {
|
||||
// if we removed the default proxy config, set another one instead
|
||||
if (linphone_core_get_account_list(LC) != NULL) {
|
||||
linphone_core_set_default_account(LC, (LinphoneAccount *)(linphone_core_get_account_list(LC)->data));
|
||||
if (accountList != NULL) {
|
||||
linphone_core_set_default_account(LC, (LinphoneAccount *)(accountList->data));
|
||||
}
|
||||
}
|
||||
[self transformLinphoneCoreToKeys];
|
||||
bctbx_free(accountList);
|
||||
}
|
||||
|
||||
- (void)removeLdap {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ extern NSString *const kLinphoneConfStateParticipantListChanged;
|
|||
extern NSString *const kLinphoneConfStateChanged;
|
||||
extern NSString *const kLinphoneMagicSearchStarted;
|
||||
extern NSString *const kLinphoneMagicSearchFinished;
|
||||
extern NSString *const kLinphoneMagicSearchMoreAvailable;
|
||||
extern NSString *const kDisplayModeChanged;
|
||||
|
||||
|
||||
extern NSString *const kLinphoneMsgNotificationAppGroupId;
|
||||
|
|
@ -174,6 +176,7 @@ typedef struct _LinphoneManagerSounds {
|
|||
|
||||
- (void)silentPushFailed:(NSTimer*)timer;
|
||||
|
||||
- (MSList *) createAccountsNotHiddenList; // needs to be unref
|
||||
- (void)removeAllAccounts;
|
||||
|
||||
+ (BOOL)isMyself:(const LinphoneAddress *)addr;
|
||||
|
|
@ -192,6 +195,8 @@ typedef struct _LinphoneManagerSounds {
|
|||
- (BOOL)isCTCallCenterExist;
|
||||
- (void) checkLocalNetworkPermission;
|
||||
|
||||
+ (BOOL) getChatroomPushEnabled:(LinphoneChatRoom *)chatroom;
|
||||
+ (void) setChatroomPushEnabled:(LinphoneChatRoom *)chatroom withPushEnabled:(BOOL)enabled;
|
||||
|
||||
@property (readonly) BOOL isTesting;
|
||||
@property(readonly, strong) FastAddressBook *fastAddressBook;
|
||||
|
|
|
|||
|
|
@ -81,13 +81,14 @@ NSString *const kLinphoneConfStateChanged = @"kLinphoneConfStateChanged";
|
|||
NSString *const kLinphoneConfStateParticipantListChanged = @"kLinphoneConfStateParticipantListChanged";
|
||||
NSString *const kLinphoneMagicSearchStarted = @"LinphoneMagicSearchStarted";
|
||||
NSString *const kLinphoneMagicSearchFinished = @"LinphoneMagicSearchFinished";
|
||||
NSString *const kLinphoneMagicSearchMoreAvailable = @"LinphoneMagicSearchMoreAvailable";
|
||||
NSString *const kDisplayModeChanged = @"DisplayModeChanged";
|
||||
|
||||
NSString *const kLinphoneMsgNotificationAppGroupId = @"group.org.linphone.phone.msgNotification";
|
||||
|
||||
const int kLinphoneAudioVbrCodecDefaultBitrate = 36; /*you can override this from linphonerc or linphonerc-factory*/
|
||||
|
||||
extern void libmsamr_init(MSFactory *factory);
|
||||
extern void libmsx264_init(MSFactory *factory);
|
||||
extern void libmsopenh264_init(MSFactory *factory);
|
||||
extern void libmssilk_init(MSFactory *factory);
|
||||
extern void libmswebrtc_init(MSFactory *factory);
|
||||
|
|
@ -276,6 +277,14 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
|
|||
[self lpConfigSetString:@"conflate" forKey:@"handle_content_encoding" inSection:@"misc"];
|
||||
#endif
|
||||
}
|
||||
|
||||
if ([self lpConfigStringForKey:@"display_link_account_popup"] == nil) {
|
||||
[self lpConfigSetBool:true forKey:@"display_link_account_popup"];
|
||||
}
|
||||
|
||||
if ([self lpConfigStringForKey:@"hide_link_phone_number"] == nil) {
|
||||
[self lpConfigSetInt:1 forKey:@"hide_link_phone_number"];
|
||||
}
|
||||
|
||||
[self migrateFromUserPrefs];
|
||||
[self loadAvatar];
|
||||
|
|
@ -637,6 +646,11 @@ static void linphone_iphone_global_state_changed(LinphoneCore *lc, LinphoneGloba
|
|||
if (theLinphoneCore && linphone_core_get_global_state(theLinphoneCore) != LinphoneGlobalOff)
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneGlobalStateUpdate object:self userInfo:dict];
|
||||
});
|
||||
|
||||
if (state == LinphoneGlobalOn) {
|
||||
// reload friends
|
||||
[self.fastAddressBook fetchContactsInBackGroundThread];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)globalStateChangedNotificationHandler:(NSNotification *)notif {
|
||||
|
|
@ -1254,7 +1268,7 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
[LinphoneManager.instance lpConfigSetInt:0 forKey:@"must_link_account_time"];
|
||||
} else {
|
||||
LinphoneAccount *account = linphone_core_get_default_account(LC);
|
||||
LinphoneAccountParams const *accountParams = linphone_account_get_params(account);
|
||||
LinphoneAccountParams const *accountParams = account ? linphone_account_get_params(account) : NULL;
|
||||
if (account &&
|
||||
strcmp(linphone_account_params_get_domain(accountParams),
|
||||
[LinphoneManager.instance lpConfigStringForKey:@"domain_name"
|
||||
|
|
@ -1275,7 +1289,14 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
handler:^(UIAlertAction * action) {
|
||||
[PhoneMainView.instance changeCurrentView:AssistantLinkView.compositeViewDescription];
|
||||
}];
|
||||
|
||||
UIAlertAction* otherAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Never ask again", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[LinphoneManager.instance lpConfigSetBool:false forKey:@"display_link_account_popup"];
|
||||
}];
|
||||
defaultAction.accessibilityLabel = @"Later";
|
||||
[errView addAction:otherAction];
|
||||
[errView addAction:defaultAction];
|
||||
[errView addAction:continueAction];
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
|
|
@ -1294,7 +1315,7 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
NSDate *nextTime =
|
||||
[NSDate dateWithTimeIntervalSince1970:[self lpConfigIntForKey:@"must_link_account_time" withDefault:1]];
|
||||
NSDate *now = [NSDate date];
|
||||
if (nextTime.timeIntervalSince1970 > 0 && [now earlierDate:nextTime] == nextTime) {
|
||||
if (nextTime.timeIntervalSince1970 > 0 && [now earlierDate:nextTime] == nextTime && [LinphoneManager.instance lpConfigBoolForKey:@"display_link_account_popup"] && ![LinphoneManager.instance lpConfigIntForKey:@"hide_link_phone_number"]) {
|
||||
LinphoneAccount *account = linphone_core_get_default_account(LC);
|
||||
if (account) {
|
||||
const char *username = linphone_address_get_username(linphone_account_params_get_identity_address(linphone_account_get_params(account)));
|
||||
|
|
@ -1334,22 +1355,37 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
}
|
||||
}
|
||||
|
||||
- (void)activateBasicChatroomCPIMForLinphoneAccounts {
|
||||
- (void)enableLinphoneAccountSpecificSettings {
|
||||
const MSList *accountsList = linphone_core_get_account_list(theLinphoneCore);
|
||||
while (accountsList) {
|
||||
LinphoneAccount * account = accountsList->data;
|
||||
LinphoneAccountParams const * currentParams = linphone_account_get_params(account);
|
||||
LinphoneAddress const * currentAddress = linphone_account_params_get_identity_address(currentParams);
|
||||
char * addressIdentity = linphone_address_as_string(currentAddress);
|
||||
|
||||
if (strcmp(linphone_address_get_domain(currentAddress), "sip.linphone.org") == 0 && !linphone_account_params_cpim_in_basic_chat_room_enabled(currentParams) ) {
|
||||
|
||||
LOGI(@"Enabling CPIM in basic chatroom for user %s", linphone_address_get_username(currentAddress));
|
||||
if (strcmp(linphone_address_get_domain(currentAddress), "sip.linphone.org") == 0) {
|
||||
LinphoneAccountParams * newParams = linphone_account_params_clone(linphone_account_get_params(account));
|
||||
linphone_account_params_enable_cpim_in_basic_chat_room(newParams, true);
|
||||
if (!linphone_account_params_cpim_in_basic_chat_room_enabled(currentParams) ) {
|
||||
LOGI(@"Enabling CPIM in basic chatroom for account [%s]", addressIdentity);
|
||||
linphone_account_params_enable_cpim_in_basic_chat_room(newParams, true);
|
||||
}
|
||||
|
||||
const char* current_lime_url = linphone_account_params_get_lime_server_url(currentParams);
|
||||
if (!current_lime_url){
|
||||
const char* core_lime_url = linphone_core_get_lime_x3dh_server_url(LC);
|
||||
if (core_lime_url) {
|
||||
LOGI(@"Copying core's LIME X3DH server URL [%s] to account [%s]", core_lime_url, addressIdentity);
|
||||
linphone_account_params_set_lime_server_url(newParams, core_lime_url);
|
||||
} else {
|
||||
LOGI(@"Account [%s] didn't have a LIME X3DH server URL, setting one: [%s]", addressIdentity, core_lime_url);
|
||||
linphone_account_params_set_lime_server_url(newParams, "https://lime.linphone.org/lime-server/lime-server.php");
|
||||
}
|
||||
}
|
||||
linphone_account_set_params(account, newParams);
|
||||
linphone_account_params_unref(newParams);
|
||||
}
|
||||
|
||||
ms_free(addressIdentity);
|
||||
accountsList = accountsList->next;
|
||||
}
|
||||
}
|
||||
|
|
@ -1360,7 +1396,7 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
linphone_core_start([LinphoneManager getLc]);
|
||||
|
||||
[self configurePushProviderForAccounts];
|
||||
[self activateBasicChatroomCPIMForLinphoneAccounts];
|
||||
[self enableLinphoneAccountSpecificSettings];
|
||||
}
|
||||
|
||||
- (void)createLinphoneCore {
|
||||
|
|
@ -1429,7 +1465,6 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
MSFactory *f = linphone_core_get_ms_factory(theLinphoneCore);
|
||||
libmssilk_init(f);
|
||||
libmsamr_init(f);
|
||||
libmsx264_init(f);
|
||||
libmsopenh264_init(f);
|
||||
libmswebrtc_init(f);
|
||||
libmscodec2_init(f);
|
||||
|
|
@ -1459,6 +1494,7 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
- (void)destroyLinphoneCore {
|
||||
// just in case
|
||||
[self removeCTCallCenterCb];
|
||||
[MagicSearchSingleton destroyInstance];
|
||||
|
||||
if (theLinphoneCore != nil) { // just in case application terminate before linphone core initialization
|
||||
|
||||
|
|
@ -1488,8 +1524,6 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
- (void)resetLinphoneCore {
|
||||
[self destroyLinphoneCore];
|
||||
[self createLinphoneCore];
|
||||
// reload friends
|
||||
[self.fastAddressBook fetchContactsInBackGroundThread];
|
||||
}
|
||||
|
||||
static int comp_call_id(const LinphoneCall *call, const char *callid) {
|
||||
|
|
@ -1884,7 +1918,10 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
}
|
||||
[self checkLocalNetworkPermission];
|
||||
// For OutgoingCall, show CallOutgoingView
|
||||
[CallManager.instance startCallWithAddr:iaddr isSas:FALSE isVideo:false isConference:false];
|
||||
LinphoneVideoActivationPolicy *policy = linphone_core_get_video_activation_policy(LC);
|
||||
BOOL initiateVideoCall = linphone_video_activation_policy_get_automatically_initiate(policy);
|
||||
[CallManager.instance startCallWithAddr:iaddr isSas:FALSE isVideo:initiateVideoCall isConference:false];
|
||||
linphone_video_activation_policy_unref(policy);
|
||||
}
|
||||
|
||||
#pragma mark - Misc Functions
|
||||
|
|
@ -2210,6 +2247,23 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (MSList *) createAccountsNotHiddenList {
|
||||
MSList *list = NULL;
|
||||
const MSList *accounts = linphone_core_get_account_list(LC);
|
||||
while (accounts) {
|
||||
const char *isHidden = linphone_account_get_custom_param(accounts->data, "hidden");
|
||||
if (isHidden == NULL || strcmp(linphone_account_get_custom_param(accounts->data, "hidden"), "1") != 0) {
|
||||
if (!list) {
|
||||
list = bctbx_list_new(accounts->data);
|
||||
} else {
|
||||
bctbx_list_append(list, accounts->data);
|
||||
}
|
||||
}
|
||||
accounts = accounts->next;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
- (void)removeAllAccounts {
|
||||
linphone_core_clear_accounts(LC);
|
||||
linphone_core_clear_all_auth_info(LC);
|
||||
|
|
@ -2303,6 +2357,31 @@ void linphone_iphone_conference_state_changed(LinphoneCore *lc, LinphoneConferen
|
|||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneConfStateChanged object:nil userInfo:dict];
|
||||
}
|
||||
|
||||
+ (BOOL) getChatroomPushEnabled:(LinphoneChatRoom *)chatroom {
|
||||
bool currently_enabled = true;
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kLinphoneMsgNotificationAppGroupId];
|
||||
NSDictionary *chatroomsPushStatus = [defaults dictionaryForKey:@"chatroomsPushStatus"];
|
||||
if (chatroomsPushStatus != nil && chatroom) {
|
||||
char *uri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(chatroom));
|
||||
NSString* pushStatus = [chatroomsPushStatus objectForKey:[NSString stringWithUTF8String:uri]];
|
||||
currently_enabled = (pushStatus == nil) || [pushStatus isEqualToString:@"enabled"];
|
||||
ms_free(uri);
|
||||
}
|
||||
return currently_enabled;
|
||||
}
|
||||
|
||||
+ (void) setChatroomPushEnabled:(LinphoneChatRoom *)chatroom withPushEnabled:(BOOL)enabled {
|
||||
if (!chatroom) return;
|
||||
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kLinphoneMsgNotificationAppGroupId];
|
||||
NSMutableDictionary *chatroomsPushStatus = [[NSMutableDictionary alloc] initWithDictionary:[defaults dictionaryForKey:@"chatroomsPushStatus"]];
|
||||
if (chatroomsPushStatus == nil) chatroomsPushStatus = [[NSMutableDictionary dictionary] init];
|
||||
|
||||
char *uri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(chatroom));
|
||||
[chatroomsPushStatus setValue:(enabled ? @"enabled" : @"disabled") forKey:[NSString stringWithUTF8String:uri]];
|
||||
ms_free(uri);
|
||||
|
||||
[defaults setObject:chatroomsPushStatus forKey:@"chatroomsPushStatus"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -57,7 +57,7 @@
|
|||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onSideMenuClick:" destination="-1" eventType="touchUpInside" id="iOC-wy-MPP"/>
|
||||
<action selector="onQualityClick:" destination="-1" eventType="touchUpInside" id="Pir-Ib-ywJ"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -81,6 +81,22 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="365" height="357"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="chat_read.png" translatesAutoresizingMaskIntoConstraints="NO" id="LPj-VT-0fH" userLabel="imdmIcon">
|
||||
<rect key="frame" x="372" y="342" width="10" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delivery failed"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ephemeral_messages_color_A.png" id="7JB-ZL-0lZ" userLabel="ephemeralIcon">
|
||||
<rect key="frame" x="352" y="346" width="10" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
</imageView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00:00:00" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="IRV-qN-sRj" userLabel="ephemeralTime">
|
||||
<rect key="frame" x="285" y="346" width="65" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
||||
<color key="textColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VAJ-tE-fsa">
|
||||
<rect key="frame" x="0.0" y="10" width="382" height="347"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
|
@ -185,22 +201,6 @@
|
|||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<dataDetectorType key="dataDetectorTypes" link="YES"/>
|
||||
</textView>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="chat_read.png" translatesAutoresizingMaskIntoConstraints="NO" id="LPj-VT-0fH" userLabel="imdmIcon">
|
||||
<rect key="frame" x="372" y="337" width="10" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delivery failed"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ephemeral_messages_color_A.png" id="7JB-ZL-0lZ" userLabel="ephemeralIcon">
|
||||
<rect key="frame" x="351" y="336" width="10" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
</imageView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00:00:00" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="IRV-qN-sRj" userLabel="ephemeralTime">
|
||||
<rect key="frame" x="282" y="336" width="65" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
||||
<color key="textColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view tag="28021" contentMode="scaleToFill" id="bhq-9n-zYF" userLabel="voiceRecording">
|
||||
<rect key="frame" x="7" y="252" width="351" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
||||
|
|
@ -261,7 +261,7 @@
|
|||
<image name="color_M.png" width="2" height="2"/>
|
||||
<image name="ephemeral_messages_color_A.png" width="136" height="158.39999389648438"/>
|
||||
<image name="linphone_logo.png" width="41.599998474121094" height="42.400001525878906"/>
|
||||
<image name="menu_reply_default.png" width="25" height="25"/>
|
||||
<image name="menu_reply_default.png" width="60" height="60"/>
|
||||
<image name="vr_play.png" width="200" height="200"/>
|
||||
<image name="vr_wave.png" width="1078" height="90"/>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -59,14 +59,14 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<textView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" editable="NO" text="Lore ipsum..." translatesAutoresizingMaskIntoConstraints="NO" id="CYa-If-oB4" userLabel="messageText" customClass="UITextViewNoDefine">
|
||||
<rect key="frame" x="0.0" y="0.0" width="126" height="40"/>
|
||||
<rect key="frame" x="4" y="0.0" width="118" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<dataDetectorType key="dataDetectorTypes" link="YES"/>
|
||||
</textView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="chat_read.png" translatesAutoresizingMaskIntoConstraints="NO" id="Nod-GX-0kg" userLabel="imdmIcon">
|
||||
<rect key="frame" x="133" y="30" width="10" height="10"/>
|
||||
<rect key="frame" x="133" y="28" width="10" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
</imageView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="00:00:00" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GDJ-O8-m6J" userLabel="ephemeralTime">
|
||||
|
|
@ -93,6 +93,6 @@
|
|||
<image name="chat_read.png" width="20" height="20"/>
|
||||
<image name="color_A.png" width="2" height="2"/>
|
||||
<image name="ephemeral_messages_color_A.png" width="136" height="158.39999389648438"/>
|
||||
<image name="menu_reply_default.png" width="25" height="25"/>
|
||||
<image name="menu_reply_default.png" width="60" height="60"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -66,15 +66,11 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view hidden="YES" autoresizesSubviews="NO" userInteractionEnabled="NO" tag="7" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7DE-KJ-9Q3" userLabel="unreadCountView" customClass="UIBouncingView">
|
||||
<rect key="frame" x="338" y="12" width="21" height="21"/>
|
||||
<rect key="frame" x="338" y="12" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" tag="8" contentMode="scaleAspectFit" fixedFrame="YES" image="chat_list_indicator.png" translatesAutoresizingMaskIntoConstraints="NO" id="NXj-A8-YLh" userLabel="unreadCountImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="21" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="9" contentMode="left" fixedFrame="YES" text="99" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="7" translatesAutoresizingMaskIntoConstraints="NO" id="ZXq-Do-7Ua" userLabel="unreadCountLabel">
|
||||
<rect key="frame" x="0.0" y="0.0" width="21" height="21"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" none="YES"/>
|
||||
|
|
@ -88,11 +84,11 @@
|
|||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="forward_message_default.png" id="rbY-QS-6QH" userLabel="transferIcon">
|
||||
<rect key="frame" x="338" y="33" width="21" height="21"/>
|
||||
<rect key="frame" x="338" y="33" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="ephemeral_messages_color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="q18-yi-ol3">
|
||||
<rect key="frame" x="338" y="54" width="21" height="21"/>
|
||||
<rect key="frame" x="338" y="54" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
|
|
@ -103,7 +99,6 @@
|
|||
</objects>
|
||||
<resources>
|
||||
<image name="avatar.png" width="414.39999389648438" height="414.39999389648438"/>
|
||||
<image name="chat_list_indicator.png" width="28" height="28"/>
|
||||
<image name="chat_read.png" width="20" height="20"/>
|
||||
<image name="ephemeral_messages_color_A.png" width="136" height="158.39999389648438"/>
|
||||
<image name="forward_message_default.png" width="187" height="148"/>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -23,18 +24,18 @@
|
|||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" insetsLayoutMarginsFromSafeArea="NO" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="Z2U-vm-azg" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<rect key="frame" x="0.0" y="5" width="44" height="28"/>
|
||||
<rect key="frame" x="0.0" y="8" width="44" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" insetsLayoutMarginsFromSafeArea="NO" text="John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f3q-pd-EF5" userLabel="displayNameLabel">
|
||||
<rect key="frame" x="43" y="11" width="185" height="16"/>
|
||||
<rect key="frame" x="43" y="0.0" width="185" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" fixedFrame="YES" insetsLayoutMarginsFromSafeArea="NO" text="Today - 18h42" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hEV-7I-B0v" userLabel="contactDateLabel">
|
||||
<rect key="frame" x="200" y="13" width="159" height="12"/>
|
||||
<rect key="frame" x="229" y="16" width="130" height="12"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
|
|
@ -42,12 +43,15 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</tableViewCellContentView>
|
||||
<point key="canvasLocation" x="61.5" y="52"/>
|
||||
<point key="canvasLocation" x="60" y="51.27436281859071"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="avatar.png" width="414.39999389648438" height="414.39999389648438"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="890.39999999999998" y="192.50374812593705"/>
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="UIChatCreateCollectionViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="100" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="100" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fHV-en-AZD" userLabel="displayNameLabel">
|
||||
<rect key="frame" x="14" y="18" width="92" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" fixedFrame="YES" image="conference_delete.png" translatesAutoresizingMaskIntoConstraints="NO" id="yfP-hQ-SXb" userLabel="selectedImage">
|
||||
<rect key="frame" x="1" y="23" width="10" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</view>
|
||||
<size key="customSize" width="170" height="45"/>
|
||||
<connections>
|
||||
<outlet property="nameLabel" destination="fHV-en-AZD" id="gOU-sp-v0V"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="2" y="86"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="conference_delete.png" width="17.600000381469727" height="17.600000381469727"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
<connections>
|
||||
<outlet property="contentCollection" destination="ZgY-Ye-8DD" id="hlD-Fw-g1z"/>
|
||||
<outlet property="dismissButton" destination="KrT-j6-YOy" id="K5m-Mw-Cjx"/>
|
||||
<outlet property="icsIcon" destination="gkH-jk-DYU" id="Xkl-Ip-skO"/>
|
||||
<outlet property="leftBar" destination="Iov-AL-8Xz" id="eKb-4B-unZ"/>
|
||||
<outlet property="originalMessageGone" destination="B26-sw-o4w" id="Gwh-dh-GRN"/>
|
||||
<outlet property="senderName" destination="uuW-tW-1Sj" id="Yao-6A-SBh"/>
|
||||
|
|
@ -68,6 +69,10 @@
|
|||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES"/>
|
||||
<state key="normal" image="reply_cancel.png"/>
|
||||
</button>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="voip_meeting_schedule.png" translatesAutoresizingMaskIntoConstraints="NO" id="gkH-jk-DYU">
|
||||
<rect key="frame" x="16" y="23" width="35" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
|
|
@ -77,6 +82,7 @@
|
|||
</objects>
|
||||
<resources>
|
||||
<image name="reply_cancel.png" width="60" height="60"/>
|
||||
<image name="voip_meeting_schedule.png" width="20" height="20"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -11,11 +11,14 @@
|
|||
<connections>
|
||||
<outlet property="authButton" destination="lWW-wB-FMR" id="C7W-JM-WFQ"/>
|
||||
<outlet property="authView" destination="CCn-Oz-I0M" id="fSM-6k-paN"/>
|
||||
<outlet property="backgroundColor" destination="cqN-1f-6SE" id="gjg-LB-xLT"/>
|
||||
<outlet property="cancelButton" destination="B1K-CB-3of" id="KKi-Xc-ldA"/>
|
||||
<outlet property="confirmationButton" destination="SbQ-re-fGQ" id="yiv-a9-o8E"/>
|
||||
<outlet property="firstView" destination="ef9-Iu-Bcb" id="hKx-op-r7Z"/>
|
||||
<outlet property="forwardImage" destination="1Wh-Yi-cUe" id="YQq-bt-pk1"/>
|
||||
<outlet property="groupCallImage" destination="SVn-4k-9yc" id="sAP-8V-ttn"/>
|
||||
<outlet property="securityImage" destination="bbo-g3-bGy" id="qZa-li-yrl"/>
|
||||
<outlet property="subscribeLabel" destination="Xbl-Qs-GaE" id="Qnf-pA-nL0"/>
|
||||
<outlet property="titleLabel" destination="jLz-g1-cTe" id="qaj-OB-2r1"/>
|
||||
<outlet property="view" destination="2Vb-Xy-rci" id="nNw-EJ-AY3"/>
|
||||
</connections>
|
||||
|
|
@ -25,27 +28,32 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" alpha="0.89999999999999991" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_C.png" translatesAutoresizingMaskIntoConstraints="NO" id="cqN-1f-6SE" userLabel="backgroundColor">
|
||||
<rect key="frame" x="0.0" y="0.0" width="377" height="667"/>
|
||||
<view contentMode="scaleToFill" id="ef9-Iu-Bcb" userLabel="firstView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2BQ-o9-xv2">
|
||||
<rect key="frame" x="28" y="139" width="320" height="365"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="2BQ-o9-xv2">
|
||||
<rect key="frame" x="25" y="114" width="325" height="440"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_C.png" translatesAutoresizingMaskIntoConstraints="NO" id="cqN-1f-6SE" userLabel="backgroundColor">
|
||||
<rect key="frame" x="-17" y="-17" width="360" height="474"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.26666668059999998" green="0.26666668059999998" blue="0.26666668059999998" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" insetsLayoutMarginsFromSafeArea="NO" image="security_2_indicator.png" translatesAutoresizingMaskIntoConstraints="NO" id="bbo-g3-bGy" userLabel="securityImage">
|
||||
<rect key="frame" x="130" y="0.0" width="56" height="68"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<rect key="frame" x="130" y="15" width="64" height="68"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Are you sure you want to delete all your selection?" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="jLz-g1-cTe" userLabel="titleLabel">
|
||||
<rect key="frame" x="-10" y="15" width="336" height="279"/>
|
||||
<rect key="frame" x="-8" y="15" width="347" height="350"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="21"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="B1K-CB-3of" userLabel="cancelButton" customClass="UIRoundBorderedButton">
|
||||
<rect key="frame" x="8" y="308" width="139" height="42"/>
|
||||
<rect key="frame" x="16" y="383" width="139" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" title="CANCEL" backgroundImage="color_H.png">
|
||||
<color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -57,11 +65,11 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view hidden="YES" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="CCn-Oz-I0M" userLabel="authView">
|
||||
<rect key="frame" x="61" y="273" width="240" height="27"/>
|
||||
<rect key="frame" x="65" y="345" width="243" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lWW-wB-FMR" userLabel="authButton">
|
||||
<rect key="frame" x="26" y="2" width="17" height="22"/>
|
||||
<rect key="frame" x="24" y="0.0" width="22" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="checkbox_unchecked.png"/>
|
||||
<state key="selected" image="checkbox_checked.png"/>
|
||||
|
|
@ -70,7 +78,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Do not show again" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dQL-Sf-slc">
|
||||
<rect key="frame" x="55" y="2" width="176" height="21"/>
|
||||
<rect key="frame" x="57" y="10" width="173" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
|
|
@ -79,7 +87,7 @@
|
|||
</subviews>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SbQ-re-fGQ" userLabel="confirmationButton" customClass="UIRoundBorderedButton">
|
||||
<rect key="frame" x="169" y="308" width="143" height="42"/>
|
||||
<rect key="frame" x="177" y="383" width="136" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" title="DELETE" backgroundImage="color_I.png">
|
||||
<color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -91,20 +99,34 @@
|
|||
</connections>
|
||||
</button>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="forward_message_default.png" translatesAutoresizingMaskIntoConstraints="NO" id="1Wh-Yi-cUe">
|
||||
<rect key="frame" x="89" y="50" width="138" height="54"/>
|
||||
<rect key="frame" x="100" y="50" width="136" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="voip_conference_new.png" translatesAutoresizingMaskIntoConstraints="NO" id="SVn-4k-9yc">
|
||||
<rect key="frame" x="89" y="50" width="138" height="54"/>
|
||||
<rect key="frame" x="100" y="50" width="136" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<label hidden="YES" opaque="NO" tag="13" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="https://subscribe.linphone.org" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xbl-Qs-GaE" userLabel="subscribeLabel">
|
||||
<rect key="frame" x="-42" y="291" width="414" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.98766469960000003" green="0.27512490750000002" blue="0.029739789660000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="tfG-O1-yfD" appends="YES" id="Jcg-KH-U5B"/>
|
||||
</connections>
|
||||
</label>
|
||||
</subviews>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<point key="canvasLocation" x="871.20000000000005" y="261.31934032983509"/>
|
||||
<point key="canvasLocation" x="548" y="34"/>
|
||||
</view>
|
||||
<tapGestureRecognizer id="tfG-O1-yfD" userLabel="onSubscribeTap">
|
||||
<connections>
|
||||
<action selector="onSubscribeTap:" destination="-1" id="Zq2-mP-ccM"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="checkbox_checked.png" width="27.200000762939453" height="27.200000762939453"/>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
@property(weak, nonatomic) IBOutlet UIView *outcallView;
|
||||
|
||||
- (IBAction)onSecurityClick:(id)sender;
|
||||
- (IBAction)onQualityClick:(id)sender;
|
||||
- (IBAction)onSideMenuClick:(id)sender;
|
||||
- (IBAction)onRegistrationStateClick:(id)sender;
|
||||
+ (UIImage *)imageForState:(LinphoneRegistrationState)state;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#import "LinphoneManager.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
@implementation StatusBarView {
|
||||
|
||||
|
|
@ -193,11 +194,13 @@
|
|||
message = NSLocalizedString(@"Fetching remote configuration", nil);
|
||||
} else if (account == NULL) {
|
||||
state = LinphoneRegistrationNone;
|
||||
if (linphone_core_get_account_list(LC) != NULL) {
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
if (accounts != NULL) {
|
||||
message = NSLocalizedString(@"No default account", nil);
|
||||
} else {
|
||||
message = NSLocalizedString(@"No account configured", nil);
|
||||
}
|
||||
bctbx_free(accounts);
|
||||
|
||||
} else {
|
||||
state = linphone_account_get_state(account);
|
||||
|
|
@ -329,14 +332,9 @@
|
|||
correspondantCode = [code substringToIndex:2];
|
||||
myCode = [code substringFromIndex:2];
|
||||
}
|
||||
NSString *message =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"\nConfirmation security\n\n"
|
||||
@"Say: %@\n"
|
||||
@"Confirm that your interlocutor\n"
|
||||
@"says: %@",
|
||||
nil),
|
||||
myCode.uppercaseString, correspondantCode.uppercaseString];
|
||||
|
||||
NSString *message = [NSString stringWithFormat:NSLocalizedString(@"\nCommunication security:\n\nTo raise the security level, you can check the following codes with your correspondent.\n\nSay: %1$@\n\nYour correspondent must say: %2$@", nil),
|
||||
myCode.uppercaseString, correspondantCode.uppercaseString];
|
||||
|
||||
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive &&
|
||||
floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) {
|
||||
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
|
||||
|
|
@ -368,14 +366,14 @@
|
|||
UIFont *baseFont = [UIFont systemFontOfSize:21.0];
|
||||
[attrString addAttribute:NSFontAttributeName value:baseFont range:NSMakeRange(0, length)];
|
||||
UIFont *boldFont = [UIFont boldSystemFontOfSize:23.0];
|
||||
[attrString addAttribute:NSFontAttributeName value:boldFont range:[message rangeOfString:@"Confirmation security"]];
|
||||
[attrString addAttribute:NSFontAttributeName value:boldFont range:[message rangeOfString:@"Communication security"]];
|
||||
UIColor *color = [UIColor colorWithRed:(150 / 255.0) green:(193 / 255.0) blue:(31 / 255.0) alpha:1.0];
|
||||
[attrString addAttribute:NSForegroundColorAttributeName value:color range:[message rangeOfString:myCode.uppercaseString]];
|
||||
[attrString addAttribute:NSForegroundColorAttributeName value:color range:[message rangeOfString:correspondantCode.uppercaseString]];
|
||||
|
||||
securityDialog = [UIConfirmationDialog ShowWithAttributedMessage:attrString
|
||||
cancelMessage:NSLocalizedString(@"DENY", nil)
|
||||
confirmMessage:NSLocalizedString(@"ACCEPT", nil)
|
||||
cancelMessage:NSLocalizedString(@"Later", nil)
|
||||
confirmMessage:NSLocalizedString(@"Correct", nil)
|
||||
onCancelClick:^() {
|
||||
if (linphone_core_get_current_call(LC) == call) {
|
||||
linphone_call_set_authentication_token_verified(call, NO);
|
||||
|
|
@ -393,6 +391,7 @@
|
|||
|
||||
securityDialog.securityImage.hidden = FALSE;
|
||||
[securityDialog setSpecialColor];
|
||||
[securityDialog setWhiteCancel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -400,6 +399,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (IBAction)onQualityClick:(id)sender {
|
||||
[ControlsViewModelBridge toggleStatsVisibility];
|
||||
}
|
||||
|
||||
- (IBAction)onSideMenuClick:(id)sender {
|
||||
UICompositeView *cvc = PhoneMainView.instance.mainViewController;
|
||||
[cvc hideSideMenu:(cvc.sideMenuView.frame.origin.x == 0)];
|
||||
|
|
@ -408,10 +411,15 @@
|
|||
- (IBAction)onRegistrationStateClick:(id)sender {
|
||||
if (linphone_core_get_default_account(LC)) {
|
||||
linphone_core_refresh_registers(LC);
|
||||
} else if (linphone_core_get_account_list(LC)) {
|
||||
[PhoneMainView.instance changeCurrentView:SettingsView.compositeViewDescription];
|
||||
} else {
|
||||
[PhoneMainView.instance changeCurrentView:AssistantView.compositeViewDescription];
|
||||
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
if (accounts) {
|
||||
[PhoneMainView.instance changeCurrentView:SettingsView.compositeViewDescription];
|
||||
} else {
|
||||
[PhoneMainView.instance changeCurrentView:AssistantView.compositeViewDescription];
|
||||
}
|
||||
bctbx_free(accounts);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
}
|
||||
|
||||
- (IBAction)onBackToCallClick:(id)sender {
|
||||
[PhoneMainView.instance popToView:ActiveCallOrConferenceView.compositeViewDescription];
|
||||
[PhoneMainView.instance popToView:[CallsViewModelBridge callViewToDisplay]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -192,14 +192,20 @@
|
|||
_voiceRecordingFile = nil;
|
||||
LinphoneContent *voiceContent = [UIChatBubbleTextCell voiceContent:self.message];
|
||||
if (voiceContent) {
|
||||
_voiceRecordingFile = [NSString stringWithUTF8String:[VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] ? linphone_content_get_plain_file_path(voiceContent) : linphone_content_get_file_path(voiceContent)];
|
||||
if ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId])
|
||||
const char *fileName = ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] ? linphone_content_get_plain_file_path(voiceContent) : linphone_content_get_file_path(voiceContent));
|
||||
if (fileName == nil) {
|
||||
linphone_content_set_file_path(voiceContent, [[LinphoneManager imagesDirectory] stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]].UTF8String);
|
||||
linphone_chat_message_download_content(self.message, voiceContent);
|
||||
}
|
||||
_voiceRecordingFile = fileName ? [NSString stringWithUTF8String:fileName] : nil;
|
||||
if (fileName && [VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId]) {
|
||||
[encrptedFilePaths setValue:_voiceRecordingFile forKey:[NSString stringWithUTF8String:linphone_content_get_name(voiceContent)]];
|
||||
}
|
||||
_vrTimerLabel.text = [self formattedDuration:linphone_content_get_file_duration(voiceContent)/1000];
|
||||
_vrWaveMaskPlayback.frame = CGRectZero;
|
||||
_vrWaveMaskPlayback.backgroundColor = linphone_chat_message_is_outgoing(self.message) ? UIColor.orangeColor : UIColor.grayColor;
|
||||
}
|
||||
|
||||
|
||||
const bctbx_list_t *contents = linphone_chat_message_get_contents(self.message);
|
||||
|
||||
size_t contentCount = bctbx_list_size(contents);
|
||||
|
|
@ -234,7 +240,8 @@
|
|||
if (strcmp(cPath, "") != 0) {
|
||||
NSString *tempPath = [NSString stringWithUTF8String:cPath];
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
filePath = [paths objectAtIndex:0];
|
||||
filePath = [NSString stringWithFormat:@"%@/%s", [paths objectAtIndex:0],linphone_chat_message_get_message_id(super.message)];
|
||||
[FileUtil ensureDirectoryExistsWithPath:filePath];
|
||||
filePath = [filePath stringByAppendingPathComponent:name];
|
||||
[[NSFileManager defaultManager] moveItemAtPath:tempPath toPath:filePath error:nil];
|
||||
}
|
||||
|
|
@ -300,7 +307,8 @@
|
|||
if (strcmp(cPath, "") != 0) {
|
||||
NSString *tempPath = [NSString stringWithUTF8String:cPath];
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
filePath = [paths objectAtIndex:0];
|
||||
filePath = [NSString stringWithFormat:@"%@/%s", [paths objectAtIndex:0],linphone_chat_message_get_message_id(super.message)];
|
||||
[FileUtil ensureDirectoryExistsWithPath:filePath];
|
||||
filePath = [filePath stringByAppendingPathComponent:fileName];
|
||||
[[NSFileManager defaultManager] moveItemAtPath:tempPath toPath:filePath error:nil];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,10 +46,8 @@
|
|||
[self setFrame:CGRectMake(0, 0, sub.frame.size.width, sub.frame.size.height)];
|
||||
[self addSubview:sub];
|
||||
self.icsBubbleView = [[ICSBubbleView alloc] init];
|
||||
self.icsBubbleView.frame = CGRectMake(_messageText.frame.origin.x, _messageText.frame.origin.y+25, CONFERENCE_INVITATION_WIDTH-80, CONFERENCE_INVITATION_HEIGHT-20);
|
||||
[self.innerView addSubview:self.icsBubbleView];
|
||||
[(ICSBubbleView*)self.icsBubbleView setLayoutConstraintsWithView:self.backgroundColorImage];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,16 +119,21 @@
|
|||
}
|
||||
|
||||
- (void)setChatMessageForCbs:(LinphoneChatMessage *)amessage {
|
||||
if (!amessage || amessage == _message) {
|
||||
if (amessage == _message) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_message){
|
||||
linphone_chat_message_unref(_message);
|
||||
}
|
||||
_message = amessage;
|
||||
linphone_chat_message_set_user_data(_message, (void *)CFBridgingRetain(self));
|
||||
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(_message);
|
||||
linphone_chat_message_cbs_set_msg_state_changed(cbs, message_status);
|
||||
linphone_chat_message_cbs_set_participant_imdn_state_changed(cbs, participant_imdn_status);
|
||||
linphone_chat_message_cbs_set_user_data(cbs, (void *)_event);
|
||||
if (amessage){
|
||||
linphone_chat_message_ref(amessage);
|
||||
linphone_chat_message_set_user_data(_message, (void *)CFBridgingRetain(self));
|
||||
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(_message);
|
||||
linphone_chat_message_cbs_set_msg_state_changed(cbs, message_status);
|
||||
linphone_chat_message_cbs_set_participant_imdn_state_changed(cbs, participant_imdn_status);
|
||||
linphone_chat_message_cbs_set_user_data(cbs, (void *)_event);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message {
|
||||
|
|
@ -168,7 +171,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (_messageText && ![LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message]) {
|
||||
if (_messageText && ![LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message] && ![ICSBubbleView isConferenceInvitationMessageWithCmessage:self.message]) {
|
||||
[_messageText setHidden:FALSE];
|
||||
/* We need to use an attributed string here so that data detector don't mess
|
||||
* with the text style. See http://stackoverflow.com/a/20669356 */
|
||||
|
|
@ -346,8 +349,10 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
}
|
||||
|
||||
static void participant_imdn_status(LinphoneChatMessage* msg, const LinphoneParticipantImdnState *state) {
|
||||
ChatConversationImdnView *imdnView = VIEW(ChatConversationImdnView);
|
||||
[imdnView updateImdnList];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
ChatConversationImdnView *imdnView = VIEW(ChatConversationImdnView);
|
||||
[imdnView updateImdnList];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)displayImdmStatus:(LinphoneChatMessageState)state {
|
||||
|
|
@ -399,7 +404,7 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
return cached;
|
||||
}
|
||||
|
||||
CGSize size = [self ViewHeightForMessageText:chat withWidth:width textForImdn:nil];
|
||||
CGSize size = [self ViewHeightForMessageText:chat withWidth:width textForImdn:nil];
|
||||
size.height += linphone_chat_message_is_forward(chat) || linphone_chat_message_is_reply(chat) ? REPLY_OR_FORWARD_TAG_HEIGHT : 0;
|
||||
size.height += linphone_chat_message_is_reply(chat) ? REPLY_CHAT_BUBBLE_HEIGHT+5 : 0;
|
||||
|
||||
|
|
@ -491,7 +496,7 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
+ (CGSize)ViewHeightForMessageText:(LinphoneChatMessage *)chat withWidth:(int)width textForImdn:(NSString *)imdnText {
|
||||
|
||||
if ([ICSBubbleView isConferenceInvitationMessageWithCmessage:chat]) {
|
||||
return CGSizeMake(CONFERENCE_INVITATION_WIDTH, CONFERENCE_INVITATION_HEIGHT);
|
||||
return CGSizeMake(CONFERENCE_INVITATION_WIDTH, CONFERENCE_INVITATION_HEIGHT+[ICSBubbleView getDescriptionHeightFromContentWithCmessage:chat]);
|
||||
}
|
||||
|
||||
NSString *messageText = [UIChatBubbleTextCell TextMessageForChat:chat];
|
||||
|
|
@ -791,6 +796,8 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
|
||||
_replyTransferIcon.hidden = ! linphone_chat_message_is_reply(_message) && !linphone_chat_message_is_forward(_message);
|
||||
_replyTransferLabel.hidden = ! linphone_chat_message_is_reply(_message) && !linphone_chat_message_is_forward(_message);
|
||||
[(ICSBubbleView*)self.icsBubbleView updateTopLayoutConstraintsWithView:self.backgroundColorImage replyOrForward:linphone_chat_message_is_reply(_message)||linphone_chat_message_is_forward(_message)];
|
||||
|
||||
|
||||
if (linphone_chat_message_is_reply(_message)) {
|
||||
CGRect replyFrame = CGRectMake(10, _replyTransferLabel.frame.origin.y+_replyTransferLabel.frame.size.height+5,MAX(self.contactDateLabel.frame.size.width-20,180), REPLY_CHAT_BUBBLE_HEIGHT);
|
||||
|
|
@ -848,10 +855,13 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
|
||||
-(void) buildActions {
|
||||
LinphoneChatMessage *message = self.message;
|
||||
LinphoneEventLog *event = self.event;
|
||||
|
||||
_messageActionsTitles = [[NSMutableArray alloc] init];
|
||||
_messageActionsBlocks = [[NSMutableArray alloc] init];
|
||||
_messageActionsIcons = [[NSMutableArray alloc] init];
|
||||
|
||||
|
||||
[VIEW(ChatConversationView).messageField resignFirstResponder];
|
||||
UIChatBubbleTextCell *thiz = self;
|
||||
|
||||
LinphoneChatMessageState state = linphone_chat_message_get_state(self.message);
|
||||
|
|
@ -869,7 +879,7 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
}
|
||||
|
||||
|
||||
if (linphone_chat_message_get_utf8_text(message)) {
|
||||
if (linphone_chat_message_get_utf8_text(message) && ![ICSBubbleView isConferenceInvitationMessageWithCmessage:message]) {
|
||||
[_messageActionsTitles addObject:NSLocalizedString(@"Copy text", nil)];
|
||||
[_messageActionsIcons addObject:@"menu_copy_text_default"];
|
||||
[_messageActionsBlocks addObject:^{
|
||||
|
|
@ -896,16 +906,43 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
[VIEW(ChatConversationView) initiateReplyViewForMessage:message];
|
||||
}];
|
||||
|
||||
if (linphone_chat_message_is_outgoing(self.message) || linphone_chat_room_get_nb_participants(linphone_chat_message_get_chat_room(self.message)) > 1) {
|
||||
LinphoneChatRoom *chatroom = linphone_chat_message_get_chat_room(self.message);
|
||||
|
||||
if (linphone_chat_room_get_nb_participants(chatroom) > 1) {
|
||||
[_messageActionsTitles addObject:NSLocalizedString(@"Infos", nil)];
|
||||
[_messageActionsIcons addObject:@"menu_info"];
|
||||
[_messageActionsBlocks addObject:^{
|
||||
[thiz dismissPopup];
|
||||
ChatConversationImdnView *view = VIEW(ChatConversationImdnView);
|
||||
view.msg = message;
|
||||
view.event = event;
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
}];
|
||||
}
|
||||
|
||||
if (!linphone_chat_message_is_outgoing(self.message)
|
||||
&& [FastAddressBook getContactWithAddress:linphone_chat_message_get_from_address(self.message)] == nil
|
||||
&& !(linphone_chat_room_get_capabilities(chatroom) & LinphoneChatRoomCapabilitiesOneToOne) ) {
|
||||
|
||||
LinphoneAddress *fromAddress = linphone_address_clone(linphone_chat_message_get_from_address(self.message));
|
||||
[_messageActionsTitles addObject:NSLocalizedString(@"Add to contact", nil)];
|
||||
[_messageActionsIcons addObject:@"contact_add_default"];
|
||||
[_messageActionsBlocks addObject:^{
|
||||
[thiz dismissPopup];
|
||||
linphone_address_clean(fromAddress);
|
||||
char *lAddress = linphone_address_as_string_uri_only(fromAddress);
|
||||
if (lAddress != NULL) {
|
||||
NSString *normSip = [NSString stringWithUTF8String:lAddress];
|
||||
normSip = [normSip hasPrefix:@"sip:"] ? [normSip substringFromIndex:4] : normSip;
|
||||
normSip = [normSip hasPrefix:@"sips:"] ? [normSip substringFromIndex:5] : normSip;
|
||||
[ContactSelection setAddAddress:normSip];
|
||||
[ContactSelection setSelectionMode:ContactSelectionModeEdit];
|
||||
[ContactSelection enableSipFilter:FALSE];
|
||||
[PhoneMainView.instance changeCurrentView:ContactsListView.compositeViewDescription];
|
||||
ms_free(lAddress);
|
||||
}
|
||||
linphone_address_unref(fromAddress);
|
||||
}];
|
||||
}
|
||||
|
||||
[_messageActionsTitles addObject:NSLocalizedString(@"Delete", nil)];
|
||||
[_messageActionsIcons addObject:@"menu_delete"];
|
||||
|
|
@ -930,7 +967,7 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
int cellHeight = 45;
|
||||
int numberOfItems = (int) _messageActionsTitles.count;
|
||||
CGRect screenRect = UIScreen.mainScreen.bounds;
|
||||
int menuHeight = numberOfItems * cellHeight + 15;
|
||||
int menuHeight = numberOfItems * cellHeight;
|
||||
|
||||
CGRect frame = CGRectMake(
|
||||
linphone_chat_message_is_outgoing(self.message) ? screenRect.size.width - width - 10 : 10,
|
||||
|
|
@ -942,7 +979,8 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
_popupMenu.scrollEnabled = false;
|
||||
_popupMenu.dataSource = self;
|
||||
_popupMenu.delegate = self;
|
||||
|
||||
_popupMenu.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
|
||||
_popupMenu.layer.masksToBounds = false;
|
||||
|
||||
_popupMenu.layer.shadowColor = [UIColor darkGrayColor].CGColor;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#import "PhoneMainView.h"
|
||||
#import "LinphoneManager.h"
|
||||
#import "Utils.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
@implementation UIChatCell
|
||||
|
||||
|
|
@ -38,6 +39,10 @@
|
|||
[self addSubview:sub];
|
||||
}
|
||||
[_imdmIcon setHidden:TRUE];
|
||||
_unreadCountView.backgroundColor = VoipTheme.primary_color;
|
||||
_unreadCountView.layer.cornerRadius = 10;
|
||||
_unreadCountView.clipsToBounds = true;
|
||||
_unreadCountLabel.textAlignment = NSTextAlignmentCenter;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +82,7 @@
|
|||
} else {
|
||||
_addressLabel.text = [NSString stringWithUTF8String:LINPHONE_DUMMY_SUBJECT];
|
||||
}
|
||||
bctbx_list_free(participants);
|
||||
} else {
|
||||
const char *subject = linphone_chat_room_get_subject(chatRoom);
|
||||
_addressLabel.text = [NSString stringWithUTF8String:subject ?: LINPHONE_DUMMY_SUBJECT];
|
||||
|
|
@ -132,7 +138,8 @@
|
|||
_chatContentLabel.frame = newFrame;
|
||||
}
|
||||
} else {
|
||||
NSString *text = [[FastAddressBook displayNameForAddress:linphone_chat_message_get_from_address(last_msg)]
|
||||
NSString *conferenceInfo = [ICSBubbleView getConferenceSummaryWithCmessage:last_msg];
|
||||
NSString *text = conferenceInfo != nil ? conferenceInfo : [[FastAddressBook displayNameForAddress:linphone_chat_message_get_from_address(last_msg)]
|
||||
stringByAppendingFormat:@" : %@", [UIChatBubbleTextCell TextMessageForChat:last_msg]];
|
||||
// shorten long messages
|
||||
/*if ([text length] > 50)
|
||||
|
|
|
|||
|
|
@ -21,9 +21,8 @@
|
|||
#import "ChatConversationCreateView.h"
|
||||
|
||||
@interface UIChatCreateCollectionViewCell : UICollectionViewCell
|
||||
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
|
||||
@property UILabel *nameLabel;
|
||||
@property (strong, nonatomic) ChatConversationCreateView *controller;
|
||||
@property (strong, nonatomic) NSString *uri;
|
||||
- (id)initWithName:(NSString *)identifier;
|
||||
- (void)onDelete;
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -18,27 +18,31 @@
|
|||
*/
|
||||
|
||||
#import "UIChatCreateCollectionViewCell.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
@implementation UIChatCreateCollectionViewCell
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
}
|
||||
|
||||
- (id)initWithName:(NSString *)identifier {
|
||||
if (self != nil) {
|
||||
NSArray *arrayOfViews =
|
||||
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil];
|
||||
if ([arrayOfViews count] >= 1) {
|
||||
UIChatCreateCollectionViewCell *sub = ((UIChatCreateCollectionViewCell *)[arrayOfViews objectAtIndex:0]);
|
||||
[self addSubview:sub];
|
||||
_nameLabel = sub.nameLabel;
|
||||
}
|
||||
}
|
||||
[_nameLabel setText:identifier];
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
self.contentView.translatesAutoresizingMaskIntoConstraints = false;
|
||||
[SnapkitBridge matchParentDimensionsWithView:self.contentView topInset:10];
|
||||
|
||||
self.nameLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||
self.nameLabel.numberOfLines = 1;
|
||||
[self.contentView addSubview:self.nameLabel];
|
||||
[SnapkitBridge matchParentDimensionsWithView:self.nameLabel leftInset:20];
|
||||
[SnapkitBridge heightWithView:self heiht:50];
|
||||
|
||||
UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"conference_delete"]];
|
||||
image.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[self.contentView addSubview:image];
|
||||
[SnapkitBridge squareWithView:image size:15];
|
||||
[SnapkitBridge alignParentLeftWithView:image];
|
||||
[SnapkitBridge centerYWithView:image];
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onDelete)];
|
||||
tap.numberOfTouchesRequired = 1;
|
||||
[self addGestureRecognizer:tap];
|
||||
[image addGestureRecognizer:tap];
|
||||
image.userInteractionEnabled = true;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -60,4 +64,6 @@
|
|||
[_controller.tableController.tableView reloadData];
|
||||
_controller.nextButton.enabled = (_controller.tableController.contactsGroup.count > 0) || _controller.isForEditing;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (weak, nonatomic) IBOutlet UICollectionView *contentCollection;
|
||||
@property NSArray *dataContent;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *originalMessageGone;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *icsIcon;
|
||||
|
||||
-(void) configureForMessage:(LinphoneChatMessage *)message withDimissBlock:(void (^)(void))dismissBlock hideDismiss:(BOOL)hideDismiss withClickBlock:(void (^)(void))clickBlock;
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
-(void) viewDidLoad {
|
||||
_contentCollection.dataSource = self;
|
||||
[_icsIcon setImageNamed:@"voip_meeting_schedule" tintColor:VoipTheme.voip_dark_gray];
|
||||
[_contentCollection registerClass:UICollectionViewCell.class forCellWithReuseIdentifier:@"dataContent"];
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +52,7 @@
|
|||
_contentCollection.hidden = true;
|
||||
_senderName.hidden = true;
|
||||
_originalMessageGone.hidden = false;
|
||||
_icsIcon.hidden = true;
|
||||
return;
|
||||
}
|
||||
if (hideDismiss) {
|
||||
|
|
@ -60,9 +62,12 @@
|
|||
_originalMessageGone.hidden = true;
|
||||
self.message = message;
|
||||
self.dataContent = [self loadDataContent];
|
||||
BOOL isIcal = [ICSBubbleView isConferenceInvitationMessageWithCmessage:message];
|
||||
_icsIcon.hidden = !isIcal;
|
||||
|
||||
NSString *sender = [FastAddressBook displayNameForAddress:linphone_chat_message_get_from_address(message)];
|
||||
_senderName.text = sender;
|
||||
const char * text = linphone_chat_message_get_text_content(message);
|
||||
const char * text = isIcal ? [ICSBubbleView getSubjectFromContentWithCmessage:message].UTF8String : linphone_chat_message_get_text_content(message);
|
||||
if (text && strlen(text) == 0)
|
||||
text = nil;
|
||||
_textContent.text = text ? [NSString stringWithUTF8String:text] : @"";
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@
|
|||
#pragma mark -
|
||||
|
||||
- (void)accessoryForCell:(UITableViewCell *)cell atPath:(NSIndexPath *)indexPath {
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleGray;
|
||||
if ([self isEditing]) {
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleGray;
|
||||
UIButton *checkBoxButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
UIImage *image = nil;
|
||||
if ([_selectedItems containsObject:indexPath]) {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
- (UIViewController *)getCurrentViewController;
|
||||
- (UIInterfaceOrientation)currentOrientation;
|
||||
- (void)clearCache:(NSArray *)exclude;
|
||||
- (void)removeEntryFromCache:(NSString *)key;
|
||||
- (IBAction)onRightSwipe:(id)sender;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -305,6 +305,9 @@
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (void)removeEntryFromCache:(NSString *)key {
|
||||
[viewControllerCache removeObjectForKey:key];
|
||||
}
|
||||
|
||||
- (void)clearCache:(NSArray *)exclude {
|
||||
|
||||
|
|
@ -313,7 +316,7 @@
|
|||
bool remove = true;
|
||||
|
||||
/*ImagePickerView can be used as popover and we do NOT want to free it*/;
|
||||
if ([key isEqualToString:ImagePickerView.compositeViewDescription.name] || [key isEqualToString:ActiveCallOrConferenceView.compositeViewDescription.name]) {
|
||||
if ([key isEqualToString:ImagePickerView.compositeViewDescription.name] || [key isEqualToString:SingleCallView.compositeViewDescription.name] || [key isEqualToString:ConferenceCallView.compositeViewDescription.name]) {
|
||||
remove = false;
|
||||
} else if (exclude != nil) {
|
||||
for (UICompositeViewDescription *description in exclude) {
|
||||
|
|
@ -336,6 +339,9 @@
|
|||
}
|
||||
|
||||
- (IBAction)onRightSwipe:(id)sender {
|
||||
if (linphone_core_get_calls_nb(LC) > 0) {
|
||||
return;
|
||||
}
|
||||
[self hideSideMenu:NO];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "UIRoundBorderedButton.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "UICompositeView.h"
|
||||
#import "UIRoundBorderedButton.h"
|
||||
|
||||
typedef void (^UIConfirmationBlock)(void);
|
||||
|
||||
@interface UIConfirmationDialog : UIViewController {
|
||||
@interface UIConfirmationDialog : UIViewController <UICompositeViewDelegate, UIGestureRecognizerDelegate, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource>{
|
||||
UIConfirmationBlock onCancelCb;
|
||||
UIConfirmationBlock onConfirmCb;
|
||||
}
|
||||
|
|
@ -49,13 +52,18 @@ typedef void (^UIConfirmationBlock)(void);
|
|||
@property (weak, nonatomic) IBOutlet UIImageView *groupCallImage;
|
||||
@property(weak, nonatomic) IBOutlet UIRoundBorderedButton *confirmationButton;
|
||||
@property (weak, nonatomic) IBOutlet UIView *authView;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *backgroundColor;
|
||||
@property(weak, nonatomic) IBOutlet UILabel *titleLabel;
|
||||
@property(weak, nonatomic) IBOutlet UIView *firstView;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *authButton;
|
||||
@property(weak, nonatomic) IBOutlet UILabel *subscribeLabel;
|
||||
|
||||
|
||||
- (void)setSpecialColor;
|
||||
-(void) setWhiteCancel;
|
||||
- (IBAction)onCancelClick:(id)sender;
|
||||
- (IBAction)onConfirmationClick:(id)sender;
|
||||
- (IBAction)onAuthClick:(id)sender;
|
||||
- (IBAction)onSubscribeTap:(id)sender;
|
||||
- (void)dismiss;
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#import "UIConfirmationDialog.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import "linphoneapp-Swift.h""
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
@implementation UIConfirmationDialog
|
||||
+ (UIConfirmationDialog *)initDialog:(NSString *)cancel
|
||||
|
|
@ -33,6 +33,8 @@
|
|||
dialog.view.frame = PhoneMainView.instance.mainViewController.view.frame;
|
||||
[controller.view addSubview:dialog.view];
|
||||
[controller addChildViewController:dialog];
|
||||
dialog.backgroundColor.layer.cornerRadius = 10;
|
||||
dialog.backgroundColor.layer.masksToBounds = true;
|
||||
|
||||
dialog->onCancelCb = onCancel;
|
||||
dialog->onConfirmCb = onConfirm;
|
||||
|
|
@ -48,9 +50,21 @@
|
|||
[[UIColor colorWithPatternImage:[UIImage imageNamed:@"color_A.png"]] CGColor];
|
||||
dialog.cancelButton.layer.borderColor =
|
||||
[[UIColor colorWithPatternImage:[UIImage imageNamed:@"color_F.png"]] CGColor];
|
||||
if (linphone_core_get_post_quantum_available()) {
|
||||
[dialog.securityImage setImage:[UIImage imageNamed:@"post_quantum_secure.png"]];
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
|
||||
action:@selector(onCancelClick:)];
|
||||
tapGestureRecognizer.delegate = self;
|
||||
[self.firstView addGestureRecognizer:tapGestureRecognizer];
|
||||
}
|
||||
|
||||
|
||||
+ (UIConfirmationDialog *)ShowWithMessage:(NSString *)message
|
||||
cancelMessage:(NSString *)cancel
|
||||
confirmMessage:(NSString *)confirm
|
||||
|
|
@ -131,4 +145,12 @@
|
|||
- (void)dismiss {
|
||||
[self onCancelClick:nil];
|
||||
}
|
||||
|
||||
- (IBAction)onSubscribeTap:(id)sender {
|
||||
UIGestureRecognizer *gest = sender;
|
||||
NSString *url = ((UILabel *)gest.view).text;
|
||||
if (![UIApplication.sharedApplication openURL:[NSURL URLWithString:url]]) {
|
||||
LOGE(@"Failed to open %@, invalid URL", url);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -50,28 +50,34 @@
|
|||
normAddr = linphone_account_normalize_phone_number(account,
|
||||
_addressLabel.text.UTF8String);
|
||||
}
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, normAddr);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, normAddr, true);
|
||||
_chatButton.enabled = _callButton.enabled = _encryptedChatButton.enabled = (addr != NULL);
|
||||
|
||||
_chatButton.accessibilityLabel =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"Chat with %@", nil), _addressLabel.text];
|
||||
_callButton.accessibilityLabel = [NSString stringWithFormat:NSLocalizedString(@"Call %@", nil), _addressLabel.text];
|
||||
// Test presence
|
||||
Contact *contact;
|
||||
contact = addr ? [FastAddressBook getContactWithAddress:(addr)] : NULL;
|
||||
|
||||
Contact *contact = addr ? [FastAddressBook getContactWithAddress:(addr)] : NULL;
|
||||
LinphoneFriend *contactFriend = NULL;
|
||||
if (contact && contact.friend) {
|
||||
contactFriend = contact.friend;
|
||||
} else if (addr) {
|
||||
contactFriend = linphone_core_find_friend(LC, addr);
|
||||
}
|
||||
|
||||
ContactDetailsView *contactDetailsView = VIEW(ContactDetailsView);
|
||||
_linphoneImage.hidden = TRUE;
|
||||
if (contact) {
|
||||
const LinphonePresenceModel *model = contact.friend ? linphone_friend_get_presence_model_for_uri_or_tel(contact.friend, _addressLabel.text.UTF8String) : NULL;
|
||||
|
||||
if (contactFriend) {
|
||||
const LinphonePresenceModel *model = contactFriend ? linphone_friend_get_presence_model_for_uri_or_tel(contactFriend, _addressLabel.text.UTF8String) : NULL;
|
||||
|
||||
self.linphoneImage.hidden = [LinphoneManager.instance lpConfigBoolForKey:@"hide_linphone_contacts" inSection:@"app"] ||
|
||||
!((model && linphone_presence_model_get_basic_status(model) == LinphonePresenceBasicStatusOpen) ||
|
||||
(account && !linphone_account_is_phone_number(account,
|
||||
_addressLabel.text.UTF8String) &&
|
||||
[FastAddressBook isSipURIValid:_addressLabel.text]));
|
||||
ContactDetailsView *contactDetailsView = VIEW(ContactDetailsView);
|
||||
self.inviteButton.hidden = !ENABLE_SMS_INVITE || [[contactDetailsView.contact sipAddresses] count] > 0 || !self.linphoneImage.hidden;
|
||||
self.inviteButton.hidden = !ENABLE_SMS_INVITE || [[contactDetailsView.contact sipAddresses] count] > 0 || !self.linphoneImage.hidden;
|
||||
[self shouldHideEncryptedChatView:account && linphone_account_params_get_conference_factory_uri(linphone_account_get_params(account)) && model && linphone_presence_model_has_capability(model, LinphoneFriendCapabilityLimeX3dh)];
|
||||
_chatButton.hidden = [LinphoneManager.instance lpConfigBoolForKey:@"force_lime_chat_rooms"];
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
|
|
@ -103,7 +109,7 @@
|
|||
normAddr = linphone_account_normalize_phone_number(account,
|
||||
_addressLabel.text.UTF8String);
|
||||
}
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, normAddr);
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, normAddr, true);
|
||||
|
||||
// Test presence
|
||||
Contact *contact = [FastAddressBook getContactWithAddress:(addr)];
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@
|
|||
if (addressField && (!dtmf || !linphone_core_in_call(LC))) {
|
||||
NSString *newAddress = [NSString stringWithFormat:@"%@%c", addressField.text, digit];
|
||||
[addressField setText:newAddress];
|
||||
linphone_core_play_dtmf(LC, digit, -1);
|
||||
} else {
|
||||
linphone_call_send_dtmf(linphone_core_get_current_call(LC), digit);
|
||||
linphone_core_play_dtmf(LC, digit, 100);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@
|
|||
// Set up the cell...
|
||||
if (linphone_call_log_was_conference(callLog)) {
|
||||
const char *subject = linphone_conference_info_get_subject(linphone_call_log_get_conference_info(callLog));
|
||||
displayNameLabel.text = [NSString stringWithFormat:@"%s",subject];
|
||||
displayNameLabel.text = [NSString stringWithUTF8String:subject];
|
||||
[_avatarImage setImage:[UIImage imageNamed:@"voip_multiple_contacts_avatar"]];
|
||||
_stateImage.hidden = true;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -92,12 +92,6 @@
|
|||
[_playButton setImage:[UIImage imageFromSystemBarButton:UIBarButtonSystemItemPlay:[UIColor blackColor]] forState:UIControlStateNormal];
|
||||
[_stopButton setTitle:@"" forState:UIControlStateNormal];
|
||||
[_stopButton setImage:[UIImage imageFromSystemBarButton:UIBarButtonSystemItemRefresh:[UIColor blackColor]] forState:UIControlStateNormal];
|
||||
if (linphone_player_get_is_video_available(player)) {
|
||||
linphone_player_set_window_id(player, (__bridge void *)VIEW(RecordingsListView).videoView);
|
||||
VIEW(RecordingsListView).videoView.hidden = NO;
|
||||
} else {
|
||||
VIEW(RecordingsListView).videoView.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isOpened {
|
||||
|
|
@ -195,6 +189,12 @@ void on_eof_reached(LinphonePlayer *pl) {
|
|||
[_playButton setTitle:@"" forState:UIControlStateNormal];
|
||||
[_playButton setImage:[UIImage imageFromSystemBarButton:UIBarButtonSystemItemPause:[UIColor blackColor]] forState:UIControlStateNormal];
|
||||
linphone_player_start(player);
|
||||
if (linphone_player_get_is_video_available(player)) {
|
||||
linphone_player_set_window_id(player, (__bridge void *)VIEW(RecordingsListView).videoView);
|
||||
VIEW(RecordingsListView).videoView.hidden = NO;
|
||||
} else {
|
||||
VIEW(RecordingsListView).videoView.hidden = YES;
|
||||
}
|
||||
break;
|
||||
case LinphonePlayerPlaying:
|
||||
NSLog(@"Pause");
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@
|
|||
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
|
||||
@property (strong, nonatomic) IBOutlet UIToolbar *toolbar;
|
||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *shareButton;
|
||||
|
||||
|
||||
@property(nonatomic, assign) __block NSString *recording;
|
||||
|
||||
- (id)initWithIdentifier:(NSString*)identifier;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,8 @@ static UILinphoneAudioPlayer *player;
|
|||
NSArray *parsedRecording = [LinphoneUtils parseRecordingName:_recording];
|
||||
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
|
||||
[dateFormat setDateFormat:@"HH:mm:ss"];
|
||||
_nameLabel.text = [[[parsedRecording objectAtIndex:0] stringByAppendingString:@" @ "] stringByAppendingString:[dateFormat stringFromDate:[parsedRecording objectAtIndex:1]]];
|
||||
NSString *b = [[parsedRecording objectAtIndex:0] containsString:@"conf-id"] ? NSLocalizedString(@"Meeting", nil) : [parsedRecording objectAtIndex:0];
|
||||
_nameLabel.text = [[b stringByAppendingString:@" @ "] stringByAppendingString:[dateFormat stringFromDate:[parsedRecording objectAtIndex:1]]];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +90,8 @@ static UILinphoneAudioPlayer *player;
|
|||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
|
||||
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
if (!VIEW(RecordingsListView).tableController.isEditing)
|
||||
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
}
|
||||
|
||||
- (void)updateFrame {
|
||||
|
|
@ -104,10 +106,11 @@ static UILinphoneAudioPlayer *player;
|
|||
|
||||
-(void)setSelected:(BOOL)selected animated:(BOOL)animated{
|
||||
[super setSelected:selected animated:animated];
|
||||
_toolbar.hidden = !selected;
|
||||
if (!selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selected || (selected && VIEW(RecordingsListView).tableController.isEditing)) {
|
||||
_toolbar.hidden = true;
|
||||
return;
|
||||
}
|
||||
if (player && [player isCreated]) {
|
||||
[player close];
|
||||
}
|
||||
|
|
@ -121,6 +124,7 @@ static UILinphoneAudioPlayer *player;
|
|||
player.view.frame = _playerView.frame;
|
||||
player.view.bounds = _playerView.bounds;
|
||||
[player open];
|
||||
_toolbar.hidden = false;
|
||||
}
|
||||
|
||||
- (void)onShareButtonPressed {
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -20,6 +20,7 @@ import linphonesw
|
|||
var previousFilter : String?
|
||||
var magicSearch : MagicSearch
|
||||
var magicSearchDelegate : MagicSearchDelegate?
|
||||
var lastSearch : [SearchResult]?
|
||||
|
||||
|
||||
override init() {
|
||||
|
|
@ -30,10 +31,12 @@ import linphonesw
|
|||
magicSearchDelegate = MagicSearchDelegateStub(onSearchResultsReceived: { (magicSearch: MagicSearch) in
|
||||
self.needUpdateLastSearchContacts = true
|
||||
self.ongoingSearch = false
|
||||
self.lastSearch = magicSearch.lastSearch
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Contact magic search -- filter = \(String(describing: self.previousFilter)) -- \(magicSearch.lastSearch.count) contact founds")
|
||||
NotificationCenter.default.post(name: Notification.Name(kLinphoneMagicSearchFinished), object: self)
|
||||
}, onLdapHaveMoreResults: { (magicSearch: MagicSearch, ldap: Ldap) in
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Ldap have more result")
|
||||
NotificationCenter.default.post(name: Notification.Name(kLinphoneMagicSearchMoreAvailable), object: self)
|
||||
})
|
||||
|
||||
magicSearch.addDelegate(delegate: magicSearchDelegate!)
|
||||
|
|
@ -47,17 +50,26 @@ import linphonesw
|
|||
return theMagicSearchSingleton!
|
||||
}
|
||||
|
||||
@objc static func destroyInstance() {
|
||||
theMagicSearchSingleton = nil
|
||||
}
|
||||
|
||||
|
||||
func getContactFromAddr(addr: Address) -> Contact? {
|
||||
return LinphoneManager.instance().fastAddressBook.addressBookMap.object(forKey: addr.asStringUriOnly() as Any) as? Contact
|
||||
}
|
||||
func getContactFromPhoneNb(phoneNb: String) -> Contact? {
|
||||
let contactKey = FastAddressBook.localizedLabel(FastAddressBook.normalizeSipURI( lc?.defaultAccount?.normalizePhoneNumber(username: phoneNb) ?? phoneNb))
|
||||
let contactKey = FastAddressBook.localizedLabel(FastAddressBook.normalizeSipURI(lc?.defaultAccount?.normalizePhoneNumber(username: phoneNb) ?? phoneNb, use_prefix: true))
|
||||
return LinphoneManager.instance().fastAddressBook.addressBookMap.object(forKey: contactKey as Any) as? Contact
|
||||
}
|
||||
|
||||
func searchAndAddMatchingContact(searchResult: SearchResult) -> Contact? {
|
||||
if let friend = searchResult.friend {
|
||||
if (searchResult.sourceFlags == MagicSearchSource.LdapServers.rawValue), let newContact = Contact(friend: friend.getCobject) {
|
||||
// Contact comes from LDAP, creating a new one
|
||||
newContact.createdFromLdapOrProvisioning = true
|
||||
return newContact
|
||||
}
|
||||
if let addr = friend.address, let foundContact = getContactFromAddr(addr: addr) {
|
||||
return foundContact
|
||||
}
|
||||
|
|
@ -66,11 +78,6 @@ import linphonesw
|
|||
return foundContact
|
||||
}
|
||||
}
|
||||
// No contacts found (searchResult likely comes from LDAP), creating a new one
|
||||
if let newContact = Contact(friend: friend.getCobject) {
|
||||
newContact.createdFromLdap = true
|
||||
return newContact
|
||||
}
|
||||
}
|
||||
|
||||
if let addr = searchResult.address, let foundContact = getContactFromAddr(addr: addr) {
|
||||
|
|
@ -81,6 +88,11 @@ import linphonesw
|
|||
return foundContact
|
||||
}
|
||||
|
||||
// Friend comes from provisioning
|
||||
if let addr = searchResult.address, let friend = searchResult.friend, let newContact = Contact(friend: friend.getCobject) {
|
||||
newContact.createdFromLdapOrProvisioning = true
|
||||
return newContact
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -91,8 +103,10 @@ import linphonesw
|
|||
@objc func getLastSearchResults() -> UnsafeMutablePointer<bctbx_list_t>? {
|
||||
|
||||
var cList: UnsafeMutablePointer<bctbx_list_t>? = nil
|
||||
for data in magicSearch.lastSearch {
|
||||
cList = bctbx_list_append(cList, UnsafeMutableRawPointer(data.getCobject))
|
||||
if let search = lastSearch {
|
||||
for data in search {
|
||||
cList = bctbx_list_append(cList, UnsafeMutableRawPointer(data.getCobject))
|
||||
}
|
||||
}
|
||||
return cList
|
||||
}
|
||||
|
|
@ -100,13 +114,9 @@ import linphonesw
|
|||
@objc func getLastSearchContacts() -> [Contact] {
|
||||
if (needUpdateLastSearchContacts) {
|
||||
lastSearchContacts = []
|
||||
var addedContactNames : [String] = []
|
||||
for res in magicSearch.lastSearch {
|
||||
if let contact = searchAndAddMatchingContact(searchResult: res) {
|
||||
if (!addedContactNames.contains(contact.displayName)) {
|
||||
addedContactNames.append(contact.displayName)
|
||||
lastSearchContacts.append(contact)
|
||||
}
|
||||
lastSearchContacts.append(contact)
|
||||
}
|
||||
}
|
||||
needUpdateLastSearchContacts = false
|
||||
|
|
|
|||
|
|
@ -123,3 +123,4 @@
|
|||
@end
|
||||
|
||||
void main_view_chat_room_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomState newState);
|
||||
void main_view_chat_room_conference_joined(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
|
||||
|
|
|
|||
|
|
@ -374,7 +374,6 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
break;
|
||||
}
|
||||
case LinphoneCallOutgoingInit:
|
||||
case LinphoneCallOutgoingEarlyMedia:
|
||||
case LinphoneCallOutgoingProgress:
|
||||
case LinphoneCallOutgoingRinging: {
|
||||
|
|
@ -386,7 +385,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
break;
|
||||
}
|
||||
case LinphoneCallPausedByRemote:
|
||||
case LinphoneCallPausedByRemote:break;
|
||||
case LinphoneCallConnected: {
|
||||
if (![LinphoneManager.instance isCTCallCenterExist]) {
|
||||
/*only register CT call center CB for connected call*/
|
||||
|
|
@ -418,6 +417,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
case LinphoneCallUpdating:
|
||||
break;
|
||||
|
||||
}
|
||||
if (state == LinphoneCallEnd || state == LinphoneCallError || floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max)
|
||||
[self updateApplicationBadgeNumber];
|
||||
|
|
@ -453,9 +453,19 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
LinphoneManager *lm = LinphoneManager.instance;
|
||||
LOGI(@"%s", linphone_global_state_to_string(linphone_core_get_global_state(LC)));
|
||||
|
||||
NSString* groupName = [NSString stringWithFormat:@"group.%@.linphoneExtension",[[NSBundle mainBundle] bundleIdentifier]];
|
||||
|
||||
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName];
|
||||
NSDictionary *dict = [defaults valueForKey:@"photoData"];
|
||||
NSDictionary *dictFile = [defaults valueForKey:@"icloudData"];
|
||||
NSDictionary *dictUrl = [defaults valueForKey:@"url"];
|
||||
|
||||
// If we've been started by a remote push notification,
|
||||
// we'll already be on the corresponding chat conversation view, no need to go anywhere else
|
||||
if (![[self currentView].name isEqualToString:@"ChatConversationView"]) {
|
||||
if (dict||dictFile||dictUrl){
|
||||
[self changeCurrentView:ChatsListView.compositeViewDescription];
|
||||
}else if (![[self currentView].name isEqualToString:@"ChatConversationView"]) {
|
||||
|
||||
if (linphone_core_get_global_state(LC) != LinphoneGlobalOn) {
|
||||
[self changeCurrentView:DialerView.compositeViewDescription];
|
||||
|
|
@ -607,7 +617,8 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
[self _changeCurrentView:viewStack.lastObject ?: DialerView.compositeViewDescription
|
||||
transition:[PhoneMainView getBackwardTransition]
|
||||
animated:ANIMATED];
|
||||
animated:ANIMATED
|
||||
addViewToStack:FALSE];
|
||||
return [mainViewController getCurrentViewController];
|
||||
}
|
||||
|
||||
|
|
@ -621,18 +632,19 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
|
||||
|
||||
- (void)changeCurrentView:(UICompositeViewDescription *)view {
|
||||
[self _changeCurrentView:view transition:nil animated:ANIMATED];
|
||||
[self _changeCurrentView:view transition:nil animated:ANIMATED addViewToStack:TRUE];
|
||||
}
|
||||
|
||||
- (UIViewController *)_changeCurrentView:(UICompositeViewDescription *)view
|
||||
transition:(CATransition *)transition
|
||||
animated:(BOOL)animated {
|
||||
animated:(BOOL)animated
|
||||
addViewToStack:(BOOL)addViewToStack {
|
||||
PhoneMainView *vc = [[RootViewManager instance] setViewControllerForDescription:view];
|
||||
if (![view equal:vc.currentView] || vc != self) {
|
||||
LOGI(@"Change current view to %@", view.name);
|
||||
[self setPreviousViewName:vc.currentView.name];
|
||||
NSMutableArray *viewStack = [RootViewManager instance].viewDescriptionStack;
|
||||
[viewStack addObject:view];
|
||||
if (addViewToStack) [viewStack addObject:view];
|
||||
if (animated && transition == nil)
|
||||
transition = [PhoneMainView getTransition:vc.currentView new:view];
|
||||
[vc.mainViewController setViewTransition:(animated ? transition : nil)];
|
||||
|
|
@ -653,7 +665,8 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
while (viewStack.count > 0 && ![[viewStack lastObject] equal:view]) {
|
||||
[viewStack removeLastObject];
|
||||
}
|
||||
return [self _changeCurrentView:view transition:[PhoneMainView getBackwardTransition] animated:ANIMATED];
|
||||
BOOL addView = (viewStack.count == 0); // if we couldn't find the view in the stack, we need to add it
|
||||
return [self _changeCurrentView:view transition:[PhoneMainView getBackwardTransition] animated:ANIMATED addViewToStack:addView];
|
||||
}
|
||||
|
||||
- (void) setPreviousViewName:(NSString*)previous{
|
||||
|
|
@ -884,6 +897,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
|
||||
LinphoneChatRoomCbs *cbs = linphone_factory_create_chat_room_cbs(linphone_factory_get());
|
||||
linphone_chat_room_cbs_set_state_changed(cbs, main_view_chat_room_state_changed);
|
||||
linphone_chat_room_cbs_set_conference_joined(cbs, main_view_chat_room_conference_joined);
|
||||
linphone_chat_room_add_callbacks(room, cbs);
|
||||
|
||||
return room;
|
||||
|
|
@ -901,31 +915,34 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
[view clearMessageView];
|
||||
view.chatRoom = cr;
|
||||
view.peerAddress = linphone_address_as_string(linphone_chat_room_get_peer_address(cr));
|
||||
view.localAddress = linphone_address_as_string(linphone_chat_room_get_local_address(cr));
|
||||
self.currentRoom = view.chatRoom;
|
||||
|
||||
if (PhoneMainView.instance.currentView == view.compositeViewDescription)
|
||||
[view configureForRoom:FALSE];
|
||||
else
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
}
|
||||
|
||||
void main_view_chat_room_conference_joined(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
|
||||
PhoneMainView *view = PhoneMainView.instance;
|
||||
LOGI(@"Chat room [%p] conference joined.", cr);
|
||||
linphone_chat_room_remove_callbacks(cr, linphone_chat_room_get_current_callbacks(cr));
|
||||
[view goToChatRoom:cr];
|
||||
if (!IPAD)
|
||||
return;
|
||||
|
||||
if (PhoneMainView.instance.currentView != ChatsListView.compositeViewDescription && PhoneMainView.instance.currentView != ChatConversationView.compositeViewDescription)
|
||||
return;
|
||||
|
||||
ChatsListView *mainView = VIEW(ChatsListView);
|
||||
[mainView.tableController loadData];
|
||||
[mainView.tableController selectFirstRow];
|
||||
}
|
||||
|
||||
void main_view_chat_room_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomState newState) {
|
||||
PhoneMainView *view = PhoneMainView.instance;
|
||||
switch (newState) {
|
||||
case LinphoneChatRoomStateCreated: {
|
||||
LOGI(@"Chat room [%p] created on server.", cr);
|
||||
linphone_chat_room_remove_callbacks(cr, linphone_chat_room_get_current_callbacks(cr));
|
||||
[view goToChatRoom:cr];
|
||||
if (!IPAD)
|
||||
break;
|
||||
|
||||
if (PhoneMainView.instance.currentView != ChatsListView.compositeViewDescription && PhoneMainView.instance.currentView != ChatConversationView.compositeViewDescription)
|
||||
break;
|
||||
|
||||
ChatsListView *mainView = VIEW(ChatsListView);
|
||||
[mainView.tableController loadData];
|
||||
[mainView.tableController selectFirstRow];
|
||||
break;
|
||||
}
|
||||
case LinphoneChatRoomStateCreationFailed:
|
||||
LOGE(@"Chat room [%p] could not be created on server.", cr);
|
||||
linphone_chat_room_remove_callbacks(cr, linphone_chat_room_get_current_callbacks(cr));
|
||||
|
|
@ -958,4 +975,8 @@ void main_view_chat_room_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomSta
|
|||
}
|
||||
}
|
||||
|
||||
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
||||
[UIDeviceBridge notifyDisplayModeSwitch];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -147,8 +147,6 @@
|
|||
NSString *recordingPath = subAr[indexPath.row];
|
||||
[cell setRecording:recordingPath];
|
||||
[super accessoryForCell:cell atPath:indexPath];
|
||||
//accessoryForCell set it to gray but we don't want it
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
[cell updateFrame];
|
||||
cell.contentView.userInteractionEnabled = false;
|
||||
return cell;
|
||||
|
|
|
|||
|
|
@ -22,12 +22,12 @@
|
|||
#import "LinphoneAppDelegate.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import "Utils.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
#import "DCRoundSwitch.h"
|
||||
|
||||
#import "IASKSpecifierValuesViewController.h"
|
||||
#import "IASKPSTextFieldSpecifierViewCell.h"
|
||||
#import "IASKPSTitleValueSpecifierViewCell.h"
|
||||
#import "IASKSpecifier.h"
|
||||
#import "IASKTextField.h"
|
||||
#include "linphone/lpconfig.h"
|
||||
|
|
@ -247,7 +247,7 @@
|
|||
[field setTextColor:LINPHONE_MAIN_COLOR];
|
||||
}
|
||||
|
||||
if ([cell isKindOfClass:[IASKPSTitleValueSpecifierViewCell class]]) {
|
||||
if ([cell isKindOfClass:[UITableViewCell class]]) {
|
||||
cell.detailTextLabel.textColor = [UIColor grayColor];
|
||||
} else {
|
||||
cell.detailTextLabel.textColor = LINPHONE_MAIN_COLOR;
|
||||
|
|
@ -445,8 +445,11 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
linphone_account_creator_set_password(creator, _tmpPwd.UTF8String);
|
||||
[settingsStore setObject:_tmpPwd forKey:@"account_mandatory_password_preference"];
|
||||
|
||||
MSList *accountList = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
LinphoneAccount *account = bctbx_list_nth_data(linphone_core_get_account_list(LC),
|
||||
[settingsStore integerForKey:@"current_proxy_config_preference"]);
|
||||
bctbx_free(accountList);
|
||||
|
||||
if (account != NULL) {
|
||||
const LinphoneAuthInfo *auth = linphone_account_find_auth_info(account);
|
||||
if (auth) {
|
||||
|
|
@ -521,11 +524,26 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
[keys addObject:@"download_bandwidth_preference"];
|
||||
} else if ([@"auto_download_mode" compare:notif.object] == NSOrderedSame) {
|
||||
NSString *download_mode = [notif.userInfo objectForKey:@"auto_download_mode"];
|
||||
removeFromHiddenKeys = [download_mode isEqualToString:@"Customize"];
|
||||
if (removeFromHiddenKeys)
|
||||
[LinphoneManager.instance lpConfigSetInt:10000000 forKey:@"auto_download_incoming_files_max_size"];
|
||||
[keys addObject:@"auto_download_incoming_files_max_size"];
|
||||
}
|
||||
if([download_mode isEqualToString:@"Customize"]){
|
||||
[LinphoneManager.instance lpConfigSetBool:FALSE forKey:@"auto_download_mode_is_never"];
|
||||
removeFromHiddenKeys = [download_mode isEqualToString:@"Customize"];
|
||||
[LinphoneManager.instance lpConfigSetInt:10000000 forKey:@"auto_download_incoming_files_max_size"];
|
||||
[keys addObject:@"auto_download_incoming_files_max_size"];
|
||||
[hiddenKeys addObject:@"auto_write_to_gallery_mode"];
|
||||
} else {
|
||||
[LinphoneManager.instance lpConfigSetBool:FALSE forKey:@"auto_download_mode_is_never"];
|
||||
[hiddenKeys addObject:@"auto_download_incoming_files_max_size"];
|
||||
}
|
||||
}else if ([@"vfs_enabled_mode" compare:notif.object] == NSOrderedSame) {
|
||||
removeFromHiddenKeys = [[notif.userInfo objectForKey:@"vfs_enabled_mode"] boolValue];
|
||||
if(removeFromHiddenKeys){
|
||||
[LinphoneManager.instance lpConfigSetBool:TRUE forKey:@"vfs_enabled_mode"];
|
||||
[LinphoneManager.instance lpConfigSetBool:FALSE forKey:@"auto_write_to_gallery_preference"];
|
||||
[hiddenKeys addObject:@"auto_write_to_gallery_mode"];
|
||||
[hiddenKeys addObject:@"vfs_enabled_mode"];
|
||||
[keys addObject:@"vfs_enabled"];
|
||||
}
|
||||
}
|
||||
|
||||
for (NSString *key in keys) {
|
||||
if (removeFromHiddenKeys)
|
||||
|
|
@ -552,11 +570,12 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
return [[IASKSpecifier alloc] initWithSpecifier:dict];
|
||||
}
|
||||
} else {
|
||||
if ([[specifier key] isEqualToString:@"media_encryption_preference"]) {
|
||||
BOOL pq_available = linphone_core_get_post_quantum_available();
|
||||
if ([[specifier key] isEqualToString:pq_available ? @"media_encryption_preference_pq_enabled" : @"media_encryption_preference"]) {
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]];
|
||||
if (!linphone_core_media_encryption_supported(LC, LinphoneMediaEncryptionZRTP)) {
|
||||
NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]];
|
||||
[titles removeObject:@"ZRTP"];
|
||||
[titles removeObject:pq_available ? @"ZRTP" : @"ZRTP Post Quantum"];
|
||||
[dict setObject:titles forKey:@"Titles"];
|
||||
NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]];
|
||||
[values removeObject:@"ZRTP"];
|
||||
|
|
@ -583,7 +602,7 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
}
|
||||
|
||||
if ([specifier.key hasPrefix:@"menu_account_"]) {
|
||||
const bctbx_list_t *accounts = linphone_core_get_account_list(LC);
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
int index = [specifier.key substringFromIndex:@"menu_account_".length].intValue - 1;
|
||||
if (index < bctbx_list_size(accounts)) {
|
||||
LinphoneAccount *account = (LinphoneAccount *)bctbx_list_nth_data(accounts, index);
|
||||
|
|
@ -591,6 +610,7 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
stringWithUTF8String:linphone_address_get_username(linphone_account_params_get_identity_address(linphone_account_get_params(account)))];
|
||||
[specifier.specifierDict setValue:name forKey:kIASKTitle];
|
||||
}
|
||||
bctbx_free(accounts);
|
||||
}
|
||||
|
||||
if ([specifier.key hasPrefix:@"ldap_"]) {
|
||||
|
|
@ -625,18 +645,25 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
- (NSSet *)findHiddenKeys {
|
||||
LinphoneManager *lm = LinphoneManager.instance;
|
||||
NSMutableSet *hiddenKeys = [NSMutableSet set];
|
||||
|
||||
const MSList *accounts = linphone_core_get_account_list(LC);
|
||||
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
for (size_t i = bctbx_list_size(accounts) + 1; i <= 5; i++) {
|
||||
[hiddenKeys addObject:[NSString stringWithFormat:@"menu_account_%lu", i]];
|
||||
}
|
||||
|
||||
bctbx_free(accounts);
|
||||
const MSList *ldaps = linphone_core_get_ldap_list(LC);
|
||||
for (size_t i = bctbx_list_size(ldaps) + 1; i <= 5; i++) {
|
||||
[hiddenKeys addObject:[NSString stringWithFormat:@"ldap_%lu", i]];
|
||||
}
|
||||
if (!linphone_core_sip_transport_supported(LC, LinphoneTransportTls)) {
|
||||
[hiddenKeys addObject:@"media_encryption_preference"];
|
||||
[hiddenKeys addObject:@"media_encryption_preference_pq_enabled"];
|
||||
} else {
|
||||
if (linphone_core_get_post_quantum_available()) {
|
||||
[hiddenKeys addObject:@"media_encryption_preference"];
|
||||
} else {
|
||||
[hiddenKeys addObject:@"media_encryption_preference_pq_enabled"];
|
||||
}
|
||||
}
|
||||
|
||||
if (!linphone_core_ldap_available(LC)) {
|
||||
|
|
@ -761,6 +788,13 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
if (![[lm lpConfigStringForKey:@"auto_download_mode"] isEqualToString:@"Customize"]) {
|
||||
[hiddenKeys addObject:@"auto_download_incoming_files_max_size"];
|
||||
}
|
||||
|
||||
if ([lm lpConfigBoolForKey:@"vfs_enabled_mode"]) {
|
||||
[hiddenKeys addObject:@"auto_write_to_gallery_mode"];
|
||||
[hiddenKeys addObject:@"vfs_enabled_mode"];
|
||||
}else{
|
||||
[hiddenKeys addObject:@"vfs_enabled"];
|
||||
}
|
||||
|
||||
return hiddenKeys;
|
||||
}
|
||||
|
|
@ -851,25 +885,34 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
[PhoneMainView.instance changeCurrentView:AssistantView.compositeViewDescription];
|
||||
return;
|
||||
} else if ([key isEqual:@"account_mandatory_remove_button"]) {
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Warning", nil)
|
||||
message:NSLocalizedString(@"Are you sure to want to remove your proxy setup?", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
NSString *popUpText;
|
||||
NSString *appDomain = [LinphoneManager.instance lpConfigStringForKey:@"domain_name"
|
||||
inSection:@"app"
|
||||
withDefault:@"sip.linphone.org"];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
MSList *accountList = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
LinphoneAccount *account = bctbx_list_nth_data(accountList,
|
||||
[settingsStore integerForKey:@"current_proxy_config_preference"]);
|
||||
|
||||
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Yes", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[settingsStore removeAccount];
|
||||
[self recomputeAccountLabelsAndSync];
|
||||
[_settingsController.navigationController popViewControllerAnimated:NO];
|
||||
}];
|
||||
bool isLinphoneAccount = strcmp(appDomain.UTF8String, linphone_account_params_get_domain(linphone_account_get_params(account))) == 0;
|
||||
if (isLinphoneAccount) {
|
||||
popUpText = NSLocalizedString(@"Your account will only be deleted locally.\nTo delete it permanently, go to our account management platform:", nil);
|
||||
} else {
|
||||
popUpText = NSLocalizedString(@"Your account will only be deleted locally.\nTo delete it permanently, go on your SIP provider website.", nil);
|
||||
}
|
||||
bctbx_free(accountList);
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[errView addAction:continueAction];
|
||||
[self presentViewController:errView animated:YES completion:nil];
|
||||
UIConfirmationDialog *dialog = [UIConfirmationDialog ShowWithMessage:popUpText
|
||||
cancelMessage:nil
|
||||
confirmMessage:nil
|
||||
onCancelClick:nil
|
||||
onConfirmationClick:^() {
|
||||
[settingsStore removeAccount];
|
||||
[self recomputeAccountLabelsAndSync];
|
||||
[_settingsController.navigationController popViewControllerAnimated:NO];
|
||||
}];
|
||||
dialog.subscribeLabel.hidden = !isLinphoneAccount; // Only display link to https://subscribe.linphone.org for linphone accounts
|
||||
|
||||
} else if ([key isEqual:@"account_mandatory_change_password"]) {
|
||||
UIAlertController *alertView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Change your password", nil)
|
||||
message:NSLocalizedString(@"Please enter and confirm your new password", nil)
|
||||
|
|
@ -901,8 +944,11 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
if (pwd && ![pwd isEqualToString:@""]) {
|
||||
if ([pwd isEqualToString:conf_pwd]) {
|
||||
_tmpPwd = pwd;
|
||||
LinphoneAccount *account = bctbx_list_nth_data(linphone_core_get_account_list(LC),
|
||||
[settingsStore integerForKey:@"current_proxy_config_preference"]);
|
||||
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
LinphoneAccount *account = bctbx_list_nth_data(accounts,
|
||||
[settingsStore integerForKey:@"current_proxy_config_preference"]);
|
||||
bctbx_free(accounts);
|
||||
const LinphoneAuthInfo *ai = linphone_account_find_auth_info(account);
|
||||
|
||||
LinphoneAccountCreator *account_creator = linphone_account_creator_new(
|
||||
|
|
|
|||
|
|
@ -66,8 +66,11 @@
|
|||
changeCurrentView:AssistantView.compositeViewDescription];
|
||||
}]];
|
||||
BOOL mustLink = ([LinphoneManager.instance lpConfigIntForKey:@"must_link_account_time"] > 0);
|
||||
BOOL hasAccount = linphone_core_get_account_list(LC) != NULL;
|
||||
if (mustLink && hasAccount) {
|
||||
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
BOOL hasAccount = accounts != NULL;
|
||||
bctbx_free(accounts);
|
||||
if (mustLink && hasAccount && ![LinphoneManager.instance lpConfigIntForKey:@"hide_link_phone_number"]) {
|
||||
[_sideMenuEntries
|
||||
addObject:[[SideMenuEntry alloc] initWithTitle:NSLocalizedString(@"Link my account", nil)
|
||||
image:[UIImage imageNamed:@"menu_link_account.png"]
|
||||
|
|
@ -104,7 +107,7 @@
|
|||
}
|
||||
|
||||
[_sideMenuEntries addObject:[[SideMenuEntry alloc] initWithTitle:VoipTexts.conference_scheduled
|
||||
image:[UIImage imageNamed:@"voip_conference_new.png"]
|
||||
image:[UIImage imageNamed:@"side_menu_voip_meeting_schedule"]
|
||||
tapBlock:^() {
|
||||
[PhoneMainView.instance
|
||||
changeCurrentView:ScheduledConferencesView.compositeViewDescription];
|
||||
|
|
@ -127,9 +130,12 @@
|
|||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (section == 0) {
|
||||
|
||||
BOOL hasDefault = (linphone_core_get_default_account(LC) != NULL);
|
||||
// default account is shown in the header already
|
||||
size_t count = bctbx_list_size(linphone_core_get_account_list(LC));
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
size_t count = bctbx_list_size(accounts);
|
||||
bctbx_free(accounts);
|
||||
return MAX(0, (int)count - (hasDefault ? 1 : 0));
|
||||
} else {
|
||||
return [_sideMenuEntries count];
|
||||
|
|
@ -142,12 +148,14 @@
|
|||
// isLcInitialized called here because this is called when going in bg after LC destroy
|
||||
if (indexPath.section == 0 && [LinphoneManager isLcInitialized]) {
|
||||
// do not display default account here, it is already in header view
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
int idx =
|
||||
linphone_core_get_default_account(LC)
|
||||
? bctbx_list_index(linphone_core_get_account_list(LC), linphone_core_get_default_account(LC))
|
||||
? bctbx_list_index(accounts, linphone_core_get_default_account(LC))
|
||||
: HUGE_VAL;
|
||||
LinphoneAccount *account = bctbx_list_nth_data(linphone_core_get_account_list(LC),
|
||||
LinphoneAccount *account = bctbx_list_nth_data(accounts,
|
||||
(int)indexPath.row + (idx <= indexPath.row ? 1 : 0));
|
||||
bctbx_free(accounts);
|
||||
if (account) {
|
||||
cell.textLabel.text = [NSString stringWithUTF8String:linphone_account_params_get_identity(linphone_account_get_params(account))];
|
||||
cell.imageView.image = [StatusBarView imageForState:linphone_account_get_state(account)];
|
||||
|
|
|
|||
|
|
@ -70,7 +70,9 @@
|
|||
_addressLabel.text = str ? [NSString stringWithUTF8String:str] : NSLocalizedString(@"No address", nil);
|
||||
if (str) ms_free(str);
|
||||
} else {
|
||||
_nameLabel.text = linphone_core_get_account_list(LC) ? NSLocalizedString(@"No default account", nil) : NSLocalizedString(@"No account", nil);
|
||||
MSList *accounts = [LinphoneManager.instance createAccountsNotHiddenList];
|
||||
_nameLabel.text = accounts ? NSLocalizedString(@"No default account", nil) : NSLocalizedString(@"No account", nil);
|
||||
bctbx_free(accounts);
|
||||
// display direct IP:port address so that we can be reached
|
||||
LinphoneAddress *addr = linphone_core_get_primary_contact_parsed(LC);
|
||||
if (addr) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import AVFoundation
|
|||
@objc class CallAppData: NSObject {
|
||||
@objc var batteryWarningShown = false
|
||||
@objc var videoRequested = false /*set when user has requested for video*/
|
||||
@objc var isConference = true
|
||||
@objc var isConference = false
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +49,7 @@ import AVFoundation
|
|||
var actionsToPerformOnceWhenCoreIsOn : [(()->Void)] = []
|
||||
var conference: Conference?
|
||||
var callkitAudioSessionActivated : Bool? = nil // if "nil", ignore.
|
||||
var actionToFulFill : CXCallAction? = nil;
|
||||
|
||||
var backgroundContextCall : Call?
|
||||
@objc var backgroundContextCameraIsEnabled : Bool = false
|
||||
|
|
@ -556,7 +557,7 @@ import AVFoundation
|
|||
switch cstate {
|
||||
case .IncomingReceived:
|
||||
let addr = call.remoteAddress
|
||||
var displayName = incomingDisplayName(call: call)
|
||||
var displayName = incomingDisplayName(call: call)
|
||||
|
||||
if (CallManager.callKitEnabled()) {
|
||||
let isConference = isConferenceCall(call: call)
|
||||
|
|
@ -608,7 +609,13 @@ import AVFoundation
|
|||
CallManager.instance().speakerBeforePause = false
|
||||
CallManager.instance().changeRouteToSpeaker()
|
||||
}
|
||||
actionToFulFill?.fulfill()
|
||||
actionToFulFill = nil
|
||||
break
|
||||
case .Paused:
|
||||
actionToFulFill?.fulfill()
|
||||
actionToFulFill = nil
|
||||
break
|
||||
case .OutgoingInit,
|
||||
.OutgoingProgress,
|
||||
.OutgoingRinging,
|
||||
|
|
@ -625,7 +632,16 @@ import AVFoundation
|
|||
Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call started connecting with uuid \(uuid!) and callId \(callId!)")
|
||||
CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!)
|
||||
} else {
|
||||
CallManager.instance().referedToCall = callId
|
||||
if CallManager.instance().isConferenceCall(call: call) {
|
||||
let uuid = UUID()
|
||||
let callInfo = CallInfo.newOutgoingCallInfo(addr: call.remoteAddress!, isSas: call.params?.mediaEncryption == .ZRTP, displayName: VoipTexts.conference_default_title, isVideo: call.params?.videoEnabled == true, isConference:true)
|
||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo, forKey: uuid)
|
||||
CallManager.instance().providerDelegate.uuids.updateValue(uuid, forKey: "")
|
||||
CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid)
|
||||
Core.get().activateAudioSession(actived: true)
|
||||
} else {
|
||||
CallManager.instance().referedToCall = callId
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
|
|
@ -695,7 +711,7 @@ import AVFoundation
|
|||
}
|
||||
break
|
||||
case .Released:
|
||||
call.userData = nil
|
||||
CallManager.setAppData(sCall : call, appData : nil);
|
||||
break
|
||||
case .Referred:
|
||||
CallManager.instance().referedFromCall = call.callLog?.callId
|
||||
|
|
@ -706,7 +722,7 @@ import AVFoundation
|
|||
|
||||
let readyForRoutechange = CallManager.instance().callkitAudioSessionActivated == nil || (CallManager.instance().callkitAudioSessionActivated == true)
|
||||
if (readyForRoutechange && (cstate == .IncomingReceived || cstate == .OutgoingInit || cstate == .Connected || cstate == .StreamsRunning)) {
|
||||
if ((call.currentParams?.videoEnabled ?? false) && CallManager.instance().isReceiverEnabled()) {
|
||||
if ((call.currentParams?.videoEnabled ?? false) && CallManager.instance().isReceiverEnabled() && call.conference == nil) {
|
||||
CallManager.instance().changeRouteToSpeaker()
|
||||
} else if (isBluetoothAvailable()) {
|
||||
// Use bluetooth device by default if one is available
|
||||
|
|
@ -775,6 +791,7 @@ import AVFoundation
|
|||
do {
|
||||
if let core = lc, let params = try? core.createConferenceParams(conference: nil) {
|
||||
params.videoEnabled = false // We disable video for local conferencing (cf Android)
|
||||
params.subject = VoipTexts.conference_local_title
|
||||
let conference = core.conference != nil ? core.conference : try core.createConferenceWithParams(params: params)
|
||||
try conference?.addParticipants(calls: core.calls)
|
||||
}
|
||||
|
|
@ -783,8 +800,12 @@ import AVFoundation
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@objc func applyInternationalPrefix() -> Bool {
|
||||
if let account = lc?.defaultAccount, let params = account.params {
|
||||
return params.useInternationalPrefixForCallsAndChats
|
||||
}
|
||||
return true; // Legacy behavior
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -36,10 +36,16 @@ class ScheduledConferenceData {
|
|||
let participantsShort = MutableLiveData<String>()
|
||||
let participantsExpanded = MutableLiveData<String>()
|
||||
let rawDate : Date
|
||||
let isConferenceCancelled = MutableLiveData(false)
|
||||
let canEdit = MutableLiveData(false)
|
||||
let isFinished : Bool
|
||||
let selectedForDeletion = MutableLiveData(false)
|
||||
private var conferenceSchedulerDelegate : ConferenceSchedulerDelegateStub? = nil
|
||||
private var conferenceScheduler : ConferenceScheduler? = nil
|
||||
|
||||
|
||||
init (conferenceInfo: ConferenceInfo) {
|
||||
init (conferenceInfo: ConferenceInfo, isFinished: Bool = false) {
|
||||
self.conferenceInfo = conferenceInfo
|
||||
self.isFinished = isFinished
|
||||
expanded.value = false
|
||||
|
||||
address.value = conferenceInfo.uri?.asStringUriOnly()
|
||||
|
|
@ -51,14 +57,24 @@ class ScheduledConferenceData {
|
|||
rawDate = Date(timeIntervalSince1970:TimeInterval(conferenceInfo.dateTime))
|
||||
|
||||
let durationFormatter = DateComponentsFormatter()
|
||||
durationFormatter.unitsStyle = .positional
|
||||
durationFormatter.allowedUnits = [.minute, .second ]
|
||||
durationFormatter.zeroFormattingBehavior = [ .pad ]
|
||||
duration.value = conferenceInfo.duration > 0 ? durationFormatter.string(from: TimeInterval(conferenceInfo.duration)) : nil
|
||||
durationFormatter.unitsStyle = .abbreviated
|
||||
duration.value = conferenceInfo.duration > 0 ? durationFormatter.string(from: TimeInterval(conferenceInfo.duration*60)) : nil
|
||||
|
||||
organizer.value = conferenceInfo.organizer?.addressBookEnhancedDisplayName()
|
||||
|
||||
computeParticipantsLists()
|
||||
|
||||
isConferenceCancelled.value = conferenceInfo.state == .Cancelled
|
||||
|
||||
if let organizerAddress = conferenceInfo.organizer {
|
||||
let localAccount = Core.get().accountList.filter { account in
|
||||
account.params?.identityAddress != nil && organizerAddress.weakEqual(address2: account.params!.identityAddress!)
|
||||
}.first
|
||||
canEdit.value = localAccount != nil
|
||||
} else {
|
||||
canEdit.value = false
|
||||
Log.e("[Scheduled Conference] No organizer SIP URI found for: \(conferenceInfo.uri?.asStringUriOnly())")
|
||||
}
|
||||
}
|
||||
|
||||
func destroy() {
|
||||
|
|
@ -73,6 +89,10 @@ class ScheduledConferenceData {
|
|||
String(describing: participant.addressBookEnhancedDisplayName())
|
||||
}.joined(separator: ", ")
|
||||
|
||||
if (participantsShort.value?.count == 0) {
|
||||
participantsShort.value = " "
|
||||
}
|
||||
|
||||
participantsExpanded.value = conferenceInfo.participants.map {(participant) in
|
||||
String(describing: participant.addressBookEnhancedDisplayName())+" ("+String(describing: participant.asStringUriOnly())+")"
|
||||
}.joined(separator: "\n")
|
||||
|
|
@ -81,4 +101,30 @@ class ScheduledConferenceData {
|
|||
func gotoAssociatedChat() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
func deleteConference() {
|
||||
conferenceSchedulerDelegate = ConferenceSchedulerDelegateStub(
|
||||
onStateChanged: { scheduler, state in
|
||||
Log.i("[Conference Deletion] Conference scheduler state is \(state)")
|
||||
if (state == .Ready) {
|
||||
if let chatRoomParams = ConferenceSchedulingViewModel.shared.getConferenceInvitationsChatRoomParams() {
|
||||
scheduler.sendInvitations(chatRoomParams: chatRoomParams) // Send cancel ICS
|
||||
Log.e("[Conference Deletion] sent cancel ICS.")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (conferenceInfo.state != .Cancelled && canEdit.value == true) {
|
||||
Log.i("[Scheduled Conferences] Cancelling conference \(conferenceInfo.subject)")
|
||||
self.conferenceScheduler = try? Core.get().createConferenceScheduler()
|
||||
if (self.conferenceScheduler != nil) {
|
||||
self.conferenceScheduler?.addDelegate(delegate: conferenceSchedulerDelegate!)
|
||||
self.conferenceScheduler?.cancelConference(conferenceInfo: conferenceInfo)
|
||||
}
|
||||
} else {
|
||||
Core.get().deleteConferenceInformation(conferenceInfo: conferenceInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ class ConferenceSchedulingViewModel {
|
|||
let description = MutableLiveData<String>()
|
||||
|
||||
let scheduleForLater = MutableLiveData<Bool>()
|
||||
let scheduledDateTime = MutableLiveData<Date>()
|
||||
|
||||
let scheduledDate = MutableLiveData<Date>()
|
||||
let scheduledTime = MutableLiveData<Date>()
|
||||
|
||||
var scheduledTimeZone = MutableLiveData<Int>()
|
||||
static let timeZones: [TimeZoneData] = computeTimeZonesList()
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ class ConferenceSchedulingViewModel {
|
|||
private var chatRooomDelegate : ChatRoomDelegate? = nil
|
||||
private var conferenceSchedulerDelegate : ConferenceSchedulerDelegateStub? = nil
|
||||
|
||||
var existingConfInfo:ConferenceInfo? = nil
|
||||
var existingConfInfo:MutableLiveData<ConferenceInfo?> = MutableLiveData()
|
||||
|
||||
init () {
|
||||
|
||||
|
|
@ -79,14 +80,10 @@ class ConferenceSchedulingViewModel {
|
|||
}
|
||||
self.address.value = conferenceAddress
|
||||
|
||||
if (self.sendInviteViaChat.value == true) {
|
||||
if (self.scheduleForLater.value == true && self.sendInviteViaChat.value == true) {
|
||||
// Send conference info even when conf is not scheduled for later
|
||||
// as the conference server doesn't invite participants automatically
|
||||
if let chatRoomParams = try?self.core.createDefaultChatRoomParams() {
|
||||
chatRoomParams.backend = ChatRoomBackend.FlexisipChat
|
||||
chatRoomParams.groupEnabled = false
|
||||
chatRoomParams.encryptionEnabled = true
|
||||
chatRoomParams.subject = self.subject.value!
|
||||
if let chatRoomParams = self.getConferenceInvitationsChatRoomParams() {
|
||||
scheduler.sendInvitations(chatRoomParams: chatRoomParams)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -133,13 +130,23 @@ class ConferenceSchedulingViewModel {
|
|||
scheduleForLater.observe { _ in
|
||||
self.continueEnabled.value = self.allMandatoryFieldsFilled()
|
||||
}
|
||||
scheduledDateTime.observe { _ in
|
||||
scheduledDate.observe { _ in
|
||||
self.continueEnabled.value = self.allMandatoryFieldsFilled()
|
||||
}
|
||||
scheduledTime.observe { _ in
|
||||
self.continueEnabled.value = self.allMandatoryFieldsFilled()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func isEndToEndEncryptedChatAvailable() -> Bool {
|
||||
let core = Core.get()
|
||||
return core.limeX3DhEnabled &&
|
||||
((core.limeX3DhServerUrl != nil && core.limeX3DhServerUrl.count > 0) || core.defaultAccount?.params?.limeServerUrl != nil) &&
|
||||
core.defaultAccount?.params?.conferenceFactoryUri != nil
|
||||
}
|
||||
|
||||
func reset() {
|
||||
|
||||
subject.value = ""
|
||||
|
|
@ -147,8 +154,9 @@ class ConferenceSchedulingViewModel {
|
|||
isEncrypted.value = false
|
||||
sendInviteViaChat.value = true
|
||||
sendInviteViaEmail.value = false
|
||||
scheduledDateTime.value = Date()
|
||||
|
||||
scheduledDate.value = nil
|
||||
scheduledTime.value = nil
|
||||
|
||||
scheduledTimeZone.value = ConferenceSchedulingViewModel.timeZones.indices.filter {
|
||||
ConferenceSchedulingViewModel.timeZones[$0].timeZone.identifier == NSTimeZone.default.identifier
|
||||
}.first
|
||||
|
|
@ -158,7 +166,7 @@ class ConferenceSchedulingViewModel {
|
|||
}.first
|
||||
continueEnabled.value = false
|
||||
selectedAddresses.value = []
|
||||
existingConfInfo = nil
|
||||
existingConfInfo.value = nil
|
||||
description.value = ""
|
||||
|
||||
}
|
||||
|
|
@ -191,7 +199,7 @@ class ConferenceSchedulingViewModel {
|
|||
conferenceScheduler = try? Core.get().createConferenceScheduler()
|
||||
conferenceScheduler?.addDelegate(delegate: conferenceSchedulerDelegate!)
|
||||
|
||||
guard let conferenceInfo = existingConfInfo != nil ? existingConfInfo : try Factory.Instance.createConferenceInfo() else {
|
||||
guard let conferenceInfo = existingConfInfo.value != nil ? existingConfInfo.value??.clone() : try Factory.Instance.createConferenceInfo() else {
|
||||
Log.e("[Conference Creation/Update] Failed, unable to get conf info.")
|
||||
return
|
||||
}
|
||||
|
|
@ -206,7 +214,7 @@ class ConferenceSchedulingViewModel {
|
|||
}
|
||||
conferenceScheduler?.account = localAccount
|
||||
conferenceScheduler?.info = conferenceInfo // Will trigger the conference creation automatically
|
||||
existingConfInfo = conferenceInfo
|
||||
existingConfInfo.value = conferenceInfo
|
||||
|
||||
} catch {
|
||||
Log.e("[Conference Creation] Failed \(error)")
|
||||
|
|
@ -216,14 +224,15 @@ class ConferenceSchedulingViewModel {
|
|||
|
||||
|
||||
private func allMandatoryFieldsFilled() -> Bool {
|
||||
return subject.value != nil && subject.value!.count > 0 && (scheduleForLater.value != true || scheduledDateTime.value != nil);
|
||||
return subject.value != nil && subject.value!.count > 0 && (scheduleForLater.value != true || (scheduledDate.value != nil && scheduledTime.value != nil) );
|
||||
}
|
||||
|
||||
|
||||
private func getConferenceStartTimestamp() -> Double {
|
||||
return scheduleForLater.value == true ?
|
||||
scheduledDateTime.value!.timeIntervalSince1970 +
|
||||
Double(ConferenceSchedulingViewModel.timeZones[scheduledTimeZone.value!].timeZone.secondsFromGMT()-TimeZone.current.secondsFromGMT())
|
||||
let days = Int32(scheduledDate.value!.timeIntervalSince1970)/86400
|
||||
let time = Int32(scheduledTime.value!.timeIntervalSince1970)%86400
|
||||
|
||||
return scheduleForLater.value == true ? TimeInterval(days * 86400 + time) + Double(ConferenceSchedulingViewModel.timeZones[scheduledTimeZone.value!].timeZone.secondsFromGMT()-TimeZone.current.secondsFromGMT())
|
||||
: Date().timeIntervalSince1970
|
||||
}
|
||||
|
||||
|
|
@ -238,5 +247,16 @@ class ConferenceSchedulingViewModel {
|
|||
return [Duration(value: 30, display: "30min"), Duration(value: 60, display: "1h"), Duration(value: 120, display: "2h")]
|
||||
}
|
||||
|
||||
func getConferenceInvitationsChatRoomParams() -> ChatRoomParams? {
|
||||
if let chatRoomParams = try?self.core.createDefaultChatRoomParams() {
|
||||
chatRoomParams.encryptionEnabled = self.isEndToEndEncryptedChatAvailable()
|
||||
chatRoomParams.groupEnabled = false
|
||||
chatRoomParams.backend = chatRoomParams.encryptionEnabled ? .FlexisipChat : .Basic
|
||||
chatRoomParams.subject = self.subject.value!
|
||||
return chatRoomParams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,13 +31,17 @@ class ScheduledConferencesViewModel {
|
|||
var conferences : MutableLiveData<[ScheduledConferenceData]> = MutableLiveData([])
|
||||
var daySplitted : [Date : [ScheduledConferenceData]] = [:]
|
||||
var coreDelegate: CoreDelegateStub?
|
||||
var showTerminated = MutableLiveData(false)
|
||||
let editionEnabled = MutableLiveData(false)
|
||||
let conferenceScheduler = try? Core.get().createConferenceScheduler()
|
||||
|
||||
|
||||
init () {
|
||||
|
||||
coreDelegate = CoreDelegateStub(
|
||||
onConferenceInfoReceived: { (core, conferenceInfo) in
|
||||
Log.i("[Scheduled Conferences] New conference info received")
|
||||
self.conferences.value!.append(ScheduledConferenceData(conferenceInfo: conferenceInfo))
|
||||
self.conferences.value!.append(ScheduledConferenceData(conferenceInfo: conferenceInfo,isFinished: false))
|
||||
self.conferences.notifyValue()
|
||||
}
|
||||
|
||||
|
|
@ -48,11 +52,20 @@ class ScheduledConferencesViewModel {
|
|||
func computeConferenceInfoList() {
|
||||
conferences.value!.removeAll()
|
||||
let now = Date().timeIntervalSince1970 // Linphone uses time_t in seconds
|
||||
let oneHourAgo = now - 3600 // Show all conferences from 1 hour ago and forward
|
||||
core.getConferenceInformationListAfterTime(time: time_t(oneHourAgo)).filter{$0.duration != 0}.forEach { conferenceInfo in
|
||||
conferences.value!.append(ScheduledConferenceData(conferenceInfo: conferenceInfo))
|
||||
|
||||
if (showTerminated.value == true) {
|
||||
core.conferenceInformationList.filter{$0.duration != 0 && (TimeInterval($0.dateTime) + TimeInterval($0.duration) < now)}.forEach { conferenceInfo in
|
||||
conferences.value!.append(ScheduledConferenceData(conferenceInfo: conferenceInfo,isFinished: true))
|
||||
}
|
||||
} else {
|
||||
let twoHoursAgo = now - 7200 // Show all conferences from 2 hour ago and forward
|
||||
core.getConferenceInformationListAfterTime(time: time_t(twoHoursAgo)).filter{$0.duration != 0}.forEach { conferenceInfo in
|
||||
conferences.value!.append(ScheduledConferenceData(conferenceInfo: conferenceInfo,isFinished: false))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
daySplitted = [:]
|
||||
conferences.value!.forEach { (conferenceInfo) in
|
||||
let startDateDay = dateAtBeginningOfDay(for: conferenceInfo.rawDate)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ import linphonesw
|
|||
}
|
||||
|
||||
|
||||
static let compositeDescription = UICompositeViewDescription(ConferenceHistoryDetailsView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: SideMenuView.self, fullscreen: false, isLeftFragment: false,fragmentWith: nil)
|
||||
static let compositeDescription = UICompositeViewDescription(ConferenceHistoryDetailsView.self, statusBar: StatusBarView.self, tabBar: TabBarView.classForCoder(), sideMenu: SideMenuView.self, fullscreen: false, isLeftFragment: false,fragmentWith: HistoryListView.classForCoder())
|
||||
static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription }
|
||||
func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription }
|
||||
|
||||
|
|
@ -65,6 +65,7 @@ import linphonesw
|
|||
title:"")
|
||||
super.nextButton.isHidden = true
|
||||
|
||||
super.backButton.isHidden = UIDevice.ipad()
|
||||
|
||||
let schedulingStack = UIStackView()
|
||||
schedulingStack.axis = .vertical
|
||||
|
|
@ -106,7 +107,6 @@ import linphonesw
|
|||
|
||||
// Organiser
|
||||
|
||||
organiserLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
contentView.addSubview(organiserLabel)
|
||||
organiserLabel.matchParentSideBorders().height(form_input_height).alignUnder(view: schedulingStack,withMargin: form_margin*2).done()
|
||||
organiserLabel.textAlignment = .left
|
||||
|
|
@ -120,12 +120,10 @@ import linphonesw
|
|||
organizerTableView.allowsFocus = false
|
||||
}
|
||||
organizerTableView.separatorStyle = .singleLine
|
||||
organizerTableView.separatorColor = VoipTheme.light_grey_color
|
||||
organizerTableView.tag = 1;
|
||||
organizerTableView.matchParentSideBorders().height(VoipParticipantCell.cell_height).alignUnder(view: organiserLabel,withMargin: form_margin).done()
|
||||
|
||||
// Participants
|
||||
participantsLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
contentView.addSubview(participantsLabel)
|
||||
participantsLabel.matchParentSideBorders().height(form_input_height).alignUnder(view: organizerTableView,withMargin: form_margin).done()
|
||||
participantsLabel.textAlignment = .left
|
||||
|
|
@ -139,7 +137,6 @@ import linphonesw
|
|||
participantsListTableView.allowsFocus = false
|
||||
}
|
||||
participantsListTableView.separatorStyle = .singleLine
|
||||
participantsListTableView.separatorColor = VoipTheme.light_grey_color
|
||||
|
||||
// Goto chat - v2
|
||||
/*
|
||||
|
|
@ -152,6 +149,14 @@ import linphonesw
|
|||
|
||||
chatButton.centerX().alignParentBottom(withMargin: 3*self.form_margin).alignUnder(view: participantsListTableView,withMargin: 3*self.form_margin).done()
|
||||
*/
|
||||
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.organiserLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
self.organizerTableView.separatorColor = VoipTheme.separatorColor.get()
|
||||
self.participantsLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
self.participantsListTableView.separatorColor = VoipTheme.separatorColor.get()
|
||||
self.view.backgroundColor = VoipTheme.voipBackgroundBWColor.get()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,13 +29,16 @@ import SVProgressHUD
|
|||
|
||||
let participantsListTableView = UITableView()
|
||||
|
||||
let datePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledDateTime,pickerMode: .date, readOnly:true)
|
||||
let datePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledDate,pickerMode: .date, readOnly:true)
|
||||
let timeZoneValue = StyledValuePicker(liveIndex: ConferenceSchedulingViewModel.shared.scheduledTimeZone,options: ConferenceSchedulingViewModel.timeZones.map({ (tzd: TimeZoneData) -> String in tzd.descWithOffset()}), readOnly:true)
|
||||
let durationValue = StyledValuePicker(liveIndex: ConferenceSchedulingViewModel.shared.scheduledDuration,options: ConferenceSchedulingViewModel.durationList.map({ (duration: Duration) -> String in duration.display}), readOnly:true)
|
||||
let timePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledDateTime,pickerMode: .time, readOnly:true)
|
||||
let timePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledTime,pickerMode: .time, readOnly:true)
|
||||
let descriptionLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_description_hint)
|
||||
let descriptionInput = StyledTextView(VoipTheme.conference_scheduling_font, placeHolder:VoipTexts.conference_schedule_description_hint,liveValue: ConferenceSchedulingViewModel.shared.description, readOnly:true)
|
||||
let createButton = FormButton(backgroundStateColors: VoipTheme.primary_colors_background)
|
||||
|
||||
let leftColumn = UIView()
|
||||
let rightColumn = UIView()
|
||||
let scheduleForm = UIView()
|
||||
|
||||
static let compositeDescription = UICompositeViewDescription(ConferenceSchedulingSummaryView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: SideMenuView.self, fullscreen: false, isLeftFragment: false,fragmentWith: nil)
|
||||
static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription }
|
||||
|
|
@ -76,15 +79,12 @@ import SVProgressHUD
|
|||
schedulingStack.alignUnder(view: subjectInput,withMargin: 3*form_margin).matchParentSideBorders(insetedByDx: form_margin).done()
|
||||
|
||||
|
||||
let scheduleForm = UIView()
|
||||
schedulingStack.addArrangedSubview(scheduleForm)
|
||||
scheduleForm.matchParentSideBorders().done()
|
||||
ConferenceSchedulingViewModel.shared.scheduleForLater.readCurrentAndObserve { (forLater) in scheduleForm.isHidden = forLater != true }
|
||||
ConferenceSchedulingViewModel.shared.scheduleForLater.readCurrentAndObserve { (forLater) in self.scheduleForm.isHidden = forLater != true }
|
||||
|
||||
// Left column (Date & Time)
|
||||
let leftColumn = UIView()
|
||||
scheduleForm.addSubview(leftColumn)
|
||||
leftColumn.matchParentWidthDividedBy(2.2).alignParentLeft(withMargin: form_margin).alignParentTop(withMargin: form_margin).done()
|
||||
leftColumn.matchParentWidthDividedBy(2.2).alignParentLeft().alignParentTop(withMargin: form_margin).done()
|
||||
|
||||
let dateLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_date)
|
||||
leftColumn.addSubview(dateLabel)
|
||||
|
|
@ -104,9 +104,8 @@ import SVProgressHUD
|
|||
|
||||
|
||||
// Right column (Duration & Timezone)
|
||||
let rightColumn = UIView()
|
||||
scheduleForm.addSubview(rightColumn)
|
||||
rightColumn.matchParentWidthDividedBy(2.2).alignParentRight(withMargin: form_margin).alignParentTop().done()
|
||||
rightColumn.matchParentWidthDividedBy(2.2).alignParentRight().alignParentTop().done()
|
||||
|
||||
let durationLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_duration)
|
||||
rightColumn.addSubview(durationLabel)
|
||||
|
|
@ -125,31 +124,26 @@ import SVProgressHUD
|
|||
rightColumn.wrapContentY().done()
|
||||
|
||||
// Description
|
||||
let descriptionLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_description_title)
|
||||
scheduleForm.addSubview(descriptionLabel)
|
||||
descriptionLabel.alignUnder(view: leftColumn,withMargin: form_margin).alignUnder(view: rightColumn,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).done()
|
||||
|
||||
descriptionInput.textContainer.maximumNumberOfLines = 5
|
||||
descriptionInput.textContainer.lineBreakMode = .byWordWrapping
|
||||
scheduleForm.addSubview(descriptionInput)
|
||||
descriptionInput.alignUnder(view: descriptionLabel,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).height(description_height).alignParentBottom(withMargin: form_margin*2).done()
|
||||
|
||||
scheduleForm.wrapContentY().done()
|
||||
|
||||
|
||||
// Sending method
|
||||
let viaChatLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_send_invite_chat_summary)
|
||||
contentView.addSubview(viaChatLabel)
|
||||
viaChatLabel.matchParentSideBorders(insetedByDx: form_margin).alignUnder(view: schedulingStack,withMargin: 2*form_margin).done()
|
||||
viaChatLabel.numberOfLines = 2
|
||||
ConferenceSchedulingViewModel.shared.sendInviteViaChat.readCurrentAndObserve { (sendChat) in
|
||||
viaChatLabel.isHidden = sendChat != true || ConferenceSchedulingViewModel.shared.scheduleForLater.value != true
|
||||
}
|
||||
|
||||
// Participants
|
||||
let participantsLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_participants_list)
|
||||
participantsLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
let participantsLabel = StyledLabel(VoipTheme.conference_scheduling_font, " "+VoipTexts.conference_schedule_participants_list)
|
||||
contentView.addSubview(participantsLabel)
|
||||
participantsLabel.matchParentSideBorders().height(form_input_height).alignUnder(view: viaChatLabel,withMargin: form_margin*2).done()
|
||||
participantsLabel.textAlignment = .center
|
||||
participantsLabel.matchParentSideBorders().height(form_input_height).alignUnder(view: viaChatLabel,withMargin: form_margin).done()
|
||||
participantsLabel.textAlignment = .left
|
||||
|
||||
|
||||
contentView.addSubview(participantsListTableView)
|
||||
|
|
@ -161,7 +155,7 @@ import SVProgressHUD
|
|||
participantsListTableView.allowsFocus = false
|
||||
}
|
||||
participantsListTableView.separatorStyle = .singleLine
|
||||
participantsListTableView.separatorColor = VoipTheme.light_grey_color
|
||||
participantsListTableView.backgroundColor = .clear
|
||||
|
||||
ConferenceSchedulingViewModel.shared.selectedAddresses.readCurrentAndObserve { (addresses) in
|
||||
self.participantsListTableView.reloadData()
|
||||
|
|
@ -172,8 +166,13 @@ import SVProgressHUD
|
|||
|
||||
// Create / Schedule
|
||||
contentView.addSubview(createButton)
|
||||
createButton.centerX().alignParentBottom(withMargin: 3*self.form_margin).alignUnder(view: participantsListTableView,withMargin: 3*self.form_margin).width(0).done()
|
||||
ConferenceSchedulingViewModel.shared.scheduleForLater.readCurrentAndObserve { _ in
|
||||
self.createButton.title = ConferenceSchedulingViewModel.shared.scheduleForLater.value == true ? VoipTexts.conference_schedule_start.uppercased() : VoipTexts.conference_group_call_create.uppercased()
|
||||
self.createButton.title = ConferenceSchedulingViewModel.shared.scheduleForLater.value == true ? ConferenceSchedulingViewModel.shared.existingConfInfo.value != nil ? VoipTexts.conference_schedule_edit.uppercased() : VoipTexts.conference_schedule_start.uppercased() : VoipTexts.conference_group_call_create.uppercased()
|
||||
self.createButton.addSidePadding()
|
||||
}
|
||||
ConferenceSchedulingViewModel.shared.existingConfInfo.readCurrentAndObserve { _ in
|
||||
self.createButton.title = ConferenceSchedulingViewModel.shared.scheduleForLater.value == true ? ConferenceSchedulingViewModel.shared.existingConfInfo.value != nil ? VoipTexts.conference_schedule_edit.uppercased() : VoipTexts.conference_schedule_start.uppercased() : VoipTexts.conference_group_call_create.uppercased()
|
||||
self.createButton.addSidePadding()
|
||||
}
|
||||
|
||||
|
|
@ -210,21 +209,40 @@ import SVProgressHUD
|
|||
}
|
||||
}
|
||||
ConferenceSchedulingViewModel.shared.scheduleForLater.readCurrentAndObserve { (later) in
|
||||
self.createButton.title = ConferenceSchedulingViewModel.shared.scheduleForLater.value == true ? VoipTexts.conference_schedule_start.uppercased() : VoipTexts.conference_group_call_create.uppercased()
|
||||
self.createButton.title = ConferenceSchedulingViewModel.shared.scheduleForLater.value == true ? ConferenceSchedulingViewModel.shared.existingConfInfo.value != nil ? VoipTexts.conference_schedule_edit.uppercased() : VoipTexts.conference_schedule_start.uppercased() : VoipTexts.conference_group_call_create.uppercased()
|
||||
viaChatLabel.isHidden = later != true || ConferenceSchedulingViewModel.shared.sendInviteViaChat.value != true
|
||||
viaChatLabel.removeConstraints().matchParentSideBorders(insetedByDx: self.form_margin).alignUnder(view: schedulingStack,withMargin: (viaChatLabel.isHidden ? 0 : 1)*self.form_margin).done()
|
||||
if (viaChatLabel.isHidden) {
|
||||
viaChatLabel.height(0).done()
|
||||
}
|
||||
|
||||
self.createButton.addSidePadding()
|
||||
}
|
||||
|
||||
createButton.centerX().alignParentBottom(withMargin: 3*self.form_margin).alignUnder(view: participantsListTableView,withMargin: 3*self.form_margin).done()
|
||||
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.view.backgroundColor = VoipTheme.voipBackgroundBWColor.get()
|
||||
participantsLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
self.participantsListTableView.separatorColor = VoipTheme.separatorColor.get()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
datePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledDateTime
|
||||
datePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledDate
|
||||
timeZoneValue.setIndex(index: ConferenceSchedulingViewModel.shared.scheduledTimeZone.value!)
|
||||
durationValue.setIndex(index: ConferenceSchedulingViewModel.shared.scheduledDuration.value!)
|
||||
timePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledDateTime
|
||||
timePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledTime
|
||||
|
||||
descriptionInput.text = ConferenceSchedulingViewModel.shared.description.value
|
||||
descriptionLabel.removeConstraints().alignUnder(view: leftColumn,withMargin: form_margin).alignUnder(view: rightColumn,withMargin: form_margin).matchParentSideBorders().done()
|
||||
descriptionInput.removeConstraints().alignUnder(view: descriptionLabel,withMargin: form_margin).matchParentSideBorders().height(description_height).alignParentBottom(withMargin: form_margin*2).done()
|
||||
if (ConferenceSchedulingViewModel.shared.description.value == nil || ConferenceSchedulingViewModel.shared.description.value!.count == 0) {
|
||||
descriptionLabel.height(0).done()
|
||||
descriptionInput.height(0).done()
|
||||
}
|
||||
// Wrap form
|
||||
scheduleForm.removeConstraints().matchParentSideBorders().wrapContentY().done()
|
||||
|
||||
createButton.addSidePadding()
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
|
@ -233,6 +251,7 @@ import SVProgressHUD
|
|||
|
||||
func goBackParticipantsListSelection() {
|
||||
let view: ChatConversationCreateView = VIEW(ChatConversationCreateView.compositeViewDescription())
|
||||
view.unfragmentCompositeDescription()
|
||||
let addresses = ConferenceSchedulingViewModel.shared.selectedAddresses.value!.map { (address) in String(address.asStringUriOnly()) }
|
||||
view.tableController.contactsGroup = (addresses as NSArray).mutableCopy() as? NSMutableArray
|
||||
view.tableController.notFirstTime = true
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
import UIKit
|
||||
import Foundation
|
||||
import linphonesw
|
||||
import IQKeyboardManager
|
||||
|
||||
@objc class ConferenceSchedulingView: BackNextNavigationView, UICompositeViewDelegate {
|
||||
|
||||
|
|
@ -29,17 +30,19 @@ import linphonesw
|
|||
static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription }
|
||||
func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription }
|
||||
|
||||
let datePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledDateTime,pickerMode: .date)
|
||||
let datePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledDate,pickerMode: .date)
|
||||
let timeZoneValue = StyledValuePicker(liveIndex: ConferenceSchedulingViewModel.shared.scheduledTimeZone,options: ConferenceSchedulingViewModel.timeZones.map({ (tzd: TimeZoneData) -> String in tzd.descWithOffset()}))
|
||||
let durationValue = StyledValuePicker(liveIndex: ConferenceSchedulingViewModel.shared.scheduledDuration,options: ConferenceSchedulingViewModel.durationList.map({ (duration: Duration) -> String in duration.display}))
|
||||
let timePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledDateTime,pickerMode: .time)
|
||||
let timePicker = StyledDatePicker(liveValue: ConferenceSchedulingViewModel.shared.scheduledTime,pickerMode: .time)
|
||||
let descriptionInput = StyledTextView(VoipTheme.conference_scheduling_font, placeHolder:VoipTexts.conference_schedule_description_hint,liveValue: ConferenceSchedulingViewModel.shared.description)
|
||||
let subjectInput = StyledTextView(VoipTheme.conference_scheduling_font, placeHolder:VoipTexts.conference_schedule_subject_hint, liveValue: ConferenceSchedulingViewModel.shared.subject,maxLines:1)
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad(
|
||||
backAction: {
|
||||
ConferenceSchedulingViewModel.shared.reset()
|
||||
PhoneMainView.instance().popView(self.compositeViewDescription())
|
||||
},nextAction: {
|
||||
self.gotoParticipantsListSelection()
|
||||
|
|
@ -52,13 +55,11 @@ import linphonesw
|
|||
contentView.addSubview(subjectLabel)
|
||||
subjectLabel.alignParentLeft(withMargin: form_margin).alignParentTop().done()
|
||||
|
||||
let subjectInput = StyledTextView(VoipTheme.conference_scheduling_font, placeHolder:VoipTexts.conference_schedule_subject_hint, liveValue: ConferenceSchedulingViewModel.shared.subject,maxLines:1)
|
||||
contentView.addSubview(subjectInput)
|
||||
subjectInput.alignUnder(view: subjectLabel,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).height(form_input_height).done()
|
||||
|
||||
let schedulingStack = UIStackView()
|
||||
schedulingStack.axis = .vertical
|
||||
schedulingStack.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
contentView.addSubview(schedulingStack)
|
||||
schedulingStack.alignUnder(view: subjectInput,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).done()
|
||||
|
||||
|
|
@ -132,19 +133,25 @@ import linphonesw
|
|||
descriptionInput.textContainer.maximumNumberOfLines = 5
|
||||
descriptionInput.textContainer.lineBreakMode = .byWordWrapping
|
||||
scheduleForm.addSubview(descriptionInput)
|
||||
descriptionInput.alignUnder(view: descriptionLabel,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).height(description_height).alignParentBottom(withMargin: form_margin*2).done()
|
||||
|
||||
scheduleForm.wrapContentY().done()
|
||||
descriptionInput.alignUnder(view: descriptionLabel,withMargin: 2*form_margin).matchParentSideBorders(insetedByDx: form_margin).height(description_height).done()
|
||||
|
||||
// Sending methods
|
||||
let viaChatSwitch = StyledCheckBox(liveValue: ConferenceSchedulingViewModel.shared.sendInviteViaChat)
|
||||
contentView.addSubview(viaChatSwitch)
|
||||
viaChatSwitch.alignParentLeft(withMargin: form_margin).alignUnder(view: schedulingStack,withMargin: 2*form_margin).done()
|
||||
|
||||
let viaChatView = UIView()
|
||||
scheduleForm.addSubview(viaChatView)
|
||||
viaChatView.alignUnder(view: descriptionInput,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).alignParentBottom(withMargin: form_margin*4).done()
|
||||
|
||||
let viaChatSwitch = StyledCheckBox()
|
||||
viaChatSwitch.liveValue = ConferenceSchedulingViewModel.shared.sendInviteViaChat
|
||||
viaChatView.addSubview(viaChatSwitch)
|
||||
viaChatSwitch.alignParentLeft().done()
|
||||
|
||||
let viaChatLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_send_invite_chat)
|
||||
contentView.addSubview(viaChatLabel)
|
||||
viaChatLabel.toRightOf(viaChatSwitch,withLeftMargin: form_margin).alignUnder(view: schedulingStack,withMargin: 2*form_margin).alignHorizontalCenterWith(viaChatSwitch).done()
|
||||
viaChatView.addSubview(viaChatLabel)
|
||||
viaChatLabel.toRightOf(viaChatSwitch,withLeftMargin: form_margin).alignHorizontalCenterWith(viaChatSwitch).done()
|
||||
|
||||
viaChatView.wrapContentY().done()
|
||||
|
||||
/* Hidden as in Android 9.6.2022
|
||||
|
||||
let viaMailSwitch = StyledCheckBox(liveValue: ConferenceSchedulingViewModel.shared.sendInviteViaEmail)
|
||||
|
|
@ -183,34 +190,51 @@ import linphonesw
|
|||
let mandatoryLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_mandatory_field)
|
||||
mandatoryLabel.addIndicatorIcon(iconName: "voip_mandatory", trailing: false)
|
||||
contentView.addSubview(mandatoryLabel)
|
||||
mandatoryLabel.alignUnder(view: viaChatSwitch,withMargin: 2*form_margin).centerX().matchParentSideBorders().done()
|
||||
mandatoryLabel.textAlignment = .center
|
||||
|
||||
mandatoryLabel.alignParentBottom().done()
|
||||
let lastView = UIView()
|
||||
contentView.addSubview(lastView)
|
||||
lastView.alignUnder(view: mandatoryLabel).alignParentBottom().done()
|
||||
|
||||
// Schedule for later observer
|
||||
ConferenceSchedulingViewModel.shared.scheduleForLater.readCurrentAndObserve { (forLater) in
|
||||
self.subjectInput.setPlaceHolder(phText: forLater == true ? VoipTexts.conference_schedule_subject_hint : VoipTexts.conference_group_call_subject_hint)
|
||||
scheduleForm.isHidden = forLater != true
|
||||
super.titleLabel.text = forLater == true ? VoipTexts.conference_schedule_title : VoipTexts.conference_group_call_title
|
||||
viaChatSwitch.isHidden = forLater != true
|
||||
viaChatLabel.isHidden = forLater != true
|
||||
super.titleLabel.text = forLater == true ? ConferenceSchedulingViewModel.shared.existingConfInfo.value != nil ? VoipTexts.conference_schedule_edit : VoipTexts.conference_schedule_title : VoipTexts.conference_group_call_title
|
||||
mandatoryLabel.removeConstraints().done()
|
||||
mandatoryLabel.alignUnder(view: forLater == true ? scheduleForm : scheduleForLater,withMargin: 2*self.form_margin).centerX().matchParentSideBorders().done()
|
||||
}
|
||||
ConferenceSchedulingViewModel.shared.existingConfInfo.readCurrentAndObserve { (confInfo) in
|
||||
super.titleLabel.text = ConferenceSchedulingViewModel.shared.scheduleForLater.value == true ? ConferenceSchedulingViewModel.shared.existingConfInfo.value != nil ? VoipTexts.conference_schedule_edit : VoipTexts.conference_schedule_title : VoipTexts.conference_group_call_title
|
||||
}
|
||||
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.view.backgroundColor = VoipTheme.voipBackgroundBWColor.get()
|
||||
schedulingStack.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
datePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledDateTime
|
||||
datePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledDate
|
||||
timeZoneValue.setIndex(index: ConferenceSchedulingViewModel.shared.scheduledTimeZone.value!)
|
||||
durationValue.setIndex(index: ConferenceSchedulingViewModel.shared.scheduledDuration.value!)
|
||||
timePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledDateTime
|
||||
timePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledTime
|
||||
descriptionInput.text = ConferenceSchedulingViewModel.shared.description.value
|
||||
IQKeyboardManager.shared().isEnabled = true
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
IQKeyboardManager.shared().isEnabled = false
|
||||
super.viewWillDisappear(animated)
|
||||
}
|
||||
|
||||
|
||||
func gotoParticipantsListSelection() {
|
||||
let view: ChatConversationCreateView = self.VIEW(ChatConversationCreateView.compositeViewDescription());
|
||||
let view: ChatConversationCreateView = self.VIEW(ChatConversationCreateView.compositeViewDescription())
|
||||
view.unfragmentCompositeDescription()
|
||||
let addresses = ConferenceSchedulingViewModel.shared.selectedAddresses.value!.map { (address) in String(address.asStringUriOnly()) }
|
||||
view.tableController.contactsGroup = (addresses as NSArray).mutableCopy() as? NSMutableArray
|
||||
view.isForEditing = false
|
||||
|
|
|
|||
|
|
@ -22,16 +22,17 @@ import UIKit
|
|||
import linphonesw
|
||||
|
||||
|
||||
@objc class ConferenceWaitingRoomFragment: UIViewController, UICompositeViewDelegate { // Replaces CallView
|
||||
@objc class ConferenceWaitingRoomView: UIViewController, UICompositeViewDelegate { // Replaces CallView
|
||||
|
||||
// Layout constants
|
||||
let common_margin = 17.0
|
||||
let switch_camera_button_size = 50
|
||||
let switch_camera_button_size = 35
|
||||
let switch_camera_button_margins = 7.0
|
||||
let content_inset = 12.0
|
||||
let button_spacing = 15.0
|
||||
let center_view_corner_radius = 20.0
|
||||
let button_width = 150
|
||||
let layout_picker_inset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
|
||||
|
||||
|
||||
var audioRoutesView : AudioRoutesView? = nil
|
||||
|
|
@ -47,15 +48,19 @@ import linphonesw
|
|||
|
||||
var conferenceUrl : String? = nil
|
||||
let conferenceSubject = MutableLiveData<String>()
|
||||
|
||||
let controlsView = ControlsView(showVideo: true, controlsViewModel: ConferenceWaitingRoomViewModel.sharedModel)
|
||||
var layoutPicker : CallControlButton? = nil
|
||||
let layoutPickerView = ConferenceLayoutPickerView(orientation: UIDevice.current.orientation)
|
||||
|
||||
static let compositeDescription = UICompositeViewDescription(ConferenceWaitingRoomFragment.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: nil, fullscreen: false, isLeftFragment: false,fragmentWith: nil)
|
||||
|
||||
static let compositeDescription = UICompositeViewDescription(ConferenceWaitingRoomView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: SideMenuView.self, 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()
|
||||
|
||||
view.addSubview(subject)
|
||||
subject.centerX().alignParentTop(withMargin: common_margin).done()
|
||||
|
|
@ -64,16 +69,15 @@ import linphonesw
|
|||
}
|
||||
|
||||
// Controls
|
||||
let controlsView = ControlsView(showVideo: true, controlsViewModel: ConferenceWaitingRoomViewModel.sharedModel)
|
||||
view.addSubview(controlsView)
|
||||
controlsView.alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done()
|
||||
|
||||
// Layoout picker
|
||||
let layoutPicker = CallControlButton(imageInset : UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8),buttonTheme: VoipTheme.conf_waiting_room_layout_picker, onClickAction: {
|
||||
layoutPicker = CallControlButton(imageInset : layout_picker_inset,buttonTheme: VoipTheme.conf_waiting_room_layout_picker, onClickAction: {
|
||||
ConferenceWaitingRoomViewModel.sharedModel.showLayoutPicker.value = ConferenceWaitingRoomViewModel.sharedModel.showLayoutPicker.value != true
|
||||
})
|
||||
view.addSubview(layoutPicker)
|
||||
layoutPicker.alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).alignParentRight(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||
view.addSubview(layoutPicker!)
|
||||
layoutPicker!.alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).alignParentRight(withMargin:SharedLayoutConstants.buttons_bottom_margin).done()
|
||||
|
||||
ConferenceWaitingRoomViewModel.sharedModel.joinLayout.readCurrentAndObserve { layout in
|
||||
var icon = ""
|
||||
|
|
@ -85,18 +89,28 @@ import linphonesw
|
|||
ConferenceWaitingRoomViewModel.sharedModel.isVideoEnabled.value = false
|
||||
break
|
||||
}
|
||||
layoutPicker.applyTintedIcons(tintedIcons: [UIButton.State.normal.rawValue : TintableIcon(name: icon ,tintColor: LightDarkColor(.white,.white))])
|
||||
self.layoutPicker?.applyTintedIcons(tintedIcons: [UIButton.State.normal.rawValue : TintableIcon(name: icon ,tintColor: LightDarkColor(.white,.white))])
|
||||
}
|
||||
|
||||
ConferenceWaitingRoomViewModel.sharedModel.isVideoEnabled.observe { video in
|
||||
if (video == true && ConferenceWaitingRoomViewModel.sharedModel.joinLayout.value == .AudioOnly) {
|
||||
ConferenceWaitingRoomViewModel.sharedModel.joinLayout.value = .ActiveSpeaker
|
||||
}
|
||||
}
|
||||
|
||||
let layoutPickerView = ConferenceLayoutPickerView()
|
||||
view.addSubview(layoutPickerView)
|
||||
layoutPickerView.alignAbove(view:layoutPicker,withMargin:button_spacing).alignVerticalCenterWith(layoutPicker).done()
|
||||
|
||||
ConferenceWaitingRoomViewModel.sharedModel.showLayoutPicker.readCurrentAndObserve { show in
|
||||
layoutPicker.isSelected = show == true
|
||||
layoutPickerView.isHidden = show != true
|
||||
self.layoutPicker?.isSelected = show == true
|
||||
self.layoutPickerView.isHidden = show != true
|
||||
if (show == true) {
|
||||
self.view.bringSubviewToFront(layoutPickerView)
|
||||
self.view.bringSubviewToFront(self.layoutPickerView)
|
||||
}
|
||||
}
|
||||
|
||||
self.view.onClick{
|
||||
if (ConferenceWaitingRoomViewModel.sharedModel.showLayoutPicker.value == true) {
|
||||
ConferenceWaitingRoomViewModel.sharedModel.showLayoutPicker.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,16 +145,16 @@ import linphonesw
|
|||
self.start.isEnabled = joining != true
|
||||
//self.localVideo.isHidden = joining == true (UX question as video window goes black by the core, better black or hidden ?)
|
||||
self.noVideoLabel.isHidden = joining == true
|
||||
layoutPicker.isHidden = joining == true
|
||||
self.layoutPicker?.isHidden = joining == true
|
||||
if (joining == true) {
|
||||
self.view.addSubview(self.conferenceJoinSpinner)
|
||||
self.conferenceJoinSpinner.square(IncomingOutgoingCommonView.spinner_size).center().done()
|
||||
self.conferenceJoinSpinner.square(AbstractIncomingOutgoingCallView.spinner_size).center().done()
|
||||
self.conferenceJoinSpinner.startRotation()
|
||||
controlsView.isHidden = true
|
||||
self.controlsView.isHidden = true
|
||||
} else {
|
||||
self.conferenceJoinSpinner.stopRotation()
|
||||
self.conferenceJoinSpinner.removeFromSuperview()
|
||||
controlsView.isHidden = false
|
||||
self.controlsView.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,9 +165,7 @@ import linphonesw
|
|||
localVideo.contentMode = .scaleAspectFill
|
||||
localVideo.backgroundColor = .black
|
||||
self.view.addSubview(localVideo)
|
||||
localVideo.matchParentSideBorders(insetedByDx: content_inset).alignAbove(view:buttonsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).alignUnder(view: subject,withMargin: common_margin).done()
|
||||
localVideo.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().videoPreviewEnabled = false
|
||||
|
|
@ -182,7 +194,41 @@ import linphonesw
|
|||
}
|
||||
audioRoutesView!.alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done()
|
||||
|
||||
|
||||
|
||||
layoutRotatableElements()
|
||||
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.view.backgroundColor = VoipTheme.voipBackgroundColor.get()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func layoutRotatableElements() {
|
||||
layoutPickerView.removeConstraints().done()
|
||||
localVideo.removeConstraints().done()
|
||||
switchCamera.removeConstraints().done()
|
||||
if ([.landscapeLeft, .landscapeRight].contains( UIDevice.current.orientation)) {
|
||||
layoutPickerView.alignAbove(view:layoutPicker!,withMargin:button_spacing).alignVerticalCenterWith(layoutPicker!).done()
|
||||
localVideo.matchParentSideBorders().alignParentBottom().alignParentTop().done()
|
||||
localVideo.layer.cornerRadius = 0
|
||||
switchCamera.alignParentTop(withMargin: switch_camera_button_margins).alignParentRight(withMargin: switch_camera_button_margins + (UIDevice.hasNotch() && UIDevice.current.orientation == .landscapeRight ? 30.0 : 0.0)).square(switch_camera_button_size).done()
|
||||
} else {
|
||||
layoutPickerView.alignAbove(view:layoutPicker!,withMargin:button_spacing).alignVerticalCenterWith(layoutPicker!).done()
|
||||
localVideo.matchParentSideBorders(insetedByDx: content_inset).alignAbove(view:buttonsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).alignUnder(view: subject,withMargin: common_margin).done()
|
||||
localVideo.layer.cornerRadius = center_view_corner_radius
|
||||
switchCamera.alignParentTop(withMargin: switch_camera_button_margins).alignParentRight(withMargin: switch_camera_button_margins).square(switch_camera_button_size).done()
|
||||
}
|
||||
view.sendSubviewToBack(localVideo)
|
||||
}
|
||||
|
||||
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
|
||||
super.didRotate(from: fromInterfaceOrientation)
|
||||
self.layoutRotatableElements()
|
||||
Core.get().videoPreviewEnabled = ConferenceWaitingRoomViewModel.sharedModel.isVideoEnabled.value == true
|
||||
}
|
||||
|
||||
override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
|
||||
Core.get().videoPreviewEnabled = false
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
|
@ -20,19 +20,25 @@
|
|||
import UIKit
|
||||
import Foundation
|
||||
import linphonesw
|
||||
import EventKit
|
||||
import EventKitUI
|
||||
|
||||
@objc class ICSBubbleView: UIView {
|
||||
@objc class ICSBubbleView: UIView, EKEventEditViewDelegate {
|
||||
|
||||
|
||||
let corner_radius = 7.0
|
||||
let border_width = 2.0
|
||||
let rows_spacing = 6.0
|
||||
let inner_padding = 8.0
|
||||
let forward_reply_title_height = 10.0
|
||||
let indicator_y = 3.0
|
||||
let share_size = 25
|
||||
let join_share_width = 150.0
|
||||
|
||||
|
||||
|
||||
let inviteTitle = StyledLabel(VoipTheme.conference_invite_title_font, VoipTexts.conference_invite_title)
|
||||
let inviteCancelled = StyledLabel(VoipTheme.conference_cancelled_title_font, VoipTexts.conference_cancel_title)
|
||||
let inviteUpdated = StyledLabel(VoipTheme.conference_updated_title_font, VoipTexts.conference_update_title)
|
||||
|
||||
let subject = StyledLabel(VoipTheme.conference_invite_subject_font)
|
||||
let participants = StyledLabel(VoipTheme.conference_invite_desc_font)
|
||||
let date = StyledLabel(VoipTheme.conference_invite_desc_font)
|
||||
|
|
@ -42,40 +48,46 @@ import linphonesw
|
|||
let joinShare = UIStackView()
|
||||
let join = FormButton(title:VoipTexts.conference_invite_join.uppercased(), backgroundStateColors: VoipTheme.button_green_background)
|
||||
let share = UIImageView(image:UIImage(named:"voip_export")?.tinted(with: VoipTheme.primaryTextColor.get()))
|
||||
|
||||
var icsFile : String? = nil
|
||||
|
||||
|
||||
var conferenceData: ScheduledConferenceData? = nil {
|
||||
didSet {
|
||||
if let data = conferenceData {
|
||||
subject.text = data.subject.value
|
||||
participants.text = VoipTexts.conference_invite_participants_count.replacingOccurrences(of: "%d", with: String(data.conferenceInfo.participants.count+1))
|
||||
participants.addIndicatorIcon(iconName: "conference_schedule_participants_default",padding : 0.0, y: -indicator_y, trailing: false)
|
||||
date.text = " "+TimestampUtils.dateToString(date: data.rawDate)
|
||||
date.text = TimestampUtils.dateToString(date: data.rawDate)
|
||||
date.addIndicatorIcon(iconName: "conference_schedule_calendar_default", padding: 0.0, y:-indicator_y, trailing:false)
|
||||
timeDuration.text = " \(data.time.value) ( \(data.duration.value) )"
|
||||
timeDuration.text = "\(data.time.value)" + (data.duration.value != nil ? " ( \(data.duration.value) )" : "")
|
||||
timeDuration.addIndicatorIcon(iconName: "conference_schedule_time_default",padding : 0.0, y: -indicator_y, trailing: false)
|
||||
descriptionTitle.isHidden = data.description.value == nil || data.description.value!.count == 0
|
||||
descriptionValue.isHidden = descriptionTitle.isHidden
|
||||
descriptionValue.text = data.description.value
|
||||
inviteTitle.isHidden = [.Cancelled,.Updated].contains(data.conferenceInfo.state)
|
||||
inviteCancelled.isHidden = data.conferenceInfo.state != .Cancelled
|
||||
inviteUpdated.isHidden = data.conferenceInfo.state != .Updated
|
||||
join.isEnabled = data.isConferenceCancelled.value != true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
super.init(frame:.zero)
|
||||
|
||||
layer.cornerRadius = corner_radius
|
||||
clipsToBounds = true
|
||||
backgroundColor = VoipTheme.voip_light_gray
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.backgroundColor = VoipTheme.chatBubbleBGColor.get()
|
||||
}
|
||||
|
||||
let rows = UIStackView()
|
||||
rows.axis = .vertical
|
||||
rows.spacing = rows_spacing
|
||||
|
||||
|
||||
addSubview(rows)
|
||||
|
||||
rows.addArrangedSubview(inviteTitle)
|
||||
rows.addArrangedSubview(inviteCancelled)
|
||||
rows.addArrangedSubview(inviteUpdated)
|
||||
rows.addArrangedSubview(subject)
|
||||
rows.addArrangedSubview(participants)
|
||||
rows.addArrangedSubview(date)
|
||||
|
|
@ -83,6 +95,8 @@ import linphonesw
|
|||
rows.addArrangedSubview(descriptionTitle)
|
||||
rows.addArrangedSubview(descriptionValue)
|
||||
|
||||
descriptionValue.numberOfLines = 5
|
||||
|
||||
|
||||
addSubview(joinShare)
|
||||
joinShare.axis = .horizontal
|
||||
|
|
@ -92,19 +106,48 @@ import linphonesw
|
|||
joinShare.addArrangedSubview(join)
|
||||
rows.matchParentSideBorders(insetedByDx: inner_padding).alignParentTop(withMargin: inner_padding).done()
|
||||
joinShare.alignParentBottom(withMargin: inner_padding).width(join_share_width).alignParentRight(withMargin: inner_padding).done()
|
||||
|
||||
|
||||
join.onClick {
|
||||
let view : ConferenceWaitingRoomFragment = self.VIEW(ConferenceWaitingRoomFragment.compositeViewDescription())
|
||||
let view : ConferenceWaitingRoomView = self.VIEW(ConferenceWaitingRoomView.compositeViewDescription())
|
||||
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
||||
view.setDetails(subject: (self.conferenceData?.subject.value)!, url: (self.conferenceData?.address.value)!)
|
||||
}
|
||||
|
||||
share.onClick {
|
||||
let ics = URL(string: "file://"+self.icsFile!)
|
||||
UIApplication.shared.open(ics!)
|
||||
let eventStore = EKEventStore()
|
||||
eventStore.requestAccess( to: EKEntityType.event, completion:{(granted, error) in
|
||||
DispatchQueue.main.async {
|
||||
if (granted) && (error == nil) {
|
||||
let event = EKEvent(eventStore: eventStore)
|
||||
event.title = self.conferenceData?.subject.value
|
||||
event.startDate = self.conferenceData?.rawDate
|
||||
if let duration = self.conferenceData?.conferenceInfo.duration, duration > 0 {
|
||||
event.endDate = event.startDate.addingTimeInterval(TimeInterval(duration*60))
|
||||
} else {
|
||||
event.endDate = event.startDate.addingTimeInterval(TimeInterval(3600))
|
||||
}
|
||||
event.calendar = eventStore.defaultCalendarForNewEvents
|
||||
if let description = self.conferenceData?.description.value, description.count > 0 {
|
||||
event.notes = description + "\n\n"
|
||||
}
|
||||
event.notes = (event.notes != nil ? event.notes! : "") + "\(VoipTexts.call_action_participants_list):\n\(self.conferenceData?.participantsExpanded.value)"
|
||||
if let urlString = self.conferenceData?.conferenceInfo.uri?.asStringUriOnly() {
|
||||
event.url = URL(string:urlString)
|
||||
}
|
||||
let addController = EKEventEditViewController()
|
||||
addController.event = event
|
||||
addController.eventStore = eventStore
|
||||
PhoneMainView.instance().present(addController, animated: false)
|
||||
addController.editViewDelegate = self;
|
||||
} else {
|
||||
VoipDialog.toast(message: VoipTexts.conference_unable_to_share_via_calendar)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
|
@ -115,7 +158,6 @@ import linphonesw
|
|||
if (content.isIcalendar) {
|
||||
if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: content) {
|
||||
self.conferenceData = ScheduledConferenceData(conferenceInfo: conferenceInfo)
|
||||
self.icsFile = content.filePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +174,76 @@ import linphonesw
|
|||
}
|
||||
|
||||
@objc func setLayoutConstraints(view:UIView) {
|
||||
matchDimensionsWith(view: view, insetedByDx: inner_padding).done()
|
||||
matchBordersWith(view: view, insetedByDx: inner_padding).done()
|
||||
}
|
||||
|
||||
@objc func updateTopLayoutConstraints(view:UIView, replyOrForward: Bool) {
|
||||
updateTopBorderWith(view: view, inset: inner_padding + (replyOrForward ? forward_reply_title_height : 0.0)).done()
|
||||
}
|
||||
|
||||
func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
|
||||
controller.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc static func getSubjectFromContent(cmessage: OpaquePointer) -> String {
|
||||
let message = ChatMessage.getSwiftObject(cObject: cmessage)
|
||||
var subject = ""
|
||||
message.contents.forEach { content in
|
||||
if (content.isIcalendar) {
|
||||
if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: content) {
|
||||
subject = conferenceInfo.subject
|
||||
}
|
||||
}
|
||||
}
|
||||
return subject
|
||||
}
|
||||
|
||||
@objc static func getConferenceInfo(cmessage: OpaquePointer) -> OpaquePointer? {
|
||||
let message = ChatMessage.getSwiftObject(cObject: cmessage)
|
||||
var result : OpaquePointer? = nil
|
||||
message.contents.forEach { content in
|
||||
if (content.isIcalendar) {
|
||||
if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: content) {
|
||||
result = conferenceInfo.getCobject
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@objc static func getConferenceSummary(cmessage: OpaquePointer) -> String? {
|
||||
let message = ChatMessage.getSwiftObject(cObject: cmessage)
|
||||
var subject:String? = nil
|
||||
message.contents.forEach { content in
|
||||
if (content.isIcalendar) {
|
||||
if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: content) {
|
||||
subject = conferenceInfo.state == .New ? VoipTexts.conference_invite_title + conferenceInfo.subject :
|
||||
conferenceInfo.state == .Updated ? VoipTexts.conference_update_title + conferenceInfo.subject :
|
||||
VoipTexts.conference_cancel_title + conferenceInfo.subject
|
||||
}
|
||||
}
|
||||
}
|
||||
return subject
|
||||
}
|
||||
|
||||
|
||||
@objc static func getDescriptionHeightFromContent(cmessage: OpaquePointer) -> CGFloat {
|
||||
let message = ChatMessage.getSwiftObject(cObject: cmessage)
|
||||
var height = 0.0
|
||||
message.contents.forEach { content in
|
||||
if (content.isIcalendar) {
|
||||
if let conferenceInfo = try? Factory.Instance.createConferenceInfoFromIcalendarContent(content: content) {
|
||||
let description = NSString(string: conferenceInfo.description)
|
||||
if (description.length > 0) {
|
||||
let dummyTitle = StyledLabel(VoipTheme.conference_invite_desc_title_font, VoipTexts.conference_description_title)
|
||||
let dummyLabel = StyledLabel(VoipTheme.conference_invite_desc_font)
|
||||
let rect = CGSize(width: CGFloat(CONFERENCE_INVITATION_WIDTH-80), height: CGFloat.greatestFiniteMagnitude)
|
||||
height = dummyTitle.intrinsicContentSize.height + description.boundingRect(with: rect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: dummyLabel.font!], context: nil).height
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return height
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,18 +27,20 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
let corner_radius = 7.0
|
||||
let border_width = 2.0
|
||||
static let button_size = 40
|
||||
let delete_checkbox_margin = 5
|
||||
|
||||
let clockIcon = UIImageView(image: UIImage(named: "conference_schedule_time_default"))
|
||||
let clockIcon = UIImageView()
|
||||
let timeDuration = StyledLabel(VoipTheme.conference_invite_desc_font)
|
||||
let organiser = StyledLabel(VoipTheme.conference_invite_desc_font)
|
||||
let subject = StyledLabel(VoipTheme.conference_invite_subject_font)
|
||||
let participantsIcon = UIImageView(image: UIImage(named: "conference_schedule_participants_default"))
|
||||
let subject = StyledLabel(VoipTheme.conference_list_subject_font)
|
||||
let cancelledLabel = StyledLabel(VoipTheme.conference_cancelled_title_font)
|
||||
let participantsIcon = UIImageView()
|
||||
let participants = StyledLabel(VoipTheme.conference_invite_desc_font)
|
||||
let infoConf = UIButton()
|
||||
|
||||
let descriptionTitle = StyledLabel(VoipTheme.conference_invite_desc_font, VoipTexts.conference_description_title)
|
||||
let descriptionValue = StyledLabel(VoipTheme.conference_invite_desc_font)
|
||||
let urlTitle = StyledLabel(VoipTheme.conference_invite_desc_font, VoipTexts.conference_schedule_address_title)
|
||||
let descriptionTitle = StyledLabel(VoipTheme.conference_list_address_desc_font, VoipTexts.conference_description_title)
|
||||
let descriptionValue = StyledLabel(VoipTheme.conference_list_address_desc_font)
|
||||
let urlTitle = StyledLabel(VoipTheme.conference_list_address_desc_font, VoipTexts.conference_schedule_address_title)
|
||||
let urlValue = StyledLabel(VoipTheme.conference_scheduling_font)
|
||||
let copyLink = CallControlButton(width:button_size,height:button_size,buttonTheme: VoipTheme.scheduled_conference_action("voip_copy"))
|
||||
let joinConf = FormButton(title:VoipTexts.conference_invite_join.uppercased(), backgroundStateColors: VoipTheme.button_green_background)
|
||||
|
|
@ -47,17 +49,29 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
var owningTableView : UITableView? = nil
|
||||
let joinEditDelete = UIStackView()
|
||||
let expandedRows = UIStackView()
|
||||
let selectionCheckBox = StyledCheckBox()
|
||||
let myContentView = UIView()
|
||||
|
||||
var conferenceData: ScheduledConferenceData? = nil {
|
||||
didSet {
|
||||
if let data = conferenceData {
|
||||
timeDuration.text = "\(data.time.value)"+(data.duration.value != nil ? " ( \(data.duration.value) )" : "")
|
||||
timeDuration.text = "\(data.time.value)"+(data.duration.value != nil ? " (\(data.duration.value))" : "")
|
||||
organiser.text = VoipTexts.conference_schedule_organizer+data.organizer.value!
|
||||
subject.text = data.subject.value!
|
||||
cancelledLabel.text = data.isConferenceCancelled.value == true ? ( data.canEdit.value == true ? VoipTexts.conference_scheduled_cancelled_by_me: VoipTexts.conference_scheduled_cancelled_by_organizer) : nil
|
||||
cancelledLabel.isHidden = data.isConferenceCancelled.value != true
|
||||
descriptionValue.text = data.description.value!
|
||||
urlValue.text = data.address.value!
|
||||
self.joinConf.isHidden = data.isConferenceCancelled.value == true
|
||||
self.editConf.isHidden = data.canEdit.value != true || data.isConferenceCancelled.value == true
|
||||
self.urlTitle.isHidden = data.isConferenceCancelled.value == true
|
||||
self.urlValue.isHidden = data.isConferenceCancelled.value == true
|
||||
self.copyLink.isHidden = data.isConferenceCancelled.value == true
|
||||
data.expanded.readCurrentAndObserve { expanded in
|
||||
self.contentView.layer.borderWidth = expanded == true ? 2.0 : 0.0
|
||||
self.myContentView.backgroundColor =
|
||||
data.conferenceInfo.state == .Cancelled ? VoipTheme.voip_conference_cancelled_bg_color :
|
||||
data.isFinished ? VoipTheme.backgroundColor3.get() : VoipTheme.backgroundColor4.get()
|
||||
self.myContentView.layer.borderWidth = expanded == true ? 2.0 : 0.0
|
||||
self.descriptionTitle.isHidden = expanded != true || self.descriptionValue.text?.count == 0
|
||||
self.descriptionValue.isHidden = expanded != true || self.descriptionValue.text?.count == 0
|
||||
self.infoConf.isSelected = expanded == true
|
||||
|
|
@ -66,18 +80,18 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
self.expandedRows.isHidden = expanded != true
|
||||
self.joinEditDelete.isHidden = expanded != true
|
||||
if let myAddress = Core.get().defaultAccount?.params?.identityAddress {
|
||||
self.editConf.isHidden = expanded != true || data.conferenceInfo.organizer?.weakEqual(address2: myAddress) != true
|
||||
self.editConf.isHidden = expanded != true || data.conferenceInfo.organizer?.weakEqual(address2: myAddress) != true || data.conferenceInfo.state == .Cancelled
|
||||
} else {
|
||||
self.editConf.isHidden = true
|
||||
}
|
||||
self.participants.removeConstraints().alignUnder(view: self.subject,withMargin: 15).toRightOf(self.participantsIcon,withLeftMargin:10).toRightOf(self.participantsIcon,withLeftMargin:10).toLeftOf(self.infoConf,withRightMargin: 15).done()
|
||||
self.joinEditDelete.removeConstraints().alignUnder(view: self.expandedRows,withMargin: 15).alignParentRight(withMargin: 10).done()
|
||||
self.participants.removeConstraints().alignUnder(view: self.subject,withMargin: 10).toRightOf(self.participantsIcon,withLeftMargin:10).toRightOf(self.participantsIcon,withLeftMargin:10).toLeftOf(self.infoConf,withRightMargin: 15).done()
|
||||
self.joinEditDelete.removeConstraints().alignUnder(view: self.expandedRows,withMargin: 10).alignParentRight(withMargin: 10).done()
|
||||
if (expanded == true) {
|
||||
self.joinEditDelete.alignParentBottom(withMargin: 10).done()
|
||||
} else {
|
||||
self.participants.alignParentBottom(withMargin: 10).done()
|
||||
}
|
||||
|
||||
self.selectionCheckBox.liveValue = data.selectedForDeletion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -86,46 +100,55 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
|
||||
contentView.layer.cornerRadius = corner_radius
|
||||
contentView.clipsToBounds = true
|
||||
contentView.backgroundColor = VoipTheme.header_background_color
|
||||
contentView.layer.borderColor = VoipTheme.primary_color.cgColor
|
||||
contentView.addSubview(myContentView)
|
||||
contentView.backgroundColor = .clear
|
||||
backgroundColor = .clear
|
||||
myContentView.layer.cornerRadius = corner_radius
|
||||
myContentView.clipsToBounds = true
|
||||
myContentView.backgroundColor = VoipTheme.header_background_color
|
||||
myContentView.layer.borderColor = VoipTheme.primary_color.cgColor
|
||||
myContentView.matchParentDimmensions(insetedBy: UIEdgeInsets(top: 5,left: 0,bottom: 5,right: 0)).done()
|
||||
|
||||
myContentView.addSubview(clockIcon)
|
||||
clockIcon.alignParentTop(withMargin: 10).square(20).alignParentLeft(withMargin: 10).done()
|
||||
|
||||
myContentView.addSubview(timeDuration)
|
||||
timeDuration.alignParentTop(withMargin: 10).toRightOf(clockIcon,withLeftMargin:10).alignHorizontalCenterWith(clockIcon).done()
|
||||
|
||||
myContentView.addSubview(organiser)
|
||||
organiser.alignParentTop(withMargin: 10).toRightOf(timeDuration, withLeftMargin:10).alignParentRight(withMargin:10).alignHorizontalCenterWith(clockIcon).done()
|
||||
|
||||
|
||||
contentView.addSubview(clockIcon)
|
||||
clockIcon.alignParentTop(withMargin: 15).square(15).alignParentLeft(withMargin: 10).done()
|
||||
|
||||
contentView.addSubview(timeDuration)
|
||||
timeDuration.alignParentTop(withMargin: 15).toRightOf(clockIcon,withLeftMargin:10).alignHorizontalCenterWith(clockIcon).done()
|
||||
let subjectCancel = UIStackView()
|
||||
subjectCancel.axis = .vertical
|
||||
myContentView.addSubview(subjectCancel)
|
||||
subjectCancel.alignUnder(view: timeDuration,withMargin: 10).matchParentSideBorders(insetedByDx: 10.0).done()
|
||||
|
||||
contentView.addSubview(organiser)
|
||||
organiser.alignParentTop(withMargin: 15).toRightOf(timeDuration, withLeftMargin:10).alignParentRight(withMargin:10).alignHorizontalCenterWith(clockIcon).done()
|
||||
subjectCancel.addArrangedSubview(cancelledLabel)
|
||||
subjectCancel.addArrangedSubview(subject)
|
||||
|
||||
contentView.addSubview(subject)
|
||||
subject.alignUnder(view: timeDuration,withMargin: 15).alignParentLeft(withMargin: 10).done()
|
||||
|
||||
contentView.addSubview(participantsIcon)
|
||||
participantsIcon.alignUnder(view: subject,withMargin: 15).square(15).alignParentLeft(withMargin: 10).done()
|
||||
myContentView.addSubview(participantsIcon)
|
||||
participantsIcon.alignUnder(view: subject,withMargin: 5).square(25).alignParentLeft(withMargin: 10).done()
|
||||
|
||||
//infoConf.onClick {
|
||||
contentView.onClick {
|
||||
self.conferenceData?.toggleExpand()
|
||||
self.owningTableView?.reloadData()
|
||||
}
|
||||
contentView.addSubview(infoConf)
|
||||
myContentView.addSubview(infoConf)
|
||||
infoConf.imageView?.contentMode = .scaleAspectFit
|
||||
infoConf.alignUnder(view: subject,withMargin: 15).square(30).alignParentRight(withMargin: 10).alignHorizontalCenterWith(participantsIcon).done()
|
||||
infoConf.alignUnder(view: subject,withMargin: 5).square(25).alignParentRight(withMargin: 10).done()
|
||||
infoConf.applyTintedIcons(tintedIcons: VoipTheme.conference_info_button)
|
||||
|
||||
|
||||
contentView.addSubview(participants)
|
||||
participants.alignUnder(view: subject,withMargin: 15).toRightOf(participantsIcon,withLeftMargin:10).toRightOf(participantsIcon,withLeftMargin:10).toLeftOf(infoConf,withRightMargin: 15).done()
|
||||
|
||||
|
||||
myContentView.addSubview(participants)
|
||||
participants.alignUnder(view: subject,withMargin: 10).toRightOf(participantsIcon,withLeftMargin:10).toRightOf(participantsIcon,withLeftMargin:10).toLeftOf(infoConf,withRightMargin: 15).done()
|
||||
|
||||
expandedRows.axis = .vertical
|
||||
expandedRows.spacing = 10
|
||||
contentView.addSubview(expandedRows)
|
||||
myContentView.addSubview(expandedRows)
|
||||
expandedRows.alignUnder(view: participants,withMargin: 15).matchParentSideBorders(insetedByDx:10).done()
|
||||
|
||||
|
||||
expandedRows.addArrangedSubview(descriptionTitle)
|
||||
expandedRows.addArrangedSubview(descriptionValue)
|
||||
|
||||
|
|
@ -146,15 +169,15 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
joinEditDelete.axis = .horizontal
|
||||
joinEditDelete.spacing = 10
|
||||
joinEditDelete.distribution = .equalSpacing
|
||||
|
||||
contentView.addSubview(joinEditDelete)
|
||||
joinEditDelete.alignUnder(view: expandedRows,withMargin: 15).alignParentRight(withMargin: 10).done()
|
||||
|
||||
|
||||
myContentView.addSubview(joinEditDelete)
|
||||
joinEditDelete.alignUnder(view: expandedRows,withMargin: 10).alignParentRight(withMargin: 10).done()
|
||||
|
||||
|
||||
joinEditDelete.addArrangedSubview(joinConf)
|
||||
joinConf.width(150).done()
|
||||
joinConf.onClick {
|
||||
let view : ConferenceWaitingRoomFragment = self.VIEW(ConferenceWaitingRoomFragment.compositeViewDescription())
|
||||
let view : ConferenceWaitingRoomView = self.VIEW(ConferenceWaitingRoomView.compositeViewDescription())
|
||||
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
||||
view.setDetails(subject: (self.conferenceData?.subject.value)!, url: (self.conferenceData?.address.value)!)
|
||||
}
|
||||
|
|
@ -166,9 +189,10 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
VoipDialog.toast(message: VoipTexts.conference_edit_error)
|
||||
return
|
||||
}
|
||||
let infoDate = Date(timeIntervalSince1970: Double(confData.conferenceInfo.dateTime))
|
||||
ConferenceSchedulingViewModel.shared.reset()
|
||||
ConferenceSchedulingViewModel.shared.scheduledDateTime.value = infoDate
|
||||
let seconds = confData.conferenceInfo.dateTime % 86400
|
||||
ConferenceSchedulingViewModel.shared.scheduledDate.value = Date(timeIntervalSince1970:TimeInterval(confData.conferenceInfo.dateTime - seconds))
|
||||
ConferenceSchedulingViewModel.shared.scheduledTime.value = Date(timeIntervalSince1970:TimeInterval(seconds))
|
||||
ConferenceSchedulingViewModel.shared.description.value = confData.description.value
|
||||
ConferenceSchedulingViewModel.shared.subject.value = confData.subject.value
|
||||
ConferenceSchedulingViewModel.shared.scheduledDuration.value = ConferenceSchedulingViewModel.durationList.firstIndex(where: {$0.value == confData.conferenceInfo.duration})
|
||||
|
|
@ -177,7 +201,7 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
confData.conferenceInfo.participants.forEach {
|
||||
ConferenceSchedulingViewModel.shared.selectedAddresses.value?.append($0)
|
||||
}
|
||||
ConferenceSchedulingViewModel.shared.existingConfInfo = confData.conferenceInfo
|
||||
ConferenceSchedulingViewModel.shared.existingConfInfo.value = confData.conferenceInfo
|
||||
// TOODO TimeZone (as Android 14.6.2022) ConferenceSchedulingViewModel.shared.scheduledTimeZone.value = self.conferenceData?.timezone
|
||||
let view : ConferenceSchedulingView = self.VIEW(ConferenceSchedulingView.compositeViewDescription())
|
||||
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
||||
|
|
@ -185,16 +209,35 @@ class ScheduledConferencesCell: UITableViewCell {
|
|||
|
||||
joinEditDelete.addArrangedSubview(deleteConf)
|
||||
deleteConf.onClick {
|
||||
let delete = ButtonAttributes(text:VoipTexts.conference_info_confirm_removal_delete, action: {
|
||||
Core.get().deleteConferenceInformation(conferenceInfo: self.conferenceData!.conferenceInfo)
|
||||
ScheduledConferencesViewModel.shared.computeConferenceInfoList()
|
||||
self.owningTableView?.reloadData()
|
||||
VoipDialog.toast(message: VoipTexts.conference_info_removed)
|
||||
}, isDestructive:false)
|
||||
let cancel = ButtonAttributes(text:VoipTexts.cancel, action: {}, isDestructive:true)
|
||||
VoipDialog(message:VoipTexts.conference_info_confirm_removal, givenButtons: [cancel,delete]).show()
|
||||
self.askConfirmationTodeleteEntry()
|
||||
}
|
||||
|
||||
myContentView.addSubview(selectionCheckBox)
|
||||
selectionCheckBox.alignParentRight(withMargin: delete_checkbox_margin).alignUnder(view:organiser, withMargin: delete_checkbox_margin).done()
|
||||
ScheduledConferencesViewModel.shared.editionEnabled.readCurrentAndObserve { editing in
|
||||
self.selectionCheckBox.isHidden = editing != true
|
||||
}
|
||||
onLongClick {
|
||||
ScheduledConferencesViewModel.shared.editionEnabled.value = true
|
||||
}
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.clockIcon.image = UIImage(named: "conference_schedule_time_default")?.tinted(with: VoipTheme.voipDrawableColor.get())
|
||||
self.participantsIcon.image = UIImage(named: "conference_schedule_participants_default")?.tinted(with: VoipTheme.voipDrawableColor.get())
|
||||
}
|
||||
}
|
||||
|
||||
func askConfirmationTodeleteEntry() {
|
||||
let delete = ButtonAttributes(text:VoipTexts.conference_info_confirm_removal_delete, action: {
|
||||
self.deleteEntry()
|
||||
VoipDialog.toast(message: VoipTexts.conference_info_removed)
|
||||
}, isDestructive:false)
|
||||
let cancel = ButtonAttributes(text:VoipTexts.cancel, action: {}, isDestructive:true)
|
||||
VoipDialog(message:VoipTexts.conference_info_confirm_removal, givenButtons: [cancel,delete]).show()
|
||||
}
|
||||
|
||||
func deleteEntry() {
|
||||
self.conferenceData?.deleteConference()
|
||||
ScheduledConferencesViewModel.shared.computeConferenceInfoList()
|
||||
self.owningTableView?.reloadData()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
|
|
|
|||
|
|
@ -23,9 +23,12 @@ import Foundation
|
|||
import linphonesw
|
||||
|
||||
@objc class ScheduledConferencesView: BackNextNavigationView, UICompositeViewDelegate, UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
|
||||
let conferenceListView = UITableView()
|
||||
let noConference = StyledLabel(VoipTheme.empty_list_font,VoipTexts.conference_no_schedule)
|
||||
let filters = UIStackView()
|
||||
let selectAllButton = CallControlButton(buttonTheme:VoipTheme.nav_button("deselect_all"))
|
||||
let separator = UIView()
|
||||
|
||||
static let compositeDescription = UICompositeViewDescription(ScheduledConferencesView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: SideMenuView.self, fullscreen: false, isLeftFragment: false,fragmentWith: nil)
|
||||
static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription }
|
||||
|
|
@ -35,17 +38,63 @@ import linphonesw
|
|||
|
||||
super.viewDidLoad(
|
||||
backAction: {
|
||||
PhoneMainView.instance().popView(self.compositeViewDescription())
|
||||
if (ScheduledConferencesViewModel.shared.editionEnabled.value == true) {
|
||||
ScheduledConferencesViewModel.shared.editionEnabled.value = false
|
||||
} else {
|
||||
PhoneMainView.instance().popView(self.compositeViewDescription())
|
||||
}
|
||||
},nextAction: {
|
||||
ConferenceSchedulingViewModel.shared.reset()
|
||||
PhoneMainView.instance().changeCurrentView(ConferenceSchedulingView.compositeDescription)
|
||||
if (ScheduledConferencesViewModel.shared.editionEnabled.value == true) {
|
||||
self.deleteSelection()
|
||||
} else {
|
||||
ConferenceSchedulingViewModel.shared.reset()
|
||||
PhoneMainView.instance().changeCurrentView(ConferenceSchedulingView.compositeDescription)
|
||||
}
|
||||
},
|
||||
nextActionEnableCondition: MutableLiveData(),
|
||||
title:VoipTexts.conference_scheduled)
|
||||
super.titleLabel.applyStyle(VoipTheme.navigation_header_font)
|
||||
|
||||
// Select all
|
||||
selectAllButton.setImage(UIImage(named: "deselect_all"), for: .selected)
|
||||
selectAllButton.setImage(UIImage(named: "select_all_default"), for: .normal)
|
||||
topBar.addSubview(selectAllButton)
|
||||
selectAllButton.toLeftOf(nextButton,withRightMargin: CGFloat(side_buttons_margin)).matchParentHeight().done()
|
||||
|
||||
// Filter buttons
|
||||
let showTerminated = getFilterButton(title: VoipTexts.conference_scheduled_terminated_filter)
|
||||
showTerminated.onClick {
|
||||
ScheduledConferencesViewModel.shared.showTerminated.value = true
|
||||
}
|
||||
filters.addArrangedSubview(showTerminated)
|
||||
|
||||
let showScheduled = getFilterButton(title: VoipTexts.conference_scheduled_future_filter)
|
||||
showScheduled.onClick {
|
||||
ScheduledConferencesViewModel.shared.showTerminated.value = false
|
||||
|
||||
}
|
||||
filters.addArrangedSubview(showScheduled)
|
||||
|
||||
ScheduledConferencesViewModel.shared.showTerminated.readCurrentAndObserve { it in
|
||||
showTerminated.isSelected = it == true
|
||||
showScheduled.isSelected = it != true
|
||||
self.noConference.text = it != true ? VoipTexts.conference_no_schedule : VoipTexts.conference_no_terminated_schedule
|
||||
ScheduledConferencesViewModel.shared.computeConferenceInfoList()
|
||||
self.conferenceListView.reloadData()
|
||||
self.noConference.isHidden = !ScheduledConferencesViewModel.shared.daySplitted.isEmpty
|
||||
}
|
||||
|
||||
self.view.addSubview(filters)
|
||||
filters.spacing = 10
|
||||
filters.alignParentLeft(withMargin: 10).alignUnder(view: super.topBar,withMargin: self.form_margin).done()
|
||||
|
||||
super.nextButton.applyTintedIcons(tintedIcons: VoipTheme.conference_create_button)
|
||||
|
||||
self.view.addSubview(separator)
|
||||
separator.matchParentSideBorders().height(1).alignUnder(view: filters,withMargin: self.form_margin).done()
|
||||
|
||||
// Conference list
|
||||
|
||||
self.view.addSubview(conferenceListView)
|
||||
conferenceListView.alignUnder(view: filters).done()
|
||||
conferenceListView.isScrollEnabled = true
|
||||
conferenceListView.dataSource = self
|
||||
conferenceListView.delegate = self
|
||||
|
|
@ -56,11 +105,53 @@ import linphonesw
|
|||
conferenceListView.allowsFocus = false
|
||||
}
|
||||
conferenceListView.separatorStyle = .singleLine
|
||||
conferenceListView.separatorColor = .white
|
||||
conferenceListView.backgroundColor = .clear
|
||||
|
||||
view.addSubview(noConference)
|
||||
noConference.center().done()
|
||||
|
||||
ScheduledConferencesViewModel.shared.editionEnabled.readCurrentAndObserve { editing in
|
||||
if (editing == true) {
|
||||
self.selectAllButton.isSelected = false
|
||||
self.selectAllButton.isHidden = false
|
||||
super.nextButton.applyTintedIcons(tintedIcons: VoipTheme.generic_delete_button)
|
||||
super.backButton.applyTintedIcons(tintedIcons: VoipTheme.generic_cancel)
|
||||
self.nextButton.isEnabled = ScheduledConferencesViewModel.shared.conferences.value?.filter{$0.selectedForDeletion.value == true}.count ?? 0 > 0
|
||||
} else {
|
||||
self.selectAllButton.isHidden = true
|
||||
ScheduledConferencesViewModel.shared.conferences.value?.forEach {$0.selectedForDeletion.value = false}
|
||||
super.nextButton.applyTintedIcons(tintedIcons: VoipTheme.conference_create_button)
|
||||
super.backButton.applyTintedIcons(tintedIcons: VoipTheme.generic_back)
|
||||
self.nextButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
self.selectAllButton.onClick {
|
||||
let selectIt = !self.selectAllButton.isSelected
|
||||
ScheduledConferencesViewModel.shared.conferences.value?.forEach {$0.selectedForDeletion.value = selectIt}
|
||||
}
|
||||
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.view.backgroundColor = VoipTheme.voipBackgroundBWColor.get()
|
||||
self.separator.backgroundColor = VoipTheme.separatorColor.get()
|
||||
self.conferenceListView.separatorColor = .clear
|
||||
self.conferenceListView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
func getFilterButton(title:String) -> UIButton {
|
||||
let filter_button_height = 35.0
|
||||
let button = ButtonWithStateBackgrounds(backgroundStateColors: VoipTheme.button_conference_list_filter)
|
||||
button.setTitle(title, for: .normal)
|
||||
button.setTitleColor(.black, for: .normal)
|
||||
button.setTitleColor(VoipTheme.primary_color, for: .selected)
|
||||
button.height(filter_button_height).done()
|
||||
button.layer.cornerRadius = filter_button_height / 2
|
||||
button.clipsToBounds = true
|
||||
button.applyTitleStyle(VoipTheme.conf_list_filter_button_font)
|
||||
button.width(0).done()
|
||||
button.addSidePadding()
|
||||
return button
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -69,9 +160,10 @@ import linphonesw
|
|||
super.viewWillAppear(animated)
|
||||
self.conferenceListView.reloadData()
|
||||
self.conferenceListView.removeConstraints().done()
|
||||
self.conferenceListView.matchParentSideBorders(insetedByDx: 10).alignUnder(view: super.topBar,withMargin: self.form_margin).alignParentBottom().done()
|
||||
self.conferenceListView.matchParentSideBorders(insetedByDx: 10).alignUnder(view: separator).alignParentBottom().done()
|
||||
noConference.isHidden = !ScheduledConferencesViewModel.shared.daySplitted.isEmpty
|
||||
super.nextButton.isEnabled = Core.get().defaultAccount != nil
|
||||
ScheduledConferencesViewModel.shared.editionEnabled.value = false
|
||||
}
|
||||
|
||||
// TableView datasource delegate
|
||||
|
|
@ -99,12 +191,7 @@ import linphonesw
|
|||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
let daysArray = Array(ScheduledConferencesViewModel.shared.daySplitted.keys.sorted().reversed())
|
||||
let day = daysArray[indexPath.section]
|
||||
guard let data = ScheduledConferencesViewModel.shared.daySplitted[day]?[indexPath.row] else {
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
return data.expanded.value! ? UITableView.automaticDimension : 100
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -117,8 +204,38 @@ import linphonesw
|
|||
}
|
||||
cell.conferenceData = data
|
||||
cell.owningTableView = tableView
|
||||
data.selectedForDeletion.readCurrentAndObserve { selected in
|
||||
let selectedCount = ScheduledConferencesViewModel.shared.conferences.value?.filter{$0.selectedForDeletion.value == true}.count ?? 0
|
||||
let totalCount = ScheduledConferencesViewModel.shared.conferences.value?.count ?? 0
|
||||
self.nextButton.isEnabled = ScheduledConferencesViewModel.shared.editionEnabled.value == false || selectedCount > 0
|
||||
self.selectAllButton.isSelected = selectedCount == totalCount
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
|
||||
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
if editingStyle == .delete {
|
||||
let cell = tableView.cellForRow(at: indexPath) as! ScheduledConferencesCell
|
||||
cell.askConfirmationTodeleteEntry()
|
||||
}
|
||||
}
|
||||
|
||||
func deleteSelection () {
|
||||
let selectedCount = ScheduledConferencesViewModel.shared.conferences.value?.filter{$0.selectedForDeletion.value == true}.count ?? 0
|
||||
let delete = ButtonAttributes(text:VoipTexts.conference_info_confirm_removal_delete, action: {
|
||||
ScheduledConferencesViewModel.shared.conferences.value?.forEach {
|
||||
$0.deleteConference()
|
||||
}
|
||||
ScheduledConferencesViewModel.shared.computeConferenceInfoList()
|
||||
self.conferenceListView.reloadData()
|
||||
VoipDialog.toast(message: selectedCount == 1 ? VoipTexts.conference_info_removed : VoipTexts.conference_infos_removed)
|
||||
ScheduledConferencesViewModel.shared.editionEnabled.value = false
|
||||
}, isDestructive:false)
|
||||
let cancel = ButtonAttributes(text:VoipTexts.cancel, action: {}, isDestructive:true)
|
||||
VoipDialog(message:selectedCount == 1 ? VoipTexts.conference_info_confirm_removal : VoipTexts.conference_infos_confirm_removal, givenButtons: [cancel,delete]).show()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
54
Classes/Swift/Extensions/IOS/SnapkitBridge.swift
Normal file
54
Classes/Swift/Extensions/IOS/SnapkitBridge.swift
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import Photos
|
||||
import linphonesw
|
||||
|
||||
|
||||
@objc class SnapkitBridge: NSObject {
|
||||
@objc static func matchParentDimensions(view:UIView) {
|
||||
view.matchParentDimmensions().done()
|
||||
}
|
||||
|
||||
@objc static func matchParentDimensions(view:UIView,leftInset:CGFloat) {
|
||||
view.matchParentDimmensions(insetedBy: UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: 0)).done()
|
||||
}
|
||||
|
||||
@objc static func matchParentDimensions(view:UIView,topInset:CGFloat) {
|
||||
view.matchParentDimmensions(insetedBy: UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0)).done()
|
||||
}
|
||||
|
||||
@objc static func height(view:UIView,heiht:Int) {
|
||||
view.height(heiht).done()
|
||||
}
|
||||
@objc static func square(view:UIView,size:Int) {
|
||||
view.square(size).done()
|
||||
}
|
||||
|
||||
@objc static func alignParentLeft(view:UIView) {
|
||||
view.alignParentLeft().done()
|
||||
}
|
||||
|
||||
@objc static func centerY(view:UIView) {
|
||||
view.centerY().done()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -22,9 +22,9 @@ import SnapKit
|
|||
import UIKit
|
||||
|
||||
extension UIButton {
|
||||
func addSidePadding(p:CGFloat = 10) {
|
||||
func addSidePadding(p:CGFloat = 10) { // Requires a width to be set prior to this ! SnapKit does not support updateOrCreate.
|
||||
if let w = titleLabel?.textWidth {
|
||||
width(w+2*p).done()
|
||||
updateWidth(w+2*p).done()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,10 +48,32 @@ extension UIDevice {
|
|||
}
|
||||
|
||||
static func notchHeight() -> CGFloat {
|
||||
guard #available(iOS 11.0, *), let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top else {
|
||||
guard #available(iOS 11.0, *), let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top, let sidePadding = UIApplication.shared.keyWindow?.safeAreaInsets.left else {
|
||||
return 0
|
||||
}
|
||||
return topPadding
|
||||
return [.landscapeRight,.landscapeLeft].contains(UIDevice.current.orientation) ? sidePadding : topPadding
|
||||
}
|
||||
|
||||
static func switchedDisplayMode() -> Bool {
|
||||
let displayMode = UserDefaults.standard.string(forKey: "displayMode")
|
||||
if #available(iOS 13.0, *) {
|
||||
if UITraitCollection.current.userInterfaceStyle == .light {
|
||||
UserDefaults.standard.set("light", forKey: "displayMode")
|
||||
} else {
|
||||
UserDefaults.standard.set("dark", forKey: "displayMode")
|
||||
}
|
||||
}
|
||||
return displayMode != nil && displayMode != UserDefaults.standard.string(forKey: "displayMode")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@objc class UIDeviceBridge : NSObject {
|
||||
static let displayModeSwitched = MutableLiveData<Bool>()
|
||||
@objc static func switchedDisplayMode() -> Bool {
|
||||
return UIDevice.switchedDisplayMode()
|
||||
}
|
||||
@objc static func notifyDisplayModeSwitch() {
|
||||
displayModeSwitched.notifyValue()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,4 +29,10 @@ extension UILabel {
|
|||
let labelSize = myText.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: myFont], context: nil)
|
||||
return ceil(labelSize.width)
|
||||
}
|
||||
|
||||
func addSidePadding(p:CGFloat = 5.0) {
|
||||
if let w = textWidth {
|
||||
width(w+2*p).done()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,14 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func squareMax(_ size:Int) -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.height.lessThanOrEqualTo(size).priority(.high)
|
||||
make.width.equalTo(snp.height).priority(.high)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
|
||||
func makeHeightMatchWidth() -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
|
|
@ -47,6 +55,13 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func makeWidthMatchHeight() -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.width.equalTo(snp.height)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func size(w:CGFloat,h:CGFloat) -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.width.equalTo(w)
|
||||
|
|
@ -55,6 +70,14 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func updateSize(w:CGFloat,h:CGFloat) -> UIView {
|
||||
snp.updateConstraints { (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)
|
||||
|
|
@ -73,6 +96,13 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func updateWidth(_ h:CGFloat) -> UIView {
|
||||
snp.updateConstraints { (make) in
|
||||
make.width.equalTo(h)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func width(_ h:Int) -> UIView {
|
||||
return width(CGFloat(h))
|
||||
}
|
||||
|
|
@ -122,7 +152,17 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func matchDimensionsWith(view:UIView, insetedByDx:CGFloat = 0) -> UIView {
|
||||
func matchParentDimmensions(insetedBy:UIEdgeInsets) -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.left.equalToSuperview().offset(insetedBy.left)
|
||||
make.top.equalToSuperview().offset(insetedBy.top)
|
||||
make.right.equalToSuperview().offset(-insetedBy.right)
|
||||
make.bottom.equalToSuperview().offset(-insetedBy.bottom)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func matchBordersWith(view:UIView, insetedByDx:CGFloat = 0) -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.left.top.equalTo(view).offset(insetedByDx)
|
||||
make.right.bottom.equalTo(view).offset(-insetedByDx)
|
||||
|
|
@ -130,6 +170,13 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func updateTopBorderWith(view:UIView, inset:CGFloat = 0) -> UIView {
|
||||
snp.updateConstraints { (make) in
|
||||
make.top.equalTo(view).offset(inset)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func matchParentEdges() -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.edges.equalToSuperview()
|
||||
|
|
@ -222,10 +269,21 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func updateAlignParentBottom(withMargin:CGFloat = 0.0) -> UIView {
|
||||
snp.updateConstraints { (make) in
|
||||
make.bottom.equalToSuperview().offset(-withMargin)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func alignParentBottom(withMargin:Int) -> UIView {
|
||||
return alignParentBottom(withMargin:CGFloat(withMargin))
|
||||
}
|
||||
|
||||
func updateAlignParentBottom(withMargin:Int) -> UIView {
|
||||
return updateAlignParentBottom(withMargin:CGFloat(withMargin))
|
||||
}
|
||||
|
||||
func alignAbove(view:UIView, withMargin:CGFloat = 0.0) -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.bottom.equalTo(view.snp.top).offset(-withMargin)
|
||||
|
|
@ -258,6 +316,13 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func updateAlignParentLeft(withMargin:CGFloat = 0.0) -> UIView {
|
||||
snp.updateConstraints { (make) in
|
||||
make.left.equalToSuperview().offset(withMargin)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func alignParentLeft(withMargin:Int) -> UIView {
|
||||
return alignParentLeft(withMargin:CGFloat(withMargin))
|
||||
}
|
||||
|
|
@ -269,10 +334,23 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func updateAlignParentRight(withMargin:CGFloat = 0) -> UIView {
|
||||
snp.updateConstraints { (make) in
|
||||
make.right.equalToSuperview().offset(-withMargin)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func alignParentRight(withMargin:CGFloat) -> UIView {
|
||||
return alignParentRight(withMargin:Int(withMargin))
|
||||
}
|
||||
|
||||
func alignRightWith(_ view:UIView) -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
make.right.equalTo(view.snp.right)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func toRightOf(_ view:UIView, withLeftMargin:Int = 0) -> UIView {
|
||||
snp.makeConstraints { (make) in
|
||||
|
|
@ -363,12 +441,28 @@ extension UIView {
|
|||
return self
|
||||
}
|
||||
|
||||
func wrapContent(inset:UIEdgeInsets) -> UIView {
|
||||
subviews.first?.snp.makeConstraints({ make in
|
||||
make.left.equalToSuperview().offset(inset.left)
|
||||
})
|
||||
subviews.last?.snp.makeConstraints({ make in
|
||||
make.right.equalToSuperview().offset(-inset.right)
|
||||
})
|
||||
subviews.first?.snp.makeConstraints({ make in
|
||||
make.top.equalToSuperview().offset(inset.top)
|
||||
})
|
||||
subviews.last?.snp.makeConstraints({ make in
|
||||
make.bottom.equalToSuperview().offset(-inset.bottom)
|
||||
})
|
||||
return self
|
||||
}
|
||||
|
||||
func done() {
|
||||
// to avoid the unused variable warning
|
||||
}
|
||||
|
||||
// Onclick
|
||||
|
||||
// Single click
|
||||
|
||||
class TapGestureRecognizer: UITapGestureRecognizer {
|
||||
var action : (()->Void)? = nil
|
||||
}
|
||||
|
|
@ -387,6 +481,22 @@ extension UIView {
|
|||
sender.action!()
|
||||
}
|
||||
|
||||
// Long click
|
||||
class LongPressGestureRecognizer: UILongPressGestureRecognizer {
|
||||
var action : (()->Void)? = nil
|
||||
}
|
||||
func onLongClick(action : @escaping ()->Void ){
|
||||
let tap = LongPressGestureRecognizer(target: self , action: #selector(self.handleLongClick(_:)))
|
||||
tap.action = action
|
||||
tap.cancelsTouchesInView = false
|
||||
self.addGestureRecognizer(tap)
|
||||
self.isUserInteractionEnabled = true
|
||||
|
||||
}
|
||||
@objc func handleLongClick(_ sender: LongPressGestureRecognizer) {
|
||||
sender.action!()
|
||||
}
|
||||
|
||||
func VIEW<T>( _ desc: UICompositeViewDescription) -> T{
|
||||
return PhoneMainView.instance().mainViewController.getCachedController(desc.name) as! T
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,15 +23,16 @@ import linphonesw
|
|||
extension Address {
|
||||
|
||||
func initials() -> String? {
|
||||
var initials = initials(displayName: addressBookEnhancedDisplayName())
|
||||
var initials = Address.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: " ")
|
||||
static func initials(displayName: String?) -> String? { // Basic ImproveMe
|
||||
let separator = displayName?.contains(" ") == true ? " " : "."
|
||||
return displayName?.components(separatedBy: separator)
|
||||
.reduce("") {
|
||||
($0.isEmpty ? "" : "\($0.first?.uppercased() ?? "")") +
|
||||
($1.isEmpty ? "" : "\($1.first?.uppercased() ?? "")")
|
||||
|
|
|
|||
|
|
@ -39,10 +39,7 @@ extension Call {
|
|||
|
||||
extension Call : CustomStringConvertible {
|
||||
public var description: String {
|
||||
if let callId = callLog?.callId {
|
||||
return "<Call-ID: \(callId)>"
|
||||
}
|
||||
return "<Raw pointer:\(Unmanaged.passUnretained(self).toOpaque())>"
|
||||
return "<Call-ID: \(callLog?.callId ?? "pending") pointer:\(Unmanaged.passUnretained(self).toOpaque()) is conference:\(conference != nil) >"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
139
Classes/Swift/FileUtil.swift
Normal file
139
Classes/Swift/FileUtil.swift
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import linphonesw
|
||||
|
||||
@objc class FileUtil: NSObject {
|
||||
public class func bundleFilePath(_ file: NSString) -> String? {
|
||||
return Bundle.main.path(forResource: file.deletingPathExtension, ofType: file.pathExtension)
|
||||
}
|
||||
|
||||
public class func bundleFilePathAsUrl(_ file: NSString) -> URL? {
|
||||
if let bPath = bundleFilePath(file) {
|
||||
return URL.init(fileURLWithPath: bPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public class func documentsDirectory() -> URL {
|
||||
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
|
||||
let documentsDirectory = paths[0]
|
||||
return documentsDirectory
|
||||
}
|
||||
|
||||
public class func libraryDirectory() -> URL {
|
||||
let paths = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)
|
||||
let documentsDirectory = paths[0]
|
||||
return documentsDirectory
|
||||
}
|
||||
|
||||
public class func sharedContainerUrl(appGroupName:String) -> URL {
|
||||
return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)!
|
||||
}
|
||||
|
||||
|
||||
@objc public class func ensureDirectoryExists(path:String) {
|
||||
if !FileManager.default.fileExists(atPath: path) {
|
||||
do {
|
||||
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class func ensureFileExists(path:String) {
|
||||
if !FileManager.default.fileExists(atPath: path) {
|
||||
FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public class func fileExists(path:String) -> Bool {
|
||||
return FileManager.default.fileExists(atPath: path)
|
||||
}
|
||||
|
||||
public class func fileExistsAndIsNotEmpty(path:String) -> Bool {
|
||||
guard FileManager.default.fileExists(atPath: path) else {return false}
|
||||
do {
|
||||
let attribute = try FileManager.default.attributesOfItem(atPath: path)
|
||||
if let size = attribute[FileAttributeKey.size] as? NSNumber {
|
||||
return size.doubleValue > 0
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public class func write(string:String, toPath:String) {
|
||||
do {
|
||||
try string.write(to: URL(fileURLWithPath:toPath), atomically: true, encoding: String.Encoding.utf8)
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
public class func delete(path:String) {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: path)
|
||||
print("FIle \(path) was removed")
|
||||
} catch {
|
||||
print("Error deleting file at path \(path) error is \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
public class func mkdir(path:String) {
|
||||
do {
|
||||
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
|
||||
print("Dir \(path) was created")
|
||||
} catch {
|
||||
print("Error creating dir at path \(path) error is \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class func copy(_ fromPath:String, _ toPath: String, overWrite:Bool) {
|
||||
do {
|
||||
if (overWrite && fileExists(path: toPath)) {
|
||||
delete(path: toPath)
|
||||
}
|
||||
try FileManager.default.copyItem(at: URL(fileURLWithPath:fromPath), to: URL(fileURLWithPath:toPath))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For debugging
|
||||
|
||||
public class func showListOfFilesInSharedDir(appGroupName:String) {
|
||||
let fileManager = FileManager.default
|
||||
do {
|
||||
let fileURLs = try fileManager.contentsOfDirectory(at: FileUtil.sharedContainerUrl(appGroupName: appGroupName), includingPropertiesForKeys: nil)
|
||||
fileURLs.forEach{print($0)}
|
||||
} catch {
|
||||
print("Error while enumerating files \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ extension ProviderDelegate: CXProviderDelegate {
|
|||
|
||||
if (UIApplication.shared.applicationState != .active) {
|
||||
CallManager.instance().backgroundContextCall = call
|
||||
CallManager.instance().backgroundContextCameraIsEnabled = call!.params?.videoEnabled ?? false
|
||||
CallManager.instance().backgroundContextCameraIsEnabled = call?.params?.videoEnabled == true || call?.callLog?.wasConference() == true
|
||||
call?.cameraEnabled = false // Disable camera while app is not on foreground
|
||||
}
|
||||
CallManager.instance().callkitAudioSessionActivated = false
|
||||
|
|
@ -205,8 +205,10 @@ extension ProviderDelegate: CXProviderDelegate {
|
|||
let uuid = action.callUUID
|
||||
let callId = callInfos[uuid]?.callId
|
||||
let call = CallManager.instance().callByCallId(callId: callId)
|
||||
action.fulfill()
|
||||
|
||||
if (call == nil) {
|
||||
Log.directLog(BCTBX_LOG_ERROR, text: "CXSetHeldCallAction: no call !")
|
||||
action.fail()
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -215,33 +217,52 @@ extension ProviderDelegate: CXProviderDelegate {
|
|||
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
|
||||
}
|
||||
|
||||
let state = action.isOnHold ? "Paused" : "Resumed"
|
||||
Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: Call with call-id: [\(String(describing: callId))] and UUID: [\(uuid)] paused status changed to: [\(state)]")
|
||||
if (action.isOnHold) {
|
||||
if (call!.params?.localConferenceMode ?? false) {
|
||||
return
|
||||
}
|
||||
CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled()
|
||||
try call!.pause()
|
||||
} else {
|
||||
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)
|
||||
action.fulfill()
|
||||
}else{
|
||||
let state = action.isOnHold ? "Paused" : "Resumed"
|
||||
Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: Call with call-id: [\(String(describing: callId))] and UUID: [\(uuid)] paused status changed to: [\(state)]")
|
||||
if (action.isOnHold) {
|
||||
CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled()
|
||||
try call!.pause()
|
||||
// fullfill() the action now to indicate to Callkit that this call is no longer active, even if the
|
||||
// SIP transaction is not completed yet. At this stage, the media streams are off.
|
||||
// If callkit is not aware that the pause action is completed, it will terminate this call if we
|
||||
// attempt to resume another one.
|
||||
action.fulfill()
|
||||
} else {
|
||||
try call!.resume()
|
||||
if (CallManager.instance().lc?.conference != nil && CallManager.instance().lc?.callsNb ?? 0 > 1) {
|
||||
try CallManager.instance().lc?.enterConference()
|
||||
action.fulfill()
|
||||
NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self)
|
||||
} else {
|
||||
try call!.resume()
|
||||
// We'll notify callkit that the action is fulfilled when receiving the 200Ok, which is the point
|
||||
// where we actually start the media streams.
|
||||
CallManager.instance().actionToFulFill = action;
|
||||
// HORRIBLE HACK HERE - PLEASE APPLE FIX THIS !!
|
||||
// When resuming a SIP call after a native call has ended remotely, didActivate: audioSession
|
||||
// is never called.
|
||||
// It looks like in this case, it is implicit.
|
||||
// As a result we have to notify the Core that the AudioSession is active.
|
||||
// The SpeakerBox demo application written by Apple exhibits this behavior.
|
||||
// https://developer.apple.com/documentation/callkit/making_and_receiving_voip_calls_with_callkit
|
||||
// We can clearly see there that startAudio() is called immediately in the CXSetHeldCallAction
|
||||
// handler, while it is called from didActivate: audioSession otherwise.
|
||||
// Callkit's design is not consistent, or its documentation imcomplete, wich is somewhat disapointing.
|
||||
//
|
||||
Log.directLog(BCTBX_LOG_DEBUG, text: "Assuming AudioSession is active when executing a CXSetHeldCallAction with isOnHold=false.")
|
||||
CallManager.instance().lc?.activateAudioSession(actived: true)
|
||||
CallManager.instance().callkitAudioSessionActivated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Log.directLog(BCTBX_LOG_ERROR, text: "CallKit: Call set held (paused or resumed) \(uuid) failed because \(error)")
|
||||
action.fail()
|
||||
}
|
||||
}
|
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
||||
|
||||
|
||||
do {
|
||||
|
||||
let uuid = action.callUUID
|
||||
|
|
|
|||
|
|
@ -79,14 +79,9 @@ import linphonesw
|
|||
scrollView.alignUnder(view: topBar, withMargin: content_margin_top).alignParentBottom().matchParentSideBorders().done()
|
||||
scrollView.addSubview(contentView)
|
||||
contentView.matchBordersOf(view: view).alignParentBottom().alignParentTop().done() // don't forget a bottom constraint b/w last element of contentview and contentview
|
||||
|
||||
}
|
||||
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
topBar.backgroundColor = VoipTheme.voipToolbarBackgroundColor.get()
|
||||
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.topBar.backgroundColor = VoipTheme.voipToolbarBackgroundColor.get()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,10 @@ class TimestampUtils {
|
|||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateStyle = .long
|
||||
dateFormatter.timeStyle = .none
|
||||
return dateFormatter.string(from: date)
|
||||
let dayFormatter = DateFormatter()
|
||||
dayFormatter.dateFormat = "EEEE"
|
||||
let day = dayFormatter.string(from: date)
|
||||
return day.prefix(1).uppercased() + day.dropFirst()+" "+dateFormatter.string(from: date)
|
||||
}
|
||||
|
||||
static func timeToString(date:Date) -> String {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class LightDarkColor {
|
||||
@objc class LightDarkColor : NSObject {
|
||||
var light: UIColor
|
||||
var dark : UIColor
|
||||
init(_ l:UIColor,_ d:UIColor){
|
||||
|
|
@ -27,7 +27,7 @@ class LightDarkColor {
|
|||
dark = d
|
||||
}
|
||||
|
||||
func get() -> UIColor {
|
||||
@objc func get() -> UIColor {
|
||||
if #available(iOS 13.0, *) {
|
||||
if UITraitCollection.current.userInterfaceStyle == .light {
|
||||
return light
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue