mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 02:58:07 +00:00
Merge release/5.1 into master.
This includes the rework of the chat conversation in Swift, and every fixes since the 5.0 release.
This commit is contained in:
parent
329193d2fa
commit
0d602260be
225 changed files with 12199 additions and 2946 deletions
131
.gitlab-ci.yml
131
.gitlab-ci.yml
|
|
@ -1,55 +1,98 @@
|
|||
variables:
|
||||
workspace: linphone.xcworkspace
|
||||
scheme: linphone
|
||||
destination: name=iPhone 13 Pro
|
||||
testResult_path: derivedData/Logs/Test
|
||||
# COMMENTED FOR NOW - TODO : ENABLE CALLUI TESTS IN THE CI
|
||||
# USE ONLY THE release/5.1 VERSION OF THIS FILE FOR NOW
|
||||
#
|
||||
#
|
||||
#
|
||||
#variables:
|
||||
# workspace: linphone.xcworkspace
|
||||
# scheme: linphone
|
||||
# destination: name=iPhone 13 Pro
|
||||
# testResult_path: derivedData/Logs/Test
|
||||
|
||||
stages:
|
||||
- Build
|
||||
- UITests
|
||||
#stages:
|
||||
# - Build
|
||||
# - UITests
|
||||
|
||||
before_script:
|
||||
- pod install
|
||||
- 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
|
||||
#before_script:
|
||||
# - pod install
|
||||
# - 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
|
||||
|
||||
Compile & Build:
|
||||
stage: Build
|
||||
tags: ["macmini-m1-xcode13"]
|
||||
before_script:
|
||||
#Compile & Build:
|
||||
# stage: Build
|
||||
# tags: ["macmini-m1-xcode13"]
|
||||
# before_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
|
||||
# - xcrun simctl shutdown "$destination" && xcrun simctl erase "$destination"
|
||||
# script:
|
||||
# - xcodebuild -workspace $workspace -scheme $scheme -UseModernBuildSystem=YES -destination "$destination" -derivedDataPath derivedData
|
||||
# after_script: []
|
||||
#
|
||||
# stage: build
|
||||
# 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'
|
||||
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - derivedData/Build
|
||||
# when: always
|
||||
# expire_in: 2 hour
|
||||
|
||||
|
||||
|
||||
#after_script:
|
||||
# - ${TRAINER_EXE} -p $testResult_path/*.xcresult -o $testResult_path/
|
||||
# - ${XCPARSE_EXE} attachments $testResult_path/*.xcresult results --uti public.image
|
||||
# - mv $testResult_path/*.xcresult results && mv derivedData/logs.txt results
|
||||
|
||||
#Call Views:
|
||||
# stage: UITests
|
||||
# tags: ["macmini-m1-xcode13"]
|
||||
# dependencies: ["Compile & Build"]
|
||||
# script:
|
||||
# - xcodebuild test -workspace $workspace -scheme $scheme -sdk iphonesimulator -destination "$destination" -UseModernBuildSystem=YES -testPlan Default -derivedDataPath derivedData | tee derivedData/logs.txt
|
||||
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - results/*
|
||||
# when: always
|
||||
# reports:
|
||||
# junit:
|
||||
# - $testResult_path/*.xml
|
||||
# expire_in: 4 week
|
||||
|
||||
|
||||
variables:
|
||||
archive_scheme: linphone
|
||||
archive_path: linphone.xcarchive
|
||||
export_path: linphone-adhoc-ipa
|
||||
export_options_plist: linphone-adhoc.plist
|
||||
|
||||
job-ios:
|
||||
|
||||
stage: build
|
||||
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
|
||||
- xcrun simctl shutdown "$destination" && xcrun simctl erase "$destination"
|
||||
script:
|
||||
- xcodebuild -workspace $workspace -scheme $scheme -UseModernBuildSystem=YES -destination "$destination" -derivedDataPath derivedData
|
||||
after_script: []
|
||||
- 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'
|
||||
|
||||
|
||||
artifacts:
|
||||
paths:
|
||||
- derivedData/Build
|
||||
- $archive_path
|
||||
- $export_path
|
||||
when: always
|
||||
expire_in: 2 hour
|
||||
expire_in: 1 week
|
||||
|
||||
|
||||
|
||||
after_script:
|
||||
- ${TRAINER_EXE} -p $testResult_path/*.xcresult -o $testResult_path/
|
||||
- ${XCPARSE_EXE} attachments $testResult_path/*.xcresult results --uti public.image
|
||||
- mv $testResult_path/*.xcresult results && mv derivedData/logs.txt results
|
||||
|
||||
Call Views:
|
||||
stage: UITests
|
||||
tags: ["macmini-m1-xcode13"]
|
||||
dependencies: ["Compile & Build"]
|
||||
script:
|
||||
- xcodebuild test -workspace $workspace -scheme $scheme -sdk iphonesimulator -destination "$destination" -UseModernBuildSystem=YES -testPlan Default -derivedDataPath derivedData | tee derivedData/logs.txt
|
||||
|
||||
artifacts:
|
||||
paths:
|
||||
- results/*
|
||||
when: always
|
||||
reports:
|
||||
junit:
|
||||
- $testResult_path/*.xml
|
||||
expire_in: 4 week
|
||||
|
|
|
|||
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) {
|
||||
|
|
@ -1568,7 +1581,6 @@ UIColor *previousColor = (UIColor*)[sender backgroundColor]; \
|
|||
- (IBAction)onRemoteProvisioningLoginClick:(id)sender {
|
||||
ONCLICKBUTTON(sender, 100, {
|
||||
_waitView.hidden = NO;
|
||||
[LinphoneManager.instance lpConfigSetInt:1 forKey:@"transient_provisioning" inSection:@"misc"];
|
||||
[self configureAccount];
|
||||
});
|
||||
}
|
||||
|
|
@ -1584,10 +1596,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,14 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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"/>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
||||
<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>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ChatConversationView">
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ChatConversationViewSwift">
|
||||
<connections>
|
||||
<outlet property="addressLabel" destination="40" id="43"/>
|
||||
<outlet property="backButton" destination="9" id="Jcb-ET-bKd"/>
|
||||
|
|
@ -50,19 +49,19 @@
|
|||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="v2I-ka-LYa" userLabel="iphone6MetricsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6">
|
||||
<rect key="frame" x="0.0" y="42" width="414" height="788"/>
|
||||
<rect key="frame" x="-1" y="41" width="393" height="744"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view alpha="0.90000000000000002" tag="2" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7" userLabel="topBar">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="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="82" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="77" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
@ -77,7 +76,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="11" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bci-3K-AcG" userLabel="cancelButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="82" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="77" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -92,7 +91,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="5" contentMode="left" fixedFrame="YES" text="Contact1" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="40" userLabel="addressLabel">
|
||||
<rect key="frame" x="75" y="0.0" width="160" height="44"/>
|
||||
<rect key="frame" x="75" y="0.0" width="149" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name">
|
||||
<accessibilityTraits key="traits" none="YES"/>
|
||||
|
|
@ -102,7 +101,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" tag="6" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Wzg-i0-spp" userLabel="callButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="248" y="0.0" width="83" height="66"/>
|
||||
<rect key="frame" x="234" y="0.0" width="79" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<state key="normal" image="call_alt_start_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -114,7 +113,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="7" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Hc0-GX-fC5" userLabel="backToCallButton" customClass="UIBackToCallButton">
|
||||
<rect key="frame" x="248" y="0.0" width="83" height="66"/>
|
||||
<rect key="frame" x="234" y="0.0" width="79" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<state key="normal" image="call_back_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -127,7 +126,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="8" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Wag-Nx-kd6" userLabel="deleteButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="331" y="0.0" width="83" height="66"/>
|
||||
<rect key="frame" x="313" y="0.0" width="80" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delete all"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -141,7 +140,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="9" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FqM-Ud-i58" userLabel="editButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="331" y="0.0" width="83" height="66"/>
|
||||
<rect key="frame" x="313" y="0.0" width="80" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Edit"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -156,7 +155,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="4697" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CPn-Oc-9PX" userLabel="toggleMenuButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="331" y="0.0" width="83" height="66"/>
|
||||
<rect key="frame" x="313" y="0.0" width="80" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Edit"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -169,7 +168,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="10" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" reversesTitleShadowWhenHighlighted="YES" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="c9z-aq-2UP" userLabel="toggleSelectionButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="248" y="0.0" width="83" height="66"/>
|
||||
<rect key="frame" x="234" y="0.0" width="79" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Select all"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
@ -185,7 +184,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="5" contentMode="left" fixedFrame="YES" text="addresses" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ncq-Zc-X6j" userLabel="participantsLabel">
|
||||
<rect key="frame" x="75" y="36" width="160" height="25"/>
|
||||
<rect key="frame" x="75" y="35" width="149" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name">
|
||||
<accessibilityTraits key="traits" none="YES"/>
|
||||
|
|
@ -198,11 +197,11 @@
|
|||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||
</view>
|
||||
<view tag="12" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="49" userLabel="contentView">
|
||||
<rect key="frame" x="0.0" y="66" width="414" height="722"/>
|
||||
<rect key="frame" x="0.0" y="65" width="393" height="679"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" tag="13" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="none" allowsSelection="NO" allowsSelectionDuringEditing="YES" allowsMultipleSelectionDuringEditing="YES" rowHeight="60" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="8" userLabel="messagesTableView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="574"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="529"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<gestureRecognizers/>
|
||||
|
|
@ -214,11 +213,11 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<view hidden="YES" tag="14" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fx4-ao-53M" userLabel="composeIndicatorView">
|
||||
<rect key="frame" x="0.0" y="574" width="414" height="22"/>
|
||||
<rect key="frame" x="0.0" y="529" width="393" height="23"/>
|
||||
<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="385" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label=""/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
@ -229,7 +228,7 @@
|
|||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" tag="16" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="No conversation." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p7C-WH-uR1" userLabel="emptyTableLabel">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="574"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="539"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
@ -237,11 +236,11 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view alpha="0.90000000000000002" tag="17" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="14" userLabel="messageView">
|
||||
<rect key="frame" x="0.0" y="656" width="414" height="66"/>
|
||||
<rect key="frame" x="0.0" y="612" width="393" height="67"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" tag="19" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="73" userLabel="pictureButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="66" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="66" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Send picture"/>
|
||||
<state key="normal" image="chat_attachment_default.png">
|
||||
|
|
@ -254,7 +253,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="9019" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aTi-pm-fAG" userLabel="audioRecordingButton">
|
||||
<rect key="frame" x="66" y="0.0" width="56" height="66"/>
|
||||
<rect key="frame" x="66" y="0.0" width="56" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Send picture"/>
|
||||
<inset key="imageEdgeInsets" minX="15" minY="20" maxX="15" maxY="20"/>
|
||||
|
|
@ -267,7 +266,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="21" contentMode="scaleToFill" fixedFrame="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="15" userLabel="sendButton">
|
||||
<rect key="frame" x="349" y="0.0" width="66" height="66"/>
|
||||
<rect key="frame" x="328" y="0.0" width="65" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Send"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="30" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -281,24 +280,24 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view tag="20" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pqa-tg-5ml" userLabel="messageField" customClass="HPGrowingTextView">
|
||||
<rect key="frame" x="130" y="13" width="208" height="40"/>
|
||||
<rect key="frame" x="123" y="11" width="197" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Message field"/>
|
||||
</view>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" tag="44536" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="ephemeral_messages_color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="LN7-ci-kNn" userLabel="ephemeralIndicator">
|
||||
<rect key="frame" x="393" y="44" width="15" height="15"/>
|
||||
<rect key="frame" x="372" y="44" width="14" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||
</view>
|
||||
<view hidden="YES" tag="28021" contentMode="scaleToFill" id="Tru-Zm-4EZ" userLabel="VoiceRecording">
|
||||
<rect key="frame" x="0.0" y="596" width="414" height="60"/>
|
||||
<rect key="frame" x="0.0" y="596" width="393" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" tag="28022" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wi9-en-JCZ">
|
||||
<rect key="frame" x="12" y="13" width="24" height="34"/>
|
||||
<rect key="frame" x="12" y="12" width="24" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="delete_default.png"/>
|
||||
<connections>
|
||||
|
|
@ -306,26 +305,26 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view tag="28023" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eXD-Gd-FXA">
|
||||
<rect key="frame" x="50" y="8" width="302" height="44"/>
|
||||
<rect key="frame" x="50" y="7" width="280" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view tag="28024" contentMode="scaleToFill" id="OTf-Od-TDn" userLabel="vr_wave_mask_playback">
|
||||
<rect key="frame" x="0.0" y="0.0" width="240" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="217" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="0.93333333330000001" green="0.93333333330000001" blue="0.93333333330000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="28025" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="vr_wave.png" translatesAutoresizingMaskIntoConstraints="NO" id="m9m-2e-T7E">
|
||||
<rect key="frame" x="8" y="8" width="232" height="28"/>
|
||||
<rect key="frame" x="7" y="8" width="210" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<view tag="28026" contentMode="scaleToFill" id="TzM-ND-yp4" userLabel="vr_wave_mask_record">
|
||||
<rect key="frame" x="0.0" y="0.0" width="240" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="217" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" tag="28027" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00:00" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dMW-Ix-4k0">
|
||||
<rect key="frame" x="245" y="12" width="49" height="21"/>
|
||||
<rect key="frame" x="222" y="12" width="48" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<nil key="textColor"/>
|
||||
|
|
@ -335,7 +334,7 @@
|
|||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
<button opaque="NO" tag="28028" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FNM-bb-AlC">
|
||||
<rect key="frame" x="366" y="13" width="35" height="35"/>
|
||||
<rect key="frame" x="343" y="12" width="37" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="vr_play.png"/>
|
||||
<connections>
|
||||
|
|
@ -346,11 +345,11 @@
|
|||
<color key="backgroundColor" red="0.93333333330000001" green="0.93333333330000001" blue="0.93333333330000001" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3qd-ys-t2L" userLabel="imagesView">
|
||||
<rect key="frame" x="0.0" y="625" width="414" height="0.0"/>
|
||||
<rect key="frame" x="0.0" y="587" width="393" height="0.0"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" showsVerticalScrollIndicator="NO" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="JGQ-p2-HCX" userLabel="imagesCollectionView">
|
||||
<rect key="frame" x="2" y="0.0" width="413" height="0.0"/>
|
||||
<rect key="frame" x="2" y="0.0" width="391" height="0.0"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.98780487804878048" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="c7z-F2-r1y">
|
||||
|
|
@ -364,7 +363,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>
|
||||
|
|
@ -372,7 +371,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view hidden="YES" tag="290392" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wve-MK-7ME" userLabel="ReplyView">
|
||||
<rect key="frame" x="0.0" y="536" width="414" height="120"/>
|
||||
<rect key="frame" x="0.0" y="536" width="393" height="120"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
|
|
@ -380,7 +379,7 @@
|
|||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
<tableView hidden="YES" clipsSubviews="YES" tag="6992" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="gdT-1Q-vU2" userLabel="popupMenu">
|
||||
<rect key="frame" x="142" y="66" width="273" height="132"/>
|
||||
<rect key="frame" x="121" y="66" width="272" height="132"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</tableView>
|
||||
|
|
@ -393,23 +392,23 @@
|
|||
<point key="canvasLocation" x="365.21739130434787" y="-36.830357142857139"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="680-UL-sil" userLabel="iphone6MetricsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VoU-7Q-fgp">
|
||||
<rect key="frame" x="90" y="42" width="324" height="854"/>
|
||||
<rect key="frame" x="90" y="42" width="303" height="810"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view tag="2" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Z3y-hY-5xp" userLabel="topBar">
|
||||
<rect key="frame" x="0.0" y="0.0" width="324" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="303" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" tag="3" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_F.png" translatesAutoresizingMaskIntoConstraints="NO" id="Uvs-m3-GPj" userLabel="backgroundColor">
|
||||
<rect key="frame" x="0.0" y="0.0" width="324" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="303" 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="N2g-vL-3x8" userLabel="backButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="37" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="34" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
@ -424,7 +423,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="11" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Bqf-Gg-2Rw" userLabel="cancelButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="37" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="34" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -449,7 +448,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button hidden="YES" opaque="NO" tag="8" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RDW-7W-25T" userLabel="deleteButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="285" y="0.0" width="39" height="66"/>
|
||||
<rect key="frame" x="264" y="0.0" width="39" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delete all"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -463,7 +462,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="9" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KeL-Ej-92j" userLabel="editButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="285" y="0.0" width="39" height="66"/>
|
||||
<rect key="frame" x="264" y="0.0" width="39" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Edit"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -478,7 +477,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="4697" contentMode="scaleAspectFit" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pQX-Ll-9wL" userLabel="toggleMenuButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="285" y="0.0" width="39" height="66"/>
|
||||
<rect key="frame" x="264" y="0.0" width="39" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Edit"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -491,7 +490,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="6" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wag-QV-oUD" userLabel="callButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="248" y="0.0" width="37" height="66"/>
|
||||
<rect key="frame" x="230" y="0.0" width="34" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<state key="normal" image="call_alt_start_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -503,7 +502,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="7" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="t25-en-4LP" userLabel="backToCallButton" customClass="UIBackToCallButton">
|
||||
<rect key="frame" x="248" y="0.0" width="37" height="66"/>
|
||||
<rect key="frame" x="230" y="0.0" width="34" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<state key="normal" image="call_back_default.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
|
@ -515,7 +514,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" tag="10" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" reversesTitleShadowWhenHighlighted="YES" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4RV-US-Kr1" userLabel="toggleSelectionButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="248" y="0.0" width="37" height="66"/>
|
||||
<rect key="frame" x="230" y="0.0" width="34" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Select all"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
@ -531,7 +530,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="5" contentMode="left" fixedFrame="YES" text="addresses" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="tyU-Wy-rLs" userLabel="participantsLabel">
|
||||
<rect key="frame" x="67" y="37" width="366" height="25"/>
|
||||
<rect key="frame" x="67" y="36" width="366" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name">
|
||||
<accessibilityTraits key="traits" none="YES"/>
|
||||
|
|
@ -543,11 +542,11 @@
|
|||
</subviews>
|
||||
</view>
|
||||
<view tag="12" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OTt-fc-941" userLabel="contentView">
|
||||
<rect key="frame" x="0.0" y="66" width="324" height="788"/>
|
||||
<rect key="frame" x="0.0" y="66" width="303" height="744"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" tag="13" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="none" allowsSelection="NO" allowsSelectionDuringEditing="YES" allowsMultipleSelectionDuringEditing="YES" rowHeight="60" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="CU7-Za-RwN" userLabel="messagesTableView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="324" height="700"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="303" height="657"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<gestureRecognizers/>
|
||||
|
|
@ -557,7 +556,7 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" tag="16" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="No conversation." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pzm-tk-LH0" userLabel="emptyTableLabel">
|
||||
<rect key="frame" x="0.0" y="0.0" width="324" height="617"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="303" height="582"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
@ -565,11 +564,11 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view hidden="YES" tag="14" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="nTf-7h-Z4z" userLabel="composeIndicatorView">
|
||||
<rect key="frame" x="0.0" y="700" width="324" height="22"/>
|
||||
<rect key="frame" x="0.0" y="657" width="303" height="21"/>
|
||||
<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="I34-aL-yuS" userLabel="composeLabel">
|
||||
<rect key="frame" x="0.0" y="0.0" width="324" height="22"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="303" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label=""/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
@ -579,11 +578,11 @@
|
|||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<view tag="17" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LA5-wD-ftj" userLabel="messageView">
|
||||
<rect key="frame" x="0.0" y="722" width="324" height="66"/>
|
||||
<rect key="frame" x="0.0" y="678" width="303" height="67"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" tag="18" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_F.png" translatesAutoresizingMaskIntoConstraints="NO" id="kKc-DG-gwg" userLabel="backgroundColor">
|
||||
<rect key="frame" x="0.0" y="0.0" width="324" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="303" height="67"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<button opaque="NO" tag="19" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gSL-jE-GYO" userLabel="pictureButton">
|
||||
|
|
@ -612,13 +611,13 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view tag="20" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C02-2r-vXK" userLabel="messageField" customClass="HPGrowingTextView">
|
||||
<rect key="frame" x="59" y="13" width="230" height="40"/>
|
||||
<rect key="frame" x="53" y="12" width="215" height="42"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Message field"/>
|
||||
</view>
|
||||
<button opaque="NO" tag="21" contentMode="scaleToFill" fixedFrame="YES" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nV9-xZ-oSM" userLabel="sendButton">
|
||||
<rect key="frame" x="258" y="0.0" width="66" height="66"/>
|
||||
<rect key="frame" x="236" y="0.0" width="67" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Send"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="30" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -632,7 +631,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" tag="44536" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="ephemeral_messages_color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="Gsu-3J-HRp" userLabel="ephemeralIndicator">
|
||||
<rect key="frame" x="305" y="40" width="15" height="15"/>
|
||||
<rect key="frame" x="284" y="41" width="13" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
|
|
@ -640,7 +639,7 @@
|
|||
</subviews>
|
||||
</view>
|
||||
<tableView hidden="YES" clipsSubviews="YES" tag="6992" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="iwm-pi-mku" userLabel="popupMenu">
|
||||
<rect key="frame" x="13" y="66" width="311" height="132"/>
|
||||
<rect key="frame" x="-10" y="66" width="313" height="132"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</tableView>
|
||||
|
|
|
|||
|
|
@ -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="21701" 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="21678"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -212,6 +212,7 @@
|
|||
<outlet property="toggleSelectionButton" destination="uqG-2T-VOa" id="ytx-bj-7Qr"/>
|
||||
<outlet property="view" destination="6" id="13"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="460" y="-11"/>
|
||||
</tableViewController>
|
||||
</objects>
|
||||
<resources>
|
||||
|
|
|
|||
|
|
@ -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="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<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>
|
||||
<objects>
|
||||
|
|
@ -16,6 +19,7 @@
|
|||
<outlet property="emptyLabel" destination="Mdj-Pz-nu4" id="ijc-2c-waE"/>
|
||||
<outlet property="landscapeView" destination="lgD-Mw-h57" id="DTS-80-rMM"/>
|
||||
<outlet property="nameLabel" destination="moZ-Bg-zcv" id="Lt9-h0-2o1"/>
|
||||
<outlet property="organizationLabel" destination="pAA-jk-E4s" id="J0M-Ms-5dp"/>
|
||||
<outlet property="portraitView" destination="1" id="k69-5P-ieM"/>
|
||||
<outlet property="tableController" destination="20" id="27"/>
|
||||
<outlet property="view" destination="1" id="3"/>
|
||||
|
|
@ -24,19 +28,19 @@
|
|||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="XnN-PU-Vk7" userLabel="iphone6MetricsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1">
|
||||
<rect key="frame" x="0.0" y="42" width="375" height="559"/>
|
||||
<rect key="frame" x="0.0" y="42" width="393" height="744"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view alpha="0.90000000000000002" tag="1" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4" userLabel="topBar">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button hidden="YES" opaque="NO" tag="3" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bPQ-aJ-Lk6" userLabel="cancelButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="75" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="79" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delete all"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -50,7 +54,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="4" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9" userLabel="backButton" customClass="UIInterfaceStyleButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="75" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="79" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Back"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
@ -66,7 +70,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="5" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="MuB-yy-R9o" userLabel="deleteButton" customClass="UIInterfaceStyleToggleButton">
|
||||
<rect key="frame" x="225" y="0.0" width="75" height="66"/>
|
||||
<rect key="frame" x="236" y="0.0" width="78" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delete"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
@ -82,7 +86,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="6" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8" userLabel="editButton" customClass="UIInterfaceStyleToggleButton">
|
||||
<rect key="frame" x="300" y="0.0" width="75" height="66"/>
|
||||
<rect key="frame" x="314" y="0.0" width="79" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Edit"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
|
|
@ -99,30 +103,37 @@
|
|||
</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>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" tag="7" contentMode="scaleToFill" fixedFrame="YES" directionalLockEnabled="YES" showsHorizontalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8D6-vy-obt" userLabel="contentView">
|
||||
<rect key="frame" x="0.0" y="66" width="375" height="493"/>
|
||||
<rect key="frame" x="0.0" y="66" width="393" height="678"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView tag="8" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="B6X-C9-2vm" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<rect key="frame" x="142" y="10" width="90" height="90"/>
|
||||
<imageView tag="8" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="B6X-C9-2vm" userLabel="avatarImage">
|
||||
<rect key="frame" x="150" y="10" width="90" height="90"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="8bV-f4-pLL" appends="YES" id="4V5-Px-aHT"/>
|
||||
</connections>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" tag="9" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="John Doe" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="moZ-Bg-zcv" userLabel="nameLabel">
|
||||
<rect key="frame" x="0.0" y="108" width="375" height="40"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" tag="9" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="John Doe" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="moZ-Bg-zcv" userLabel="nameLabel" customClass="CopyableLabel" customModule="linphoneapp" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="108" width="393" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="27"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Organization" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="pAA-jk-E4s" userLabel="organizationLabel">
|
||||
<rect key="frame" x="0.0" y="148" width="393" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="22"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<tableView clipsSubviews="YES" tag="10" contentMode="scaleToFill" fixedFrame="YES" directionalLockEnabled="YES" alwaysBounceVertical="YES" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" style="plain" allowsSelection="NO" allowsSelectionDuringEditing="YES" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="19" userLabel="tableView">
|
||||
<rect key="frame" x="0.0" y="156" width="375" height="337"/>
|
||||
<rect key="frame" x="0.0" y="176" width="393" height="502"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<inset key="scrollIndicatorInsets" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="20" id="28"/>
|
||||
|
|
@ -130,26 +141,26 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</scrollView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" tag="40" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="No contact selected" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mdj-Pz-nu4" userLabel="emptyLabel">
|
||||
<rect key="frame" x="0.0" y="66" width="375" height="493"/>
|
||||
<rect key="frame" x="0.0" y="66" width="393" height="678"/>
|
||||
<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="JK8-Td-I1i" userLabel="waitView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="559"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="744"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" tag="9" contentMode="scaleToFill" fixedFrame="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="J67-KE-kHm" userLabel="activityIndicatorView">
|
||||
<rect key="frame" x="179" y="267" width="20" height="20"/>
|
||||
<rect key="frame" x="188" y="358" width="20" height="20"/>
|
||||
<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>
|
||||
|
|
@ -244,7 +255,7 @@
|
|||
<rect key="frame" x="0.0" y="66" width="667" height="267"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView tag="8" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="IJJ-eZ-rC2" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<imageView tag="8" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="IJJ-eZ-rC2" userLabel="avatarImage">
|
||||
<rect key="frame" x="46" y="8" width="62" height="62"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
|
|
@ -321,5 +332,11 @@
|
|||
<image name="edit_default.png" width="46.400001525878906" height="46.400001525878906"/>
|
||||
<image name="edit_disabled.png" width="46.400001525878906" height="46.400001525878906"/>
|
||||
<image name="valid_default.png" width="44.799999237060547" height="30.399999618530273"/>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -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="21701" 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="21678"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -12,11 +12,14 @@
|
|||
<connections>
|
||||
<outlet property="addButton" destination="6" id="91"/>
|
||||
<outlet property="allButton" destination="4" id="27"/>
|
||||
<outlet property="deleteButton" destination="DZc-zR-1Q7" id="M6N-vO-UIb"/>
|
||||
<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"/>
|
||||
<outlet property="searchBar" destination="5jE-oF-d45" id="xfS-xo-2Bm"/>
|
||||
<outlet property="selectedButtonImage" destination="A9k-KU-Dlm" id="4dX-pd-Y2D"/>
|
||||
<outlet property="switchView" destination="93" id="4iM-Fl-F9B"/>
|
||||
<outlet property="tableController" destination="TJG-JZ-YRR" id="0lt-gC-EOm"/>
|
||||
<outlet property="toggleSelectionButton" destination="5lZ-u7-Yex" id="ULR-WM-Yuo"/>
|
||||
<outlet property="topBar" destination="3" id="w1O-2o-b18"/>
|
||||
|
|
@ -179,6 +182,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 +198,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 +220,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="21507" 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="21505"/>
|
||||
<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,22 +66,22 @@
|
|||
</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"/>
|
||||
<imageView userInteractionEnabled="NO" tag="8" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="23" userLabel="avatarImage">
|
||||
<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"/>
|
||||
<bool key="isElement" value="YES"/>
|
||||
</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"/>
|
||||
<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" customClass="CopyableLabel" customModule="linphoneapp" customModuleProvider="target">
|
||||
<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,15 +89,15 @@
|
|||
<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"/>
|
||||
<bool key="isElement" value="YES"/>
|
||||
</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"/>
|
||||
<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" customClass="CopyableLabel" customModule="linphoneapp" customModuleProvider="target">
|
||||
<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"/>
|
||||
<imageView userInteractionEnabled="NO" tag="8" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="d9m-G0-1u3" userLabel="avatarImage">
|
||||
<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
|
||||
|
|
@ -82,10 +82,47 @@
|
|||
[self searchBar:_searchBar textDidChange:_searchBar.text];
|
||||
self.tableView.accessibilityIdentifier = @"Suggested addresses";
|
||||
|
||||
NSDictionary* userInfo;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector: @selector(receivePresenceNotification:)
|
||||
name: @"LinphoneFriendPresenceUpdate"
|
||||
object: userInfo];
|
||||
}
|
||||
|
||||
-(void) receivePresenceNotification:(NSNotification*)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:@"LinphoneFriendPresenceUpdate"])
|
||||
{
|
||||
NSDictionary* userInfo = notification.userInfo;
|
||||
NSString* friend = (NSString*)userInfo[@"friend"];
|
||||
|
||||
for (int i = 0; i < _addresses.count; i++)
|
||||
{
|
||||
|
||||
NSString *key = [_addresses objectAtIndex:i];
|
||||
Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:[FastAddressBook normalizeSipURI:key use_prefix:[CallManager.instance applyInternationalPrefix]]];
|
||||
if (!contact) {
|
||||
contact = [_ldapAndProvisioningContactAddressBookMap objectForKey:key];
|
||||
}
|
||||
|
||||
if (contact.friend != nil && linphone_friend_get_address(contact.friend) != nil) {
|
||||
char *curi = linphone_address_as_string_uri_only(linphone_friend_get_address(contact.friend));
|
||||
NSString *uri = [NSString stringWithUTF8String:curi];
|
||||
|
||||
if([uri isEqual:friend]){
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:0];
|
||||
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
|
||||
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) viewWillDisappear:(BOOL)animated {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneFriendPresenceUpdate" object:nil];
|
||||
[AvatarBridge removeAllObserver];
|
||||
_notFirstTime = FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -97,64 +134,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]) || [LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"]) {
|
||||
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 +217,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 +241,7 @@
|
|||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
|
||||
return 60.0;
|
||||
return 60.0;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -203,12 +252,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 +265,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]];
|
||||
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 +302,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];
|
||||
|
|
|
|||
|
|
@ -69,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;
|
||||
|
|
@ -90,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"]) {
|
||||
|
|
@ -98,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"] || [LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"]) {
|
||||
_chiffreOptionView.hidden = true;
|
||||
_isEncrypted = true;
|
||||
_tableController.isEncrypted = true;
|
||||
_allButton.hidden = true;
|
||||
_linphoneButton.hidden = true;
|
||||
_selectedButtonImage.hidden = true;
|
||||
}
|
||||
|
||||
if (_isForVoipConference) {
|
||||
_switchView.hidden = true;
|
||||
|
|
@ -110,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 {
|
||||
|
|
@ -131,14 +159,14 @@ 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"] || [LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"]; // 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 && !(_isForVoipConference||_isForOngoingVoipConference);
|
||||
|
|
@ -164,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
|
||||
|
|
@ -184,7 +211,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_tableController.contactsGroup removeAllObjects];
|
||||
if (_isForVoipConference) {
|
||||
if (_isForOngoingVoipConference) {
|
||||
[PhoneMainView.instance changeCurrentView:VIEW(ActiveCallOrConferenceView).compositeViewDescription];
|
||||
[PhoneMainView.instance popToView:VIEW(ConferenceCallView).compositeViewDescription];
|
||||
[ControlsViewModelBridge showParticipants];
|
||||
} else {
|
||||
[PhoneMainView.instance popToView:ConferenceSchedulingView.compositeViewDescription];
|
||||
|
|
@ -200,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];
|
||||
|
|
@ -280,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;
|
||||
}
|
||||
|
|
@ -302,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,23 +85,33 @@ 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,
|
||||
self.view.frame.size.width,
|
||||
messageSize.height+5)];
|
||||
if (messageSize.height > self.view.bounds.size.height/2) {
|
||||
[_msgView setFrame:CGRectMake(_msgView.frame.origin.x,
|
||||
_msgView.frame.origin.y,
|
||||
self.view.frame.size.width,
|
||||
self.view.bounds.size.height/2 +5)];
|
||||
} else {
|
||||
[_msgView setFrame:CGRectMake(_msgView.frame.origin.x,
|
||||
_msgView.frame.origin.y,
|
||||
self.view.frame.size.width,
|
||||
messageSize.height+5)];
|
||||
}
|
||||
|
||||
[_tableView setFrame:CGRectMake(_tableView.frame.origin.x,
|
||||
_msgView.frame.origin.y + _msgView.frame.size.height + 10,
|
||||
|
|
@ -299,7 +304,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;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#import "ChatConversationInfoView.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import "UIChatConversationInfoTableViewCell.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
#import "linphone/core.h"
|
||||
|
||||
|
|
@ -84,6 +85,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_room = NULL;
|
||||
_chatRoomCbs = NULL;
|
||||
_peerAddress = NULL;
|
||||
_localAddress = NULL;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
|
@ -95,10 +97,45 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector:@selector(onLinphoneCoreReady:)
|
||||
name:kLinphoneGlobalStateUpdate
|
||||
object:nil];
|
||||
|
||||
NSDictionary* userInfo;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector: @selector(receivePresenceNotification:)
|
||||
name: @"LinphoneFriendPresenceUpdate"
|
||||
object: userInfo];
|
||||
}
|
||||
|
||||
-(void) receivePresenceNotification:(NSNotification*)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:@"LinphoneFriendPresenceUpdate"])
|
||||
{
|
||||
NSDictionary* userInfo = notification.userInfo;
|
||||
NSString* friend = (NSString*)userInfo[@"friend"];
|
||||
|
||||
for (int i = 0; i < _contacts.count; i++)
|
||||
{
|
||||
|
||||
NSString *uri = _contacts[i];
|
||||
LinphoneAddress *addr = linphone_address_new(uri.UTF8String);
|
||||
|
||||
if (addr != nil) {
|
||||
char *curi = linphone_address_as_string_uri_only(addr);
|
||||
NSString *uri = [NSString stringWithUTF8String:curi];
|
||||
|
||||
if([uri isEqual:friend]){
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:0];
|
||||
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
|
||||
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneFriendPresenceUpdate" object:nil];
|
||||
[AvatarBridge removeAllObserver];
|
||||
if (!_room || !_chatRoomCbs)
|
||||
return;
|
||||
|
||||
|
|
@ -153,10 +190,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];
|
||||
}
|
||||
|
|
@ -181,7 +219,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (void)onValidate {
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
// Change subject if necessary
|
||||
if (![_oldSubject isEqualToString:_nameLabel.text])
|
||||
linphone_chat_room_set_subject(_room, _nameLabel.text.UTF8String);
|
||||
|
|
@ -277,7 +315,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
view.isForVoipConference = FALSE;
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
} else {
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
}
|
||||
|
|
@ -326,7 +364,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
cell.uri = _contacts[indexPath.row];
|
||||
LinphoneAddress *addr = linphone_address_new(cell.uri.UTF8String);
|
||||
cell.nameLabel.text = (addr == nil? cell.uri : [FastAddressBook displayNameForAddress:addr]);
|
||||
[cell.avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:YES withRoundedRadius:YES];
|
||||
[cell.avatarImage setImage:[FastAddressBook imageForAddress:addr]];
|
||||
cell.controllerView = self;
|
||||
if(![_admins containsObject:cell.uri]) {
|
||||
cell.adminLabel.enabled = FALSE;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#import "UICheckBoxTableView.h"
|
||||
|
||||
|
||||
@interface FileContext : NSObject
|
||||
@property NSMutableArray <NSString *> *typesArray;
|
||||
@property NSMutableArray <NSData *> *datasArray;
|
||||
|
|
@ -60,6 +61,7 @@
|
|||
@property(nonatomic) NSTimer *ephemeralDisplayTimer;
|
||||
@property (nullable, nonatomic) UIButton *floatingScrollButton;
|
||||
@property (nullable, nonatomic) UILabel *scrollBadge;
|
||||
@property (nullable, nonatomic) UIButton *floatingScrollBackground;
|
||||
|
||||
- (void)addEventEntry:(LinphoneEventLog *)event;
|
||||
- (void)scrollToBottom:(BOOL)animated;
|
||||
|
|
@ -70,5 +72,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];
|
||||
}
|
||||
|
||||
|
|
@ -171,9 +168,9 @@
|
|||
//[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:(count - 1) inSection:0]];
|
||||
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:(count - 1) inSection:0]
|
||||
atScrollPosition:UITableViewScrollPositionBottom
|
||||
animated:YES];
|
||||
animated:animated];
|
||||
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
|
||||
[ChatConversationView markAsRead:_chatRoom];
|
||||
[ChatConversationViewSwift markAsRead:_chatRoom];
|
||||
}
|
||||
|
||||
- (void)scrollToLastUnread:(BOOL)animated {
|
||||
|
|
@ -203,7 +200,7 @@
|
|||
index = (int)count - 1;
|
||||
|
||||
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
|
||||
[ChatConversationView markAsRead:_chatRoom];
|
||||
[ChatConversationViewSwift markAsRead:_chatRoom];
|
||||
|
||||
// Scroll to unread
|
||||
if (index < 0)
|
||||
|
|
@ -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)
|
||||
[ChatConversationViewSwift markAsRead:_chatRoom];
|
||||
}
|
||||
}
|
||||
|
||||
static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f;
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -423,7 +431,7 @@ static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f;
|
|||
title:NSLocalizedString(@"Reply", nil)
|
||||
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
|
||||
LinphoneChatMessage *msg = linphone_event_log_get_chat_message(event);
|
||||
[VIEW(ChatConversationView) initiateReplyViewForMessage:msg];
|
||||
[VIEW(ChatConversationViewSwift) initiateReplyViewForMessage:msg];
|
||||
[self scrollToBottom:TRUE];
|
||||
}];
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -213,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
|
||||
|
|
@ -233,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:)
|
||||
|
|
@ -247,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.
|
||||
|
|
@ -309,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 {
|
||||
|
|
@ -325,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)
|
||||
|
|
@ -353,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) {
|
||||
|
|
@ -375,7 +398,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
linphone_chat_room_cbs_set_is_composing_received(_chatRoomCbs, on_chat_room_is_composing_received);
|
||||
linphone_chat_room_cbs_set_conference_joined(_chatRoomCbs, on_chat_room_conference_joined);
|
||||
linphone_chat_room_cbs_set_conference_left(_chatRoomCbs, on_chat_room_conference_left);
|
||||
linphone_chat_room_cbs_set_security_event(_chatRoomCbs, on_chat_room_conference_alert);
|
||||
linphone_chat_room_cbs_set_security_event(_chatRoomCbs, on_chat_room_conference_alert);
|
||||
linphone_chat_room_cbs_set_user_data(_chatRoomCbs, (__bridge void*)self);
|
||||
linphone_chat_room_add_callbacks(_chatRoom, _chatRoomCbs);
|
||||
}
|
||||
|
|
@ -397,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];
|
||||
|
||||
|
|
@ -428,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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -485,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 {
|
||||
|
|
@ -600,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)];
|
||||
|
|
@ -659,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 {
|
||||
|
|
@ -773,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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -783,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 {
|
||||
|
|
@ -939,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];
|
||||
}
|
||||
|
||||
|
|
@ -1051,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];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1417,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]];
|
||||
}
|
||||
|
|
@ -1723,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));
|
||||
|
|
@ -1756,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)
|
||||
|
|
@ -1775,12 +1809,12 @@ 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];
|
||||
|
||||
int firstIndex = isOneToOne ? 0 : 1;
|
||||
|
||||
|
|
@ -1791,7 +1825,14 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
|
||||
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];
|
||||
}
|
||||
|
|
@ -1808,7 +1849,8 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
if ((!isEncrypted && indexPath.row == 1+firstIndex) || (isEncrypted && indexPath.row == 3+firstIndex)) {
|
||||
[self toggleMuteConversation];
|
||||
[LinphoneManager setChatroomPushEnabled:_chatRoom withPushEnabled:![LinphoneManager getChatroomPushEnabled:_chatRoom]];
|
||||
[_popupMenu reloadData];
|
||||
}
|
||||
|
||||
if ((!isEncrypted && indexPath.row == 2+firstIndex) || (isEncrypted && indexPath.row == 4+firstIndex)) {
|
||||
|
|
@ -1849,31 +1891,44 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [[UITableViewCell alloc] init];
|
||||
|
||||
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 = [LinphoneUtils resizeImage:[UIImage imageNamed:@"menu_voip_meeting_schedule"] newSize:CGSizeMake(25, 25)];
|
||||
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+firstIndex) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"menu_security_default.png"] newSize:CGSizeMake(20, 25)];
|
||||
cell.imageView.image = [UIImage imageNamed:@"menu_security_default.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Conversation's devices",nil);
|
||||
}
|
||||
|
||||
|
|
@ -1884,27 +1939,32 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
}
|
||||
|
||||
if ((isEncrypted && indexPath.row == 3+firstIndex) || (!isEncrypted && indexPath.row == 1+firstIndex)) {
|
||||
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 ([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+firstIndex) || (!isEncrypted && indexPath.row == 2+firstIndex)) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"delete_default.png"] newSize:CGSizeMake(20, 25)];
|
||||
cell.imageView.image = [UIImage imageNamed:@"delete_default.png"];
|
||||
cell.textLabel.text = NSLocalizedString(@"Delete messages",nil);
|
||||
}
|
||||
|
||||
if ((isEncrypted && ((!canEphemeral && indexPath.row == 4+firstIndex)||(canEphemeral && indexPath.row == 5+firstIndex)))
|
||||
|| (!isEncrypted && indexPath.row == 3+firstIndex)) {
|
||||
cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"chat_group_informations.png"] newSize:CGSizeMake(25, 25)];
|
||||
cell.textLabel.text = NSLocalizedString(@"Show address and identity",nil);
|
||||
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 {
|
||||
|
|
@ -2213,6 +2273,7 @@ void on_shared_player_eof_reached(LinphonePlayer *p) {
|
|||
_showReplyView = true;
|
||||
[self updateFramesInclRecordingAndReplyView];
|
||||
[self.tableController scrollToMessage:message];
|
||||
[self.messageField becomeFirstResponder];
|
||||
}
|
||||
|
||||
-(void) handlePendingTransferIfAny {
|
||||
|
|
|
|||
|
|
@ -31,4 +31,5 @@
|
|||
|
||||
- (void)loadData;
|
||||
- (void)markCellAsRead:(LinphoneChatRoom *)chatRoom;
|
||||
- (void)updateEventEntry:(LinphoneChatMessage *)msg;
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#import "ChatsListTableView.h"
|
||||
#import "UIChatCell.h"
|
||||
#import "FileTransferDelegate.h"
|
||||
|
||||
#import "linphoneapp-Swift.h"
|
||||
#import "linphone/linphonecore.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import "Utils.h"
|
||||
|
|
@ -41,6 +41,11 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
bctbx_list_free(_data);
|
||||
}
|
||||
|
||||
#pragma mark - ViewController Functions
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
|
@ -48,15 +53,53 @@
|
|||
self.tableView.accessibilityIdentifier = @"Chat list";
|
||||
[self loadData];
|
||||
_chatRooms = NULL;
|
||||
|
||||
NSDictionary* userInfo;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector: @selector(receivePresenceNotification:)
|
||||
name: @"LinphoneFriendPresenceUpdate"
|
||||
object: userInfo];
|
||||
}
|
||||
|
||||
-(void) receivePresenceNotification:(NSNotification*)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:@"LinphoneFriendPresenceUpdate"])
|
||||
{
|
||||
NSDictionary* userInfo = notification.userInfo;
|
||||
NSString* friend = (NSString*)userInfo[@"friend"];
|
||||
|
||||
for (int i = 0; i < bctbx_list_size(_data); i++)
|
||||
{
|
||||
LinphoneChatRoom *chatRoom = (LinphoneChatRoom *)bctbx_list_nth_data(_data, i);
|
||||
|
||||
bctbx_list_t *participants = linphone_chat_room_get_participants(chatRoom);
|
||||
if (linphone_chat_room_get_nb_participants(chatRoom) == 1) {
|
||||
LinphoneParticipant *firstParticipant = participants ? (LinphoneParticipant *)participants->data : NULL;
|
||||
|
||||
char *curi = linphone_address_as_string_uri_only(linphone_participant_get_address(firstParticipant));
|
||||
NSString *uri = [NSString stringWithUTF8String:curi];
|
||||
|
||||
LinphoneChatRoomCapabilitiesMask capabilities = linphone_chat_room_get_capabilities(chatRoom);
|
||||
bool oneToOne = capabilities & LinphoneChatRoomCapabilitiesOneToOne;
|
||||
if(oneToOne && [uri isEqual:friend]){
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:0];
|
||||
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
|
||||
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
// we cannot do that in viewWillAppear because we will change view while previous transition
|
||||
// was not finished, leading to "[CALayer retain]: message sent to deallocated instance" error msg
|
||||
/*
|
||||
if (IPAD && [self totalNumberOfItems] > 0) {
|
||||
[PhoneMainView.instance changeCurrentView:ChatConversationView.compositeViewDescription];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
|
@ -72,6 +115,9 @@
|
|||
}
|
||||
_chatRooms = _chatRooms->next;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneFriendPresenceUpdate" object:nil];
|
||||
[AvatarBridge removeAllObserver];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
|
|
@ -114,6 +160,7 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
|
|||
_data = [self sortChatRooms];
|
||||
[super loadData];
|
||||
|
||||
/*
|
||||
if (IPAD) {
|
||||
int idx = bctbx_list_index(_data, VIEW(ChatConversationView).chatRoom);
|
||||
// if conversation view is using a chatroom that does not exist anymore, update it
|
||||
|
|
@ -131,15 +178,28 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
|
|||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)updateEventEntry:(LinphoneChatMessage *)msg {
|
||||
int idx = bctbx_list_index(_data, linphone_chat_message_get_chat_room(msg));
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
|
||||
if (idx < 0) {
|
||||
LOGW(@"event entry doesn't exist");
|
||||
return;
|
||||
}
|
||||
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:FALSE];
|
||||
}
|
||||
|
||||
- (void)markCellAsRead:(LinphoneChatRoom *)chatRoom {
|
||||
int idx = bctbx_list_index(_data, VIEW(ChatConversationView).chatRoom);
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
|
||||
/*
|
||||
if (IPAD) {
|
||||
UIChatCell *cell = (UIChatCell *)[self.tableView cellForRowAtIndexPath:indexPath];
|
||||
[cell updateUnreadBadge];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource Functions
|
||||
|
|
@ -164,7 +224,7 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
|
|||
|
||||
[cell setChatRoom:(LinphoneChatRoom *)bctbx_list_nth_data(_data, (int)[indexPath row])];
|
||||
[super accessoryForCell:cell atPath:indexPath];
|
||||
BOOL forwardMode = VIEW(ChatConversationView).pendingForwardMessage != nil;
|
||||
BOOL forwardMode = VIEW(ChatConversationViewSwift).pendingForwardMessage != nil;
|
||||
cell.forwardIcon.hidden = !forwardMode;
|
||||
if (forwardMode) {
|
||||
cell.ephemeral.hidden = true;
|
||||
|
|
@ -186,12 +246,12 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
|
|||
return;
|
||||
|
||||
LinphoneChatRoom *chatRoom = (LinphoneChatRoom *)bctbx_list_nth_data(_data, (int)[indexPath row]);
|
||||
[PhoneMainView.instance goToChatRoom:chatRoom];
|
||||
[PhoneMainView.instance goToChatRoomSwift:chatRoom];
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
@ -232,7 +292,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@
|
|||
|
||||
- (IBAction)onAddGroupChatClick:(id)event;
|
||||
- (IBAction)onAddClick:(id)event;
|
||||
- (IBAction)onChatRoomSwiftClick:(id)event;
|
||||
- (IBAction)onEditionChangeClick:(id)sender;
|
||||
- (IBAction)onDeleteClick:(id)sender;
|
||||
|
||||
-(void) mediaSharing;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#import "PhoneMainView.h"
|
||||
|
||||
#import "ChatConversationCreateView.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
@implementation ChatsListView
|
||||
|
||||
#pragma mark - ViewController Functions
|
||||
|
|
@ -39,6 +40,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 +59,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(ChatConversationViewSwift).sharingMedia = TRUE;
|
||||
|
||||
if(VIEW(ChatConversationViewSwift).sharingMedia == false){
|
||||
forwardMode = VIEW(ChatConversationViewSwift).pendingForwardMessage != nil;
|
||||
}else{
|
||||
forwardMode = VIEW(ChatConversationViewSwift).sharingMedia != false;
|
||||
}
|
||||
_tableController.editButton.hidden = forwardMode;
|
||||
_forwardTitle.text = NSLocalizedString(@"Select a discussion or create a new one",nil);
|
||||
if(VIEW(ChatConversationViewSwift).sharingMedia == false){
|
||||
_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];
|
||||
|
|
@ -128,14 +156,18 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (IBAction)onAddGroupChatClick:(id)event {
|
||||
[self newChatCreate:TRUE];
|
||||
if (IPAD)
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneChatCreateViewChange object:VIEW(ChatConversationCreateView) userInfo:nil];
|
||||
//if (IPAD)
|
||||
//[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneChatCreateViewChange object:VIEW(ChatConversationCreateView) userInfo:nil];
|
||||
}
|
||||
|
||||
- (IBAction)onChatRoomSwiftClick:(id)event {
|
||||
[PhoneMainView.instance changeCurrentView:ChatConversationViewSwift.compositeViewDescription];
|
||||
}
|
||||
|
||||
- (IBAction)onAddClick:(id)event {
|
||||
[self newChatCreate:FALSE];
|
||||
if (IPAD)
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneChatCreateViewChange object:VIEW(ChatConversationCreateView) userInfo:nil];
|
||||
//if (IPAD)
|
||||
//[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneChatCreateViewChange object:VIEW(ChatConversationCreateView) userInfo:nil];
|
||||
}
|
||||
|
||||
- (IBAction)onEditionChangeClick:(id)sender {
|
||||
|
|
@ -173,8 +205,16 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (IBAction)onCancelForwardClicked:(id)sender {
|
||||
VIEW(ChatConversationView).pendingForwardMessage = nil;
|
||||
VIEW(ChatConversationViewSwift).sharingMedia = false;
|
||||
VIEW(ChatConversationViewSwift).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
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@
|
|||
@property(nonatomic, retain) NSString *identifier;
|
||||
@property(nonatomic, retain) NSString *firstName;
|
||||
@property(nonatomic, retain) NSString *lastName;
|
||||
@property(nonatomic, retain) NSString *organizationName;
|
||||
@property(nonatomic, retain) NSString *displayName;
|
||||
@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 +59,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];
|
||||
|
|
@ -44,6 +44,7 @@
|
|||
_identifier = _person.identifier;
|
||||
_firstName = _person.givenName;
|
||||
_lastName = _person.familyName;
|
||||
_organizationName = _person.organizationName;
|
||||
_displayName = [NSString stringWithFormat:@"%@ %@", _firstName, _lastName];
|
||||
for (CNLabeledValue<CNPhoneNumber *> *phoneNumber in _person.phoneNumbers) {
|
||||
[_phones addObject:phoneNumber.value.stringValue];
|
||||
|
|
@ -64,13 +65,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);
|
||||
|
|
@ -80,14 +85,15 @@
|
|||
for (NSString *phone in _phones) {
|
||||
linphone_friend_add_phone_number(_friend, phone.UTF8String);
|
||||
}
|
||||
if (_organizationName) {
|
||||
linphone_friend_set_organization(_friend, [_organizationName UTF8String]);
|
||||
}
|
||||
if (_friend) {
|
||||
linphone_friend_enable_subscribes(_friend, FALSE);
|
||||
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 +293,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 +376,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 +467,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 +486,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
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ typedef enum _ContactSections {
|
|||
ContactSections_None = 0, // first section is empty because we cannot set header for first section
|
||||
ContactSections_FirstName,
|
||||
ContactSections_LastName,
|
||||
ContactSections_Organization,
|
||||
ContactSections_Sip,
|
||||
ContactSections_Number,
|
||||
ContactSections_Email,
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
}
|
||||
|
||||
- (BOOL)isValid {
|
||||
BOOL hasName = (_contact.firstName.length + _contact.lastName.length > 0);
|
||||
BOOL hasName = (_contact.firstName.length + _contact.lastName.length + _contact.organizationName.length > 0);
|
||||
BOOL hasAddr =
|
||||
(_contact.phones.count + _contact.sipAddresses.count) > 0;
|
||||
return hasName && hasAddr;
|
||||
|
|
@ -156,19 +156,19 @@
|
|||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (section == ContactSections_FirstName || section == ContactSections_LastName) {
|
||||
if (section == ContactSections_FirstName || section == ContactSections_LastName || section == ContactSections_Organization) {
|
||||
/*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 {
|
||||
|
|
@ -192,6 +192,9 @@
|
|||
} else if (indexPath.section == ContactSections_LastName) {
|
||||
value = _contact.lastName;
|
||||
[cell hideDeleteButton:YES];
|
||||
} else if (indexPath.section == ContactSections_Organization) {
|
||||
value = _contact.organizationName;
|
||||
[cell hideDeleteButton:YES];
|
||||
} else if ([indexPath section] == ContactSections_Number) {
|
||||
value = _contact.phones[indexPath.row];
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad];
|
||||
|
|
@ -200,7 +203,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]];
|
||||
|
|
@ -279,11 +282,14 @@
|
|||
} else if (section == ContactSections_LastName && self.tableView.isEditing) {
|
||||
text = NSLocalizedString(@"Last name", nil);
|
||||
canAddEntry = NO;
|
||||
} else if (section == ContactSections_Organization && self.tableView.isEditing) {
|
||||
text = NSLocalizedString(@"Organization", nil);
|
||||
canAddEntry = NO;
|
||||
} else if ([self getSectionData:section].count > 0 || self.tableView.isEditing) {
|
||||
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 &&
|
||||
|
|
@ -358,7 +364,7 @@
|
|||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
||||
if (section == 0 ||
|
||||
(!self.tableView.isEditing && (section == ContactSections_FirstName || section == ContactSections_LastName))) {
|
||||
(!self.tableView.isEditing && (section == ContactSections_FirstName || section == ContactSections_LastName || section == ContactSections_LastName))) {
|
||||
return 1e-5;
|
||||
}
|
||||
return [self tableView:tableView viewForHeaderInSection:section].frame.size.height;
|
||||
|
|
@ -390,6 +396,9 @@
|
|||
case ContactSections_LastName:
|
||||
_contact.lastName = value;
|
||||
break;
|
||||
case ContactSections_Organization:
|
||||
_contact.organizationName = value;
|
||||
break;
|
||||
case ContactSections_Sip:
|
||||
[_contact setSipAddress:value atIndex:path.row];
|
||||
value = _contact.sipAddresses[path.row]; // in case of reformatting
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@
|
|||
@property(nonatomic, strong) IBOutlet UIToggleButton *editButton;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *backButton;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *cancelButton;
|
||||
@property(weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property(weak, nonatomic) IBOutlet UIImageView *avatarImage;
|
||||
@property(weak, nonatomic) IBOutlet UILabel *nameLabel;
|
||||
@property(weak, nonatomic) IBOutlet UILabel *organizationLabel;
|
||||
@property(weak, nonatomic) IBOutlet UIToggleButton *deleteButton;
|
||||
@property(weak, nonatomic) IBOutlet UIScrollView *contentView;
|
||||
@property(weak, nonatomic) IBOutlet UILabel *emptyLabel;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#import "ContactDetailsView.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import "UIContactDetailsCell.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
@implementation ContactDetailsView
|
||||
|
||||
|
|
@ -63,7 +64,7 @@
|
|||
}
|
||||
|
||||
LOGI(@"Reset data to contact %p", _contact);
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact] bordered:NO withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact]];
|
||||
[_tableController setContact:_contact];
|
||||
_emptyLabel.hidden = YES;
|
||||
_avatarImage.hidden = !_emptyLabel.hidden;
|
||||
|
|
@ -91,24 +92,25 @@
|
|||
[PhoneMainView.instance popCurrentView];
|
||||
return;
|
||||
}
|
||||
PhoneMainView.instance.currentName = _contact.displayName;
|
||||
_nameLabel.text = PhoneMainView.instance.currentName;
|
||||
|
||||
// fix no sipaddresses in contact.friend
|
||||
const MSList *sips = linphone_friend_get_addresses(_contact.friend);
|
||||
while (sips) {
|
||||
linphone_friend_remove_address(_contact.friend, sips->data);
|
||||
sips = sips->next;
|
||||
}
|
||||
|
||||
for (NSString *sipAddr in _contact.sipAddresses) {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url(LC, sipAddr.UTF8String);
|
||||
if (addr) {
|
||||
linphone_friend_add_address(_contact.friend, addr);
|
||||
linphone_address_destroy(addr);
|
||||
}
|
||||
}
|
||||
[LinphoneManager.instance.fastAddressBook saveContact:_contact];
|
||||
PhoneMainView.instance.currentName = _contact.displayName;
|
||||
_nameLabel.text = PhoneMainView.instance.currentName;
|
||||
_organizationLabel.text = _contact.organizationName;
|
||||
|
||||
// fix no sipaddresses in contact.friend
|
||||
const MSList *sips = linphone_friend_get_addresses(_contact.friend);
|
||||
while (sips) {
|
||||
linphone_friend_remove_address(_contact.friend, sips->data);
|
||||
sips = sips->next;
|
||||
}
|
||||
|
||||
for (NSString *sipAddr in _contact.sipAddresses) {
|
||||
LinphoneAddress *addr = linphone_core_interpret_url_2(LC, sipAddr.UTF8String, true);
|
||||
if (addr) {
|
||||
linphone_friend_add_address(_contact.friend, addr);
|
||||
linphone_address_destroy(addr);
|
||||
}
|
||||
}
|
||||
[LinphoneManager.instance.fastAddressBook saveContact:_contact];
|
||||
}
|
||||
|
||||
- (void)selectContact:(Contact *)acontact andReload:(BOOL)reload {
|
||||
|
|
@ -119,11 +121,12 @@
|
|||
_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];
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact]];
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];
|
||||
_organizationLabel.text = _contact.organizationName;
|
||||
[_tableController setContact:_contact];
|
||||
|
||||
if (reload) {
|
||||
|
|
@ -146,7 +149,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 +287,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 +302,21 @@
|
|||
[_editButton setImage:[UIImage imageNamed:@"valid_default.png"] forState:UIControlStateSelected];
|
||||
|
||||
[self updateBackOrCancelButton];
|
||||
[self recomputeTableViewSize:FALSE];
|
||||
|
||||
NSDictionary* userInfo;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector: @selector(receivePresenceNotification:)
|
||||
name: @"LinphoneFriendPresenceUpdate"
|
||||
object: userInfo];
|
||||
}
|
||||
|
||||
-(void) receivePresenceNotification:(NSNotification*)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:@"LinphoneFriendPresenceUpdate"])
|
||||
{
|
||||
[self resetData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)deviceOrientationDidChange:(NSNotification*)notif {
|
||||
|
|
@ -310,9 +331,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (self.contact != NULL && self.contact.createdFromLdapOrProvisioning) {
|
||||
_editButton.hidden = TRUE;
|
||||
_deleteButton.hidden = TRUE;
|
||||
}
|
||||
_nameLabel.hidden = self.tableController.isEditing;
|
||||
_organizationLabel.hidden = self.tableController.isEditing;
|
||||
[self updateBackOrCancelButton];
|
||||
|
||||
[self recomputeTableViewSize:_editButton.hidden];
|
||||
[self recomputeTableViewSize:self.tableController.isEditing];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
|
@ -343,6 +369,9 @@
|
|||
if (rm) {
|
||||
[LinphoneManager.instance.fastAddressBook deleteContact:_contact];
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneFriendPresenceUpdate" object:nil];
|
||||
[AvatarBridge removeAllObserver];
|
||||
}
|
||||
|
||||
#pragma mark - UICompositeViewDelegate Functions
|
||||
|
|
@ -397,7 +426,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_cancelButton.hidden = !editing;
|
||||
_backButton.hidden = editing;
|
||||
_nameLabel.hidden = editing;
|
||||
_organizationLabel.hidden = editing;
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];
|
||||
_organizationLabel.text = _contact.organizationName;
|
||||
|
||||
[self recomputeTableViewSize:editing];
|
||||
|
||||
|
|
@ -408,10 +439,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 = _organizationLabel.frame.origin.y + _organizationLabel.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;
|
||||
|
|
@ -442,7 +474,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_contact.firstName = _tmpContact.firstName.copy;
|
||||
_contact.lastName = _tmpContact.lastName.copy;
|
||||
_contact.avatar = _tmpContact.avatar.copy;
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact] bordered:NO withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact]];
|
||||
|
||||
while (_contact.sipAddresses.count > 0) {
|
||||
[_contact removeSipAddressAtIndex:0];
|
||||
|
|
@ -514,11 +546,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 +620,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;
|
||||
}
|
||||
|
|
@ -619,7 +651,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
[_contact setAvatar:image];
|
||||
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact] bordered:NO withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[FastAddressBook imageForContact:_contact]];
|
||||
}
|
||||
|
||||
- (void)imagePickerDelegateVideo:(NSURL*)url info:(NSDictionary *)info {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,60 @@
|
|||
[view setContact:nil];
|
||||
}
|
||||
}
|
||||
NSDictionary* userInfo;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector: @selector(receivePresenceNotification:)
|
||||
name: @"LinphoneFriendPresenceUpdate"
|
||||
object: userInfo];
|
||||
}
|
||||
|
||||
-(void)viewWillDisappear:(BOOL)animated{
|
||||
[super viewWillDisappear:animated];
|
||||
[AvatarBridge removeAllObserver];
|
||||
}
|
||||
|
||||
-(void)viewDidDisappear:(BOOL)animated{
|
||||
[super viewDidDisappear:animated];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneFriendPresenceUpdate" object:nil];
|
||||
}
|
||||
|
||||
-(void) receivePresenceNotification:(NSNotification*)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:@"LinphoneFriendPresenceUpdate"])
|
||||
{
|
||||
NSDictionary* userInfo = notification.userInfo;
|
||||
NSString* friend = (NSString*)userInfo[@"friend"];
|
||||
|
||||
NSArray<NSIndexPath *> *indexPathsVisible = self.tableView.indexPathsForVisibleRows;
|
||||
|
||||
for (int i = 0; i < indexPathsVisible.count; i++)
|
||||
{
|
||||
NSMutableArray *subAr = [addressBookMap objectForKey:[addressBookMap keyAtIndex:indexPathsVisible[i].section]];
|
||||
Contact *contact = subAr[indexPathsVisible[i].row];
|
||||
|
||||
if (contact.sipAddresses.count > 0){
|
||||
for (NSString *sip in contact.sipAddresses) {
|
||||
NSString *uri = [@"sip:" stringByAppendingString:sip];
|
||||
|
||||
if([uri isEqual:friend]){
|
||||
NSIndexPath* indexPath = indexPathsVisible[i];
|
||||
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
|
||||
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
}
|
||||
}else if (contact.phones.count > 0){
|
||||
for (NSString *phone in contact.phones) {
|
||||
NSString *uri = phone;
|
||||
|
||||
if([uri isEqual:friend]){
|
||||
NSIndexPath* indexPath = indexPathsVisible[i];
|
||||
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
|
||||
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
|
|
@ -231,7 +285,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) {
|
|||
|
||||
// Cached avatar
|
||||
UIImage *image = [FastAddressBook imageForContact:contact];
|
||||
[cell.avatarImage setImage:image bordered:NO withRoundedRadius:YES];
|
||||
[cell.avatarImage setImage:image];
|
||||
[cell setContact:contact];
|
||||
[super accessoryForCell:cell atPath:indexPath];
|
||||
cell.contentView.userInteractionEnabled = false;
|
||||
|
|
|
|||
|
|
@ -50,14 +50,17 @@ typedef enum _ContactSelectionMode { ContactSelectionModeNone, ContactSelectionM
|
|||
|
||||
@property(strong, nonatomic) IBOutlet ContactsListTableView *tableController;
|
||||
@property(strong, nonatomic) IBOutlet UIView *topBar;
|
||||
@property(strong, nonatomic) IBOutlet UIView *switchView;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *allButton;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *linphoneButton;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *addButton;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *deleteButton;
|
||||
@property(strong, nonatomic) IBOutlet UISearchBar *searchBar;
|
||||
@property(weak, nonatomic) IBOutlet UIImageView *selectedButtonImage;
|
||||
@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;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ static BOOL addAddressFromOthers = FALSE;
|
|||
@synthesize allButton;
|
||||
@synthesize linphoneButton;
|
||||
@synthesize addButton;
|
||||
@synthesize deleteButton;
|
||||
@synthesize topBar;
|
||||
|
||||
typedef enum { ContactsAll, ContactsLinphone, ContactsMAX } ContactsCategory;
|
||||
|
|
@ -96,7 +97,16 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (![[PhoneMainView.instance getPreviousViewName] isEqualToString:@"ContactDetailsView"]) {
|
||||
_searchBar.text = @"";
|
||||
}
|
||||
[self changeView:ContactsAll];
|
||||
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"only_show_sip_contacts_list"]) {
|
||||
_switchView.hidden = true;
|
||||
[self changeView:ContactsLinphone];
|
||||
} else if ([LinphoneManager.instance lpConfigBoolForKey:@"hide_sip_contacts_list"]){
|
||||
_switchView.hidden = true;
|
||||
[self changeView:ContactsAll];
|
||||
} else {
|
||||
[self changeView:ContactsAll];
|
||||
}
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
|
||||
initWithTarget:self
|
||||
|
|
@ -142,6 +152,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 +169,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 +247,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (void)refreshButtons {
|
||||
[addButton setHidden:FALSE];
|
||||
[addButton setHidden:![LinphoneManager.instance lpConfigBoolForKey:@"enable_native_address_book"] || [LinphoneManager.instance lpConfigBoolForKey:@"read_only_native_address_book"]];
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"read_only_native_address_book"]) {
|
||||
addButton.hidden = true;
|
||||
deleteButton.hidden = true;
|
||||
}
|
||||
[self changeView:[ContactSelection getSipFilterEnabled] ? ContactsLinphone : ContactsAll];
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +276,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 +298,13 @@ 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;
|
||||
}
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"read_only_native_address_book"]) {
|
||||
addButton.hidden = true;
|
||||
deleteButton.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
||||
|
|
@ -292,6 +329,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (searchText.length == 0) {
|
||||
[LinphoneManager.instance setContactsUpdated:TRUE];
|
||||
}
|
||||
_ldapMoreResultsLabel.hidden = TRUE;
|
||||
[tableController loadDataWithFilter:searchText];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
#pragma mark - Action Functions
|
||||
- (IBAction)onBackClick:(id)sender {
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -277,16 +285,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
- (BOOL)displayDebugPopup:(NSString *)address {
|
||||
LinphoneManager *mgr = LinphoneManager.instance;
|
||||
NSString *debugAddress = [mgr lpConfigStringForKey:@"debug_popup_magic" withDefault:@""];
|
||||
if (![debugAddress isEqualToString:@""] && [address isEqualToString:debugAddress]) {
|
||||
if ((![debugAddress isEqualToString:@""] && [address isEqualToString:debugAddress]) || [_addressField.text isEqual: @"#1234#"]) {
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Debug", nil)
|
||||
message:NSLocalizedString(@"Choose an action", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
|
||||
int debugLevel = [LinphoneManager.instance lpConfigIntForKey:@"debugenable_preference"];
|
||||
BOOL debugEnabled = (debugLevel >= ORTP_DEBUG && debugLevel < ORTP_ERROR);
|
||||
|
|
@ -314,31 +316,24 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}];
|
||||
[errView addAction:logAction];
|
||||
|
||||
UIAlertAction* remAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Remove account(s) and self destruct", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
linphone_core_clear_accounts([LinphoneManager getLc]);
|
||||
linphone_core_clear_all_auth_info([LinphoneManager getLc]);
|
||||
@try {
|
||||
[LinphoneManager.instance destroyLinphoneCore];
|
||||
} @catch (NSException *e) {
|
||||
LOGW(@"Exception while destroying linphone core: %@", e);
|
||||
} @finally {
|
||||
if ([NSFileManager.defaultManager
|
||||
isDeletableFileAtPath:[LinphoneManager preferenceFile:@"linphonerc"]] == YES) {
|
||||
[NSFileManager.defaultManager
|
||||
removeItemAtPath:[LinphoneManager preferenceFile:@"linphonerc"]
|
||||
error:nil];
|
||||
}
|
||||
#ifdef DEBUG
|
||||
[LinphoneManager instanceRelease];
|
||||
#endif
|
||||
}
|
||||
[UIApplication sharedApplication].keyWindow.rootViewController = nil;
|
||||
// make the application crash to be sure that user restart it properly
|
||||
LOGF(@"Self-destructing in 3..2..1..0!");
|
||||
}];
|
||||
[errView addAction:remAction];
|
||||
UIAlertAction* configAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"View config file", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
TextViewer *view = VIEW(TextViewer);
|
||||
LpConfig *conf = LinphoneManager.instance.configDb;
|
||||
char *config = linphone_config_dump(conf);
|
||||
view.textViewer = [NSString stringWithUTF8String: config];
|
||||
view.textNameViewer = @"";
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}];
|
||||
|
||||
[errView addAction:configAction];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
|
||||
[self presentViewController:errView animated:YES completion:nil];
|
||||
return true;
|
||||
|
|
@ -393,19 +388,39 @@ 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]) {
|
||||
if ([_addressField.text isEqual: @"#1234#"]) {
|
||||
[self displayDebugPopup:_addressField.text];
|
||||
_addressField.text = @"";
|
||||
}
|
||||
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
|
||||
if (!(defaultAccount && linphone_account_params_get_audio_video_conference_factory_address(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 {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#import "EphemeralSettingsView.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import "UIDeviceCell.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
|
||||
|
||||
|
|
@ -74,14 +75,14 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
#pragma mark - Action Functions
|
||||
- (IBAction)onBackClick:(id)sender {
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)onSaveClick:(id)sender {
|
||||
[self setRoomSettingsBasedOnIndex];
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
[PhoneMainView.instance popToView:view.compositeViewDescription];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,66 +8,90 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public extension ChatConversationTableView {
|
||||
extension ChatConversationTableViewSwift {
|
||||
|
||||
private enum Constants {
|
||||
static let trailingValue: CGFloat = 20.0
|
||||
static let trailingValue: CGFloat = 30.0
|
||||
static let leadingValue: CGFloat = 85.0
|
||||
static let buttonHeight: CGFloat = 40.0
|
||||
static let buttonWidth: CGFloat = 40.0
|
||||
static let buttonHeight: CGFloat = 16.0
|
||||
static let buttonWidth: CGFloat = 16.0
|
||||
}
|
||||
|
||||
/*
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
tableView.tableFooterView = UIView()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
createFloatingButton()
|
||||
}
|
||||
*/
|
||||
|
||||
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
if let lastCellRowIndex = tableView.indexPathsForVisibleRows?.last?.row {
|
||||
if( lastCellRowIndex != self.totalNumberOfItems() - 1) {
|
||||
self.floatingScrollButton?.isHidden = false
|
||||
self.scrollBadge?.isHidden = (self.scrollBadge?.text == nil)
|
||||
} else {
|
||||
self.floatingScrollButton?.isHidden = true
|
||||
self.scrollBadge?.text = nil
|
||||
}
|
||||
}
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
self.floatingScrollButton?.removeFromSuperview()
|
||||
self.floatingScrollBackground?.removeFromSuperview()
|
||||
}
|
||||
|
||||
private func createFloatingButton() {
|
||||
func createFloatingButton() {
|
||||
self.floatingScrollButton = UIButton(type: .custom)
|
||||
self.floatingScrollBackground = UIButton(type: .custom)
|
||||
self.floatingScrollButton?.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.floatingScrollBackground?.translatesAutoresizingMaskIntoConstraints = false
|
||||
constrainFloatingButtonToWindow()
|
||||
self.floatingScrollButton?.setImage(UIImage(named: "scroll_to_bottom_default"), for: .normal)
|
||||
self.floatingScrollButton?.addTarget(self, action: #selector(scrollToBottomButtonAction(_:)), for: .touchUpInside)
|
||||
var imageFloatingScrollButton = UIImage()
|
||||
if #available(iOS 13.0, *) {
|
||||
imageFloatingScrollButton = UIImage(named: "scroll_to_bottom_default")!.withTintColor(.darkGray)
|
||||
} else {
|
||||
imageFloatingScrollButton = UIImage(named: "scroll_to_bottom_default")!
|
||||
}
|
||||
self.floatingScrollButton?.setImage(imageFloatingScrollButton, for: .normal)
|
||||
self.floatingScrollButton?.isHidden = true;
|
||||
addBadgeToButon(badge: nil)
|
||||
self.floatingScrollBackground?.backgroundColor = .lightGray
|
||||
self.floatingScrollBackground?.layer.cornerRadius = 25
|
||||
self.floatingScrollBackground?.isHidden = true;
|
||||
|
||||
self.floatingScrollButton?.onClick(action: {
|
||||
self.scrollToBottomButtonAction()
|
||||
})
|
||||
self.floatingScrollBackground?.onClick(action: {
|
||||
self.scrollToBottomButtonAction()
|
||||
})
|
||||
addBadgeToButton(badge: nil)
|
||||
}
|
||||
|
||||
private func constrainFloatingButtonToWindow() {
|
||||
DispatchQueue.main.async {
|
||||
guard let keyWindow = UIApplication.shared.keyWindow,
|
||||
guard let keyWindow = self.view,
|
||||
let floatingButton = self.floatingScrollButton else { return }
|
||||
keyWindow.addSubview(self.floatingScrollBackground!)
|
||||
keyWindow.addSubview(floatingButton)
|
||||
keyWindow.trailingAnchor.constraint(equalTo: floatingButton.trailingAnchor,
|
||||
constant: Constants.trailingValue).isActive = true
|
||||
keyWindow.bottomAnchor.constraint(equalTo: floatingButton.bottomAnchor,
|
||||
constant: Constants.leadingValue).isActive = true
|
||||
keyWindow.trailingAnchor.constraint(equalTo: floatingButton.trailingAnchor, constant: Constants.trailingValue).isActive = true
|
||||
|
||||
floatingButton.bottomAnchor.constraint(equalTo: keyWindow.bottomAnchor, constant: -25).isActive = true
|
||||
|
||||
floatingButton.widthAnchor.constraint(equalToConstant:
|
||||
Constants.buttonWidth).isActive = true
|
||||
floatingButton.heightAnchor.constraint(equalToConstant:
|
||||
Constants.buttonHeight).isActive = true
|
||||
self.floatingScrollBackground?.centerYAnchor.constraint(equalTo: floatingButton.centerYAnchor).isActive = true
|
||||
self.floatingScrollBackground?.centerXAnchor.constraint(equalTo: floatingButton.centerXAnchor).isActive = true
|
||||
self.floatingScrollBackground!.widthAnchor.constraint(equalToConstant:
|
||||
Constants.buttonHeight*3).isActive = true
|
||||
self.floatingScrollBackground!.heightAnchor.constraint(equalToConstant:
|
||||
Constants.buttonHeight*3).isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction private func scrollToBottomButtonAction(_ sender: Any) {
|
||||
scroll(toBottom: true)
|
||||
@IBAction private func scrollToBottomButtonAction() {
|
||||
scrollToBottom(animated: false)
|
||||
}
|
||||
|
||||
|
||||
private func addBadgeToButon(badge: String?) {
|
||||
private func addBadgeToButton(badge: String?) {
|
||||
self.scrollBadge = UILabel()
|
||||
self.scrollBadge?.text = badge
|
||||
self.scrollBadge?.textColor = UIColor.white
|
||||
|
|
@ -86,8 +110,8 @@ public extension ChatConversationTableView {
|
|||
vertical = Double(badgeInset.top) - Double(badgeInset.bottom)
|
||||
horizontal = Double(badgeInset.left) - Double(badgeInset.right)
|
||||
|
||||
let x = (Double(scrollButton.bounds.size.width) - 10 + horizontal!)
|
||||
let y = -(Double(badgeSize.height) / 2) - 10 + vertical!
|
||||
let x = (Double(scrollButton.bounds.size.width) + 34 + horizontal!)
|
||||
let y = -(Double(badgeSize.height) / 2) - 38 + vertical!
|
||||
self.scrollBadge?.frame = CGRect(x: x, y: y, width: width, height: height)
|
||||
|
||||
self.scrollBadge!.layer.cornerRadius = self.scrollBadge!.frame.height/2
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
}
|
||||
@property(weak, nonatomic) IBOutlet UIButton *backButton;
|
||||
@property(weak, nonatomic) IBOutlet UILabel *contactLabel;
|
||||
@property(nonatomic, strong) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property(nonatomic, strong) IBOutlet UIImageView *avatarImage;
|
||||
@property(nonatomic, strong) IBOutlet UILabel *addressLabel;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *addContactButton;
|
||||
@property(nonatomic, copy, setter=setCallLogId:) NSString *callLogId;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#import "HistoryDetailsView.h"
|
||||
#import "PhoneMainView.h"
|
||||
#import "FastAddressBook.h"
|
||||
#import "linphoneapp-Swift.h"
|
||||
|
||||
@implementation HistoryDetailsView
|
||||
|
||||
|
|
@ -68,6 +69,12 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_headerView addGestureRecognizer:headerTapGesture];
|
||||
}
|
||||
|
||||
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
|
||||
_chatButton.hidden = [LinphoneManager.instance lpConfigBoolForKey:@"force_lime_chat_rooms"] || [LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"];
|
||||
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
|
||||
[self update];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
_waitView.hidden = YES;
|
||||
|
|
@ -87,11 +94,27 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector: @selector(deviceOrientationDidChange:)
|
||||
name: UIDeviceOrientationDidChangeNotification
|
||||
object: nil];
|
||||
|
||||
NSDictionary* userInfo;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector: @selector(receivePresenceNotification:)
|
||||
name: @"LinphoneFriendPresenceUpdate"
|
||||
object: userInfo];
|
||||
}
|
||||
|
||||
-(void) receivePresenceNotification:(NSNotification*)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:@"LinphoneFriendPresenceUpdate"])
|
||||
{
|
||||
[self update];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneFriendPresenceUpdate" object:nil];
|
||||
[AvatarBridge removeAllObserver];
|
||||
}
|
||||
|
||||
#pragma mark - Event Functions
|
||||
|
|
@ -144,7 +167,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
const LinphoneAddress *addr = linphone_call_log_get_remote_address(callLog);
|
||||
_addContactButton.hidden = ([FastAddressBook getContactWithAddress:addr] != nil);
|
||||
[ContactDisplay setDisplayNameLabel:_contactLabel forAddress:addr withAddressLabel:_addressLabel];
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:NO withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:addr]];
|
||||
Contact *contact = [FastAddressBook getContactWithAddress:addr];
|
||||
const LinphonePresenceModel *model = contact.friend ? linphone_friend_get_presence_model(contact.friend) : NULL;
|
||||
_linphoneImage.hidden = [LinphoneManager.instance lpConfigBoolForKey:@"hide_linphone_contacts" inSection:@"app"] ||
|
||||
|
|
@ -158,7 +181,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (void)shouldHideEncryptedChatView:(BOOL)hasLime {
|
||||
_encryptedChatView.hidden = !hasLime;
|
||||
_encryptedChatView.hidden = !hasLime || [LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"];
|
||||
CGRect newFrame = _optionsView.frame;
|
||||
if (!hasLime) {
|
||||
newFrame.origin.x = _encryptedChatView.frame.size.width * 2/3;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,36 @@
|
|||
name:kLinphoneCoreUpdate
|
||||
object:nil];
|
||||
[self loadData];
|
||||
NSDictionary* userInfo;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector: @selector(receivePresenceNotification:)
|
||||
name: @"LinphoneFriendPresenceUpdate"
|
||||
object: userInfo];
|
||||
}
|
||||
|
||||
-(void) receivePresenceNotification:(NSNotification*)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:@"LinphoneFriendPresenceUpdate"])
|
||||
{
|
||||
NSDictionary* userInfo = notification.userInfo;
|
||||
NSString* friend = (NSString*)userInfo[@"friend"];
|
||||
|
||||
const MSList *list = linphone_core_get_call_logs(LC);
|
||||
int i = 0;
|
||||
while (list != NULL) {
|
||||
LinphoneCallLog *log = (LinphoneCallLog *)list->data;
|
||||
const char *curi = linphone_address_as_string_uri_only(linphone_call_log_get_remote_address(log));
|
||||
NSString *uri = [NSString stringWithUTF8String:curi];
|
||||
|
||||
if([uri isEqual:friend]){
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:0];
|
||||
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
|
||||
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
i = i + 1;
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
|
@ -79,6 +109,8 @@
|
|||
[NSNotificationCenter.defaultCenter removeObserver:self name:kLinphoneAddressBookUpdate object:nil];
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self name:kLinphoneCoreUpdate object:nil];
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self name:kLinphoneCallUpdate object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"LinphoneFriendPresenceUpdate" object:nil];
|
||||
[AvatarBridge removeAllObserver];
|
||||
}
|
||||
|
||||
#pragma mark - Event Functions
|
||||
|
|
@ -272,9 +304,9 @@
|
|||
[ConferenceViewModelBridge showCancelledMeetingWithCConferenceInfo:confInfo];
|
||||
return;
|
||||
}
|
||||
ConferenceWaitingRoomFragment *view = VIEW(ConferenceWaitingRoomFragment);
|
||||
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);
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -61,6 +63,9 @@
|
|||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||
LOGI(@"%@", NSStringFromSelector(_cmd));
|
||||
if([LinphoneManager.instance lpConfigBoolForKey:@"account_push_presence_preference"]){
|
||||
linphone_core_set_consolidated_presence(LC, LinphoneConsolidatedPresenceOffline);
|
||||
}
|
||||
if (linphone_core_get_global_state(LC) != LinphoneGlobalOff) {
|
||||
[LinphoneManager.instance enterBackgroundMode];
|
||||
[LinphoneManager.instance.fastAddressBook clearFriends];
|
||||
|
|
@ -73,6 +78,7 @@
|
|||
// To avoid crash
|
||||
[PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription];
|
||||
}
|
||||
|
||||
[CallManager.instance stopLinphoneCore];
|
||||
}
|
||||
[SwiftUtil resetCachedAsset];
|
||||
|
|
@ -83,14 +89,24 @@
|
|||
|
||||
[LinphoneManager.instance startLinphoneCore];
|
||||
[LinphoneManager.instance.fastAddressBook reloadFriends];
|
||||
[AvatarBridge clearFriends];
|
||||
if([LinphoneManager.instance lpConfigBoolForKey:@"account_push_presence_preference"]){
|
||||
linphone_core_set_consolidated_presence(LC, LinphoneConsolidatedPresenceOnline);
|
||||
}
|
||||
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:nil];
|
||||
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
LOGI(@"%@", NSStringFromSelector(_cmd));
|
||||
LinphoneCall *call = linphone_core_get_current_call(LC);
|
||||
|
||||
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kLinphoneMsgNotificationAppGroupId];
|
||||
if (defaults) {
|
||||
[defaults setBool:false forKey:@"appactive"];
|
||||
}
|
||||
|
||||
if (!call)
|
||||
return;
|
||||
|
||||
|
|
@ -113,7 +129,12 @@
|
|||
}
|
||||
LinphoneManager *instance = LinphoneManager.instance;
|
||||
[instance becomeActive];
|
||||
|
||||
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kLinphoneMsgNotificationAppGroupId];
|
||||
if (defaults) {
|
||||
[defaults setBool:true forKey:@"appactive"];
|
||||
}
|
||||
|
||||
if (instance.fastAddressBook.needToUpdate) {
|
||||
//Update address book for external changes
|
||||
if (PhoneMainView.instance.currentView == ContactsListView.compositeViewDescription || PhoneMainView.instance.currentView == ContactDetailsView.compositeViewDescription) {
|
||||
|
|
@ -137,7 +158,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 +176,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 +204,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 +363,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;
|
||||
}
|
||||
|
||||
|
|
@ -365,31 +398,39 @@
|
|||
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options{
|
||||
NSString *scheme = [[url scheme] lowercaseString];
|
||||
if ([scheme isEqualToString:@"linphone-config"] || [scheme isEqualToString:@"linphone-config"]) {
|
||||
if ([scheme isEqualToString:@"linphone-config"]) {
|
||||
NSString *encodedURL =
|
||||
[[url absoluteString] stringByReplacingOccurrencesOfString:@"linphone-config://" withString:@""];
|
||||
[[url absoluteString] stringByReplacingOccurrencesOfString:@"linphone-config:" withString:@""];
|
||||
self.configURL = [encodedURL stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Remote configuration", nil)
|
||||
message:NSLocalizedString(@"This operation will load a remote configuration. Continue ?", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"No", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
UIAlertAction* yesAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Yes", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self showWaitingIndicator];
|
||||
[self attemptRemoteConfiguration];
|
||||
}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[errView addAction:yesAction];
|
||||
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
BOOL auto_apply_provisioning = [LinphoneManager.instance lpConfigBoolForKey:@"auto_apply_provisioning_config_uri_handler" inSection:@"app" withDefault:FALSE];
|
||||
if (auto_apply_provisioning) {
|
||||
[SVProgressHUD show];
|
||||
[self attemptRemoteConfiguration];
|
||||
[SVProgressHUD dismiss];
|
||||
} else {
|
||||
NSString *msg = [NSString stringWithFormat:NSLocalizedString(@" Do you want to download and apply configuration from this URL?\n\n%@", nil), encodedURL];
|
||||
UIConfirmationDialog* remoteConfigurationDialog =[UIConfirmationDialog ShowWithMessage:msg
|
||||
cancelMessage:nil
|
||||
confirmMessage:NSLocalizedString(@"APPLY", nil)
|
||||
onCancelClick:^() {}
|
||||
onConfirmationClick:^() {
|
||||
[SVProgressHUD show];
|
||||
[self attemptRemoteConfiguration];
|
||||
[SVProgressHUD dismiss];
|
||||
}];
|
||||
[remoteConfigurationDialog setSpecialColor];
|
||||
}
|
||||
} else if([[url scheme] isEqualToString:@"message-linphone"]) {
|
||||
[PhoneMainView.instance popToView:ChatsListView.compositeViewDescription];
|
||||
if ([[PhoneMainView.instance currentView] equal:ChatsListView.compositeViewDescription]) {
|
||||
VIEW(ChatConversationViewSwift).sharingMedia = TRUE;
|
||||
ChatsListView *view = VIEW(ChatsListView);
|
||||
[view mediaSharing];
|
||||
}else{
|
||||
[SVProgressHUD dismiss];
|
||||
VIEW(ChatConversationViewSwift).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 "/"
|
||||
|
|
@ -414,8 +455,8 @@
|
|||
linphone_address_unref(peer);
|
||||
linphone_address_unref(local);
|
||||
// TODO : Find a better fix
|
||||
VIEW(ChatConversationView).markAsRead = FALSE;
|
||||
[PhoneMainView.instance goToChatRoom:cr];
|
||||
VIEW(ChatConversationViewSwift).markAsRead = FALSE;
|
||||
[PhoneMainView.instance goToChatRoomSwift:cr];
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
|
|
@ -504,33 +545,57 @@
|
|||
|
||||
- (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) {
|
||||
|
||||
if (PhoneMainView.instance.currentView == ChatConversationViewSwift.compositeViewDescription) {
|
||||
NSDictionary *userInfo = [[[notification request] content] userInfo];
|
||||
NSString *peerAddress = userInfo[@"peer_addr"];
|
||||
NSString *localAddress = userInfo[@"local_addr"];
|
||||
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);
|
||||
}
|
||||
|
||||
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
LOGD(@"didReceiveRemoteNotification -- backgroundPush");
|
||||
if (linphone_core_get_global_state(LC) != LinphoneGlobalOn) {
|
||||
[LinphoneManager.instance startLinphoneCore];
|
||||
[LinphoneManager.instance.fastAddressBook reloadFriends];
|
||||
}
|
||||
|
||||
const MSList *accounts = linphone_core_get_account_list(LC);
|
||||
while (accounts) {
|
||||
LinphoneAccount *account = (LinphoneAccount *)accounts->data;
|
||||
linphone_account_refresh_register(account);
|
||||
accounts = accounts->next;
|
||||
}
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:kLinphoneMsgNotificationAppGroupId];
|
||||
NSMutableDictionary *chatroomsPushStatus = [[NSMutableDictionary alloc] initWithDictionary:[defaults dictionaryForKey:@"appactive"]];
|
||||
|
||||
if ([defaults boolForKey:@"appactive"] != TRUE) {
|
||||
linphone_core_enter_background(LC);
|
||||
if (linphone_core_get_calls_nb(LC) == 0) {
|
||||
linphone_core_stop(LC);
|
||||
}
|
||||
}
|
||||
completionHandler(UIBackgroundFetchResultNewData);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
||||
|
|
@ -570,7 +635,7 @@
|
|||
LinphoneAddress *local = linphone_address_new(local_address.UTF8String);
|
||||
LinphoneChatRoom *room = linphone_core_find_chat_room(LC, peer, local);
|
||||
if (room)
|
||||
[ChatConversationView markAsRead:room];
|
||||
[ChatConversationViewSwift markAsRead:room];
|
||||
|
||||
linphone_address_unref(peer);
|
||||
linphone_address_unref(local);
|
||||
|
|
@ -610,14 +675,16 @@
|
|||
LinphoneAddress *local = linphone_address_new(local_address.UTF8String);
|
||||
LinphoneChatRoom *room = linphone_core_find_chat_room(LC, peer, local);
|
||||
if (room) {
|
||||
[PhoneMainView.instance goToChatRoom:room];
|
||||
[PhoneMainView.instance resetBeforeGoToChatRoomSwift];
|
||||
[PhoneMainView.instance changeCurrentView:ChatsListView.compositeViewDescription];
|
||||
[PhoneMainView.instance goToChatRoomSwift:room];
|
||||
return;
|
||||
} else {
|
||||
[PhoneMainView.instance changeCurrentView:ChatsListView.compositeViewDescription];
|
||||
}
|
||||
[PhoneMainView.instance changeCurrentView:ChatsListView.compositeViewDescription];
|
||||
}
|
||||
} 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
|
||||
|
|
@ -718,7 +785,7 @@
|
|||
LinphoneAddress *local = linphone_address_new(local_address.UTF8String);
|
||||
LinphoneChatRoom *room = linphone_core_find_chat_room(LC, peer, local);
|
||||
if (room)
|
||||
[ChatConversationView markAsRead:room];
|
||||
[ChatConversationViewSwift markAsRead:room];
|
||||
|
||||
linphone_address_unref(peer);
|
||||
linphone_address_unref(local);
|
||||
|
|
@ -799,23 +866,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)showWaitingIndicator {
|
||||
_waitingIndicator = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Fetching remote configuration...", nil)
|
||||
message:@""
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIActivityIndicatorView *progress = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(125, 60, 30, 30)];
|
||||
progress.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
|
||||
|
||||
[_waitingIndicator setValue:progress forKey:@"accessoryView"];
|
||||
[progress setColor:[UIColor blackColor]];
|
||||
|
||||
[progress startAnimating];
|
||||
[PhoneMainView.instance presentViewController:_waitingIndicator animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)attemptRemoteConfiguration {
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(ConfigurationStateUpdateEvent:)
|
||||
name:kLinphoneConfiguringStateUpdate
|
||||
|
|
@ -823,7 +874,7 @@
|
|||
linphone_core_set_provisioning_uri(LC, [configURL UTF8String]);
|
||||
[LinphoneManager.instance destroyLinphoneCore];
|
||||
[LinphoneManager.instance launchLinphoneCore];
|
||||
[LinphoneManager.instance.fastAddressBook fetchContactsInBackGroundThread];
|
||||
[LinphoneManager.instance.fastAddressBook fetchContactsInBackGroundThread];
|
||||
}
|
||||
|
||||
#pragma mark - Prevent ImagePickerView from rotating
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -152,6 +155,7 @@
|
|||
// default values
|
||||
{
|
||||
[self setBool:NO forKey:@"account_pushnotification_preference"];
|
||||
[self setBool:NO forKey:@"account_bundle_mode_preference"];
|
||||
[self setObject:@"" forKey:@"account_mandatory_username_preference"];
|
||||
[self setObject:@"" forKey:@"account_mandatory_domain_preference"];
|
||||
[self setCString:"" forKey:@"account_display_name_preference"];
|
||||
|
|
@ -168,6 +172,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"];
|
||||
|
|
@ -180,10 +185,13 @@
|
|||
{
|
||||
BOOL pushEnabled = linphone_account_params_get_push_notification_allowed(accountParams);
|
||||
[self setBool:pushEnabled forKey:@"account_pushnotification_preference"];
|
||||
|
||||
|
||||
BOOL bundleModeEnabled = linphone_account_params_rtp_bundle_enabled(accountParams);
|
||||
[self setBool:bundleModeEnabled forKey:@"account_bundle_mode_preference"];
|
||||
|
||||
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 +242,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 +261,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 +356,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"];
|
||||
|
|
@ -430,10 +445,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
|
||||
|
|
@ -485,7 +500,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"];
|
||||
|
|
@ -509,8 +524,11 @@
|
|||
}
|
||||
|
||||
// contacts section
|
||||
if (linphone_core_ldap_available(LC)) {
|
||||
[self transformLdapToKeys:nil];
|
||||
{
|
||||
[self setInteger:[lm lpConfigBoolForKey:@"account_push_presence_preference" withDefault:YES] forKey:@"account_push_presence_preference"];
|
||||
if (linphone_core_ldap_available(LC)) {
|
||||
[self transformLdapToKeys:nil];
|
||||
}
|
||||
}
|
||||
|
||||
// advanced section
|
||||
|
|
@ -519,6 +537,7 @@
|
|||
[self setBool:ANIMATED forKey:@"animations_preference"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"backgroundmode_preference"] forKey:@"backgroundmode_preference"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"start_at_boot_preference"] forKey:@"start_at_boot_preference"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"screenshot_preference" withDefault:NO] forKey:@"screenshot_preference"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"autoanswer_notif_preference"] forKey:@"autoanswer_notif_preference"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"show_msg_in_notif" withDefault:YES] forKey:@"show_msg_in_notif"];
|
||||
[self setBool:[lm lpConfigBoolForKey:@"use_rls_presence" withDefault:YES] forKey:@"use_rls_presence"];
|
||||
|
|
@ -603,7 +622,9 @@
|
|||
if (username && [username length] > 0 && domain && [domain length] > 0) {
|
||||
int expire = [self integerForKey:@"account_expire_preference"];
|
||||
BOOL pushnotification = [self boolForKey:@"account_pushnotification_preference"];
|
||||
BOOL bundlemode = [self boolForKey:@"account_bundle_mode_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 +635,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 +646,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 +693,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);
|
||||
|
|
@ -681,8 +702,10 @@
|
|||
|
||||
// use empty string "" instead of NULL to avoid being overwritten by default proxy config values
|
||||
linphone_account_params_set_push_notification_allowed(newAccountParams, pushnotification);
|
||||
linphone_account_params_enable_rtp_bundle(newAccountParams, bundlemode);
|
||||
linphone_account_params_set_push_notification_allowed(newAccountParams, pushnotification);
|
||||
linphone_account_params_set_remote_push_notification_allowed(newAccountParams, pushnotification);
|
||||
|
||||
|
||||
linphone_account_params_set_register_enabled(newAccountParams, is_enabled);
|
||||
linphone_account_params_set_avpf_mode(newAccountParams, use_avpf);
|
||||
linphone_account_params_set_expires(newAccountParams, expire);
|
||||
|
|
@ -713,7 +736,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 +828,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 +852,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
|
||||
|
|
@ -1018,7 +1041,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)
|
||||
|
|
@ -1071,7 +1094,13 @@
|
|||
}
|
||||
|
||||
// contacts section
|
||||
|
||||
BOOL push_presence = [self boolForKey:@"account_push_presence_preference"];
|
||||
if (push_presence) {
|
||||
linphone_core_set_consolidated_presence([LinphoneManager getLc], LinphoneConsolidatedPresenceOnline);
|
||||
} else {
|
||||
linphone_core_set_consolidated_presence([LinphoneManager getLc], LinphoneConsolidatedPresenceOffline);
|
||||
}
|
||||
[lm lpConfigSetInt:push_presence forKey:@"account_push_presence_preference"];
|
||||
|
||||
BOOL ldap_changed = NO;
|
||||
for (NSString *key in self->changedDict) {
|
||||
|
|
@ -1086,6 +1115,9 @@
|
|||
// advanced section
|
||||
BOOL animations = [self boolForKey:@"animations_preference"];
|
||||
[lm lpConfigSetInt:animations forKey:@"animations_preference"];
|
||||
|
||||
BOOL screenshot = [self boolForKey:@"screenshot_preference"];
|
||||
[lm lpConfigSetInt:screenshot forKey:@"screenshot_preference"];
|
||||
|
||||
UIDevice *device = [UIDevice currentDevice];
|
||||
BOOL backgroundSupported = [device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported];
|
||||
|
|
@ -1100,7 +1132,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 {
|
||||
|
|
@ -1114,6 +1148,7 @@
|
|||
}
|
||||
}
|
||||
linphone_address_unref(rls_addr);
|
||||
bctbx_free(accountListToBeFreed);
|
||||
}
|
||||
|
||||
[lm lpConfigSetInt:[self integerForKey:@"use_rls_presence"] forKey:@"use_rls_presence"];
|
||||
|
|
@ -1155,9 +1190,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);
|
||||
|
|
@ -1178,11 +1216,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;
|
||||
|
|
@ -193,6 +196,8 @@ typedef struct _LinphoneManagerSounds {
|
|||
- (void)checkLocalNetworkPermission;
|
||||
- (void)setDnsServer;
|
||||
|
||||
+ (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);
|
||||
|
|
@ -239,7 +240,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
|
|||
NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"];
|
||||
self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil];
|
||||
|
||||
_sounds.vibrate = kSystemSoundID_Vibrate;
|
||||
//_sounds.vibrate = kSystemSoundID_Vibrate;
|
||||
|
||||
_logs = [[NSMutableArray alloc] init];
|
||||
_pushDict = [[NSMutableDictionary alloc] init];
|
||||
|
|
@ -253,6 +254,11 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
|
|||
[self renameDefaultSettings];
|
||||
[self copyDefaultSettings];
|
||||
[self overrideDefaultSettings];
|
||||
|
||||
if (![self lpConfigBoolForKey:@"disable_chat_feature" withDefault:FALSE]) {
|
||||
_sounds.vibrate = kSystemSoundID_Vibrate;
|
||||
}
|
||||
|
||||
if (![self lpConfigBoolForKey:@"migration_images_done" withDefault:FALSE]) {
|
||||
[self migrationAllImages];
|
||||
}
|
||||
|
|
@ -276,6 +282,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];
|
||||
|
|
@ -372,6 +386,10 @@ static int check_should_migrate_images(void *data, int argc, char **argv, char *
|
|||
}
|
||||
|
||||
- (void)migrationLinphoneSettings {
|
||||
NSString *appDomain = [LinphoneManager.instance lpConfigStringForKey:@"domain_name"
|
||||
inSection:@"app"
|
||||
withDefault:@"sip.linphone.org"];
|
||||
|
||||
/* AVPF migration */
|
||||
if ([self lpConfigBoolForKey:@"avpf_migration_done"] == FALSE) {
|
||||
const MSList *accounts = linphone_core_get_account_list(theLinphoneCore);
|
||||
|
|
@ -464,6 +482,26 @@ static int check_should_migrate_images(void *data, int argc, char **argv, char *
|
|||
}
|
||||
[self lpConfigSetBool:TRUE forKey:@"push_notification_migration_done"];
|
||||
}
|
||||
if ([self lpConfigBoolForKey:@"publish_enabled_migration_done"] == FALSE) {
|
||||
const MSList *accounts = linphone_core_get_account_list(theLinphoneCore);
|
||||
linphone_core_set_log_collection_upload_server_url(LC, "https://www.linphone.org:444/lft.php");
|
||||
[self lpConfigSetBool:TRUE forKey:@"update_presence_model_timestamp_before_publish_expires_refresh"];
|
||||
|
||||
while (accounts)
|
||||
{
|
||||
LinphoneAccount *account = (LinphoneAccount *)accounts->data;
|
||||
LinphoneAccountParams *newAccountParams = linphone_account_params_clone(linphone_account_get_params(account));
|
||||
|
||||
if (strcmp(appDomain.UTF8String, linphone_account_params_get_domain(newAccountParams)) == 0) {
|
||||
linphone_account_params_set_publish_enabled(newAccountParams, true);
|
||||
linphone_account_params_set_publish_expires(newAccountParams, 120);
|
||||
linphone_account_set_params(account, newAccountParams);
|
||||
}
|
||||
linphone_account_params_unref(newAccountParams);
|
||||
accounts = accounts->next;
|
||||
}
|
||||
[self lpConfigSetBool:TRUE forKey:@"publish_enabled_migration_done"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)migrationPerAccount {
|
||||
|
|
@ -474,27 +512,33 @@ static int check_should_migrate_images(void *data, int argc, char **argv, char *
|
|||
while (accounts) {
|
||||
LinphoneAccount *account = accounts->data;
|
||||
LinphoneAccountParams *newAccountParams = linphone_account_params_clone(linphone_account_get_params(account));
|
||||
// can not create group chat without conference factory
|
||||
if (!linphone_account_params_get_conference_factory_uri(newAccountParams)) {
|
||||
if (strcmp(appDomain.UTF8String, linphone_account_params_get_domain(newAccountParams)) == 0) {
|
||||
|
||||
if (strcmp(appDomain.UTF8String, linphone_account_params_get_domain(newAccountParams)) == 0) {
|
||||
// can not create group chat without conference factory
|
||||
if (!linphone_account_params_get_conference_factory_uri(newAccountParams)) {
|
||||
linphone_account_params_set_conference_factory_uri(newAccountParams, "sip:conference-factory@sip.linphone.org");
|
||||
linphone_account_set_params(account, newAccountParams);
|
||||
}
|
||||
}
|
||||
if (!linphone_account_params_get_audio_video_conference_factory_address(newAccountParams) && strcmp(appDomain.UTF8String, linphone_account_params_get_domain(newAccountParams)) == 0) {
|
||||
NSString *uri = [self lpConfigStringForKey:@"default_audio_video_conference_factory_uri" withDefault:@"sip:videoconference-factory2@sip.linphone.org"];
|
||||
LinphoneAddress *a = linphone_factory_create_address(linphone_factory_get(), uri.UTF8String);
|
||||
if (a) {
|
||||
linphone_account_params_set_audio_video_conference_factory_address(newAccountParams, a);
|
||||
linphone_account_set_params(account, newAccountParams);
|
||||
|
||||
if (!linphone_account_params_get_audio_video_conference_factory_address(newAccountParams)) {
|
||||
NSString *uri = [self lpConfigStringForKey:@"default_audio_video_conference_factory_uri" withDefault:@"sip:videoconference-factory2@sip.linphone.org"];
|
||||
LinphoneAddress *a = linphone_factory_create_address(linphone_factory_get(), uri.UTF8String);
|
||||
if (a) {
|
||||
linphone_account_params_set_audio_video_conference_factory_address(newAccountParams, a);
|
||||
linphone_account_set_params(account, newAccountParams);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (!linphone_account_params_rtp_bundle_enabled(newAccountParams)) {
|
||||
linphone_account_params_enable_rtp_bundle(newAccountParams, true);
|
||||
linphone_account_set_params(account,newAccountParams);
|
||||
}
|
||||
*/
|
||||
|
||||
LOGI(@"Setting the sip 'expires' parameters of existing account to 1 year (31536000 seconds)");
|
||||
linphone_account_params_set_expires(newAccountParams, 31536000);
|
||||
}
|
||||
|
||||
if (strcmp(appDomain.UTF8String, linphone_account_params_get_domain(newAccountParams)) == 0 && !linphone_account_params_rtp_bundle_enabled(newAccountParams)) {
|
||||
linphone_account_params_enable_rtp_bundle(newAccountParams, true);
|
||||
linphone_account_set_params(account,newAccountParams);
|
||||
}
|
||||
|
||||
linphone_account_params_unref(newAccountParams);
|
||||
accounts = accounts->next;
|
||||
}
|
||||
|
|
@ -637,6 +681,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 {
|
||||
|
|
@ -865,9 +914,9 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, LinphoneAut
|
|||
return;
|
||||
|
||||
if (hasFile) {
|
||||
if (PhoneMainView.instance.currentView == ChatConversationView.compositeViewDescription && room == PhoneMainView.instance.currentRoom)
|
||||
if (PhoneMainView.instance.currentView == ChatConversationViewSwift.compositeViewDescription && room == PhoneMainView.instance.currentRoom)
|
||||
return;
|
||||
[ChatConversationView autoDownload:msg];
|
||||
[self autoDownload:msg];
|
||||
}
|
||||
|
||||
// Post event
|
||||
|
|
@ -881,6 +930,21 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, LinphoneAut
|
|||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:self userInfo:dict];
|
||||
}
|
||||
|
||||
- (void)autoDownload:(LinphoneChatMessage *)message {
|
||||
LinphoneContent *content = linphone_chat_message_get_file_transfer_information(message);
|
||||
NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)];
|
||||
NSString *fileType = [NSString stringWithUTF8String:linphone_content_get_type(content)];
|
||||
NSString *key = [ChatConversationViewSwift getKeyFromFileType:fileType fileName:name];
|
||||
|
||||
[LinphoneManager setValueInMessageAppData:name forKey:key inMessage:message];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:VIEW(ChatConversationViewSwift)];
|
||||
if (![VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] && [ConfigManager.instance lpConfigBoolForKeyWithKey:@"auto_write_to_gallery_preference"]) {
|
||||
[ChatConversationViewSwift writeMediaToGalleryFromName:name fileType:fileType];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void linphone_iphone_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message) {
|
||||
[(__bridge LinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onMessageReceived:lc room:room message:message];
|
||||
}
|
||||
|
|
@ -1264,7 +1328,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"
|
||||
|
|
@ -1285,7 +1349,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];
|
||||
|
|
@ -1304,7 +1375,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)));
|
||||
|
|
@ -1344,22 +1415,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1370,7 +1456,7 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat
|
|||
linphone_core_start([LinphoneManager getLc]);
|
||||
|
||||
[self configurePushProviderForAccounts];
|
||||
[self activateBasicChatroomCPIMForLinphoneAccounts];
|
||||
[self enableLinphoneAccountSpecificSettings];
|
||||
}
|
||||
|
||||
- (void)createLinphoneCore {
|
||||
|
|
@ -1439,7 +1525,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);
|
||||
|
|
@ -1472,6 +1557,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
|
||||
|
||||
|
|
@ -1501,8 +1587,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) {
|
||||
|
|
@ -1817,7 +1901,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
LinphoneChatMessage *msg = linphone_chat_room_create_message(room, replyText.UTF8String);
|
||||
linphone_chat_message_send(msg);
|
||||
|
||||
[ChatConversationView markAsRead:room];
|
||||
[ChatConversationViewSwift markAsRead:room];
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1900,7 +1984,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
|
||||
|
|
@ -2226,6 +2313,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);
|
||||
|
|
@ -2319,6 +2423,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="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="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>
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="189" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="hBI-Xz-aEV" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="hBI-Xz-aEV" userLabel="avatarImage">
|
||||
<rect key="frame" x="6" y="20" width="27" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
|
|
@ -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>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="86"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="19" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="19" userLabel="avatarImage" customClass="UIImageView">
|
||||
<rect key="frame" x="10" y="11" width="42" height="42"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
|
|
@ -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,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" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" 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="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>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<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">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" insetsLayoutMarginsFromSafeArea="NO" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="Z2U-vm-azg" userLabel="avatarImage">
|
||||
<rect key="frame" x="0.0" y="8" width="44" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?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="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina5_5" orientation="landscape" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
<action selector="onDelete:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="gSd-t2-eDY"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="Zsv-H9-9Dv" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="Zsv-H9-9Dv" userLabel="avatarImage">
|
||||
<rect key="frame" x="8" y="0.0" width="35" height="42"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Linphone"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="ktO-jm-Ra6" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="ktO-jm-Ra6" userLabel="avatarImage">
|
||||
<rect key="frame" x="10" y="10" width="40" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
|
|
@ -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="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"/>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<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="14088"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
@ -14,37 +12,47 @@
|
|||
<outlet property="avatarImage" destination="23" id="24"/>
|
||||
<outlet property="linphoneImage" destination="25" id="27"/>
|
||||
<outlet property="nameLabel" destination="6" id="26"/>
|
||||
<outlet property="organizationLabel" destination="fva-Hf-er8" id="Ib6-rS-ybW"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="16">
|
||||
<rect key="frame" x="0.0" y="0.0" width="360" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="360" height="49"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" image="avatar.png" id="23" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<rect key="frame" x="6" y="6" width="32" height="32"/>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="23" userLabel="avatarImage">
|
||||
<rect key="frame" x="6" y="9" width="32" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="left" text="John Doe" lineBreakMode="tailTruncation" minimumFontSize="10" id="6" userLabel="nameLabel">
|
||||
<rect key="frame" x="46" y="0.0" width="256" height="44"/>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="left" fixedFrame="YES" text="John Doe" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="6" userLabel="nameLabel">
|
||||
<rect key="frame" x="46" y="4" width="256" height="39"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Firstname"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="21"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="linphone_user.png" id="25" userLabel="linphoneImage">
|
||||
<rect key="frame" x="319" y="10" width="25" height="25"/>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" fixedFrame="YES" image="linphone_user.png" translatesAutoresizingMaskIntoConstraints="NO" id="25" userLabel="linphoneImage">
|
||||
<rect key="frame" x="319" y="13" width="25" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="left" fixedFrame="YES" text="Organization" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="fva-Hf-er8" userLabel="organizationLabel">
|
||||
<rect key="frame" x="46" y="29" width="256" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Firstname"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="137.59999999999999" y="-10.794602698650676"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="avatar.png" width="259" height="259"/>
|
||||
<image name="linphone_user.png" width="26" height="26"/>
|
||||
<image name="avatar.png" width="414.39999389648438" height="414.39999389648438"/>
|
||||
<image name="linphone_user.png" width="41.599998474121094" height="42.400001525878906"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" 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="17125"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
|
||||
<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 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="88"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="john.doe@sip.linphone.org" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="frB-ep-LWi" userLabel="addressLabel">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="john.doe@sip.linphone.org" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="frB-ep-LWi" userLabel="addressLabel" customClass="CopyableLabel" customModule="linphoneapp" customModuleProvider="target">
|
||||
<rect key="frame" x="26" y="0.0" width="323" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="UIHistoryCell">
|
||||
|
|
@ -18,31 +20,27 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" image="avatar.png" id="J9B-Wl-Qgm" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="J9B-Wl-Qgm" userLabel="avatarImage">
|
||||
<rect key="frame" x="6" y="6" width="32" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="history_missed_default.png" id="Jpe-IK-xK1" userLabel="stateImage">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="history_missed_default.png" translatesAutoresizingMaskIntoConstraints="NO" id="Jpe-IK-xK1" userLabel="stateImage">
|
||||
<rect key="frame" x="46" y="6" width="32" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="left" text="John Doe" lineBreakMode="tailTruncation" minimumFontSize="10" id="zG2-Kg-0jD" userLabel="displayNameLabel">
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" tag="2" contentMode="left" fixedFrame="YES" text="John Doe" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zG2-Kg-0jD" userLabel="displayNameLabel">
|
||||
<rect key="frame" x="86" y="0.0" width="237" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Firstname"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="21"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Lfl-dI-bSt" userLabel="detailsButton" customClass="UIIconButton">
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lfl-dI-bSt" userLabel="detailsButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="331" y="0.0" width="44" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<state key="normal" image="list_details_default.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<state key="highlighted" image="list_details_over.png"/>
|
||||
<connections>
|
||||
|
|
@ -50,17 +48,16 @@
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="366.5" y="248"/>
|
||||
<point key="canvasLocation" x="559.5419847328244" y="174.64788732394368"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="avatar.png" width="255" height="255"/>
|
||||
<image name="history_missed_default.png" width="32" height="32"/>
|
||||
<image name="list_details_default.png" width="33" height="34"/>
|
||||
<image name="list_details_over.png" width="33" height="34"/>
|
||||
<image name="avatar.png" width="414.39999389648438" height="414.39999389648438"/>
|
||||
<image name="history_missed_default.png" width="52.799999237060547" height="52.799999237060547"/>
|
||||
<image name="list_details_default.png" width="54.400001525878906" height="55.200000762939453"/>
|
||||
<image name="list_details_over.png" width="54.400001525878906" height="55.200000762939453"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -194,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);
|
||||
|
|
@ -330,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];
|
||||
|
|
@ -369,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);
|
||||
|
|
@ -394,6 +391,7 @@
|
|||
|
||||
securityDialog.securityImage.hidden = FALSE;
|
||||
[securityDialog setSpecialColor];
|
||||
[securityDialog setWhiteCancel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -405,7 +403,6 @@
|
|||
[ControlsViewModelBridge toggleStatsVisibility];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)onSideMenuClick:(id)sender {
|
||||
UICompositeView *cvc = PhoneMainView.instance.mainViewController;
|
||||
[cvc hideSideMenu:(cvc.sideMenuView.frame.origin.x == 0)];
|
||||
|
|
@ -415,10 +412,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,16 +76,20 @@
|
|||
- (void)update:(BOOL)appear {
|
||||
[self updateSelectedButton:[PhoneMainView.instance currentView]];
|
||||
[self updateMissedCall:linphone_core_get_missed_calls_count(LC) appear:appear];
|
||||
[self updateUnreadMessage:appear];
|
||||
if (![LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"]) {
|
||||
[self updateUnreadMessage:appear];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateUnreadMessage:(BOOL)appear {
|
||||
int unreadMessage = [LinphoneManager unreadMessageCount];
|
||||
if (unreadMessage > 0) {
|
||||
_chatNotificationLabel.text = [NSString stringWithFormat:@"%i", unreadMessage];
|
||||
[_chatNotificationView startAnimating:appear];
|
||||
} else {
|
||||
[_chatNotificationView stopAnimating:appear];
|
||||
if (![LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"]) {
|
||||
if (unreadMessage > 0) {
|
||||
_chatNotificationLabel.text = [NSString stringWithFormat:@"%i", unreadMessage];
|
||||
[_chatNotificationView startAnimating:appear];
|
||||
} else {
|
||||
[_chatNotificationView stopAnimating:appear];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +113,25 @@
|
|||
[view equal:ChatConversationCreateView.compositeViewDescription] ||
|
||||
[view equal:ChatConversationInfoView.compositeViewDescription] ||
|
||||
[view equal:ChatConversationImdnView.compositeViewDescription] ||
|
||||
[view equal:ChatConversationView.compositeViewDescription];
|
||||
[view equal:ChatConversationViewSwift.compositeViewDescription];
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"] && [self viewIsCurrentlyPortrait]) {
|
||||
CGFloat itemWidth = [UIScreen mainScreen].bounds.size.width/3;
|
||||
[_chatButton setEnabled:false];
|
||||
[_chatButton setHidden:true];
|
||||
[_chatNotificationView setHidden:true];
|
||||
_historyButton.frame = CGRectMake(0, 0, itemWidth, 66);
|
||||
_contactsButton.frame = CGRectMake(itemWidth, 0, itemWidth, 66);
|
||||
_dialerButton.frame = CGRectMake(itemWidth*2, 0, itemWidth, 66);
|
||||
_selectedButtonImage.frame = CGRectMake(_selectedButtonImage.frame.origin.x, _selectedButtonImage.frame.origin.y, itemWidth, 3);
|
||||
} else if ([LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"] && ![self viewIsCurrentlyPortrait]) {
|
||||
[_chatButton setEnabled:false];
|
||||
[_chatButton setHidden:true];
|
||||
[_chatNotificationView setHidden:true];
|
||||
_historyButton.frame = CGRectMake(0, 20, 90, 90);
|
||||
_contactsButton.frame = CGRectMake(0, 120, 90, 90);
|
||||
_dialerButton.frame = CGRectMake(0, 220, 90, 90);
|
||||
_selectedButtonImage.frame = CGRectMake(_selectedButtonImage.frame.origin.x, _selectedButtonImage.frame.origin.y, 3, 90);
|
||||
}
|
||||
CGRect selectedNewFrame = _selectedButtonImage.frame;
|
||||
if ([self viewIsCurrentlyPortrait]) {
|
||||
selectedNewFrame.origin.x =
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
@property(readonly, nonatomic) LinphoneEventLog *event;
|
||||
@property(readonly, nonatomic) LinphoneChatMessage *message;
|
||||
@property(nonatomic, weak) IBOutlet UIImageView *backgroundColorImage;
|
||||
@property(nonatomic, weak) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property(nonatomic, weak) IBOutlet UIImageView *avatarImage;
|
||||
@property(nonatomic, weak) IBOutlet UILabel *contactDateLabel;
|
||||
//@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *statusInProgressSpinner;
|
||||
@property(nonatomic, weak) IBOutlet UITextViewNoDefine *messageText;
|
||||
|
|
|
|||
|
|
@ -119,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 {
|
||||
|
|
@ -196,9 +201,7 @@
|
|||
_avatarImage.hidden = TRUE;
|
||||
|
||||
} else {
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:linphone_chat_message_get_from_address(_message)]
|
||||
bordered:NO
|
||||
withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:linphone_chat_message_get_from_address(_message)]];
|
||||
_contactDateLabel.text = [self.class ContactDateForChat:_message];
|
||||
_contactDateLabel.textAlignment = NSTextAlignmentLeft;
|
||||
_avatarImage.hidden = !_isFirst;
|
||||
|
|
@ -321,11 +324,13 @@
|
|||
|
||||
- (void)onDelete {
|
||||
if (_message != NULL) {
|
||||
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
|
||||
/*
|
||||
UITableView *tableView = VIEW(ChatConversationViewSwift).tableController.tableView;
|
||||
NSIndexPath *indexPath = [tableView indexPathForCell:self];
|
||||
[tableView.dataSource tableView:tableView
|
||||
commitEditingStyle:UITableViewCellEditingStyleDelete
|
||||
forRowAtIndexPath:indexPath];
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -337,15 +342,17 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
|
||||
if (!linphone_chat_message_is_outgoing(msg) || (state != LinphoneChatMessageStateFileTransferDone && state != LinphoneChatMessageStateFileTransferInProgress)) {
|
||||
LinphoneEventLog *event = (LinphoneEventLog *)linphone_chat_message_cbs_get_user_data(linphone_chat_message_get_callbacks(msg));
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
[view.tableController updateEventEntry:event];
|
||||
[view.tableController scrollToBottom:true];
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
//[view.tableController updateEventEntry:event];
|
||||
//[view.tableController scrollToBottom:true];
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -762,7 +769,7 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
if (_message != nil) {
|
||||
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
|
||||
//UITableView *tableView = VIEW(ChatConversationViewSwift).tableController.tableView;
|
||||
BOOL is_outgoing = linphone_chat_message_is_outgoing(_message);
|
||||
CGRect bubbleFrame = _bubbleView.frame;
|
||||
int available_width = self.frame.size.width;
|
||||
|
|
@ -773,11 +780,13 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
bubbleFrame.size.width = MAX(bubbleFrame.size.width, 300);
|
||||
}
|
||||
|
||||
/*
|
||||
if (tableView.isEditing) {
|
||||
origin_x = 0;
|
||||
} else {
|
||||
origin_x = (is_outgoing ? self.frame.size.width - bubbleFrame.size.width : 0);
|
||||
}
|
||||
*/
|
||||
|
||||
CGRect r = _messageText.frame;
|
||||
r.origin.y = linphone_chat_message_is_reply(_message) ? _replyView.view.frame.origin.y + _replyView.view.frame.size.height + 5 : 3;
|
||||
|
|
@ -848,10 +857,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);
|
||||
|
|
@ -883,7 +895,7 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
[_messageActionsIcons addObject:@"menu_forward_default"];
|
||||
[_messageActionsBlocks addObject:^{
|
||||
[thiz dismissPopup];
|
||||
VIEW(ChatConversationView).pendingForwardMessage = linphone_chat_message_ref(message);
|
||||
VIEW(ChatConversationViewSwift).pendingForwardMessage = message;
|
||||
[PhoneMainView.instance changeCurrentView:VIEW(ChatsListView).compositeViewDescription];
|
||||
}];
|
||||
|
||||
|
|
@ -893,26 +905,53 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
[_messageActionsIcons addObject:@"menu_reply_default"];
|
||||
[_messageActionsBlocks addObject:^{
|
||||
[thiz dismissPopup];
|
||||
[VIEW(ChatConversationView) initiateReplyViewForMessage:message];
|
||||
[VIEW(ChatConversationViewSwift) 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"];
|
||||
[_messageActionsBlocks addObject:^{
|
||||
[thiz dismissPopup];
|
||||
linphone_chat_room_delete_message(linphone_chat_message_get_chat_room(message), message);
|
||||
[VIEW(ChatConversationView).tableController reloadData];
|
||||
//[VIEW(ChatConversationViewSwift).tableController reloadData];
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -924,7 +963,7 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
return;
|
||||
|
||||
|
||||
[VIEW(ChatConversationView).tableController dismissMessagesPopups];
|
||||
//[VIEW(ChatConversationViewSwift).tableController dismissMessagesPopups];
|
||||
[self buildActions];
|
||||
int width = 250;
|
||||
int cellHeight = 45;
|
||||
|
|
@ -932,17 +971,19 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
CGRect screenRect = UIScreen.mainScreen.bounds;
|
||||
int menuHeight = numberOfItems * cellHeight;
|
||||
|
||||
/*
|
||||
CGRect frame = CGRectMake(
|
||||
linphone_chat_message_is_outgoing(self.message) ? screenRect.size.width - width - 10 : 10,
|
||||
(self.frame.origin.y + self.frame.size.height) - [VIEW(ChatConversationView).tableController .tableView contentOffset].y > screenRect.size.height /2 ? self.frame.origin.y - menuHeight - 10: self.frame.origin.y + self.frame.size.height,
|
||||
(self.frame.origin.y + self.frame.size.height) - [VIEW(ChatConversationViewSwift).tableController .tableView contentOffset].y > screenRect.size.height /2 ? self.frame.origin.y - menuHeight - 10: self.frame.origin.y + self.frame.size.height,
|
||||
width,
|
||||
menuHeight);
|
||||
menuHeight);*/
|
||||
|
||||
_popupMenu = [[UITableView alloc]initWithFrame:frame];
|
||||
//_popupMenu = [[UITableView alloc]initWithFrame:frame];
|
||||
_popupMenu.scrollEnabled = false;
|
||||
_popupMenu.dataSource = self;
|
||||
_popupMenu.delegate = self;
|
||||
|
||||
_popupMenu.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
|
||||
_popupMenu.layer.masksToBounds = false;
|
||||
|
||||
_popupMenu.layer.shadowColor = [UIColor darkGrayColor].CGColor;
|
||||
|
|
@ -955,11 +996,11 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
_popupMenu.editing = NO;
|
||||
_popupMenu.userInteractionEnabled = true;
|
||||
[_popupMenu reloadData];
|
||||
[VIEW(ChatConversationView).tableController.view addSubview:_popupMenu];
|
||||
//[VIEW(ChatConversationViewSwift).tableController.view addSubview:_popupMenu];
|
||||
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOutsideMenu:)];
|
||||
tapGestureRecognizer.cancelsTouchesInView = NO;
|
||||
tapGestureRecognizer.numberOfTapsRequired = 1;
|
||||
[VIEW(ChatConversationView).tableController.view addGestureRecognizer:tapGestureRecognizer];
|
||||
//[VIEW(ChatConversationViewSwift).tableController.view addGestureRecognizer:tapGestureRecognizer];
|
||||
}
|
||||
|
||||
-(void) dismissPopup {
|
||||
|
|
@ -972,10 +1013,12 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
|
|||
|
||||
|
||||
-(void) tapOutsideMenu:(UITapGestureRecognizer *) g {
|
||||
CGPoint p = [g locationInView:VIEW(ChatConversationView).tableController.view];
|
||||
/*
|
||||
CGPoint p = [g locationInView:VIEW(ChatConversationViewSwift).tableController.view];
|
||||
if (!CGRectContainsPoint(_popupMenu.frame,p)) {
|
||||
[self dismissPopup];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@
|
|||
LinphoneChatRoom *chatRoom;
|
||||
}
|
||||
|
||||
@property(nonatomic, strong) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property(readonly, nonatomic) LinphoneEventLog *event;
|
||||
@property(nonatomic, strong) IBOutlet UIImageView *avatarImage;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *securityImage;
|
||||
@property(nonatomic, strong) IBOutlet UILabel *addressLabel;
|
||||
@property(nonatomic, strong) IBOutlet UILabel *chatContentLabel;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -73,14 +78,15 @@
|
|||
const LinphoneAddress *addr = firstParticipant ? linphone_participant_get_address(firstParticipant) : linphone_chat_room_get_peer_address(chatRoom);
|
||||
if (addr) {
|
||||
[ContactDisplay setDisplayNameLabel:_addressLabel forAddress:addr];
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:NO withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:addr]];
|
||||
} 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];
|
||||
[_avatarImage setImage:[UIImage imageNamed:@"chat_group_avatar.png"] bordered:NO withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[UIImage imageNamed:@"chat_group_avatar.png"]];
|
||||
}
|
||||
// TODO update security image when security level changed
|
||||
[_securityImage setImage:[FastAddressBook imageForSecurityLevel:linphone_chat_room_get_security_level(chatRoom)]];
|
||||
|
|
@ -89,11 +95,11 @@
|
|||
|
||||
LinphoneChatMessage *last_msg = linphone_chat_room_get_last_message_in_history(chatRoom);
|
||||
if (last_msg) {
|
||||
BOOL imdnInSnap = FALSE;
|
||||
BOOL imdnInSnap = TRUE;
|
||||
if (imdnInSnap) {
|
||||
BOOL outgoing = linphone_chat_message_is_outgoing(last_msg);
|
||||
NSString *text = [UIChatBubbleTextCell TextMessageForChat:last_msg];
|
||||
if (outgoing) {
|
||||
if (capabilities & LinphoneChatRoomCapabilitiesOneToOne) {
|
||||
// shorten long messages
|
||||
/*if ([text length] > 50)
|
||||
text = [[text substringToIndex:50] stringByAppendingString:@"[...]"];*/
|
||||
|
|
@ -117,6 +123,13 @@
|
|||
_chatContentLabel.attributedText = boldText;
|
||||
}
|
||||
|
||||
if (outgoing){
|
||||
linphone_chat_message_set_user_data(last_msg, (void *)CFBridgingRetain(self));
|
||||
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(last_msg);
|
||||
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);
|
||||
}
|
||||
|
||||
LinphoneChatMessageState state = linphone_chat_message_get_state(last_msg);
|
||||
if (outgoing && (state == LinphoneChatMessageStateDeliveredToUser || state == LinphoneChatMessageStateDisplayed || state == LinphoneChatMessageStateNotDelivered || state == LinphoneChatMessageStateFileTransferError)) {
|
||||
|
|
@ -132,7 +145,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)
|
||||
|
|
@ -214,4 +228,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState state) {
|
||||
LOGI(@"State for message [%p] changed to %s", msg, linphone_chat_message_state_to_string(state));
|
||||
if (state == LinphoneChatMessageStateFileTransferInProgress)
|
||||
return;
|
||||
|
||||
if (!linphone_chat_message_is_outgoing(msg) || (state != LinphoneChatMessageStateFileTransferDone && state != LinphoneChatMessageStateFileTransferInProgress)) {
|
||||
ChatsListView *view = VIEW(ChatsListView);
|
||||
[view.tableController updateEventEntry:msg];
|
||||
}
|
||||
}
|
||||
|
||||
static void participant_imdn_status(LinphoneChatMessage* msg, const LinphoneParticipantImdnState *state) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
ChatConversationImdnView *imdnView = VIEW(ChatConversationImdnView);
|
||||
[imdnView updateImdnList];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
@interface UIChatConversationImdnTableViewCell : UITableViewCell
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIRoundedImageView *avatar;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *avatar;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *displayName;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *dateLabel;
|
||||
- (id)initWithIdentifier:(NSString *)identifier;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
@interface UIChatConversationInfoTableViewCell : UITableViewCell <UIGestureRecognizerDelegate>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *avatarImage;
|
||||
@property (weak, nonatomic) IBOutlet UIIconButton *removeButton;
|
||||
@property (weak, nonatomic) IBOutlet UIView *adminButton;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *adminLabel;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
@property(weak, nonatomic) IBOutlet UILabel *addressLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *selectedImage;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *linphoneImage;
|
||||
@property (weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *avatarImage;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *securityImage;
|
||||
@property (weak, nonatomic) IBOutlet UIView *greyView;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
@ -657,6 +663,8 @@
|
|||
// 4. side menu
|
||||
self.sideMenuView.frame = sideMenuFrame;
|
||||
self.sideMenuViewController.view.frame = self.sideMenuView.bounds;
|
||||
[PhoneMainView.instance.mainViewController.view bringSubviewToFront:_sideMenuView];
|
||||
[PhoneMainView.instance.mainViewController.view bringSubviewToFront:_sideMenuViewController.view];
|
||||
|
||||
// Commit animation
|
||||
if (tabBar != nil || statusBar != nil || sideMenu != nil || fullscreen != nil) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
@interface UIContactCell : UITableViewCell
|
||||
|
||||
@property(nonatomic, strong) IBOutlet UILabel *nameLabel;
|
||||
@property(nonatomic, strong) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property(nonatomic, strong) IBOutlet UILabel *organizationLabel;
|
||||
@property(nonatomic, strong) IBOutlet UIImageView *avatarImage;
|
||||
@property(weak, nonatomic) IBOutlet UIImageView *linphoneImage;
|
||||
@property(nonatomic, assign) Contact *contact;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@
|
|||
_linphoneImage.hidden = TRUE;
|
||||
if(_contact) {
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];
|
||||
_organizationLabel.text = [FastAddressBook ogrganizationForContact:_contact];
|
||||
_linphoneImage.hidden = [LinphoneManager.instance lpConfigBoolForKey:@"hide_linphone_contacts" inSection:@"app"] ||
|
||||
! ((_contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(_contact.friend)) == LinphonePresenceBasicStatusOpen) || [FastAddressBook contactHasValidSipDomain:_contact]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"] || [LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"];
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
|
|
@ -80,7 +86,7 @@
|
|||
}
|
||||
|
||||
- (void)shouldHideEncryptedChatView:(BOOL)hasLime {
|
||||
_encryptedChatView.hidden = !hasLime;
|
||||
_encryptedChatView.hidden = !hasLime || [LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"];
|
||||
CGRect newFrame = _optionsView.frame;
|
||||
if (!hasLime) {
|
||||
newFrame.origin.x = _addressLabel.frame.origin.x + _callButton.frame.size.width * 2/3;
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
@property (nonatomic, assign) LinphoneCallLog *callLog;
|
||||
|
||||
@property(weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage;
|
||||
@property(weak, nonatomic) IBOutlet UIImageView *avatarImage;
|
||||
@property(nonatomic, strong) IBOutlet UILabel *displayNameLabel;
|
||||
@property(weak, nonatomic) IBOutlet UIImageView *stateImage;
|
||||
@property(weak, nonatomic) IBOutlet UIIconButton *detailsButton;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
[displayNameLabel.text stringByAppendingString:[NSString stringWithFormat:@" (%lu)", count]];
|
||||
}
|
||||
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:NO withRoundedRadius:YES];
|
||||
[_avatarImage setImage:[FastAddressBook imageForAddress:addr]];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -90,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 {
|
||||
|
|
@ -105,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];
|
||||
}
|
||||
|
|
@ -122,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
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@
|
|||
- (void)getOrCreateOneToOneChatRoom:(const LinphoneAddress *)remoteAddress waitView:(UIView *)waitView isEncrypted:(BOOL)isEncrypted;
|
||||
- (LinphoneChatRoom *)createChatRoom:(const char *)subject addresses:(bctbx_list_t *)addresses andWaitView:(UIView *)waitView isEncrypted:(BOOL)isEncrypted isGroup:(BOOL)isGroup;
|
||||
- (void)goToChatRoom:(LinphoneChatRoom *)cr;
|
||||
- (void)goToChatRoomSwift:(LinphoneChatRoom *)cr;
|
||||
- (void)resetBeforeGoToChatRoomSwift;
|
||||
+ (PhoneMainView*) instance;
|
||||
|
||||
- (BOOL)isIphoneXDevice;
|
||||
|
|
@ -123,3 +125,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);
|
||||
|
|
|
|||
|
|
@ -307,9 +307,9 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
if (linphone_chat_message_is_outgoing(msg))
|
||||
return;
|
||||
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
// if we already are in the conversation, we should not ring/vibrate
|
||||
if (view.chatRoom && _currentRoom == view.chatRoom)
|
||||
if (view.linphoneChatRoom && _currentRoom == view.linphoneChatRoom)
|
||||
return;
|
||||
|
||||
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive)
|
||||
|
|
@ -375,7 +375,6 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
break;
|
||||
}
|
||||
case LinphoneCallOutgoingInit:
|
||||
case LinphoneCallOutgoingEarlyMedia:
|
||||
case LinphoneCallOutgoingProgress:
|
||||
case LinphoneCallOutgoingRinging: {
|
||||
|
|
@ -387,7 +386,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*/
|
||||
|
|
@ -419,6 +418,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
case LinphoneCallUpdating:
|
||||
break;
|
||||
|
||||
}
|
||||
if (state == LinphoneCallEnd || state == LinphoneCallError || floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max)
|
||||
[self updateApplicationBadgeNumber];
|
||||
|
|
@ -454,9 +454,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:@"ChatConversationViewSwift"]) {
|
||||
|
||||
if (linphone_core_get_global_state(LC) != LinphoneGlobalOn) {
|
||||
[self changeCurrentView:DialerView.compositeViewDescription];
|
||||
|
|
@ -608,7 +618,8 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
[self _changeCurrentView:viewStack.lastObject ?: DialerView.compositeViewDescription
|
||||
transition:[PhoneMainView getBackwardTransition]
|
||||
animated:ANIMATED];
|
||||
animated:ANIMATED
|
||||
addViewToStack:FALSE];
|
||||
return [mainViewController getCurrentViewController];
|
||||
}
|
||||
|
||||
|
|
@ -622,18 +633,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)];
|
||||
|
|
@ -654,7 +666,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{
|
||||
|
|
@ -842,7 +855,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
return;
|
||||
}
|
||||
|
||||
[self goToChatRoom:room];
|
||||
[self goToChatRoomSwift:room];
|
||||
}
|
||||
|
||||
- (LinphoneChatRoom *)createChatRoom:(const char *)subject addresses:(bctbx_list_t *)addresses andWaitView:(UIView *)waitView isEncrypted:(BOOL)isEncrypted isGroup:(BOOL)isGroup{
|
||||
|
|
@ -865,7 +878,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
return nil;
|
||||
}
|
||||
LinphoneChatRoom *basicRoom = linphone_core_get_chat_room(LC, addresses->data);
|
||||
[self goToChatRoom:basicRoom];
|
||||
[self goToChatRoomSwift:basicRoom];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
|
@ -888,6 +901,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;
|
||||
|
|
@ -905,31 +919,50 @@ 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)goToChatRoomSwift:(LinphoneChatRoom *)cr {
|
||||
_waitView.hidden = YES;
|
||||
_waitView = NULL;
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
self.currentRoom = view.linphoneChatRoom;
|
||||
[view initChatRoomWithCChatRoom:cr];
|
||||
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
}
|
||||
|
||||
- (void)resetBeforeGoToChatRoomSwift{
|
||||
ChatConversationViewSwift *view = VIEW(ChatConversationViewSwift);
|
||||
[view resetView];
|
||||
}
|
||||
|
||||
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 goToChatRoomSwift:cr];
|
||||
if (!IPAD)
|
||||
return;
|
||||
|
||||
if (PhoneMainView.instance.currentView != ChatsListView.compositeViewDescription && PhoneMainView.instance.currentView != ChatConversationViewSwift.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));
|
||||
|
|
@ -938,7 +971,7 @@ void main_view_chat_room_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomSta
|
|||
break;
|
||||
case LinphoneChatRoomStateTerminated:
|
||||
LOGI(@"Chat room [%p] has been terminated.", cr);
|
||||
[view goToChatRoom:cr];
|
||||
[view goToChatRoomSwift:cr];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -962,4 +995,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,23 +645,40 @@ 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)) {
|
||||
[hiddenKeys addObject:@"contacts_menu"];
|
||||
}
|
||||
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"disable_chat_feature"]){
|
||||
[hiddenKeys addObject:@"message_menu"];
|
||||
}
|
||||
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"disable_video_feature"]) {
|
||||
[hiddenKeys addObject:@"enable_video_preference"];
|
||||
[hiddenKeys addObject:@"video_menu"];
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
[hiddenKeys addObject:@"debug_actions_group"];
|
||||
[hiddenKeys addObject:@"release_button"];
|
||||
|
|
@ -761,6 +798,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 +895,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 +954,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(
|
||||
|
|
@ -1072,6 +1128,14 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
|
||||
// retrieve linphone logs if available
|
||||
char *filepath = linphone_core_compress_log_collection();
|
||||
|
||||
|
||||
LinphoneCoreCbs *coreCbs = linphone_factory_create_core_cbs(linphone_factory_get());
|
||||
linphone_core_cbs_set_log_collection_upload_state_changed(coreCbs, core_log_collection_upload_state_changed);
|
||||
linphone_core_add_callbacks(LC, coreCbs);
|
||||
|
||||
linphone_core_upload_log_collection(LC);
|
||||
|
||||
if (filepath != NULL) {
|
||||
NSString *filename = [[NSString stringWithUTF8String:filepath] componentsSeparatedByString:@"/"].lastObject;
|
||||
NSString *mimeType = nil;
|
||||
|
|
@ -1119,6 +1183,17 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat
|
|||
[self emailAttachments:attachments];
|
||||
}
|
||||
|
||||
void core_log_collection_upload_state_changed(LinphoneCore *core, LinphoneCoreLogCollectionUploadState state , const char* info) {
|
||||
|
||||
LOGD(@"LinphoneCoreLogCollectionUploadStateDelivered core_log_collection_upload_state_changed %s", info);
|
||||
if (state == LinphoneCoreLogCollectionUploadStateDelivered) {
|
||||
LOGD(@"LinphoneCoreLogCollectionUploadStateDelivered %s", info);
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
|
||||
pasteboard.string = [NSString stringWithUTF8String: info];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendEmailWithPrivacyAttachments {
|
||||
NSMutableArray *attachments = [[NSMutableArray alloc] initWithCapacity:4];
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
@ -103,13 +106,17 @@
|
|||
}]];
|
||||
}
|
||||
|
||||
[_sideMenuEntries addObject:[[SideMenuEntry alloc] initWithTitle:VoipTexts.conference_scheduled
|
||||
image:[UIImage imageNamed:@"menu_voip_meeting_schedule"]
|
||||
tapBlock:^() {
|
||||
[PhoneMainView.instance
|
||||
changeCurrentView:ScheduledConferencesView.compositeViewDescription];
|
||||
LinphoneAccount *defaultAccount = linphone_core_get_default_account(LC);
|
||||
if (defaultAccount && linphone_account_params_get_audio_video_conference_factory_address(linphone_account_get_params(defaultAccount))){
|
||||
|
||||
[_sideMenuEntries addObject:[[SideMenuEntry alloc] initWithTitle:VoipTexts.conference_scheduled
|
||||
image:[UIImage imageNamed:@"side_menu_voip_meeting_schedule"]
|
||||
tapBlock:^() {
|
||||
[PhoneMainView.instance
|
||||
changeCurrentView:ScheduledConferencesView.compositeViewDescription];
|
||||
|
||||
}]];
|
||||
}]];
|
||||
}
|
||||
|
||||
[_sideMenuEntries addObject:[[SideMenuEntry alloc] initWithTitle:NSLocalizedString(@"About", nil)
|
||||
image:[UIImage imageNamed:@"menu_about.png"]
|
||||
|
|
@ -127,9 +134,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 +152,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) {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ enum NetworkType: Int {
|
|||
Log.directLog(BCTBX_LOG_MESSAGE, text: "File :\(file) removed")
|
||||
|
||||
} catch {
|
||||
print("Could not remove file : \(file) \(error)")
|
||||
Log.e("Could not remove file : \(file) \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
* 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 Foundation
|
||||
import linphonesw
|
||||
|
|
@ -27,14 +27,14 @@ 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
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* CallManager is a class that manages application calls and supports callkit.
|
||||
* There is only one CallManager by calling CallManager.instance().
|
||||
*/
|
||||
* CallManager is a class that manages application calls and supports callkit.
|
||||
* There is only one CallManager by calling CallManager.instance().
|
||||
*/
|
||||
@objc class CallManager: NSObject, CoreDelegate {
|
||||
static var theCallManager: CallManager?
|
||||
let providerDelegate: ProviderDelegate! // to support callkit
|
||||
|
|
@ -49,28 +49,31 @@ import AVFoundation
|
|||
var actionsToPerformOnceWhenCoreIsOn : [(()->Void)] = []
|
||||
var conference: Conference?
|
||||
var callkitAudioSessionActivated : Bool? = nil // if "nil", ignore.
|
||||
var actionToFulFill : CXCallAction? = nil
|
||||
var endCallKitReplacedCall: Bool = true
|
||||
static var uuidReplacedCall: String?
|
||||
|
||||
var backgroundContextCall : Call?
|
||||
@objc var backgroundContextCameraIsEnabled : Bool = false
|
||||
|
||||
|
||||
fileprivate override init() {
|
||||
providerDelegate = ProviderDelegate.shared
|
||||
callController = CXCallController()
|
||||
}
|
||||
|
||||
|
||||
@objc static func instance() -> CallManager {
|
||||
if (theCallManager == nil) {
|
||||
theCallManager = CallManager()
|
||||
}
|
||||
return theCallManager!
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@objc func setCore(core: OpaquePointer) {
|
||||
lc = Core.getSwiftObject(cObject: core)
|
||||
lc?.addDelegate(delegate: self)
|
||||
}
|
||||
|
||||
|
||||
@objc static func getAppData(call: OpaquePointer) -> CallAppData? {
|
||||
let sCall = Call.getSwiftObject(cObject: call)
|
||||
return getAppData(sCall: sCall)
|
||||
|
|
@ -82,7 +85,7 @@ import AVFoundation
|
|||
}
|
||||
return Unmanaged<CallAppData>.fromOpaque(sCall.userData!).takeUnretainedValue()
|
||||
}
|
||||
|
||||
|
||||
@objc static func setAppData(call:OpaquePointer, appData: CallAppData) {
|
||||
let sCall = Call.getSwiftObject(cObject: call)
|
||||
setAppData(sCall: sCall, appData: appData)
|
||||
|
|
@ -98,12 +101,12 @@ import AVFoundation
|
|||
sCall.userData = UnsafeMutableRawPointer(Unmanaged.passRetained(appData!).toOpaque())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func findCall(callId: String?) -> OpaquePointer? {
|
||||
let call = callByCallId(callId: callId)
|
||||
return call?.getCobject
|
||||
}
|
||||
|
||||
|
||||
func callByCallId(callId: String?) -> Call? {
|
||||
if (callId == nil) {
|
||||
return nil
|
||||
|
|
@ -114,7 +117,7 @@ import AVFoundation
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@objc func stopLinphoneCore() {
|
||||
if (lc?.callsNb == 0) {
|
||||
lc?.stopAsync()
|
||||
|
|
@ -133,11 +136,11 @@ import AVFoundation
|
|||
}
|
||||
|
||||
@objc static func callKitEnabled() -> Bool {
|
||||
#if !targetEnvironment(simulator)
|
||||
#if !targetEnvironment(simulator)
|
||||
if ConfigManager.instance().lpConfigBoolForKey(key: "use_callkit", section: "app") {
|
||||
return true
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -208,17 +211,17 @@ import AVFoundation
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func displayIncomingCall(call:Call?, handle: String, hasVideo: Bool, callId: String, displayName:String) {
|
||||
let uuid = UUID()
|
||||
let callInfo = CallInfo.newIncomingCallInfo(callId: callId)
|
||||
|
||||
|
||||
providerDelegate.callInfos.updateValue(callInfo, forKey: uuid)
|
||||
providerDelegate.uuids.updateValue(uuid, forKey: callId)
|
||||
providerDelegate.reportIncomingCall(call:call, uuid: uuid, handle: handle, hasVideo: hasVideo, displayName: displayName)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@objc func acceptCall(call: OpaquePointer?, hasVideo:Bool) {
|
||||
if (call == nil) {
|
||||
Log.directLog(BCTBX_LOG_ERROR, text: "Can not accept null call!")
|
||||
|
|
@ -227,7 +230,7 @@ import AVFoundation
|
|||
let call = Call.getSwiftObject(cObject: call!)
|
||||
acceptCall(call: call, hasVideo: hasVideo)
|
||||
}
|
||||
|
||||
|
||||
func acceptCall(call: Call, hasVideo:Bool) {
|
||||
do {
|
||||
let callParams = try lc!.createCallParams(call: call)
|
||||
|
|
@ -239,7 +242,7 @@ import AVFoundation
|
|||
}
|
||||
callParams.lowBandwidthEnabled = low_bandwidth
|
||||
}
|
||||
|
||||
|
||||
//We set the record file name here because we can't do it after the call is started.
|
||||
let address = call.callLog?.fromAddress
|
||||
let writablePath = AppManager.recordingFilePathFromCall(address: address?.username ?? "")
|
||||
|
|
@ -265,14 +268,14 @@ import AVFoundation
|
|||
Log.directLog(BCTBX_LOG_ERROR, text: "accept call failed \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// for outgoing call. There is not yet callId
|
||||
@objc func startCall(addr: OpaquePointer?, isSas: Bool, isVideo: Bool, isConference: Bool = false) {
|
||||
if (addr == nil) {
|
||||
print("Can not start a call with null address!")
|
||||
Log.i("Can not start a call with null address!")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let sAddr = Address.getSwiftObject(cObject: addr!)
|
||||
if (CallManager.callKitEnabled() && !CallManager.instance().nextCallIsTransfer && lc?.conference?.isIn != true) {
|
||||
let uuid = UUID()
|
||||
|
|
@ -280,11 +283,11 @@ import AVFoundation
|
|||
let handle = CXHandle(type: .generic, value: sAddr.asStringUriOnly())
|
||||
let startCallAction = CXStartCallAction(call: uuid, handle: handle)
|
||||
let transaction = CXTransaction(action: startCallAction)
|
||||
|
||||
|
||||
let callInfo = CallInfo.newOutgoingCallInfo(addr: sAddr, isSas: isSas, displayName: name, isVideo: isVideo, isConference:isConference)
|
||||
providerDelegate.callInfos.updateValue(callInfo, forKey: uuid)
|
||||
providerDelegate.uuids.updateValue(uuid, forKey: "")
|
||||
|
||||
|
||||
setHeldOtherCalls(exceptCallid: "")
|
||||
requestTransaction(transaction, action: "startCall")
|
||||
}else {
|
||||
|
|
@ -294,30 +297,30 @@ import AVFoundation
|
|||
|
||||
func startCall(addr:String, isSas: Bool = false, isVideo: Bool, isConference: Bool = false) {
|
||||
do {
|
||||
let address = try Factory.Instance.createAddress(addr: addr)
|
||||
let address = try Factory.Instance.createAddress(addr: addr)
|
||||
startCall(addr: address.getCobject,isSas: isSas, isVideo: isVideo, isConference:isConference)
|
||||
} catch {
|
||||
Log.e("[CallManager] unable to create address for a new outgoing call : \(addr) \(error) ")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func doCall(addr: Address, isSas: Bool, isVideo: Bool, isConference:Bool = false) throws {
|
||||
let displayName = FastAddressBook.displayName(for: addr.getCobject)
|
||||
|
||||
|
||||
let lcallParams = try CallManager.instance().lc!.createCallParams(call: nil)
|
||||
if ConfigManager.instance().lpConfigBoolForKey(key: "edge_opt_preference") && AppManager.network() == .network_2g {
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Enabling low bandwidth mode")
|
||||
lcallParams.lowBandwidthEnabled = true
|
||||
}
|
||||
|
||||
|
||||
if (displayName != nil) {
|
||||
try addr.setDisplayname(newValue: displayName!)
|
||||
}
|
||||
|
||||
|
||||
if(ConfigManager.instance().lpConfigBoolForKey(key: "override_domain_with_default_one")) {
|
||||
try addr.setDomain(newValue: ConfigManager.instance().lpConfigStringForKey(key: "domain", section: "assistant"))
|
||||
}
|
||||
|
||||
|
||||
if (CallManager.instance().nextCallIsTransfer) {
|
||||
let call = CallManager.instance().lc!.currentCall
|
||||
try call?.transferTo(referTo: addr)
|
||||
|
|
@ -359,7 +362,7 @@ import AVFoundation
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func groupCall() {
|
||||
if (CallManager.callKitEnabled()) {
|
||||
let calls = lc?.calls
|
||||
|
|
@ -368,29 +371,29 @@ import AVFoundation
|
|||
}
|
||||
let firstCall = calls!.first?.callLog?.callId ?? ""
|
||||
let lastCall = (calls!.count > 1) ? calls!.last?.callLog?.callId ?? "" : ""
|
||||
|
||||
|
||||
let currentUuid = CallManager.instance().providerDelegate.uuids["\(firstCall)"]
|
||||
if (currentUuid == nil) {
|
||||
Log.directLog(BCTBX_LOG_ERROR, text: "Can not find correspondant call to group.")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let newUuid = CallManager.instance().providerDelegate.uuids["\(lastCall)"]
|
||||
let groupAction = CXSetGroupCallAction(call: currentUuid!, callUUIDToGroupWith: newUuid)
|
||||
let transcation = CXTransaction(action: groupAction)
|
||||
requestTransaction(transcation, action: "groupCall")
|
||||
|
||||
|
||||
setResumeCalls()
|
||||
} else {
|
||||
try? lc?.addAllToConference()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func removeAllCallInfos() {
|
||||
providerDelegate.callInfos.removeAll()
|
||||
providerDelegate.uuids.removeAll()
|
||||
}
|
||||
|
||||
|
||||
@objc func terminateCall(call: OpaquePointer?) {
|
||||
if (call == nil) {
|
||||
Log.directLog(BCTBX_LOG_ERROR, text: "Can not terminate null call!")
|
||||
|
|
@ -404,12 +407,12 @@ import AVFoundation
|
|||
Log.directLog(BCTBX_LOG_ERROR, text: "Failed to terminate call failed because \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func markCallAsDeclined(callId: String) {
|
||||
if !CallManager.callKitEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let uuid = providerDelegate.uuids["\(callId)"]
|
||||
if (uuid == nil) {
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Mark call \(callId) as declined.")
|
||||
|
|
@ -423,7 +426,7 @@ import AVFoundation
|
|||
providerDelegate.endCall(uuid: uuid!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func setHeld(call: OpaquePointer, hold: Bool) {
|
||||
let sCall = Call.getSwiftObject(cObject: call)
|
||||
if (!hold) {
|
||||
|
|
@ -434,13 +437,13 @@ import AVFoundation
|
|||
|
||||
func setHeld(call: Call, hold: Bool) {
|
||||
|
||||
#if targetEnvironment(simulator)
|
||||
#if targetEnvironment(simulator)
|
||||
if (hold) {
|
||||
try?call.pause()
|
||||
} else {
|
||||
try?call.resume()
|
||||
}
|
||||
#else
|
||||
#else
|
||||
let callid = call.callLog?.callId ?? ""
|
||||
let uuid = providerDelegate.uuids["\(callid)"]
|
||||
if (uuid == nil) {
|
||||
|
|
@ -450,9 +453,9 @@ import AVFoundation
|
|||
let setHeldAction = CXSetHeldCallAction(call: uuid!, onHold: hold)
|
||||
let transaction = CXTransaction(action: setHeldAction)
|
||||
requestTransaction(transaction, action: "setHeld")
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@objc func setHeldOtherCalls(exceptCallid: String) {
|
||||
for call in CallManager.instance().lc!.calls {
|
||||
if (call.callLog?.callId != exceptCallid && call.state != .Paused && call.state != .Pausing && call.state != .PausedByRemote) {
|
||||
|
|
@ -460,7 +463,7 @@ import AVFoundation
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func setResumeCalls() {
|
||||
for call in CallManager.instance().lc!.calls {
|
||||
if (call.state == .Paused || call.state == .Pausing || call.state == .PausedByRemote) {
|
||||
|
|
@ -468,7 +471,7 @@ import AVFoundation
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func performActionWhenCoreIsOn(action: @escaping ()->Void ) {
|
||||
if (globalState == .On) {
|
||||
action()
|
||||
|
|
@ -476,14 +479,14 @@ import AVFoundation
|
|||
actionsToPerformOnceWhenCoreIsOn.append(action)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func acceptVideo(call: OpaquePointer, confirm: Bool) {
|
||||
let sCall = Call.getSwiftObject(cObject: call)
|
||||
let params = try? lc?.createCallParams(call: sCall)
|
||||
params?.videoEnabled = confirm
|
||||
try? sCall.acceptUpdate(params: params)
|
||||
}
|
||||
|
||||
|
||||
func onGlobalStateChanged(core: Core, state: GlobalState, message: String) {
|
||||
if (state == .On) {
|
||||
actionsToPerformOnceWhenCoreIsOn.forEach {
|
||||
|
|
@ -493,7 +496,7 @@ import AVFoundation
|
|||
}
|
||||
globalState = state
|
||||
}
|
||||
|
||||
|
||||
func onRegistrationStateChanged(core: Core, proxyConfig: ProxyConfig, state: RegistrationState, message: String) {
|
||||
if core.proxyConfigList.count == 1 && (state == .Failed || state == .Cleared){
|
||||
// terminate callkit immediately when registration failed or cleared, supporting single proxy configuration
|
||||
|
|
@ -506,7 +509,7 @@ import AVFoundation
|
|||
continue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CallManager.instance().providerDelegate.endCall(uuid: call.value)
|
||||
}
|
||||
CallManager.instance().endCallkit = true
|
||||
|
|
@ -533,7 +536,7 @@ import AVFoundation
|
|||
return FastAddressBook.displayName(for: call.remoteAddress?.getCobject) ?? "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func onCallStateChanged(core: Core, call: Call, state cstate: Call.State, message: String) {
|
||||
let callLog = call.callLog
|
||||
let callId = callLog?.callId
|
||||
|
|
@ -541,7 +544,7 @@ import AVFoundation
|
|||
displayIncomingCall(call: call, handle: "Calling", hasVideo: false, callId: callId!, displayName: "Calling")
|
||||
} else {
|
||||
let video = (core.videoActivationPolicy?.automaticallyAccept ?? false) && (call.remoteParams?.videoEnabled ?? false)
|
||||
|
||||
|
||||
if (call.userData == nil) {
|
||||
let appData = CallAppData()
|
||||
CallManager.setAppData(sCall: call, appData: appData)
|
||||
|
|
@ -552,161 +555,194 @@ import AVFoundation
|
|||
ConferenceViewModel.shared.initConference(conference)
|
||||
ConferenceViewModel.shared.configureConference(conference)
|
||||
}
|
||||
|
||||
|
||||
switch cstate {
|
||||
case .IncomingReceived:
|
||||
let addr = call.remoteAddress
|
||||
case .IncomingReceived:
|
||||
let addr = call.remoteAddress
|
||||
var displayName = incomingDisplayName(call: call)
|
||||
|
||||
if (CallManager.callKitEnabled()) {
|
||||
let isConference = isConferenceCall(call: call)
|
||||
let isEarlyConference = isConference && CallsViewModel.shared.currentCallData.value??.isConferenceCall.value != true // Conference info not be received yet.
|
||||
if (isEarlyConference) {
|
||||
CallsViewModel.shared.currentCallData.readCurrentAndObserve { _ in
|
||||
let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if (uuid != nil) {
|
||||
displayName = "\(VoipTexts.conference_incoming_title): \(CallsViewModel.shared.currentCallData.value??.remoteConferenceSubject.value ?? "") (\(CallsViewModel.shared.currentCallData.value??.conferenceParticipantsCountLabel.value ?? ""))"
|
||||
CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if (uuid != nil) {
|
||||
// Tha app is now registered, updated the call already existed.
|
||||
CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
|
||||
} else {
|
||||
CallManager.instance().displayIncomingCall(call: call, handle: addr!.asStringUriOnly(), hasVideo: video, callId: callId!, displayName: displayName)
|
||||
}
|
||||
} else if (UIApplication.shared.applicationState != .active) {
|
||||
// not support callkit , use notif
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = NSLocalizedString("Incoming call", comment: "")
|
||||
content.body = displayName
|
||||
content.sound = UNNotificationSound.init(named: UNNotificationSoundName.init("notes_of_the_optimistic.caf"))
|
||||
content.categoryIdentifier = "call_cat"
|
||||
content.userInfo = ["CallId" : callId!]
|
||||
let req = UNNotificationRequest.init(identifier: "call_request", content: content, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(req, withCompletionHandler: nil)
|
||||
}
|
||||
break
|
||||
case .StreamsRunning:
|
||||
if (CallManager.callKitEnabled()) {
|
||||
let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if (uuid != nil) {
|
||||
let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!]
|
||||
if (callInfo != nil && callInfo!.isOutgoing && !callInfo!.connected) {
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call connected with uuid \(uuid!) and callId \(callId!)")
|
||||
CallManager.instance().providerDelegate.reportOutgoingCallConnected(uuid: uuid!)
|
||||
callInfo!.connected = true
|
||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!)
|
||||
if call.replacedCall != nil {
|
||||
endCallKitReplacedCall = false
|
||||
|
||||
let uuid = CallManager.instance().providerDelegate.uuids["\(CallManager.uuidReplacedCall)"]
|
||||
let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!]
|
||||
callInfo!.callId = CallManager.instance().referedToCall ?? ""
|
||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!)
|
||||
CallManager.instance().providerDelegate.uuids.removeValue(forKey: callId!)
|
||||
CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callInfo!.callId)
|
||||
CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
|
||||
} else if (CallManager.callKitEnabled()) {
|
||||
let isConference = isConferenceCall(call: call)
|
||||
let isEarlyConference = isConference && CallsViewModel.shared.currentCallData.value??.isConferenceCall.value != true // Conference info not be received yet.
|
||||
if (isEarlyConference) {
|
||||
CallsViewModel.shared.currentCallData.readCurrentAndObserve { _ in
|
||||
let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if (uuid != nil) {
|
||||
displayName = "\(VoipTexts.conference_incoming_title): \(CallsViewModel.shared.currentCallData.value??.remoteConferenceSubject.value ?? "") (\(CallsViewModel.shared.currentCallData.value??.conferenceParticipantsCountLabel.value ?? ""))"
|
||||
CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CallManager.instance().speakerBeforePause) {
|
||||
CallManager.instance().speakerBeforePause = false
|
||||
CallManager.instance().changeRouteToSpeaker()
|
||||
|
||||
let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if call.replacedCall == nil {
|
||||
CallManager.uuidReplacedCall = callId
|
||||
}
|
||||
break
|
||||
case .OutgoingInit,
|
||||
.OutgoingProgress,
|
||||
.OutgoingRinging,
|
||||
.OutgoingEarlyMedia:
|
||||
if (CallManager.callKitEnabled()) {
|
||||
let uuid = CallManager.instance().providerDelegate.uuids[""]
|
||||
if (uuid != nil) {
|
||||
let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!]
|
||||
callInfo!.callId = callId!
|
||||
|
||||
if (uuid != nil) {
|
||||
// Tha app is now registered, updated the call already existed.
|
||||
CallManager.instance().providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
|
||||
} else {
|
||||
CallManager.instance().displayIncomingCall(call: call, handle: addr!.asStringUriOnly(), hasVideo: video, callId: callId!, displayName: displayName)
|
||||
}
|
||||
} else if (UIApplication.shared.applicationState != .active) {
|
||||
// not support callkit , use notif
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = NSLocalizedString("Incoming call", comment: "")
|
||||
content.body = displayName
|
||||
content.sound = UNNotificationSound.init(named: UNNotificationSoundName.init("notes_of_the_optimistic.caf"))
|
||||
content.categoryIdentifier = "call_cat"
|
||||
content.userInfo = ["CallId" : callId!]
|
||||
let req = UNNotificationRequest.init(identifier: "call_request", content: content, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(req, withCompletionHandler: nil)
|
||||
}
|
||||
break
|
||||
case .StreamsRunning:
|
||||
if (CallManager.callKitEnabled()) {
|
||||
let uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if (uuid != nil) {
|
||||
let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!]
|
||||
if (callInfo != nil && callInfo!.isOutgoing && !callInfo!.connected) {
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call connected with uuid \(uuid!) and callId \(callId!)")
|
||||
CallManager.instance().providerDelegate.reportOutgoingCallConnected(uuid: uuid!)
|
||||
callInfo!.connected = true
|
||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!)
|
||||
CallManager.instance().providerDelegate.uuids.removeValue(forKey: "")
|
||||
CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callId!)
|
||||
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call started connecting with uuid \(uuid!) and callId \(callId!)")
|
||||
CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CallManager.instance().speakerBeforePause) {
|
||||
CallManager.instance().speakerBeforePause = false
|
||||
CallManager.instance().changeRouteToSpeaker()
|
||||
}
|
||||
actionToFulFill?.fulfill()
|
||||
actionToFulFill = nil
|
||||
break
|
||||
case .Paused:
|
||||
actionToFulFill?.fulfill()
|
||||
actionToFulFill = nil
|
||||
break
|
||||
case .OutgoingInit,
|
||||
.OutgoingProgress,
|
||||
.OutgoingRinging,
|
||||
.OutgoingEarlyMedia:
|
||||
if (CallManager.callKitEnabled()) {
|
||||
let uuid = CallManager.instance().providerDelegate.uuids[""]
|
||||
if (uuid != nil) {
|
||||
let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!]
|
||||
callInfo!.callId = callId!
|
||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!)
|
||||
CallManager.instance().providerDelegate.uuids.removeValue(forKey: "")
|
||||
CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callId!)
|
||||
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: outgoing call started connecting with uuid \(uuid!) and callId \(callId!)")
|
||||
CallManager.instance().providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!)
|
||||
} else {
|
||||
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
|
||||
case .End,
|
||||
.Error:
|
||||
var displayName = "Unknown"
|
||||
if (call.dir == .Incoming) {
|
||||
displayName = incomingDisplayName(call: call)
|
||||
} else if let addr = call.remoteAddress, let contactName = FastAddressBook.displayName(for: addr.getCobject) {
|
||||
displayName = contactName
|
||||
}
|
||||
}
|
||||
break
|
||||
case .End,
|
||||
.Error:
|
||||
var displayName = "Unknown"
|
||||
if (call.dir == .Incoming) {
|
||||
displayName = incomingDisplayName(call: call)
|
||||
} else if let addr = call.remoteAddress, let contactName = FastAddressBook.displayName(for: addr.getCobject) {
|
||||
displayName = contactName
|
||||
}
|
||||
|
||||
UIDevice.current.isProximityMonitoringEnabled = false
|
||||
if (CallManager.instance().lc!.callsNb == 0) {
|
||||
CallManager.instance().changeRouteToDefault()
|
||||
// disable this because I don't find anygood reason for it: _bluetoothAvailable = FALSE;
|
||||
// furthermore it introduces a bug when calling multiple times since route may not be
|
||||
// reconfigured between cause leading to bluetooth being disabled while it should not
|
||||
//CallManager.instance().bluetoothEnabled = false
|
||||
}
|
||||
|
||||
if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) {
|
||||
// Configure the notification's payload.
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = NSString.localizedUserNotificationString(forKey: NSLocalizedString("Missed call", comment: ""), arguments: nil)
|
||||
content.body = NSString.localizedUserNotificationString(forKey: displayName, arguments: nil)
|
||||
|
||||
UIDevice.current.isProximityMonitoringEnabled = false
|
||||
if (CallManager.instance().lc!.callsNb == 0) {
|
||||
CallManager.instance().changeRouteToDefault()
|
||||
// disable this because I don't find anygood reason for it: _bluetoothAvailable = FALSE;
|
||||
// furthermore it introduces a bug when calling multiple times since route may not be
|
||||
// reconfigured between cause leading to bluetooth being disabled while it should not
|
||||
//CallManager.instance().bluetoothEnabled = false
|
||||
}
|
||||
|
||||
if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) {
|
||||
// Configure the notification's payload.
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = NSString.localizedUserNotificationString(forKey: NSLocalizedString("Missed call", comment: ""), arguments: nil)
|
||||
content.body = NSString.localizedUserNotificationString(forKey: displayName, arguments: nil)
|
||||
|
||||
// Deliver the notification.
|
||||
let request = UNNotificationRequest(identifier: "call_request", content: content, trigger: nil) // Schedule the notification.
|
||||
let center = UNUserNotificationCenter.current()
|
||||
center.add(request) { (error : Error?) in
|
||||
if error != nil {
|
||||
// Deliver the notification.
|
||||
let request = UNNotificationRequest(identifier: "call_request", content: content, trigger: nil) // Schedule the notification.
|
||||
let center = UNUserNotificationCenter.current()
|
||||
center.add(request) { (error : Error?) in
|
||||
if error != nil {
|
||||
Log.directLog(BCTBX_LOG_ERROR, text: "Error while adding notification request : \(error!.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CallManager.callKitEnabled()) {
|
||||
var uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if (callId == CallManager.instance().referedToCall) {
|
||||
// refered call ended before connecting
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered to call : \(String(describing: CallManager.instance().referedToCall))")
|
||||
}
|
||||
|
||||
if (CallManager.callKitEnabled()) {
|
||||
var uuid = CallManager.instance().providerDelegate.uuids["\(callId!)"]
|
||||
if (callId == CallManager.instance().referedToCall) {
|
||||
// refered call ended before connecting
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered to call : \(String(describing: CallManager.instance().referedToCall))")
|
||||
CallManager.instance().referedFromCall = nil
|
||||
CallManager.instance().referedToCall = nil
|
||||
}
|
||||
if uuid == nil {
|
||||
// the call not yet connected
|
||||
uuid = CallManager.instance().providerDelegate.uuids[""]
|
||||
}
|
||||
if (uuid != nil) {
|
||||
if (callId == CallManager.instance().referedFromCall) {
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered from call : \(String(describing: CallManager.instance().referedFromCall))")
|
||||
CallManager.instance().referedFromCall = nil
|
||||
let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!]
|
||||
callInfo!.callId = CallManager.instance().referedToCall ?? ""
|
||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!)
|
||||
CallManager.instance().providerDelegate.uuids.removeValue(forKey: callId!)
|
||||
CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callInfo!.callId)
|
||||
CallManager.instance().referedToCall = nil
|
||||
break
|
||||
}
|
||||
if uuid == nil {
|
||||
// the call not yet connected
|
||||
uuid = CallManager.instance().providerDelegate.uuids[""]
|
||||
}
|
||||
if (uuid != nil) {
|
||||
if (callId == CallManager.instance().referedFromCall) {
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "Callkit: end refered from call : \(String(describing: CallManager.instance().referedFromCall))")
|
||||
CallManager.instance().referedFromCall = nil
|
||||
let callInfo = CallManager.instance().providerDelegate.callInfos[uuid!]
|
||||
callInfo!.callId = CallManager.instance().referedToCall ?? ""
|
||||
CallManager.instance().providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!)
|
||||
CallManager.instance().providerDelegate.uuids.removeValue(forKey: callId!)
|
||||
CallManager.instance().providerDelegate.uuids.updateValue(uuid!, forKey: callInfo!.callId)
|
||||
CallManager.instance().referedToCall = nil
|
||||
break
|
||||
}
|
||||
|
||||
if (endCallKitReplacedCall){
|
||||
let transaction = CXTransaction(action:
|
||||
CXEndCallAction(call: uuid!))
|
||||
CXEndCallAction(call: uuid!))
|
||||
CallManager.instance().requestTransaction(transaction, action: "endCall")
|
||||
}else{
|
||||
endCallKitReplacedCall = true
|
||||
}
|
||||
|
||||
}
|
||||
break
|
||||
case .Released:
|
||||
call.userData = nil
|
||||
break
|
||||
case .Referred:
|
||||
CallManager.instance().referedFromCall = call.callLog?.callId
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
break
|
||||
case .Released:
|
||||
CallManager.setAppData(sCall : call, appData : nil);
|
||||
break
|
||||
case .Referred:
|
||||
CallManager.instance().referedFromCall = call.callLog?.callId
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
|
@ -721,7 +757,7 @@ import AVFoundation
|
|||
AnyHashable("message"): message
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
// Audio messages
|
||||
|
||||
@objc func activateAudioSession() {
|
||||
|
|
@ -742,7 +778,7 @@ import AVFoundation
|
|||
}
|
||||
return speakerCard != nil ? speakerCard : earpieceCard
|
||||
}
|
||||
|
||||
|
||||
// Local Conference
|
||||
|
||||
@objc func startLocalConference() {
|
||||
|
|
@ -753,18 +789,18 @@ import AVFoundation
|
|||
}
|
||||
let firstCall = calls!.first?.callLog?.callId ?? ""
|
||||
let lastCall = (calls!.count > 1) ? calls!.last?.callLog?.callId ?? "" : ""
|
||||
|
||||
|
||||
let currentUuid = CallManager.instance().providerDelegate.uuids["\(firstCall)"]
|
||||
if (currentUuid == nil) {
|
||||
Log.directLog(BCTBX_LOG_ERROR, text: "Can not find correspondant call to group.")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let newUuid = CallManager.instance().providerDelegate.uuids["\(lastCall)"]
|
||||
let groupAction = CXSetGroupCallAction(call: currentUuid!, callUUIDToGroupWith: newUuid)
|
||||
let transcation = CXTransaction(action: groupAction)
|
||||
requestTransaction(transcation, action: "groupCall")
|
||||
|
||||
|
||||
setResumeCalls()
|
||||
} else {
|
||||
addAllToLocalConference()
|
||||
|
|
@ -775,6 +811,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 +820,12 @@ import AVFoundation
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@objc func applyInternationalPrefix() -> Bool {
|
||||
if let account = lc?.defaultAccount, let params = account.params {
|
||||
return params.useInternationalPrefixForCallsAndChats
|
||||
}
|
||||
return true; // Legacy behavior
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
106
Classes/Swift/Chat/Data/FileType.swift
Normal file
106
Classes/Swift/Chat/Data/FileType.swift
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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 Foundation
|
||||
|
||||
enum FileType : String {
|
||||
case pdf = "pdf";
|
||||
case png = "png";
|
||||
case jpg = "jpg";
|
||||
case jpeg = "jpeg";
|
||||
case bmp = "bmp";
|
||||
case heic = "heic";
|
||||
case mkv = "mkv";
|
||||
case avi = "avi";
|
||||
case mov = "mov";
|
||||
case mp4 = "mp4";
|
||||
case wav = "wav";
|
||||
case au = "au";
|
||||
case m4a = "m4a";
|
||||
case other = "other";
|
||||
|
||||
case file_pdf_default = "file_pdf_default";
|
||||
case file_picture_default = "file_picture_default";
|
||||
case file_video_default = "file_video_default";
|
||||
case file_audio_default = "file_audio_default";
|
||||
case file_default = "file_default";
|
||||
|
||||
func getGroupTypeFromFile() -> String? {
|
||||
switch self {
|
||||
case .pdf, .file_pdf_default:
|
||||
return "file_pdf_default"
|
||||
|
||||
case .png, .jpg, .jpeg, .bmp, .heic, .file_picture_default:
|
||||
return "file_picture_default"
|
||||
|
||||
case .mkv, .avi, .mov, .mp4, .file_video_default:
|
||||
return "file_video_default"
|
||||
|
||||
case .wav, .au, .m4a, .file_audio_default:
|
||||
return "file_audio_default"
|
||||
|
||||
default:
|
||||
return "file_default"
|
||||
}
|
||||
}
|
||||
|
||||
func getImageFromFile() -> UIImage? {
|
||||
switch self {
|
||||
case .pdf, .file_pdf_default:
|
||||
return UIImage(named:"file_pdf_default")
|
||||
|
||||
case .png, .jpg, .jpeg, .bmp, .heic, .file_picture_default:
|
||||
return UIImage(named:"file_picture_default")
|
||||
|
||||
case .mkv, .avi, .mov, .mp4, .file_video_default:
|
||||
return UIImage(named:"file_video_default")
|
||||
|
||||
case .wav, .au, .m4a, .file_audio_default:
|
||||
return UIImage(named:"file_audio_default")
|
||||
|
||||
default:
|
||||
return UIImage(named:"file_default")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension FileType {
|
||||
init() {
|
||||
self = .file_default
|
||||
}
|
||||
|
||||
init?(_ value: String) {
|
||||
switch value.lowercased() {
|
||||
case "pdf", "file_pdf_default":
|
||||
self = .file_pdf_default
|
||||
|
||||
case "png", "jpg", "jpeg", "bmp", "heic", "file_picture_default":
|
||||
self = .file_picture_default
|
||||
|
||||
case "mkv", "avi", "mov", "mp4", "file_video_default":
|
||||
self = .file_video_default
|
||||
|
||||
case "wav", "au", "m4a", "file_audio_default":
|
||||
self = .file_audio_default
|
||||
|
||||
default:
|
||||
self = .file_default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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 Foundation
|
||||
import linphonesw
|
||||
|
||||
|
||||
class ChatConversationTableViewModel {
|
||||
|
||||
static let sharedModel = ChatConversationTableViewModel()
|
||||
|
||||
var chatRoom: ChatRoom? = nil
|
||||
|
||||
var refreshIndexPath = MutableLiveData<Int>(0)
|
||||
|
||||
var onClickIndexPath = MutableLiveData<Int>(0)
|
||||
var onClickMessageIndexPath = 0
|
||||
|
||||
|
||||
var editModeOn = MutableLiveData<Bool>(false)
|
||||
|
||||
var messageSelected = MutableLiveData<Int>(0)
|
||||
var messageListSelected = MutableLiveData<[Bool]>([])
|
||||
|
||||
var messageListToDelete : [EventLog] = []
|
||||
|
||||
func getMessage(index: Int) -> EventLog? {
|
||||
if (chatRoom != nil) {
|
||||
let chatRoomEvents = chatRoom?.getHistoryRangeEvents(begin: index, end: index+1)
|
||||
return chatRoomEvents?.first
|
||||
}else{
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func getIndexMessage(message: ChatMessage) -> Int {
|
||||
var index = -1
|
||||
if (chatRoom == nil) {
|
||||
return index
|
||||
}
|
||||
|
||||
var indexRange = 0
|
||||
let msgId = message.messageId
|
||||
|
||||
while index == -1 {
|
||||
let chatRoomEvents = chatRoom?.getHistoryRangeEvents(begin: indexRange, end: indexRange+20)
|
||||
if chatRoomEvents?.count == 0 {
|
||||
index = -2
|
||||
}
|
||||
chatRoomEvents?.reversed().forEach({ event in
|
||||
let chat = event.chatMessage
|
||||
if (chat != nil && msgId == chat?.messageId) {
|
||||
index = indexRange
|
||||
}
|
||||
indexRange += 1
|
||||
})
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func getNBMessages() -> Int {
|
||||
if (chatRoom == nil) {
|
||||
return 0
|
||||
}
|
||||
return chatRoom!.historyEventsSize
|
||||
}
|
||||
|
||||
func eventTypeIsOfInterestForOne(toOneRoom type: EventLogType) -> Bool {
|
||||
return type.rawValue == LinphoneEventLogTypeConferenceChatMessage.rawValue || type.rawValue == LinphoneEventLogTypeConferenceEphemeralMessageEnabled.rawValue || type.rawValue == LinphoneEventLogTypeConferenceEphemeralMessageDisabled.rawValue || type.rawValue == LinphoneEventLogTypeConferenceEphemeralMessageLifetimeChanged.rawValue
|
||||
}
|
||||
|
||||
func reloadCollectionViewCell(){
|
||||
refreshIndexPath.value! += 1
|
||||
}
|
||||
|
||||
func onGridClick(indexMessage: Int, index :Int){
|
||||
onClickMessageIndexPath = indexMessage
|
||||
onClickIndexPath.value! = index
|
||||
}
|
||||
|
||||
func changeEditMode(editMode :Bool){
|
||||
editModeOn.value = editMode
|
||||
}
|
||||
|
||||
func selectAllMessages(){
|
||||
for i in 0...messageListSelected.value!.count - 1 {
|
||||
messageListSelected.value![i] = true
|
||||
messageSelected.value! += 1
|
||||
}
|
||||
refreshIndexPath.value! += 1
|
||||
}
|
||||
|
||||
func unSelectAllMessages(){
|
||||
for i in 0...messageListSelected.value!.count - 1 {
|
||||
messageListSelected.value![i] = false
|
||||
}
|
||||
messageSelected.value! = 0
|
||||
refreshIndexPath.value! += 1
|
||||
}
|
||||
|
||||
func deleteMessagesSelected(){
|
||||
for i in 0...(messageListSelected.value!.count - 1) {
|
||||
if messageListSelected.value![i] == true {
|
||||
let messageEvent = getMessage(index: i)
|
||||
//if messageEvent
|
||||
messageListToDelete.append((messageEvent)!)
|
||||
}
|
||||
}
|
||||
|
||||
messageListToDelete.forEach { chatMessage in
|
||||
chatMessage.deleteFromDatabase()
|
||||
}
|
||||
messageSelected.value! = 0
|
||||
refreshIndexPath.value! += 1
|
||||
}
|
||||
}
|
||||
584
Classes/Swift/Chat/ViewModels/ChatConversationViewModel.swift
Normal file
584
Classes/Swift/Chat/ViewModels/ChatConversationViewModel.swift
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
/*
|
||||
* 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 Foundation
|
||||
import linphonesw
|
||||
|
||||
|
||||
class ChatConversationViewModel {
|
||||
|
||||
static let sharedModel = ChatConversationViewModel()
|
||||
|
||||
let APP_GROUP_ID = "group.belledonne-communications.linphone.widget"
|
||||
|
||||
var chatRoom: ChatRoom? = nil
|
||||
var chatRoomDelegate: ChatRoomDelegate? = nil
|
||||
|
||||
var mediaCount : Int = 0
|
||||
var newMediaCount : Int = 0
|
||||
|
||||
var address: String? = nil
|
||||
var participants: String? = nil
|
||||
var subject: String? = nil
|
||||
var shareFileMessage: String? = nil
|
||||
|
||||
var debugEnabled = false
|
||||
var isVoiceRecording = false
|
||||
var showVoiceRecorderView = false
|
||||
var isPendingVoiceRecord = false
|
||||
var isPlayingVoiceRecording = false
|
||||
var isOneToOneChat = false
|
||||
|
||||
var urlFile : [URL?] = []
|
||||
var mediaURLCollection : [URL] = []
|
||||
var replyURLCollection : [URL] = []
|
||||
|
||||
var data : [Data?] = []
|
||||
var fileContext : [Data] = []
|
||||
|
||||
var progress : [Progress] = []
|
||||
var workItem : DispatchWorkItem? = nil
|
||||
|
||||
var replyMessage : OpaquePointer? = nil
|
||||
|
||||
var vrRecordTimer = Timer()
|
||||
|
||||
var voiceRecorder : Recorder? = nil
|
||||
|
||||
var secureLevel : UIImage?
|
||||
var imageT : [UIImage?] = []
|
||||
var mediaCollectionView : [UIImage] = []
|
||||
var replyCollectionView : [UIImage] = []
|
||||
|
||||
var isComposing = MutableLiveData<Bool>(false)
|
||||
var messageReceived = MutableLiveData<EventLog>()
|
||||
var stateChanged = MutableLiveData<ChatRoom>()
|
||||
var secureLevelChanged = MutableLiveData<EventLog>()
|
||||
var subjectChanged = MutableLiveData<EventLog>()
|
||||
var eventLog = MutableLiveData<EventLog>()
|
||||
var indexPathVM = MutableLiveData<Int>()
|
||||
var shareFileURL = MutableLiveData<String>()
|
||||
var shareFileName = MutableLiveData<String>()
|
||||
|
||||
func resetViewModel(){
|
||||
chatRoom?.removeDelegate(delegate: chatRoomDelegate!)
|
||||
mediaURLCollection = []
|
||||
replyURLCollection.removeAll()
|
||||
fileContext = []
|
||||
urlFile = []
|
||||
data = []
|
||||
workItem?.cancel()
|
||||
for progressItem in progress{
|
||||
progressItem.cancel()
|
||||
}
|
||||
progress.removeAll()
|
||||
}
|
||||
|
||||
func createChatConversation(){
|
||||
chatRoomDelegate = ChatRoomDelegateStub(
|
||||
onIsComposingReceived: { (room: ChatRoom, remoteAddress: Address, isComposing: Bool) -> Void in
|
||||
self.on_chat_room_is_composing_received(room, remoteAddress, isComposing)
|
||||
}, onChatMessageReceived: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_chat_message_received(room, event)
|
||||
}, onChatMessageSending: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_event_log(room, event)
|
||||
}, onParticipantAdded: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_secure_level(room, event)
|
||||
}, onParticipantRemoved: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_secure_level(room, event)
|
||||
}, onParticipantAdminStatusChanged: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_event_log(room, event)
|
||||
}, onStateChanged: { (room: ChatRoom, state: ChatRoom.State) -> Void in
|
||||
self.on_chat_room_state_changed(room)
|
||||
}, onSecurityEvent: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_secure_level(room, event)
|
||||
}, onSubjectChanged: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_subject_changed(room, event)
|
||||
}, onConferenceJoined: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_event_log(room, event)
|
||||
}, onConferenceLeft: { (room: ChatRoom, event: EventLog) -> Void in
|
||||
self.on_chat_room_event_log(room, event)
|
||||
}
|
||||
)
|
||||
chatRoom?.addDelegate(delegate: chatRoomDelegate!)
|
||||
|
||||
workItem = DispatchWorkItem {
|
||||
let indexPath = IndexPath(row: self.mediaCollectionView.count, section: 0)
|
||||
self.mediaURLCollection.append(self.urlFile[indexPath.row]!)
|
||||
self.mediaCollectionView.append(self.imageT[indexPath.row]!)
|
||||
|
||||
self.fileContext.append(self.data[indexPath.row]!)
|
||||
if(self.mediaCount + self.newMediaCount <= indexPath.row+1){
|
||||
self.indexPathVM.value = indexPath.row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func on_chat_room_is_composing_received(_ cr: ChatRoom?, _ remoteAddr: Address?, _ isComposingBool: Bool) {
|
||||
isComposing.value = (linphone_chat_room_is_remote_composing(cr?.getCobject) != 0) || bctbx_list_size(linphone_chat_room_get_composing_addresses(cr?.getCobject)) > 0
|
||||
}
|
||||
|
||||
func on_chat_room_chat_message_received(_ cr: ChatRoom?, _ event_log: EventLog?) {
|
||||
let chat = event_log?.chatMessage
|
||||
if chat == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var hasFile = false
|
||||
// if auto_download is available and file is downloaded
|
||||
if (linphone_core_get_max_size_for_auto_download_incoming_files(LinphoneManager.getLc()) > -1) && (chat?.fileTransferInformation != nil) {
|
||||
hasFile = true
|
||||
}
|
||||
|
||||
var returnValue = false;
|
||||
chat?.contents.forEach({ content in
|
||||
if !content.isFileTransfer && !content.isText && !content.isVoiceRecording && !hasFile {
|
||||
returnValue = true
|
||||
}
|
||||
})
|
||||
|
||||
if returnValue {
|
||||
return
|
||||
}
|
||||
|
||||
let from = chat?.fromAddress
|
||||
if from == nil {
|
||||
return
|
||||
}
|
||||
|
||||
messageReceived.value = event_log
|
||||
}
|
||||
|
||||
func on_chat_room_state_changed(_ cr: ChatRoom?) {
|
||||
isOneToOneChat = chatRoom!.hasCapability(mask: Int(LinphoneChatRoomCapabilitiesOneToOne.rawValue))
|
||||
secureLevel = FastAddressBook.image(for: linphone_chat_room_get_security_level(cr?.getCobject))
|
||||
stateChanged.value = cr
|
||||
}
|
||||
|
||||
func on_chat_room_subject_changed(_ cr: ChatRoom?, _ event_log: EventLog?) {
|
||||
subject = event_log?.subject != nil ? event_log?.subject : cr?.subject
|
||||
subjectChanged.value = event_log
|
||||
}
|
||||
|
||||
func on_chat_room_secure_level(_ cr: ChatRoom?, _ event_log: EventLog?) {
|
||||
secureLevel = FastAddressBook.image(for: linphone_chat_room_get_security_level(cr?.getCobject))
|
||||
secureLevelChanged.value = event_log
|
||||
}
|
||||
|
||||
func on_chat_room_event_log(_ cr: ChatRoom?, _ event_log: EventLog?) {
|
||||
eventLog.value = event_log
|
||||
}
|
||||
|
||||
func nsDataRead() -> Data? {
|
||||
let groupName = "group.\(Bundle.main.bundleIdentifier ?? "").linphoneExtension"
|
||||
let path = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupName)?.path
|
||||
let fullCacheFilePathPath = "\(path ?? "")/\("nsData")"
|
||||
return NSData(contentsOfFile: fullCacheFilePathPath) as Data?
|
||||
}
|
||||
|
||||
func sendMessage(message: String?, withExterlBodyUrl externalUrl: URL?, rootMessage: ChatMessage?) -> Bool {
|
||||
if chatRoom == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
let msg = rootMessage
|
||||
let basic = isBasicChatRoom(chatRoom?.getCobject)
|
||||
let params = linphone_account_get_params(linphone_core_get_default_account(LinphoneManager.getLc()))
|
||||
let cpimEnabled = linphone_account_params_cpim_in_basic_chat_room_enabled(params)
|
||||
|
||||
if (!basic || (cpimEnabled != 0)) && (message != nil) && message!.count > 0 {
|
||||
linphone_chat_message_add_utf8_text_content(msg?.getCobject, message)
|
||||
}
|
||||
|
||||
if (externalUrl != nil) {
|
||||
linphone_chat_message_set_external_body_url(msg?.getCobject, externalUrl!.absoluteString)
|
||||
}
|
||||
|
||||
let contentList = linphone_chat_message_get_contents(msg?.getCobject)
|
||||
if bctbx_list_size(contentList) > 0 {
|
||||
linphone_chat_message_send(msg?.getCobject)
|
||||
}
|
||||
|
||||
if basic && (cpimEnabled == 0) && (message != nil) && message!.count > 0 {
|
||||
linphone_chat_message_send(linphone_chat_room_create_message_from_utf8(chatRoom?.getCobject, message))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func isBasicChatRoom(_ room: OpaquePointer?) -> Bool {
|
||||
if room == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
let charRoomBasic = ChatRoom.getSwiftObject(cObject: room!)
|
||||
let isBasic = charRoomBasic.hasCapability(mask: Int(LinphoneChatRoomCapabilitiesBasic.rawValue))
|
||||
return isBasic
|
||||
}
|
||||
|
||||
func startUploadData(_ data: Data?, withType type: String?, withName name: String?, andMessage message: String?, rootMessage: ChatMessage?){
|
||||
let fileTransfer = FileTransferDelegate.init()
|
||||
if let msg = message {
|
||||
fileTransfer.text = msg
|
||||
}
|
||||
var resultType = "file"
|
||||
var key = "localfile"
|
||||
if type == "file_video_default" {
|
||||
resultType = "video"
|
||||
key = "localvideo"
|
||||
} else if type == "file_picture_default" {
|
||||
resultType = "image"
|
||||
key = "localimage"
|
||||
}
|
||||
fileTransfer.uploadData(data, for: chatRoom?.getCobject, type: resultType, subtype: resultType, name: name, key: key, rootMessage: rootMessage?.getCobject)
|
||||
}
|
||||
|
||||
func startFileUpload(_ data: Data?, withName name: String?, rootMessage: ChatMessage?){
|
||||
let fileTransfer = FileTransferDelegate()
|
||||
fileTransfer.uploadFile(data, for: ChatConversationViewModel.sharedModel.chatRoom?.getCobject, withName: name, rootMessage: rootMessage?.getCobject)
|
||||
}
|
||||
|
||||
func shareFile() {
|
||||
let groupName = "group.\(Bundle.main.bundleIdentifier ?? "").linphoneExtension"
|
||||
let defaults = UserDefaults(suiteName: groupName)
|
||||
let dict = defaults?.value(forKey: "photoData") as? [AnyHashable : Any]
|
||||
if let dict_notnil = dict {
|
||||
//file shared from photo lib
|
||||
shareFileMessage = dict_notnil["message"] as? String
|
||||
shareFileName.value = dict_notnil["url"] as? String
|
||||
defaults?.removeObject(forKey: "photoData")
|
||||
} else if let dictFile = defaults?.value(forKey: "icloudData") as? [AnyHashable : Any] {
|
||||
shareFileMessage = dict?["message"] as? String
|
||||
shareFileName.value = dictFile["url"] as? String
|
||||
defaults?.removeObject(forKey: "icloudData")
|
||||
} else if let dictUrl = defaults?.value(forKey: "url") as? [AnyHashable : Any] {
|
||||
shareFileMessage = dict?["message"] as? String
|
||||
shareFileURL.value = dictUrl["url"] as? String
|
||||
defaults?.removeObject(forKey: "url")
|
||||
}
|
||||
}
|
||||
|
||||
func getImageFrom(_ content: OpaquePointer?, filePath: String?, forReplyBubble: Bool) -> UIImage? {
|
||||
var filePath = filePath
|
||||
let type = String(utf8String: linphone_content_get_type(content))
|
||||
let name = String(utf8String: linphone_content_get_name(content))
|
||||
if filePath == nil {
|
||||
filePath = LinphoneManager.validFilePath(name)
|
||||
}
|
||||
|
||||
var image: UIImage? = nil
|
||||
if type == "video" {
|
||||
image = UIChatBubbleTextCell.getImageFromVideoUrl(URL(fileURLWithPath: filePath ?? ""))
|
||||
} else if type == "image" {
|
||||
image = UIImage(named: filePath ?? "")
|
||||
}
|
||||
|
||||
if let img = image {
|
||||
return img
|
||||
} else {
|
||||
return getImageFromFileName(name, forReplyBubble: forReplyBubble)
|
||||
}
|
||||
}
|
||||
|
||||
func getImageFromFileName(_ fileName: String?, forReplyBubble forReplyBubbble: Bool) -> UIImage? {
|
||||
let extensionFile = fileName?.lowercased().components(separatedBy: ".").last
|
||||
var image: UIImage?
|
||||
var text = fileName
|
||||
if fileName?.contains("voice-recording") ?? false {
|
||||
image = UIImage(named: "file_voice_default")
|
||||
text = recordingDuration(LinphoneManager.validFilePath(fileName))
|
||||
} else {
|
||||
if extensionFile == "pdf" {
|
||||
image = UIImage(named: "file_pdf_default")
|
||||
} else if ["png", "jpg", "jpeg", "bmp", "heic"].contains(extensionFile ?? "") {
|
||||
image = UIImage(named: "file_picture_default")
|
||||
} else if ["mkv", "avi", "mov", "mp4"].contains(extensionFile ?? "") {
|
||||
image = UIImage(named: "file_video_default")
|
||||
} else if ["wav", "au", "m4a"].contains(extensionFile ?? "") {
|
||||
image = UIImage(named: "file_audio_default")
|
||||
} else {
|
||||
image = UIImage(named: "file_default")
|
||||
}
|
||||
}
|
||||
|
||||
return SwiftUtil.textToImage(drawText: text!, inImage: image!, forReplyBubble: forReplyBubbble)
|
||||
}
|
||||
|
||||
func recordingDuration(_ _voiceRecordingFile: String?) -> String? {
|
||||
let core = Core.getSwiftObject(cObject: LinphoneManager.getLc())
|
||||
var result = ""
|
||||
do{
|
||||
let linphonePlayer = try core.createLocalPlayer(soundCardName: nil, videoDisplayName: nil, windowId: nil)
|
||||
try linphonePlayer.open(filename: _voiceRecordingFile!)
|
||||
result = formattedDuration(linphonePlayer.duration)!
|
||||
linphonePlayer.close()
|
||||
}catch{
|
||||
Log.e(error.localizedDescription)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func formattedDuration(_ valueMs: Int) -> String? {
|
||||
return String(format: "%02ld:%02ld", valueMs / 60000, (valueMs % 60000) / 1000)
|
||||
}
|
||||
|
||||
func writeMediaToGalleryFromName(_ name: String?, fileType: String?) {
|
||||
let filePath = LinphoneManager.validFilePath(name)
|
||||
let fileManager = FileManager.default
|
||||
if fileManager.fileExists(atPath: filePath!) {
|
||||
let data = NSData(contentsOfFile: filePath!) as Data?
|
||||
let block: (() -> Void)? = {
|
||||
if fileType == "image" {
|
||||
// we're finished, save the image and update the message
|
||||
let image = UIImage(data: data!)
|
||||
if image == nil {
|
||||
ChatConversationViewSwift.showFileDownloadError()
|
||||
return
|
||||
}
|
||||
var placeHolder: PHObjectPlaceholder? = nil
|
||||
PHPhotoLibrary.shared().performChanges({
|
||||
let request = PHAssetCreationRequest.creationRequestForAsset(from: image!)
|
||||
placeHolder = request.placeholderForCreatedAsset
|
||||
}) { success, error in
|
||||
DispatchQueue.main.async(execute: {
|
||||
if error != nil {
|
||||
Log.e("Cannot save image data downloaded \(error!.localizedDescription)")
|
||||
let errView = UIAlertController(
|
||||
title: NSLocalizedString("Transfer error", comment: ""),
|
||||
message: NSLocalizedString("Cannot write image to photo library", comment: ""),
|
||||
preferredStyle: .alert)
|
||||
|
||||
let defaultAction = UIAlertAction(
|
||||
title: "OK",
|
||||
style: .default,
|
||||
handler: { action in
|
||||
})
|
||||
|
||||
errView.addAction(defaultAction)
|
||||
PhoneMainView.instance()!.present(errView, animated: true)
|
||||
} else {
|
||||
Log.i("Image saved to \(placeHolder!.localIdentifier)")
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if fileType == "video" {
|
||||
var placeHolder: PHObjectPlaceholder?
|
||||
PHPhotoLibrary.shared().performChanges({
|
||||
let request = PHAssetCreationRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath!))
|
||||
placeHolder = request?.placeholderForCreatedAsset
|
||||
}) { success, error in
|
||||
DispatchQueue.main.async(execute: {
|
||||
if error != nil {
|
||||
Log.e("Cannot save video data downloaded \(error!.localizedDescription)")
|
||||
let errView = UIAlertController(
|
||||
title: NSLocalizedString("Transfer error", comment: ""),
|
||||
message: NSLocalizedString("Cannot write video to photo library", comment: ""),
|
||||
preferredStyle: .alert)
|
||||
let defaultAction = UIAlertAction(
|
||||
title: "OK",
|
||||
style: .default,
|
||||
handler: { action in
|
||||
})
|
||||
|
||||
errView.addAction(defaultAction)
|
||||
PhoneMainView.instance()!.present(errView, animated: true)
|
||||
} else {
|
||||
Log.i("video saved to \(placeHolder!.localIdentifier)")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if PHPhotoLibrary.authorizationStatus() == .authorized {
|
||||
block!()
|
||||
} else {
|
||||
PHPhotoLibrary.requestAuthorization({ status in
|
||||
DispatchQueue.main.async(execute: {
|
||||
if PHPhotoLibrary.authorizationStatus() == .authorized {
|
||||
block!()
|
||||
} else {
|
||||
let alert = UIAlertController(title: NSLocalizedString("Photo's permission", comment: ""), message: NSLocalizedString("Photo not authorized", comment: ""), preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default))
|
||||
PhoneMainView.instance()!.present(alert, animated: true)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createCollectionViewItem(urlFile: URL?, type: String) {
|
||||
if let url = urlFile {
|
||||
do {
|
||||
if(type == "public.image"){
|
||||
let dataResult = try Data(contentsOf: url)
|
||||
ChatConversationViewModel.sharedModel.data.append(dataResult)
|
||||
if let image = UIImage(data: dataResult) {
|
||||
ChatConversationViewModel.sharedModel.imageT.append(image)
|
||||
}else{
|
||||
ChatConversationViewModel.sharedModel.imageT.append(UIImage(named: "chat_error"))
|
||||
}
|
||||
}else if(type == "public.movie"){
|
||||
ChatConversationViewModel.sharedModel.data.append(try Data(contentsOf: url))
|
||||
var tmpImage = ChatConversationViewModel.sharedModel.createThumbnailOfVideoFromFileURL(videoURL: url.relativeString)
|
||||
if tmpImage == nil { tmpImage = UIImage(named: "chat_error")}
|
||||
ChatConversationViewModel.sharedModel.imageT.append(tmpImage)
|
||||
}else{
|
||||
|
||||
ChatConversationViewModel.sharedModel.data.append(try Data(contentsOf: url))
|
||||
let otherFile = FileType.init(url.pathExtension)
|
||||
let otherFileImage = otherFile!.getImageFromFile()
|
||||
ChatConversationViewModel.sharedModel.imageT.append(otherFileImage)
|
||||
}
|
||||
ChatConversationViewModel.sharedModel.urlFile.append(url)
|
||||
DispatchQueue.main.async(execute: ChatConversationViewModel.sharedModel.workItem!)
|
||||
}catch let error{
|
||||
Log.e(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func createCollectionViewItemForReply(urlFile: URL?, type: String) -> UIImage {
|
||||
if urlFile != nil {
|
||||
do {
|
||||
if(type == "public.image"){
|
||||
let dataResult = try Data(contentsOf: urlFile!)
|
||||
if let image = UIImage(data: dataResult) {
|
||||
return image
|
||||
}else{
|
||||
return UIImage(named: "chat_error")!
|
||||
}
|
||||
}else if(type == "public.movie"){
|
||||
var tmpImage = ChatConversationViewModel.sharedModel.createThumbnailOfVideoFromFileURL(videoURL: urlFile!.relativeString)
|
||||
if tmpImage == nil { tmpImage = UIImage(named: "chat_error")}
|
||||
return tmpImage!
|
||||
}else{
|
||||
let otherFile = FileType.init(urlFile!.pathExtension)
|
||||
let otherFileImage = otherFile!.getImageFromFile()
|
||||
return otherFileImage!
|
||||
}
|
||||
}catch let error{
|
||||
Log.e(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
return UIImage(named: "chat_error")!
|
||||
}
|
||||
|
||||
func createThumbnailOfVideoFromFileURL(videoURL: String) -> UIImage? {
|
||||
if let urlVideo = URL(string: videoURL){
|
||||
let asset = AVAsset(url: urlVideo)
|
||||
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
|
||||
assetImgGenerate.appliesPreferredTrackTransform = true
|
||||
do {
|
||||
let img = try assetImgGenerate.copyCGImage(at: CMTimeMake(value: 1, timescale: 10), actualTime: nil)
|
||||
let thumbnail = UIImage(cgImage: img)
|
||||
return thumbnail
|
||||
} catch _{
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//Voice recoder and player
|
||||
func createVoiceRecorder() {
|
||||
let core = Core.getSwiftObject(cObject: LinphoneManager.getLc())
|
||||
do{
|
||||
let p = try core.createRecorderParams()
|
||||
p.fileFormat = RecorderFileFormat.Mkv
|
||||
ChatConversationViewModel.sharedModel.voiceRecorder = try core.createRecorder(params: p)
|
||||
}catch{
|
||||
Log.e(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
func startVoiceRecording() {
|
||||
if (voiceRecorder == nil) {
|
||||
createVoiceRecorder()
|
||||
}
|
||||
CallManager.instance().activateAudioSession()
|
||||
|
||||
showVoiceRecorderView = true
|
||||
isVoiceRecording = true
|
||||
|
||||
switch linphone_recorder_get_state(voiceRecorder?.getCobject) {
|
||||
case LinphoneRecorderClosed:
|
||||
let filename = "\(String(describing: LinphoneManager.imagesDirectory()))/voice-recording-\(UUID().uuidString).mkv"
|
||||
linphone_recorder_open(voiceRecorder?.getCobject, filename)
|
||||
linphone_recorder_start(voiceRecorder?.getCobject)
|
||||
Log.i("[Chat Message Sending] Recorder is closed opening it with \(filename)")
|
||||
case LinphoneRecorderRunning:
|
||||
Log.i("[Chat Message Sending] Recorder is already recording")
|
||||
case LinphoneRecorderPaused:
|
||||
Log.i("[Chat Message Sending] Recorder isn't closed, resuming recording")
|
||||
linphone_recorder_start(voiceRecorder?.getCobject)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func stopVoiceRecording() {
|
||||
if (ChatConversationViewModel.sharedModel.voiceRecorder != nil) && linphone_recorder_get_state(ChatConversationViewModel.sharedModel.voiceRecorder?.getCobject) == LinphoneRecorderRunning {
|
||||
Log.i("[Chat Message Sending] Pausing / closing voice recorder")
|
||||
linphone_recorder_pause(ChatConversationViewModel.sharedModel.voiceRecorder?.getCobject)
|
||||
linphone_recorder_close(ChatConversationViewModel.sharedModel.voiceRecorder?.getCobject)
|
||||
}
|
||||
isVoiceRecording = false
|
||||
vrRecordTimer.invalidate()
|
||||
isPendingVoiceRecord = linphone_recorder_get_duration(ChatConversationViewModel.sharedModel.voiceRecorder?.getCobject) > 0
|
||||
}
|
||||
|
||||
func initSharedPlayer() {
|
||||
AudioPlayer.initSharedPlayer()
|
||||
}
|
||||
|
||||
func startSharedPlayer(_ path: String?) {
|
||||
AudioPlayer.startSharedPlayer(path)
|
||||
AudioPlayer.sharedModel.fileChanged.value = path
|
||||
}
|
||||
|
||||
func cancelVoiceRecordingVM() {
|
||||
showVoiceRecorderView = false
|
||||
isPendingVoiceRecord = false
|
||||
isVoiceRecording = false
|
||||
if (voiceRecorder != nil) && linphone_recorder_get_state(voiceRecorder?.getCobject) != LinphoneRecorderClosed {
|
||||
AudioPlayer.cancelVoiceRecordingVM(voiceRecorder)
|
||||
}
|
||||
}
|
||||
|
||||
func stopSharedPlayer() {
|
||||
AudioPlayer.stopSharedPlayer()
|
||||
}
|
||||
|
||||
func removeTmpFile(filePath: String?){
|
||||
if (filePath != nil) {
|
||||
if (filePath != "") {
|
||||
do {
|
||||
Log.i("[vfs] remove item at \(filePath)")
|
||||
try FileManager.default.removeItem(atPath: filePath!)
|
||||
}catch{
|
||||
Log.e("[vfs] remove item error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
725
Classes/Swift/Chat/Views/ChatConversationTableViewSwift.swift
Normal file
725
Classes/Swift/Chat/Views/ChatConversationTableViewSwift.swift
Normal file
|
|
@ -0,0 +1,725 @@
|
|||
/*
|
||||
* 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 Foundation
|
||||
import linphonesw
|
||||
import DropDown
|
||||
import QuickLook
|
||||
import SwipeCellKit
|
||||
|
||||
class ChatConversationTableViewSwift: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, QLPreviewControllerDelegate, QLPreviewControllerDataSource, SwipeCollectionViewCellDelegate {
|
||||
|
||||
static let compositeDescription = UICompositeViewDescription(ChatConversationTableViewSwift.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 }
|
||||
|
||||
lazy var collectionView: UICollectionView = {
|
||||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
var menu: DropDown? = nil
|
||||
|
||||
var basic :Bool = false
|
||||
|
||||
var floatingScrollButton : UIButton?
|
||||
var scrollBadge : UILabel?
|
||||
var floatingScrollBackground : UIButton?
|
||||
|
||||
var previewItems : [QLPreviewItem?] = []
|
||||
var afterPreviewIndex = -1
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
self.initView()
|
||||
|
||||
UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in
|
||||
self.collectionView.backgroundColor = VoipTheme.backgroundWhiteBlack.get()
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
ChatConversationTableViewModel.sharedModel.refreshIndexPath.observe { index in
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
ChatConversationTableViewModel.sharedModel.onClickIndexPath.observe { index in
|
||||
self.onGridClick(indexMessage: ChatConversationTableViewModel.sharedModel.onClickMessageIndexPath, index: index!)
|
||||
}
|
||||
|
||||
ChatConversationTableViewModel.sharedModel.editModeOn.observe { mode in
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
|
||||
collectionView.isUserInteractionEnabled = true
|
||||
collectionView.keyboardDismissMode = .interactive
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
func initView(){
|
||||
basic = isBasicChatRoom(ChatConversationTableViewModel.sharedModel.chatRoom?.getCobject)
|
||||
|
||||
view.addSubview(collectionView)
|
||||
collectionView.contentInsetAdjustmentBehavior = .always
|
||||
collectionView.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
|
||||
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
|
||||
collectionView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
|
||||
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
|
||||
collectionView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
|
||||
|
||||
collectionView.dataSource = self
|
||||
collectionView.delegate = self
|
||||
collectionView.register(MultilineMessageCell.self, forCellWithReuseIdentifier: MultilineMessageCell.reuseId)
|
||||
|
||||
(collectionView.collectionViewLayout as! UICollectionViewFlowLayout).estimatedItemSize = UICollectionViewFlowLayout.automaticSize
|
||||
(collectionView.collectionViewLayout as! UICollectionViewFlowLayout).minimumLineSpacing = 2
|
||||
|
||||
collectionView.transform = CGAffineTransform(scaleX: 1, y: -1)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
createFloatingButton()
|
||||
if ChatConversationTableViewModel.sharedModel.getNBMessages() > 0 {
|
||||
scrollToBottom(animated: false)
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.receivePresenceNotification(notification:)), name: Notification.Name("LinphoneFriendPresenceUpdate"), object: nil)
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
NotificationCenter.default.removeObserver(self, name: Notification.Name("LinphoneFriendPresenceUpdate"), object: nil)
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@objc func receivePresenceNotification(notification: NSNotification) {
|
||||
if (notification.name.rawValue == "LinphoneFriendPresenceUpdate"){
|
||||
let userInfo = notification.userInfo
|
||||
let friend = userInfo!["friend"]
|
||||
|
||||
let indexPathsVisible = self.collectionView.indexPathsForVisibleItems
|
||||
if indexPathsVisible.count > 0 {
|
||||
for i in 0...indexPathsVisible.count-1 {
|
||||
let cell = self.collectionView.cellForItem(at: indexPathsVisible[i])
|
||||
if cell != nil {
|
||||
let multilineCell = cell as! MultilineMessageCell
|
||||
if multilineCell.imageUser.isHidden == false {
|
||||
let contact = ChatConversationTableViewModel.sharedModel.getMessage(index: indexPathsVisible[i].row)?.chatMessage?.fromAddress
|
||||
if (contact != nil){
|
||||
let uri = "sip:" + contact!.username + "@" + contact!.domain
|
||||
if(uri == friend as! String){
|
||||
let indexPath = indexPathsVisible[i]
|
||||
collectionView.reloadItems(at: [indexPath])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scrollToMessage(message: ChatMessage){
|
||||
let messageIndex = ChatConversationTableViewModel.sharedModel.getIndexMessage(message: message)
|
||||
self.collectionView.scrollToItem(at: IndexPath(row: messageIndex, section: 0), at: .bottom, animated: false)
|
||||
}
|
||||
|
||||
func scrollToBottom(animated: Bool){
|
||||
DispatchQueue.main.async{
|
||||
self.collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: animated)
|
||||
}
|
||||
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
|
||||
self.floatingScrollButton?.isHidden = true
|
||||
self.floatingScrollBackground?.isHidden = true
|
||||
scrollBadge!.text = "0"
|
||||
}
|
||||
|
||||
func refreshDataAfterForeground(){
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
func refreshData(isOutgoing: Bool){
|
||||
if (ChatConversationTableViewModel.sharedModel.getNBMessages() > 1){
|
||||
let isDisplayingBottomOfTable = collectionView.contentOffset.y <= 20
|
||||
|
||||
if ChatConversationTableViewModel.sharedModel.getNBMessages() < 4 {
|
||||
collectionView.reloadData()
|
||||
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
|
||||
} else if isDisplayingBottomOfTable {
|
||||
if self.collectionView.numberOfItems(inSection: 0) > 2 {
|
||||
self.collectionView.scrollToItem(at: IndexPath(item: 1, section: 0), at: .top, animated: false)
|
||||
}
|
||||
collectionView.reloadData()
|
||||
self.scrollToBottom(animated: true)
|
||||
} else if !isOutgoing {
|
||||
if !collectionView.indexPathsForVisibleItems.isEmpty {
|
||||
let selectedCellIndex = collectionView.indexPathsForVisibleItems.sorted().first!
|
||||
let selectedCell = collectionView.cellForItem(at: selectedCellIndex)
|
||||
let visibleRect = collectionView.convert(collectionView.bounds, to: selectedCell)
|
||||
|
||||
UIView.performWithoutAnimation {
|
||||
collectionView.reloadData()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2){
|
||||
let newSelectedCell = self.collectionView.cellForItem(at: IndexPath(row: selectedCellIndex.row + 1, section: 0))
|
||||
let updatedVisibleRect = self.collectionView.convert(self.collectionView.bounds, to: newSelectedCell)
|
||||
|
||||
var contentOffset = self.collectionView.contentOffset
|
||||
contentOffset.y = contentOffset.y + (visibleRect.origin.y - updatedVisibleRect.origin.y)
|
||||
self.collectionView.contentOffset = contentOffset
|
||||
}
|
||||
}
|
||||
scrollBadge!.isHidden = false
|
||||
scrollBadge!.text = "\(ChatConversationViewModel.sharedModel.chatRoom?.unreadMessagesCount ?? 0)"
|
||||
}
|
||||
} else {
|
||||
collectionView.reloadData()
|
||||
self.scrollToBottom(animated: false)
|
||||
}
|
||||
|
||||
if ChatConversationTableViewModel.sharedModel.editModeOn.value! {
|
||||
ChatConversationTableViewModel.sharedModel.messageListSelected.value!.insert(false, at: 0)
|
||||
}
|
||||
}else{
|
||||
collectionView.reloadData()
|
||||
if(ChatConversationViewModel.sharedModel.chatRoom != nil){
|
||||
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
let contentOffsetY = scrollView.contentOffset.y
|
||||
if contentOffsetY <= 20{
|
||||
if floatingScrollButton != nil && floatingScrollBackground != nil {
|
||||
floatingScrollButton?.isHidden = true
|
||||
floatingScrollBackground?.isHidden = true
|
||||
scrollBadge?.text = "0"
|
||||
ChatConversationViewSwift.markAsRead(ChatConversationViewModel.sharedModel.chatRoom?.getCobject)
|
||||
}
|
||||
} else {
|
||||
if floatingScrollButton != nil && floatingScrollBackground != nil {
|
||||
floatingScrollButton?.isHidden = false
|
||||
floatingScrollBackground?.isHidden = false;
|
||||
if(scrollBadge?.text == "0"){
|
||||
scrollBadge?.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource -
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MultilineMessageCell.reuseId, for: indexPath) as! MultilineMessageCell
|
||||
cell.delegate = self
|
||||
if let event = ChatConversationTableViewModel.sharedModel.getMessage(index: indexPath.row){
|
||||
if(ChatConversationTableViewModel.sharedModel.editModeOn.value! && indexPath.row >= ChatConversationTableViewModel.sharedModel.messageListSelected.value!.count){
|
||||
for _ in ChatConversationTableViewModel.sharedModel.messageListSelected.value!.count...indexPath.row {
|
||||
ChatConversationTableViewModel.sharedModel.messageListSelected.value!.append(false)
|
||||
}
|
||||
}
|
||||
|
||||
cell.configure(event: event, selfIndexPathConfigure: indexPath, editMode: ChatConversationTableViewModel.sharedModel.editModeOn.value!, selected: ChatConversationTableViewModel.sharedModel.editModeOn.value! ? ChatConversationTableViewModel.sharedModel.messageListSelected.value![indexPath.row] : false)
|
||||
|
||||
if (event.chatMessage != nil && ChatConversationViewModel.sharedModel.chatRoom != nil){
|
||||
cell.onLongClickOneClick {
|
||||
if(cell.chatMessage != nil && ChatConversationViewModel.sharedModel.chatRoom != nil){
|
||||
self.initDataSource(message: cell.chatMessage!)
|
||||
self.tapChooseMenuItemMessage(contentViewBubble: cell.contentViewBubble, event: cell.eventMessage!, preContentSize: cell.preContentViewBubble.frame.size.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cell.replyContent.isHidden && event.chatMessage?.replyMessage != nil){
|
||||
cell.replyContent.onClick {
|
||||
self.scrollToMessage(message: (cell.chatMessage?.replyMessage)!)
|
||||
}
|
||||
}
|
||||
|
||||
if (!cell.imageViewBubble.isHidden || !cell.imageVideoViewBubble.isHidden){
|
||||
cell.imageViewBubble.onClick {
|
||||
self.onImageClick(chatMessage: cell.chatMessage!, index: indexPath.row)
|
||||
}
|
||||
cell.imageVideoViewBubble.onClick {
|
||||
self.onImageClick(chatMessage: cell.chatMessage!, index: indexPath.row)
|
||||
}
|
||||
}
|
||||
}
|
||||
cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1)
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
|
||||
let customCell = cell as! MultilineMessageCell
|
||||
|
||||
if customCell.isPlayingVoiceRecording {
|
||||
AudioPlayer.stopSharedPlayer()
|
||||
}
|
||||
|
||||
if customCell.ephemeralTimer != nil {
|
||||
customCell.ephemeralTimer?.invalidate()
|
||||
}
|
||||
|
||||
if customCell.chatMessageDelegate != nil {
|
||||
customCell.chatMessage?.removeDelegate(delegate: customCell.chatMessageDelegate!)
|
||||
}
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return ChatConversationTableViewModel.sharedModel.getNBMessages()
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, editActionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
|
||||
let message = ChatConversationTableViewModel.sharedModel.getMessage(index: indexPath.row)
|
||||
if orientation == .left {
|
||||
if message?.chatMessage != nil {
|
||||
let replyAction = SwipeAction(style: .default, title: "Reply") { action, indexPath in
|
||||
self.replyMessage(message: (message?.chatMessage)!)
|
||||
}
|
||||
return [replyAction]
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
|
||||
self.deleteMessage(message: message!)
|
||||
}
|
||||
return [deleteAction]
|
||||
}
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, editActionsOptionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
|
||||
var options = SwipeOptions()
|
||||
if orientation == .left {
|
||||
options.expansionStyle = .selection
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func isBasicChatRoom(_ room: OpaquePointer?) -> Bool {
|
||||
if room == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
let charRoomBasic = ChatRoom.getSwiftObject(cObject: room!)
|
||||
let isBasic = charRoomBasic.hasCapability(mask: Int(LinphoneChatRoomCapabilitiesBasic.rawValue))
|
||||
return isBasic
|
||||
}
|
||||
|
||||
func tapChooseMenuItemMessage(contentViewBubble: UIView, event: EventLog, preContentSize: CGFloat) {
|
||||
|
||||
menu!.anchorView = view
|
||||
menu!.width = 200
|
||||
|
||||
let coordinateMin = contentViewBubble.convert(contentViewBubble.frame.origin, to: view)
|
||||
let coordinateMax = contentViewBubble.convert(CGPoint(x: contentViewBubble.frame.maxX, y: contentViewBubble.frame.maxY), to: view)
|
||||
|
||||
if (coordinateMax.y + CGFloat(menu!.dataSource.count * 44) - preContentSize < view.frame.maxY) {
|
||||
menu!.bottomOffset = CGPoint(x: event.chatMessage!.isOutgoing ? coordinateMax.x - 200 : coordinateMin.x, y: coordinateMax.y - preContentSize)
|
||||
} else if ((coordinateMax.y + CGFloat(menu!.dataSource.count * 44) > view.frame.maxY) && coordinateMin.y > CGFloat(menu!.dataSource.count * 44) + (preContentSize * 2)) {
|
||||
menu!.bottomOffset = CGPoint(x: event.chatMessage!.isOutgoing ? coordinateMax.x - 200 : coordinateMin.x, y: coordinateMin.y - (preContentSize * 2) - CGFloat(menu!.dataSource.count * 44))
|
||||
} else {
|
||||
menu!.bottomOffset = CGPoint(x: event.chatMessage!.isOutgoing ? coordinateMax.x - 200 : coordinateMin.x, y: 0)
|
||||
}
|
||||
|
||||
let view: ChatConversationViewSwift = self.VIEW(ChatConversationViewSwift.compositeViewDescription())
|
||||
view.messageView.endEditing(true)
|
||||
|
||||
menu!.show()
|
||||
menu!.selectionAction = { [weak self] (index: Int, item: String) in
|
||||
guard let _ = self else { return }
|
||||
switch item {
|
||||
case VoipTexts.bubble_chat_dropDown_resend:
|
||||
self!.resendMessage(message: event.chatMessage!)
|
||||
case VoipTexts.bubble_chat_dropDown_copy_text:
|
||||
self!.copyMessage(message: event.chatMessage!)
|
||||
case VoipTexts.bubble_chat_dropDown_forward:
|
||||
self!.forwardMessage(message: event.chatMessage!)
|
||||
case VoipTexts.bubble_chat_dropDown_reply:
|
||||
self!.replyMessage(message: event.chatMessage!)
|
||||
case VoipTexts.bubble_chat_dropDown_infos:
|
||||
self!.infoMessage(event: event)
|
||||
case VoipTexts.bubble_chat_dropDown_add_to_contact:
|
||||
self!.addToContacts(message: event.chatMessage!)
|
||||
case VoipTexts.bubble_chat_dropDown_delete:
|
||||
self!.deleteMessage(message: event)
|
||||
default:
|
||||
Log.e("Error Default tapChooseMenuItemMessage ChatConversationTableViewSwift")
|
||||
}
|
||||
self!.menu!.clearSelection()
|
||||
}
|
||||
}
|
||||
|
||||
func initDataSource(message: ChatMessage) {
|
||||
menu = {
|
||||
let menu = DropDown()
|
||||
menu.dataSource = [""]
|
||||
let images = [
|
||||
"menu_resend_default",
|
||||
"menu_copy_text_default",
|
||||
"menu_forward_default",
|
||||
"menu_reply_default",
|
||||
"menu_info",
|
||||
"contact_add_default",
|
||||
"menu_delete",
|
||||
"menu_info"
|
||||
]
|
||||
menu.cellNib = UINib(nibName: "DropDownCell", bundle: nil)
|
||||
menu.customCellConfiguration = { index, title, cell in
|
||||
guard let cell = cell as? MyCell else {
|
||||
return
|
||||
}
|
||||
if(index < images.count){
|
||||
switch menu.dataSource[index] {
|
||||
case VoipTexts.bubble_chat_dropDown_resend:
|
||||
if #available(iOS 13.0, *) {
|
||||
cell.myImageView.image = UIImage(named: images[0])!.withTintColor(.darkGray)
|
||||
} else {
|
||||
cell.myImageView.image = UIImage(named: images[0])
|
||||
}
|
||||
case VoipTexts.bubble_chat_dropDown_copy_text:
|
||||
cell.myImageView.image = UIImage(named: images[1])
|
||||
case VoipTexts.bubble_chat_dropDown_forward:
|
||||
cell.myImageView.image = UIImage(named: images[2])
|
||||
case VoipTexts.bubble_chat_dropDown_reply:
|
||||
cell.myImageView.image = UIImage(named: images[3])
|
||||
case VoipTexts.bubble_chat_dropDown_infos:
|
||||
cell.myImageView.image = UIImage(named: images[4])
|
||||
case VoipTexts.bubble_chat_dropDown_add_to_contact:
|
||||
cell.myImageView.image = UIImage(named: images[5])
|
||||
case VoipTexts.bubble_chat_dropDown_delete:
|
||||
cell.myImageView.image = UIImage(named: images[6])
|
||||
default:
|
||||
cell.myImageView.image = UIImage(named: images[7])
|
||||
}
|
||||
}
|
||||
}
|
||||
return menu
|
||||
}()
|
||||
|
||||
menu!.dataSource.removeAll()
|
||||
let state = message.state
|
||||
|
||||
if (state.rawValue == LinphoneChatMessageStateNotDelivered.rawValue || state.rawValue == LinphoneChatMessageStateFileTransferError.rawValue) {
|
||||
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_resend)
|
||||
}
|
||||
|
||||
if (message.utf8Text != "" && !ICSBubbleView.isConferenceInvitationMessage(cmessage: message.getCobject!)) {
|
||||
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_copy_text)
|
||||
}
|
||||
|
||||
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_forward)
|
||||
|
||||
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_reply)
|
||||
|
||||
let chatroom = ChatConversationViewModel.sharedModel.chatRoom
|
||||
if chatroom != nil {
|
||||
if (chatroom!.nbParticipants > 1) {
|
||||
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_infos)
|
||||
}
|
||||
|
||||
let isOneToOneChat = ChatConversationViewModel.sharedModel.chatRoom!.hasCapability(mask: Int(LinphoneChatRoomCapabilitiesOneToOne.rawValue))
|
||||
if (!message.isOutgoing && FastAddressBook.getContactWith(message.fromAddress?.getCobject) == nil
|
||||
&& !isOneToOneChat && !ConfigManager.instance().lpConfigBoolForKey(key: "read_only_native_address_book")) {
|
||||
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_add_to_contact)
|
||||
}
|
||||
|
||||
menu!.dataSource.append(VoipTexts.bubble_chat_dropDown_delete)
|
||||
}
|
||||
}
|
||||
|
||||
func resendMessage(message: ChatMessage){
|
||||
if ((linphone_core_is_network_reachable(LinphoneManager.getLc()) == 0)) {
|
||||
PhoneMainView.instance().present(LinphoneUtils.networkErrorView("send a message"), animated: true)
|
||||
return;
|
||||
}else{
|
||||
message.send()
|
||||
}
|
||||
}
|
||||
|
||||
func copyMessage(message: ChatMessage){
|
||||
UIPasteboard.general.string = message.utf8Text
|
||||
}
|
||||
|
||||
func forwardMessage(message: ChatMessage){
|
||||
let view: ChatConversationViewSwift = self.VIEW(ChatConversationViewSwift.compositeViewDescription())
|
||||
view.pendingForwardMessage = message.getCobject
|
||||
let viewtoGo: ChatsListView = self.VIEW(ChatsListView.compositeViewDescription())
|
||||
PhoneMainView.instance().changeCurrentView(viewtoGo.compositeViewDescription())
|
||||
}
|
||||
|
||||
func replyMessage(message: ChatMessage){
|
||||
let view: ChatConversationViewSwift = self.VIEW(ChatConversationViewSwift.compositeViewDescription())
|
||||
if (view.messageView.messageText.text == "" && view.stackView.arrangedSubviews[3].isHidden && view.stackView.arrangedSubviews[4].isHidden){
|
||||
view.messageView.messageText.becomeFirstResponder()
|
||||
}
|
||||
view.initiateReplyView(forMessage: message.getCobject)
|
||||
}
|
||||
|
||||
func infoMessage(event: EventLog){
|
||||
let view: ChatConversationImdnView = self.VIEW(ChatConversationImdnView.compositeViewDescription())
|
||||
view.event = event.getCobject
|
||||
PhoneMainView.instance().changeCurrentView(view.compositeViewDescription())
|
||||
}
|
||||
|
||||
func addToContacts(message: ChatMessage) {
|
||||
let addr = message.fromAddress
|
||||
addr?.clean()
|
||||
if let lAddress = addr?.asStringUriOnly() {
|
||||
var normSip = String(utf8String: lAddress)
|
||||
normSip = normSip?.hasPrefix("sip:") ?? false ? (normSip as NSString?)?.substring(from: 4) : normSip
|
||||
normSip = normSip?.hasPrefix("sips:") ?? false ? (normSip as NSString?)?.substring(from: 5) : normSip
|
||||
ContactSelection.setAddAddress(normSip)
|
||||
ContactSelection.setSelectionMode(ContactSelectionModeEdit)
|
||||
ContactSelection.enableSipFilter(false)
|
||||
PhoneMainView.instance().changeCurrentView(ContactsListView.compositeViewDescription())
|
||||
}
|
||||
}
|
||||
|
||||
func deleteMessage(message: EventLog){
|
||||
let messageChat = message.chatMessage
|
||||
if messageChat != nil {
|
||||
if ChatConversationTableViewModel.sharedModel.editModeOn.value! {
|
||||
let indexDeletedMessage = ChatConversationTableViewModel.sharedModel.getIndexMessage(message: messageChat!)
|
||||
ChatConversationTableViewModel.sharedModel.messageListSelected.value!.remove(at: indexDeletedMessage)
|
||||
ChatConversationTableViewModel.sharedModel.messageSelected.value! -= 1
|
||||
}
|
||||
let chatRoom = ChatConversationViewModel.sharedModel.chatRoom
|
||||
if chatRoom != nil {
|
||||
chatRoom!.deleteMessage(message: messageChat!)
|
||||
}
|
||||
} else {
|
||||
message.deleteFromDatabase()
|
||||
}
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
public func reloadCollectionViewCell(indexPath: IndexPath){
|
||||
collectionView.reloadItems(at: [indexPath])
|
||||
}
|
||||
|
||||
func getPreviewItem(filePath: String) -> NSURL{
|
||||
let url = NSURL(fileURLWithPath: filePath)
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
|
||||
return previewItems.count
|
||||
}
|
||||
|
||||
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
|
||||
return (previewItems[index] as QLPreviewItem?)!
|
||||
}
|
||||
|
||||
func previewControllerDidDismiss(_ controller: QLPreviewController) {
|
||||
collectionView.scrollToItem(at: IndexPath(item: afterPreviewIndex, section: 0), at: .centeredVertically, animated: false)
|
||||
afterPreviewIndex = -1
|
||||
}
|
||||
|
||||
func onImageClick(chatMessage: ChatMessage, index: Int) {
|
||||
|
||||
let state = chatMessage.state
|
||||
if (state.rawValue == LinphoneChatMessageStateNotDelivered.rawValue) {
|
||||
Log.i("Messsage not delivered")
|
||||
} else {
|
||||
if (VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) || ConfigManager.instance().lpConfigBoolForKey(key: "use_in_app_file_viewer_for_non_encrypted_files", section: "app")){
|
||||
|
||||
var viewer: MediaViewer = VIEW(MediaViewer.compositeViewDescription())
|
||||
|
||||
var image = UIImage()
|
||||
if chatMessage.contents.first!.type == "image" {
|
||||
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
|
||||
var plainFile = chatMessage.contents.first!.exportPlainFile()
|
||||
|
||||
image = UIImage(contentsOfFile: plainFile)!
|
||||
|
||||
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
|
||||
plainFile = ""
|
||||
|
||||
}else {
|
||||
image = UIImage(contentsOfFile: chatMessage.contents.first!.filePath)!
|
||||
}
|
||||
}
|
||||
|
||||
viewer.imageViewer = image
|
||||
viewer.imageNameViewer = chatMessage.contents.first!.name.isEmpty ? "" : chatMessage.contents.first!.name
|
||||
viewer.imagePathViewer = chatMessage.contents.first!.exportPlainFile()
|
||||
viewer.contentType = chatMessage.contents.first!.type
|
||||
PhoneMainView.instance().changeCurrentView(viewer.compositeViewDescription())
|
||||
|
||||
} else {
|
||||
let previewController = QLPreviewController()
|
||||
self.previewItems = []
|
||||
|
||||
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
|
||||
var plainFile = chatMessage.contents.first?.exportPlainFile()
|
||||
|
||||
self.previewItems.append(self.getPreviewItem(filePath: plainFile!))
|
||||
|
||||
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
|
||||
plainFile = ""
|
||||
}else {
|
||||
self.previewItems.append(self.getPreviewItem(filePath: (chatMessage.contents.first?.filePath)!))
|
||||
}
|
||||
|
||||
afterPreviewIndex = index
|
||||
|
||||
previewController.currentPreviewItemIndex = 0
|
||||
previewController.dataSource = self
|
||||
previewController.delegate = self
|
||||
previewController.reloadData()
|
||||
PhoneMainView.instance().mainViewController.present(previewController, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func onGridClick(indexMessage: Int, index: Int) {
|
||||
let chatMessage = ChatConversationTableViewModel.sharedModel.getMessage(index: indexMessage)?.chatMessage
|
||||
let state = chatMessage!.state
|
||||
if (state.rawValue == LinphoneChatMessageStateNotDelivered.rawValue) {
|
||||
Log.i("Messsage not delivered")
|
||||
} else {
|
||||
if (VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) || ConfigManager.instance().lpConfigBoolForKey(key: "use_in_app_file_viewer_for_non_encrypted_files", section: "app")){
|
||||
|
||||
var text = ""
|
||||
var filePathString = VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) ? chatMessage!.contents[index].exportPlainFile() : chatMessage!.contents[index].filePath
|
||||
if let urlEncoded = filePathString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed){
|
||||
if !urlEncoded.isEmpty {
|
||||
if let urlFile = URL(string: "file://" + urlEncoded){
|
||||
do {
|
||||
text = try String(contentsOf: urlFile, encoding: .utf8)
|
||||
let viewer: TextViewer = VIEW(TextViewer.compositeViewDescription())
|
||||
|
||||
if chatMessage != nil {
|
||||
|
||||
viewer.textViewer = text
|
||||
viewer.textNameViewer = chatMessage!.contents[index].name.isEmpty ? "" : chatMessage!.contents[index].name
|
||||
PhoneMainView.instance().changeCurrentView(viewer.compositeViewDescription())
|
||||
}
|
||||
|
||||
} catch {
|
||||
if text == "" && (chatMessage!.contents[index].type == "image" || chatMessage!.contents[index].type == "video" || chatMessage!.contents[index].name.lowercased().components(separatedBy: ".").last == "pdf"){
|
||||
let viewer: MediaViewer = VIEW(MediaViewer.compositeViewDescription())
|
||||
|
||||
var image = UIImage()
|
||||
if chatMessage != nil {
|
||||
if chatMessage!.contents[index].type == "image" {
|
||||
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
|
||||
var plainFile = chatMessage!.contents[index].exportPlainFile()
|
||||
|
||||
image = UIImage(contentsOfFile: plainFile)!
|
||||
|
||||
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
|
||||
plainFile = ""
|
||||
|
||||
}else {
|
||||
image = UIImage(contentsOfFile: chatMessage!.contents[index].filePath)!
|
||||
}
|
||||
}
|
||||
|
||||
viewer.imageViewer = image
|
||||
viewer.imageNameViewer = chatMessage!.contents[index].name.isEmpty ? "" : chatMessage!.contents[index].name
|
||||
viewer.imagePathViewer = chatMessage!.contents[index].exportPlainFile()
|
||||
viewer.contentType = chatMessage!.contents[index].type
|
||||
PhoneMainView.instance().changeCurrentView(viewer.compositeViewDescription())
|
||||
}
|
||||
} else {
|
||||
let exportView = UIAlertController(
|
||||
title: VoipTexts.chat_message_cant_open_file_in_app_dialog_title,
|
||||
message: VoipTexts.chat_message_cant_open_file_in_app_dialog_message,
|
||||
preferredStyle: .alert)
|
||||
|
||||
let cancelAction = UIAlertAction(
|
||||
title: VoipTexts.cancel,
|
||||
style: .default,
|
||||
handler: { action in
|
||||
})
|
||||
|
||||
let exportAction = UIAlertAction(
|
||||
title: VoipTexts.chat_message_cant_open_file_in_app_dialog_export_button,
|
||||
style: .destructive,
|
||||
handler: { action in
|
||||
let previewController = QLPreviewController()
|
||||
self.previewItems = []
|
||||
|
||||
self.previewItems.append(self.getPreviewItem(filePath: filePathString))
|
||||
|
||||
|
||||
self.afterPreviewIndex = indexMessage
|
||||
|
||||
previewController.dataSource = self
|
||||
previewController.currentPreviewItemIndex = index
|
||||
previewController.delegate = self
|
||||
PhoneMainView.instance().mainViewController.present(previewController, animated: true, completion: nil)
|
||||
})
|
||||
|
||||
exportView.addAction(cancelAction)
|
||||
exportView.addAction(exportAction)
|
||||
PhoneMainView.instance()!.present(exportView, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
|
||||
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: filePathString)
|
||||
filePathString = ""
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
let previewController = QLPreviewController()
|
||||
self.previewItems = []
|
||||
chatMessage?.contents.forEach({ content in
|
||||
if(content.isFile){
|
||||
if VFSUtil.vfsEnabled(groupName: kLinphoneMsgNotificationAppGroupId) {
|
||||
var plainFile = content.exportPlainFile()
|
||||
|
||||
self.previewItems.append(self.getPreviewItem(filePath: plainFile))
|
||||
|
||||
ChatConversationViewModel.sharedModel.removeTmpFile(filePath: plainFile)
|
||||
plainFile = ""
|
||||
|
||||
}else {
|
||||
self.previewItems.append(self.getPreviewItem(filePath: (content.filePath)))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
afterPreviewIndex = indexMessage
|
||||
|
||||
previewController.dataSource = self
|
||||
previewController.currentPreviewItemIndex = index
|
||||
previewController.delegate = self
|
||||
PhoneMainView.instance().mainViewController.present(previewController, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1592
Classes/Swift/Chat/Views/ChatConversationViewSwift.swift
Normal file
1592
Classes/Swift/Chat/Views/ChatConversationViewSwift.swift
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue