forked from mirrors/linphone-iphone
Audio chat messages
This commit is contained in:
parent
bcf19d6742
commit
b66c3ad916
28 changed files with 868 additions and 98 deletions
|
|
@ -64,4 +64,16 @@ enum NetworkType: Int {
|
|||
//The recording prefix is used to identify recordings in the cache directory.
|
||||
//We will use name_dayName-day-monthName-year to separate recordings by days, then hour-minutes-seconds to order them in each day.
|
||||
}
|
||||
|
||||
@objc static func removeFile(file: String) {
|
||||
let fileManager = FileManager.default
|
||||
do {
|
||||
try fileManager.removeItem(atPath: file)
|
||||
Log.directLog(BCTBX_LOG_MESSAGE, text: "File :\(file) removed")
|
||||
|
||||
} catch {
|
||||
print("Could not remove file : \(file) \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,9 +34,18 @@
|
|||
<outlet property="sendButton" destination="15" id="27"/>
|
||||
<outlet property="tableController" destination="29" id="32"/>
|
||||
<outlet property="toggleMenuButton" destination="CPn-Oc-9PX" id="QdS-xO-bfA"/>
|
||||
<outlet property="toggleRecord" destination="aTi-pm-fAG" id="RYV-0Q-v5p"/>
|
||||
<outlet property="toggleSelectionButton" destination="c9z-aq-2UP" id="kiK-wF-8iU"/>
|
||||
<outlet property="topBar" destination="7" id="JH8-F4-Bdq"/>
|
||||
<outlet property="view" destination="6" id="11"/>
|
||||
<outlet property="vrDeleteButton" destination="wi9-en-JCZ" id="09B-Bm-ECJ"/>
|
||||
<outlet property="vrDurationLabel" destination="dMW-Ix-4k0" id="Ugl-f5-r2m"/>
|
||||
<outlet property="vrInnerView" destination="eXD-Gd-FXA" id="wBh-N1-Au9"/>
|
||||
<outlet property="vrPlayButton" destination="FNM-bb-AlC" id="NOD-GE-eIA"/>
|
||||
<outlet property="vrView" destination="Tru-Zm-4EZ" id="Rx2-ls-nMc"/>
|
||||
<outlet property="vrWave" destination="m9m-2e-T7E" id="F07-qS-Yj6"/>
|
||||
<outlet property="vrWaveMask" destination="TzM-ND-yp4" id="FKT-Gu-CyA"/>
|
||||
<outlet property="vrWaveMaskPlayer" destination="OTf-Od-TDn" id="g9D-K1-Gf0"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
|
|
@ -209,7 +218,7 @@
|
|||
<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="634"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="574"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<gestureRecognizers/>
|
||||
|
|
@ -221,7 +230,7 @@
|
|||
</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="634" width="414" height="22"/>
|
||||
<rect key="frame" x="0.0" y="574" width="414" height="22"/>
|
||||
<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">
|
||||
|
|
@ -236,7 +245,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="625"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="574"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
@ -260,6 +269,19 @@
|
|||
<action selector="onPictureClick:" destination="-1" eventType="touchUpInside" id="87"/>
|
||||
</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"/>
|
||||
<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"/>
|
||||
<state key="normal" image="vr_off.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<state key="selected" image="vr_on.png"/>
|
||||
<connections>
|
||||
<action selector="onVrStart:" destination="-1" eventType="touchUpInside" id="6QP-19-E8o"/>
|
||||
</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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
|
|
@ -275,7 +297,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<view tag="20" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pqa-tg-5ml" userLabel="messageField" customClass="HPGrowingTextView">
|
||||
<rect key="frame" x="72" y="13" width="269" height="40"/>
|
||||
<rect key="frame" x="130" y="13" width="208" height="40"/>
|
||||
<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"/>
|
||||
|
|
@ -287,6 +309,58 @@
|
|||
</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"/>
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="delete_default.png"/>
|
||||
<connections>
|
||||
<action selector="onVrDelete:" destination="-1" eventType="touchUpInside" id="yV4-iY-mvE"/>
|
||||
</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"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="vr_play.png"/>
|
||||
<connections>
|
||||
<action selector="onvrPlayPauseStop:" destination="-1" eventType="touchUpInside" id="Wka-en-Ic8"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.93333333330000001" green="0.93333333330000001" blue="0.93333333330000001" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view clipsSubviews="YES" alpha="0.90000000000000002" 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"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
|
|
@ -551,8 +625,21 @@
|
|||
<action selector="onPictureClick:" destination="-1" eventType="touchUpInside" id="Ag3-po-DGR"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" tag="9019" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zub-Ow-smm" userLabel="audioRecordingButton">
|
||||
<rect key="frame" x="66" y="0.0" width="66" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Send picture"/>
|
||||
<state key="normal" image="vr_off.png">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<state key="selected" image="vr_on.png"/>
|
||||
<connections>
|
||||
<action selector="onPictureClick:" destination="-1" eventType="touchUpInside" id="qhP-B0-dkG"/>
|
||||
<action selector="onVrStart:" destination="-1" eventType="touchUpInside" id="yWJ-st-yz2"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view tag="20" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C02-2r-vXK" userLabel="messageField" customClass="HPGrowingTextView">
|
||||
<rect key="frame" x="32" y="13" width="257" height="40"/>
|
||||
<rect key="frame" x="59" y="13" width="230" height="40"/>
|
||||
<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"/>
|
||||
|
|
@ -637,10 +724,14 @@
|
|||
<image name="delete_disabled.png" width="34.400001525878906" height="44.799999237060547"/>
|
||||
<image name="deselect_all.png" width="43.200000762939453" height="43.200000762939453"/>
|
||||
<image name="ephemeral_messages_color_A.png" width="136" height="158.39999389648438"/>
|
||||
<image name="more_menu_default.png" width="10.319999694824219" height="13.680000305175781"/>
|
||||
<image name="more_menu_default.png" width="7.1999998092651367" height="9.3599996566772461"/>
|
||||
<image name="security_1_indicator.png" width="27.5" height="32.5"/>
|
||||
<image name="select_all_default.png" width="43.200000762939453" height="43.200000762939453"/>
|
||||
<image name="select_all_disabled.png" width="43.200000762939453" height="43.200000762939453"/>
|
||||
<image name="vr_off.png" width="40" height="40"/>
|
||||
<image name="vr_on.png" width="40" height="40"/>
|
||||
<image name="vr_play.png" width="200" height="200"/>
|
||||
<image name="vr_wave.png" width="1078" height="90"/>
|
||||
<systemColor name="secondarySystemBackgroundColor">
|
||||
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
|
|
|
|||
|
|
@ -639,6 +639,25 @@ import AVFoundation
|
|||
AnyHashable("message"): message
|
||||
])
|
||||
}
|
||||
|
||||
@objc func activateAudioSession() {
|
||||
lc?.activateAudioSession(actived: true)
|
||||
}
|
||||
|
||||
@objc func getSpeakerSoundCard() -> String? {
|
||||
var speakerCard: String? = nil
|
||||
var earpieceCard: String? = nil
|
||||
lc?.audioDevices.forEach { device in
|
||||
if (device.hasCapability(capability: .CapabilityPlay)) {
|
||||
if (device.type == .Speaker) {
|
||||
speakerCard = device.id
|
||||
} else if (device.type == .Earpiece) {
|
||||
earpieceCard = device.id
|
||||
}
|
||||
}
|
||||
}
|
||||
return speakerCard != nil ? speakerCard : earpieceCard
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@
|
|||
|
||||
@protocol ChatConversationDelegate <NSObject>
|
||||
|
||||
- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message;
|
||||
- (BOOL)resendFile:(NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message;
|
||||
- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent;
|
||||
- (BOOL)resendFile:(NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent;
|
||||
- (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name;
|
||||
- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url;
|
||||
- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url voiceContent:(LinphoneContent *)voiceContent;
|
||||
- (void)tableViewIsScrolling;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -92,6 +92,28 @@
|
|||
@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *toggleMenuButton;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *ephemeralndicator;
|
||||
|
||||
|
||||
// Voice recording
|
||||
@property (strong, nonatomic) IBOutlet UIView *vrView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *vrInnerView;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *vrDeleteButton;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *vrPlayButton;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *vrWave;
|
||||
@property (weak, nonatomic) IBOutlet UIView *vrWaveMask;
|
||||
@property (weak, nonatomic) IBOutlet UIView *vrWaveMaskPlayer;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *vrDurationLabel;
|
||||
@property NSTimer *vrRecordTimer;
|
||||
@property NSTimer *vrPlayerTimer;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *toggleRecord;
|
||||
@property BOOL isVoiceRecording;
|
||||
@property BOOL isPendingVoiceRecord;
|
||||
@property BOOL isPlayingVoiceRecording;
|
||||
@property LinphoneRecorder *voiceRecorder;
|
||||
@property LinphonePlayer *sharedVoicePlayer;
|
||||
@property BOOL showVoiceRecorderView;
|
||||
@property BOOL preservePendingRecording;
|
||||
|
||||
|
||||
+ (void)markAsRead:(LinphoneChatRoom *)chatRoom;
|
||||
+ (void)autoDownload:(LinphoneChatMessage *)message;
|
||||
+(NSString *)getKeyFromFileType:(NSString *)fileType fileName:(NSString *)name;
|
||||
|
|
@ -123,4 +145,8 @@
|
|||
- (NSURL *)getICloudFileUrl:(NSString *)name;
|
||||
- (void)removeCallBacks;
|
||||
|
||||
-(void) startSharedPlayer:(const char *)path;
|
||||
-(void) stopSharedPlayer;
|
||||
-(BOOL) sharedPlayedIsPlaying:(const char *)path;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@
|
|||
[NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil),
|
||||
[NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil];
|
||||
composingVisible = false;
|
||||
[self initSharedPlayer];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -187,6 +188,12 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_imagesCollectionView registerClass:[UIImageViewDeletable class] forCellWithReuseIdentifier:NSStringFromClass([UIImageViewDeletable class])];
|
||||
[_imagesCollectionView setDataSource:self];
|
||||
[_toggleSelectionButton setImage:[UIImage imageNamed:@"select_all_default.png"] forState:UIControlStateSelected];
|
||||
|
||||
_vrInnerView.layer.cornerRadius = 5.0f;
|
||||
_vrInnerView.layer.masksToBounds = YES;
|
||||
_vrWaveMaskPlayer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"color_L"]]; // rgba(1,88,7,0.2);
|
||||
_showVoiceRecorderView = false;
|
||||
|
||||
}
|
||||
|
||||
- (void)refreshData {
|
||||
|
|
@ -202,6 +209,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(applicationWillEnterBackground)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(keyboardWillShow:)
|
||||
name:UIKeyboardWillShowNotification
|
||||
|
|
@ -222,6 +233,16 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector:@selector(onLinphoneCoreReady:)
|
||||
name:kLinphoneGlobalStateUpdate
|
||||
object:nil];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(endVoicePlayingIfDoingSO:)
|
||||
name:kLinphoneVoiceMessagePlayerLostFocus
|
||||
object:nil];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(endVoicePlayingIfDoingSO:)
|
||||
name:kLinphoneVoiceMessagePlayerEOF
|
||||
object:nil];
|
||||
if ([_fileContext count] > 0) {
|
||||
[UIView animateWithDuration:0
|
||||
delay:0
|
||||
|
|
@ -236,6 +257,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
CGRect tableViewFrame = [_tableController.tableView frame];
|
||||
tableViewFrame.size.height -= 100;
|
||||
[_tableController.tableView setFrame:tableViewFrame];
|
||||
[self updateFramesInclRecordingView];
|
||||
}
|
||||
completion:nil];
|
||||
}
|
||||
|
|
@ -245,10 +267,20 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
CGRect popupFrame = _popupMenu.frame;
|
||||
popupFrame.size.height = 44 * [_popupMenu numberOfRowsInSection:0];
|
||||
_popupMenu.frame = popupFrame;
|
||||
|
||||
// Voice recording
|
||||
_vrView.hidden = true;
|
||||
_preservePendingRecording = false;
|
||||
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
||||
if (!_preservePendingRecording)
|
||||
[self cancelVoiceRecording];
|
||||
else if (_isVoiceRecording)
|
||||
[self stopVoiceRecording];
|
||||
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
[self removeCallBacks];
|
||||
|
|
@ -256,7 +288,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_messageField resignFirstResponder];
|
||||
|
||||
[self setComposingVisible:false withDelay:0]; // will hide the "user is composing.." message
|
||||
|
||||
|
||||
[self stopAllPlays];
|
||||
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
PhoneMainView.instance.currentRoom = NULL;
|
||||
}
|
||||
|
|
@ -287,10 +321,20 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_backButton.hidden = _tableController.isEditing;
|
||||
[_tableController scrollToBottom:true];
|
||||
[self refreshImageDrawer];
|
||||
[self stopAllPlays];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)applicationWillEnterBackground{
|
||||
if (!_preservePendingRecording)
|
||||
[self cancelVoiceRecording];
|
||||
else if (_isVoiceRecording)
|
||||
[self stopVoiceRecording];
|
||||
}
|
||||
|
||||
|
||||
- (void)configureForRoom:(BOOL)editing {
|
||||
if (!_chatRoom) {
|
||||
_chatView.hidden = YES;
|
||||
|
|
@ -456,16 +500,24 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL *)externalUrl {
|
||||
- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL *)externalUrl andVoiceContent:(LinphoneContent *)voiceContent {
|
||||
if (_chatRoom == NULL) {
|
||||
LOGW(@"Cannot send message: No chatroom");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LinphoneChatMessage *msg = linphone_chat_room_create_message(_chatRoom, [message UTF8String]);
|
||||
LinphoneChatMessage *msg = linphone_chat_room_create_empty_message(_chatRoom);
|
||||
if (message && message.length > 0)
|
||||
linphone_chat_message_add_utf8_text_content(msg, message.UTF8String);
|
||||
|
||||
if (externalUrl) {
|
||||
linphone_chat_message_set_external_body_url(msg, [[externalUrl absoluteString] UTF8String]);
|
||||
}
|
||||
|
||||
// Voice recording
|
||||
|
||||
if (voiceContent)
|
||||
linphone_chat_message_add_content(msg, voiceContent);
|
||||
|
||||
// we must ref & unref message because in case of error, it will be destroy otherwise
|
||||
linphone_chat_message_send(msg);
|
||||
|
|
@ -512,10 +564,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[sheet addButtonWithTitle:NSLocalizedString(@"Send to this friend", nil)
|
||||
block:^() {
|
||||
if (![[self.messageField text] isEqualToString:@""]) {
|
||||
[self sendMessageInMessageField];
|
||||
[self sendMessageInMessageFieldWithVoiceContent:nil];
|
||||
}
|
||||
if (url)
|
||||
[self sendMessage:url withExterlBodyUrl:nil];
|
||||
[self sendMessage:url withExterlBodyUrl:nil andVoiceContent:nil];
|
||||
else
|
||||
[self startFileUpload:data withName:fileName];
|
||||
}];
|
||||
|
|
@ -600,8 +652,8 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
_addressLabel.frame = frame;
|
||||
}
|
||||
|
||||
- (void)sendMessageInMessageField {
|
||||
if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil]) {
|
||||
- (void)sendMessageInMessageFieldWithVoiceContent:(LinphoneContent *)voiceContent {
|
||||
if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil andVoiceContent:voiceContent]) {
|
||||
scrollOnGrowingEnabled = FALSE;
|
||||
[_messageField setText:@""];
|
||||
scrollOnGrowingEnabled = TRUE;
|
||||
|
|
@ -657,6 +709,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
CGRect tableRect = [_tableController.view frame];
|
||||
tableRect.size.height -= diff;
|
||||
[_tableController.view setFrame:tableRect];
|
||||
[self updateFramesInclRecordingView];
|
||||
|
||||
// if we're showing the compose message, update it position
|
||||
if (![_composeLabel isHidden]) {
|
||||
|
|
@ -681,28 +734,40 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (IBAction)onSendClick:(id)event {
|
||||
LinphoneContent *voiceContent = nil;
|
||||
if (_isPendingVoiceRecord && _voiceRecorder && linphone_recorder_get_file(_voiceRecorder)) {
|
||||
voiceContent = linphone_recorder_create_content(_voiceRecorder);
|
||||
_isPendingVoiceRecord = false;
|
||||
[self cancelVoiceRecording];
|
||||
[self stopVoiceRecordPlayer];
|
||||
}
|
||||
|
||||
if (!linphone_core_is_network_reachable(LC)) {
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
|
||||
//return;
|
||||
}
|
||||
if ([_fileContext count] > 0) {
|
||||
if (linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesConference) {
|
||||
[self startMultiFilesUpload];
|
||||
[self startMultiFilesUploadWithVoiceContent:voiceContent];
|
||||
} else {
|
||||
int i = 0;
|
||||
for (i = 0; i < [_fileContext count]-1; ++i) {
|
||||
[self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL];
|
||||
[self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL voiceContent:voiceContent];
|
||||
}
|
||||
if (isOneToOne) {
|
||||
[self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL];
|
||||
[self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL voiceContent:voiceContent];
|
||||
if (![[self.messageField text] isEqualToString:@""]) {
|
||||
[self sendMessage:[_messageField text] withExterlBodyUrl:nil];
|
||||
[self sendMessage:[_messageField text] withExterlBodyUrl:nil andVoiceContent:voiceContent];
|
||||
}
|
||||
} else {
|
||||
[self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:[self.messageField text]];
|
||||
[self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:[self.messageField text] voiceContent:voiceContent];
|
||||
}
|
||||
}
|
||||
|
||||
[self clearMessageView];
|
||||
return;
|
||||
}
|
||||
[self sendMessageInMessageField];
|
||||
[self sendMessageInMessageFieldWithVoiceContent:voiceContent];
|
||||
}
|
||||
|
||||
- (IBAction)onListTap:(id)sender {
|
||||
|
|
@ -759,14 +824,11 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
- (IBAction)onMessageChange:(id)sender {
|
||||
if ([[_messageField text] length] > 0) {
|
||||
[_sendButton setEnabled:TRUE];
|
||||
} else {
|
||||
[_sendButton setEnabled:FALSE];
|
||||
}
|
||||
[self setSendButtonState];
|
||||
}
|
||||
|
||||
- (IBAction)onPictureClick:(id)event {
|
||||
_preservePendingRecording = true;
|
||||
[_messageField resignFirstResponder];
|
||||
[ImagePickerView SelectImageFromDevice:self atPosition:_pictureButton inView:self.view withDocumentMenuDelegate:self];
|
||||
|
||||
|
|
@ -800,15 +862,15 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
#pragma mark ChatRoomDelegate
|
||||
|
||||
- (BOOL)startMultiFilesUpload {
|
||||
- (BOOL)startMultiFilesUploadWithVoiceContent:(LinphoneContent *)voiceContent {
|
||||
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
|
||||
[fileTransfer setText:[self.messageField text]];
|
||||
[fileTransfer uploadFileContent:_fileContext forChatRoom:_chatRoom];
|
||||
[fileTransfer uploadFileContent:_fileContext forChatRoom:_chatRoom andVoiceContent:voiceContent];
|
||||
[_tableController scrollToBottom:true];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (BOOL)startUploadData:(NSData *)data withType:(NSString*)type withName:(NSString *)name andMessage:(NSString *)message {
|
||||
- (BOOL)startUploadData:(NSData *)data withType:(NSString*)type withName:(NSString *)name andMessage:(NSString *)message voiceContent:(LinphoneContent *)voiceContent {
|
||||
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
|
||||
if (message)
|
||||
[fileTransfer setText:message];
|
||||
|
|
@ -818,7 +880,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
} else if ([type isEqualToString:@"image"]) {
|
||||
key = @"localimage";
|
||||
}
|
||||
[fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key];
|
||||
[fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key voiceContent:voiceContent];
|
||||
[_tableController scrollToBottom:true];
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -830,26 +892,26 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message {
|
||||
- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent {
|
||||
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
|
||||
if (message)
|
||||
[fileTransfer setText:message];
|
||||
[fileTransfer uploadFileContent:newFileContext forChatRoom:_chatRoom];
|
||||
[fileTransfer uploadFileContent:newFileContext forChatRoom:_chatRoom andVoiceContent:voiceContent];
|
||||
[_tableController scrollToBottom:true];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (BOOL)resendFile: (NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message {
|
||||
- (BOOL)resendFile: (NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent{
|
||||
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
|
||||
if (message)
|
||||
[fileTransfer setText:message];
|
||||
[fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key];
|
||||
[fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key voiceContent:voiceContent];
|
||||
[_tableController scrollToBottom:true];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url {
|
||||
[self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url]];
|
||||
- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url voiceContent:(LinphoneContent *)voiceContent {
|
||||
[self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] andVoiceContent:voiceContent];
|
||||
}
|
||||
|
||||
#pragma mark ImagePickerDelegate
|
||||
|
|
@ -1077,6 +1139,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_messageView frame].origin.y - tableFrame.origin.y - composeIndicatorCompensation;
|
||||
[_tableController.view setFrame:tableFrame];
|
||||
|
||||
|
||||
// Scroll to bottom
|
||||
NSInteger lastSection = [_tableController.tableView numberOfSections] - 1;
|
||||
if (lastSection >= 0) {
|
||||
|
|
@ -1102,9 +1165,12 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
|
||||
[_tableController.tableView setFrame:tableViewFrame];
|
||||
}
|
||||
if (_showVoiceRecorderView)
|
||||
_vrView.hidden = true;
|
||||
[self updateFramesInclRecordingView];
|
||||
|
||||
}
|
||||
completion:^(BOOL finished){
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -1158,6 +1224,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
tableFrame.size.height =
|
||||
[_messageView frame].origin.y - tableFrame.origin.y - composeIndicatorCompensation;
|
||||
[_tableController.view setFrame:tableFrame];
|
||||
|
||||
}
|
||||
|
||||
if ([_fileContext count] > 0){
|
||||
|
|
@ -1170,6 +1237,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
CGRect tableViewFrame = [_tableController.tableView frame];
|
||||
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
|
||||
[_tableController.tableView setFrame:tableViewFrame];
|
||||
|
||||
}
|
||||
|
||||
// Scroll
|
||||
|
|
@ -1183,10 +1251,13 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
animated:FALSE];
|
||||
}
|
||||
}
|
||||
if (_showVoiceRecorderView)
|
||||
_vrView.hidden = true;
|
||||
[self updateFramesInclRecordingView];
|
||||
|
||||
|
||||
}
|
||||
completion:^(BOOL finished){
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -1395,7 +1466,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
[imgView setUuid:[_fileContext.uuidsArray objectAtIndex:[indexPath item]]];
|
||||
[imgView setDeleteDelegate:self];
|
||||
[imgView setFrame:imgFrame];
|
||||
[_sendButton setEnabled:TRUE];
|
||||
[self setSendButtonState];
|
||||
return imgView;
|
||||
}
|
||||
|
||||
|
|
@ -1416,10 +1487,10 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
CGRect tableViewFrame = [_tableController.tableView frame];
|
||||
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
|
||||
[_tableController.tableView setFrame:tableViewFrame];
|
||||
[self updateFramesInclRecordingView];
|
||||
}
|
||||
completion:nil];
|
||||
if ([_messageField.text isEqualToString:@""])
|
||||
[_sendButton setEnabled:FALSE];
|
||||
[self setSendButtonState];
|
||||
} else {
|
||||
// resizing imagesView
|
||||
CGRect imagesFrame = [_imagesView frame];
|
||||
|
|
@ -1430,6 +1501,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
CGRect tableViewFrame = [_tableController.tableView frame];
|
||||
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
|
||||
[_tableController.tableView setFrame:tableViewFrame];
|
||||
[self updateFramesInclRecordingView];
|
||||
[_imagesCollectionView reloadData];
|
||||
}
|
||||
}
|
||||
|
|
@ -1592,4 +1664,268 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
|
|||
}
|
||||
|
||||
|
||||
// Voice redcording
|
||||
|
||||
|
||||
- (IBAction)onVrDelete:(id)sender {
|
||||
[self cancelVoiceRecording];
|
||||
[self stopVoiceRecordPlayer];
|
||||
}
|
||||
|
||||
- (IBAction)onvrPlayPauseStop:(id)sender {
|
||||
if (_isVoiceRecording) {
|
||||
[self stopVoiceRecording];
|
||||
} else {
|
||||
if (_isPlayingVoiceRecording)
|
||||
[self stopVoiceRecordPlayer];
|
||||
else
|
||||
[self playRecordedMessage];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onVrStart:(id)sender {
|
||||
if (_isVoiceRecording) {
|
||||
[self stopVoiceRecording];
|
||||
} else {
|
||||
[self startVoiceRecording];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) createVoiceRecorder {
|
||||
LinphoneRecorderParams *p = linphone_core_create_recorder_params(LC);
|
||||
linphone_recorder_params_set_file_format(p, LinphoneRecorderFileFormatWav);
|
||||
_voiceRecorder = linphone_core_create_recorder(LC, p);
|
||||
[CallManager.instance activateAudioSession];
|
||||
}
|
||||
|
||||
-(void) cancelVoiceRecording {
|
||||
_showVoiceRecorderView = false;
|
||||
_toggleRecord.selected = false;
|
||||
[self updateFramesInclRecordingView];
|
||||
_isPendingVoiceRecord = false;
|
||||
_isVoiceRecording = false;
|
||||
if (_voiceRecorder && linphone_recorder_get_state(_voiceRecorder) != LinphoneRecorderClosed) {
|
||||
linphone_recorder_close(_voiceRecorder);
|
||||
const char *recordingFile = linphone_recorder_get_file(_voiceRecorder);
|
||||
if (recordingFile) {
|
||||
[AppManager removeFileWithFile:[NSString stringWithUTF8String:recordingFile]];
|
||||
}
|
||||
}
|
||||
[self setSendButtonState];
|
||||
}
|
||||
|
||||
-(void) stopVoiceRecording {
|
||||
if (_voiceRecorder && linphone_recorder_get_state(_voiceRecorder) == LinphoneRecorderRunning) {
|
||||
LOGI(@"[Chat Message Sending] Pausing / closing voice recorder");
|
||||
linphone_recorder_pause(_voiceRecorder);
|
||||
linphone_recorder_close(_voiceRecorder);
|
||||
_vrDurationLabel.text = [self formattedDuration:linphone_recorder_get_duration(_voiceRecorder)];
|
||||
}
|
||||
_isVoiceRecording = false;
|
||||
if ([LinphoneManager.instance lpConfigBoolForKey:@"voice_recording_send_right_away" withDefault:false]) {
|
||||
[self onSendClick:nil];
|
||||
}
|
||||
[_vrPlayButton setImage:[UIImage imageNamed:@"vr_play"] forState:UIControlStateNormal];
|
||||
_toggleRecord.selected = false;
|
||||
_vrWaveMask.frame = CGRectZero;
|
||||
[_vrRecordTimer invalidate];
|
||||
_isPendingVoiceRecord = linphone_recorder_get_duration(_voiceRecorder) > 0;
|
||||
[self setSendButtonState];
|
||||
|
||||
}
|
||||
|
||||
-(void) startVoiceRecording {
|
||||
|
||||
if (!_voiceRecorder)
|
||||
[self createVoiceRecorder];
|
||||
|
||||
_toggleRecord.selected = true;
|
||||
[_vrPlayButton setImage:[UIImage imageNamed:@"vr_stop"] forState:UIControlStateNormal];
|
||||
|
||||
|
||||
_showVoiceRecorderView = true;
|
||||
[self updateFramesInclRecordingView];
|
||||
_isVoiceRecording = true;
|
||||
_vrWaveMaskPlayer.frame = CGRectZero;
|
||||
|
||||
switch (linphone_recorder_get_state(_voiceRecorder)) {
|
||||
case LinphoneRecorderClosed: {
|
||||
NSString *filename = [NSString stringWithFormat:@"%@/voice-recording-%@.wav",[LinphoneManager imagesDirectory], [NSUUID UUID].UUIDString];
|
||||
linphone_recorder_open(_voiceRecorder, filename.UTF8String);
|
||||
linphone_recorder_start(_voiceRecorder);
|
||||
LOGW(@"[Chat Message Sending] Recorder is closed opening it with %@",filename);
|
||||
break;
|
||||
};
|
||||
case LinphoneRecorderRunning: {
|
||||
LOGW(@"[Chat Message Sending] Recorder is already recording");
|
||||
break;
|
||||
}
|
||||
case LinphoneRecorderPaused: {
|
||||
LOGW(@"[Chat Message Sending] Recorder isn't closed, resuming recording");
|
||||
linphone_recorder_start(_voiceRecorder);
|
||||
}
|
||||
}
|
||||
_vrWaveMask.frame = _vrWave.frame;
|
||||
_vrDurationLabel.text = [self formattedDuration:linphone_recorder_get_duration(_voiceRecorder)];
|
||||
_vrRecordTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
|
||||
target:self
|
||||
selector:@selector(voiceRecordTimerUpdate)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
|
||||
|
||||
}
|
||||
|
||||
-(void) voiceRecordTimerUpdate {
|
||||
int recorderDuration = linphone_recorder_get_duration(_voiceRecorder);
|
||||
if (recorderDuration > [LinphoneManager.instance lpConfigIntForKey:@"voice_recording_max_duration" withDefault:60000]) {
|
||||
LOGW(@"[Chat Message Sending] Max duration for voice recording exceeded, stopping. (max = %d)",[LinphoneManager.instance lpConfigIntForKey:@"voice_recording_max_duration" withDefault:60000]);
|
||||
[self stopVoiceRecording];
|
||||
} else {
|
||||
_vrDurationLabel.text = [self formattedDuration:linphone_recorder_get_duration(_voiceRecorder)];
|
||||
CGRect r = _vrWaveMask.frame;
|
||||
r.origin.x += 30;
|
||||
r.size.width -= 30;
|
||||
if (r.origin.x > _vrWave.frame.size.width) {
|
||||
r = _vrWave.frame;
|
||||
_vrWaveMask.frame = r;
|
||||
} else {
|
||||
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
_vrWaveMask.frame = r;
|
||||
}completion:^(BOOL finished) {}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Playback Shared Player (new recording & chat bubble)
|
||||
|
||||
- (void) initSharedPlayer {
|
||||
LOGI(@"[Voice Message] Creating shared player");
|
||||
_sharedVoicePlayer = linphone_core_create_local_player(LC, [CallManager.instance getSpeakerSoundCard].UTF8String, nil, nil);
|
||||
LinphonePlayerCbs *cbs = linphone_factory_create_player_cbs(linphone_factory_get());
|
||||
linphone_player_cbs_set_eof_reached(cbs, on_shared_player_eof_reached);
|
||||
linphone_player_cbs_set_user_data(cbs, (__bridge void*)self);
|
||||
linphone_player_add_callbacks(_sharedVoicePlayer, cbs);
|
||||
}
|
||||
|
||||
-(void) startSharedPlayer:(const char *)path {
|
||||
LOGI(@"[Voice Message] Starting shared player path = %s",path);
|
||||
if (linphone_player_get_user_data(_sharedVoicePlayer)) {
|
||||
LOGI(@"[Voice Message] a play was requested (%s), but there is already one going (%s)",path,(const char *)linphone_player_get_user_data(_sharedVoicePlayer) );
|
||||
NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:linphone_player_get_user_data(_sharedVoicePlayer)]};
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerLostFocus object:nil userInfo:userInfo];
|
||||
}
|
||||
[CallManager.instance changeRouteToSpeaker];
|
||||
linphone_player_set_user_data(_sharedVoicePlayer, (void *)path);
|
||||
linphone_player_open(_sharedVoicePlayer, path);
|
||||
linphone_player_start(_sharedVoicePlayer);
|
||||
}
|
||||
|
||||
-(void) stopSharedPlayer {
|
||||
LOGI(@"[Voice Message] Stopping shared player path = %s",linphone_player_get_user_data(_sharedVoicePlayer) ? (const char *)linphone_player_get_user_data(_sharedVoicePlayer) : "nil");
|
||||
linphone_player_pause(_sharedVoicePlayer);
|
||||
linphone_player_seek(_sharedVoicePlayer,0);
|
||||
linphone_player_close(_sharedVoicePlayer);
|
||||
linphone_player_set_user_data(_sharedVoicePlayer, nil);
|
||||
}
|
||||
|
||||
-(BOOL) sharedPlayedIsPlaying:(const char *)path {
|
||||
return path && linphone_player_get_user_data(_sharedVoicePlayer) && !strcmp(path,linphone_player_get_user_data(_sharedVoicePlayer));
|
||||
}
|
||||
|
||||
void on_shared_player_eof_reached(LinphonePlayer *p) {
|
||||
LOGI(@"[Voice Message] End of file reached for player");
|
||||
const char * currentPlayedFile = (const char *) linphone_player_get_user_data(p);
|
||||
if (currentPlayedFile) {
|
||||
NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:currentPlayedFile]};
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerEOF object:nil userInfo:userInfo];
|
||||
}
|
||||
|
||||
// ChatConversationView *view = (__bridge ChatConversationView *)linphone_player_cbs_get_user_data(linphone_player_get_current_callbacks(p));
|
||||
// [view stopVoiceRecordPlayer];
|
||||
}
|
||||
|
||||
// Playback of new recordings
|
||||
|
||||
-(void) playRecordedMessage {
|
||||
[_vrPlayButton setImage:[UIImage imageNamed:@"vr_stop"] forState:UIControlStateNormal];
|
||||
_vrDurationLabel.text = [self formattedDuration:linphone_player_get_duration(_sharedVoicePlayer)];
|
||||
_vrWaveMask.frame = CGRectZero;
|
||||
CGRect r = CGRectZero;
|
||||
r.size.height = _vrInnerView.frame.size.height;
|
||||
_vrWaveMaskPlayer.frame = r;
|
||||
_vrPlayerTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
|
||||
target:self
|
||||
selector:@selector(voicePlayTimerUpdate)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
[self startSharedPlayer:linphone_recorder_get_file(_voiceRecorder)];
|
||||
[self animPlayerOnce];
|
||||
_isPlayingVoiceRecording = true;
|
||||
}
|
||||
|
||||
-(void) voicePlayTimerUpdate {
|
||||
_vrDurationLabel.text = [self formattedDuration:linphone_player_get_duration(_sharedVoicePlayer)];
|
||||
[self animPlayerOnce];
|
||||
}
|
||||
|
||||
-(void) animPlayerOnce {
|
||||
CGRect r = _vrWaveMaskPlayer.frame;
|
||||
r.size.width += _vrInnerView.frame.size.width / ((linphone_player_get_duration(_sharedVoicePlayer) / 1000)+1) ;
|
||||
if (r.size.width > _vrInnerView.frame.size.width) {
|
||||
r.size.width = _vrInnerView.frame.size.width;
|
||||
}
|
||||
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
_vrWaveMaskPlayer.frame = r;
|
||||
}completion:^(BOOL finished) {}];
|
||||
}
|
||||
|
||||
-(void) endVoicePlayingIfDoingSO:(NSNotification *)notif {
|
||||
if (_isPlayingVoiceRecording)
|
||||
[self stopVoiceRecordPlayer];
|
||||
}
|
||||
|
||||
-(void) stopVoiceRecordPlayer {
|
||||
[self stopSharedPlayer];
|
||||
[_vrPlayButton setImage:[UIImage imageNamed:@"vr_play"] forState:UIControlStateNormal];
|
||||
_isPlayingVoiceRecording = false;
|
||||
[_vrPlayerTimer invalidate];
|
||||
_vrWaveMaskPlayer.frame = CGRectZero;
|
||||
}
|
||||
|
||||
-(NSString *)formattedDuration:(long)valueMs {
|
||||
return [NSString stringWithFormat:@"%02ld:%02ld", valueMs/ 60000, (valueMs % 60000) / 1000 ];
|
||||
}
|
||||
|
||||
-(void) updateFramesInclRecordingView { // place below the messages table.
|
||||
BOOL showHide = _showVoiceRecorderView != !_vrView.hidden;
|
||||
if (showHide)
|
||||
_vrView.hidden = !_showVoiceRecorderView;
|
||||
|
||||
CGRect vrFrame = _vrView.frame;
|
||||
CGRect tableFrame = _tableController.tableView.frame;
|
||||
if (showHide) {
|
||||
tableFrame.size.height = _showVoiceRecorderView ? tableFrame.size.height - vrFrame.size.height : tableFrame.size.height + vrFrame.size.height;
|
||||
_tableController.tableView.frame = tableFrame;
|
||||
[_tableController.tableView reloadData];
|
||||
}
|
||||
vrFrame.origin.y = tableFrame.origin.y+tableFrame.size.height;
|
||||
_vrView.frame = vrFrame;
|
||||
}
|
||||
|
||||
-(void) stopAllPlays {
|
||||
if (linphone_player_get_user_data(_sharedVoicePlayer)) {
|
||||
NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:linphone_player_get_user_data(_sharedVoicePlayer)]};
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerLostFocus object:nil userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
// send button state
|
||||
|
||||
-(void) setSendButtonState {
|
||||
_sendButton.enabled = !_isVoiceRecording && ((_isPendingVoiceRecord && linphone_recorder_get_duration(_voiceRecorder) > 0) || [[_messageField text] length] > 0 || _fileContext.count > 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)onLoginClick:(id)sender {
|
||||
if (!linphone_core_is_network_reachable(LC)) {
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView] animated:YES completion:nil];
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"configure an account"] animated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ extern NSString *const kLinphoneFileTransferRecvUpdate;
|
|||
extern NSString *const kLinphoneQRCodeFound;
|
||||
extern NSString *const kLinphoneChatCreateViewChange;
|
||||
extern NSString *const kLinphoneEphemeralMessageDeletedInRoom;
|
||||
extern NSString *const kLinphoneVoiceMessagePlayerEOF;
|
||||
extern NSString *const kLinphoneVoiceMessagePlayerLostFocus;
|
||||
|
||||
extern NSString *const kLinphoneMsgNotificationAppGroupId;
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ NSString *const kLinphoneFileTransferRecvUpdate = @"LinphoneFileTransferRecvUpda
|
|||
NSString *const kLinphoneQRCodeFound = @"LinphoneQRCodeFound";
|
||||
NSString *const kLinphoneChatCreateViewChange = @"LinphoneChatCreateViewChange";
|
||||
NSString *const kLinphoneEphemeralMessageDeletedInRoom = @"LinphoneEphemeralMessageDeletedInRoom";
|
||||
NSString *const kLinphoneVoiceMessagePlayerEOF = @"LinphoneVoiceMessagePlayerEOF";
|
||||
NSString *const kLinphoneVoiceMessagePlayerLostFocus = @"LinphoneVoiceMessagePlayerLostFocus";
|
||||
|
||||
|
||||
NSString *const kLinphoneMsgNotificationAppGroupId = @"group.org.linphone.phone.msgNotification";
|
||||
|
|
@ -1784,7 +1786,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
- (void)call:(const LinphoneAddress *)iaddr {
|
||||
// First verify that network is available, abort otherwise.
|
||||
if (!linphone_core_is_network_reachable(theLinphoneCore)) {
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView] animated:YES completion:nil];
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"place a call"] animated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,16 @@
|
|||
<outlet property="plusLongGestureRecognizer" destination="daf-cW-dRj" id="O5u-t0-uMe"/>
|
||||
<outlet property="resendRecognizer" destination="5ZI-Ip-lGl" id="G2r-On-6mV"/>
|
||||
<outlet property="totalView" destination="8I3-n2-0kS" id="aa8-j9-saW"/>
|
||||
<outlet property="vrPlayPause" destination="7Zn-bp-e0Y" id="ed8-ZL-VpS"/>
|
||||
<outlet property="vrTimerLabel" destination="VUD-m6-g1J" id="tOj-bF-YHd"/>
|
||||
<outlet property="vrView" destination="bhq-9n-zYF" id="PT7-3a-6tn"/>
|
||||
<outlet property="vrWave" destination="B5G-6m-k8r" id="fXd-ze-WQg"/>
|
||||
<outlet property="vrWaveMaskPlayback" destination="a7V-w2-tIE" id="vRZ-VF-sJV"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="UGz-WT-BUv">
|
||||
<rect key="frame" x="0.0" y="0.0" width="428" height="321"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="428" height="381"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="hD2-19-7IH" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
|
|
@ -57,11 +62,11 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Y7i-Gm-AdY" userLabel="innerView">
|
||||
<rect key="frame" x="39" y="20" width="382" height="297"/>
|
||||
<rect key="frame" x="39" y="20" width="382" height="357"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" alpha="0.20000000298023224" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="U2P-5n-gg8" userLabel="backgroundColorImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="365" height="297"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="365" height="357"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8I3-n2-0kS" userLabel="view">
|
||||
|
|
@ -158,28 +163,60 @@
|
|||
</connections>
|
||||
</button>
|
||||
<textView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" editable="NO" text="Lore ipsum..." translatesAutoresizingMaskIntoConstraints="NO" id="cx9-0K-P9L" userLabel="messageText" customClass="UITextViewNoDefine">
|
||||
<rect key="frame" x="0.0" y="262" width="365" height="35"/>
|
||||
<rect key="frame" x="0.0" y="322" width="365" height="35"/>
|
||||
<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 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="287" width="10" height="10"/>
|
||||
<rect key="frame" x="372" y="347" 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="286" width="10" height="10"/>
|
||||
<rect key="frame" x="351" 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="282" y="286" width="65" height="10"/>
|
||||
<rect key="frame" x="282" 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 tag="28021" contentMode="scaleToFill" id="bhq-9n-zYF" userLabel="voiceRecording">
|
||||
<rect key="frame" x="7" y="262" width="351" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
|
||||
<subviews>
|
||||
<view tag="28024" contentMode="scaleToFill" id="a7V-w2-tIE" userLabel="vr_wave_mask_playback">
|
||||
<rect key="frame" x="8" y="10" width="335" height="42"/>
|
||||
<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>
|
||||
<button opaque="NO" tag="28028" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7Zn-bp-e0Y">
|
||||
<rect key="frame" x="8" y="13" width="35" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="vr_play.png"/>
|
||||
<connections>
|
||||
<action selector="onVRPlayPauseClick:" destination="-1" eventType="touchUpInside" id="ffk-KD-q9Q"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="28025" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="vr_wave.png" translatesAutoresizingMaskIntoConstraints="NO" id="B5G-6m-k8r">
|
||||
<rect key="frame" x="52" y="16" width="223" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<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="VUD-m6-g1J">
|
||||
<rect key="frame" x="287" y="20" width="48" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="5ZI-Ip-lGl" appends="YES" id="1iY-46-rRR"/>
|
||||
|
|
@ -217,5 +254,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="vr_play.png" width="200" height="200"/>
|
||||
<image name="vr_wave.png" width="1078" height="90"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,16 @@
|
|||
@property (strong, nonatomic) IBOutlet UILongPressGestureRecognizer *plusLongGestureRecognizer;
|
||||
@property(strong, nonatomic) NSMutableArray<UIChatContentView *> *contentViews;
|
||||
|
||||
// Video recordings
|
||||
@property (weak, nonatomic) IBOutlet UIView *vrView;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *vrPlayPause;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *vrTimerLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *vrWave;
|
||||
@property (weak, nonatomic) IBOutlet UIView *vrWaveMaskPlayback;
|
||||
@property NSTimer *vrPlayerTimer;
|
||||
@property NSString *voiceRecordingFile;
|
||||
|
||||
|
||||
|
||||
- (void)setEvent:(LinphoneEventLog *)event;
|
||||
- (void)setChatMessage:(LinphoneChatMessage *)message;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@
|
|||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AVKit/AVKit.h>
|
||||
|
||||
#define voicePlayer VIEW(ChatConversationView).sharedVoicePlayer
|
||||
#define chatView VIEW(ChatConversationView)
|
||||
|
||||
|
||||
|
||||
@implementation UIChatBubblePhotoCell {
|
||||
FileTransferDelegate *_ftd;
|
||||
CGSize imageSize, bubbleSize, videoDefaultSize;
|
||||
|
|
@ -54,6 +59,8 @@
|
|||
assetIsLoaded = FALSE;
|
||||
self.contentView.userInteractionEnabled = NO;
|
||||
_contentViews = [[NSMutableArray alloc] init];
|
||||
self.vrWaveMaskPlayback.layer.cornerRadius = 10.0f;
|
||||
self.vrWaveMaskPlayback.layer.masksToBounds = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -151,32 +158,55 @@
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)update {
|
||||
if (self.message == nil) {
|
||||
LOGW(@"Cannot update message room cell: NULL message");
|
||||
return;
|
||||
}
|
||||
[super update];
|
||||
|
||||
|
||||
NSMutableDictionary<NSString *, NSString *> *encrptedFilePaths = NULL;
|
||||
if ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId]) {
|
||||
encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:self.message];
|
||||
if (!encrptedFilePaths) {
|
||||
encrptedFilePaths = [NSMutableDictionary dictionary];
|
||||
}
|
||||
}
|
||||
|
||||
_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])
|
||||
[encrptedFilePaths setValue:_voiceRecordingFile forKey:[NSString stringWithUTF8String:linphone_content_get_name(voiceContent)]];
|
||||
[self setVoiceMessageDuration];
|
||||
_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);
|
||||
if (voiceContent)
|
||||
contentCount--;
|
||||
BOOL multiParts = ((linphone_chat_message_get_text_content(self.message) != NULL) ? bctbx_list_size(contents) > 2 : bctbx_list_size(contents) > 1);
|
||||
if (voiceContent && !multiParts) {
|
||||
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
if (multiParts) {
|
||||
if (!assetIsLoaded) {
|
||||
NSMutableDictionary<NSString *, NSString *> *encrptedFilePaths = NULL;
|
||||
if ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId]) {
|
||||
encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:self.message];
|
||||
if (!encrptedFilePaths) {
|
||||
encrptedFilePaths = [NSMutableDictionary dictionary];
|
||||
}
|
||||
}
|
||||
|
||||
_imageGestureRecognizer.enabled = NO;
|
||||
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES;
|
||||
|
||||
const bctbx_list_t *it = contents;
|
||||
int i;
|
||||
for (it = contents, i=0; it != NULL; it=bctbx_list_next(it)){
|
||||
LinphoneContent *content = (LinphoneContent *)it->data;
|
||||
if (linphone_content_is_voice_recording(content)) { // Handled elsewhere
|
||||
continue;
|
||||
}
|
||||
if (linphone_content_is_file_transfer(content) || linphone_content_is_file(content)){
|
||||
UIChatContentView *contentView = [[UIChatContentView alloc] initWithFrame: CGRectMake(0,0,0,0)];
|
||||
if([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] && (linphone_chat_message_is_outgoing(self.message) || linphone_content_is_file(content))) {
|
||||
|
|
@ -214,8 +244,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *url = linphone_chat_message_get_external_body_url(self.message);
|
||||
BOOL is_external =
|
||||
(url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(self.message);
|
||||
|
|
@ -713,16 +741,95 @@
|
|||
textFrame.origin = CGPointMake(textFrame.origin.x, self.finalAssetView.frame.origin.y + self.finalAssetView.frame.size.height);
|
||||
else
|
||||
// When image hasn't be download
|
||||
textFrame.origin = CGPointMake(textFrame.origin.x, _imageSubView.frame.size.height + _imageSubView.frame.origin.y - 10);
|
||||
textFrame.origin = CGPointMake(textFrame.origin.x, _voiceRecordingFile ? _fileView.frame.origin.y : _imageSubView.frame.size.height + _imageSubView.frame.origin.y - 10);
|
||||
if (!utf8Text) {
|
||||
textFrame.size.height = 0;
|
||||
} else {
|
||||
textFrame.size.height = bubbleFrame.size.height - 90;//textFrame.origin.x;
|
||||
}
|
||||
|
||||
if (_voiceRecordingFile) {
|
||||
CGRect vrFrame = _vrView.frame;
|
||||
vrFrame.origin.y = _contentViews.count == 0 && !utf8Text ? _fileView.frame.origin.y : textFrame.origin.y;
|
||||
_vrView.frame = vrFrame;
|
||||
textFrame.origin.y += VOICE_RECORDING_PLAYER_HEIGHT;
|
||||
_vrView.hidden = NO;
|
||||
} else {
|
||||
_vrView.hidden = YES;
|
||||
}
|
||||
|
||||
self.messageText.frame = textFrame;
|
||||
}
|
||||
|
||||
// Voice messages
|
||||
|
||||
static AVAudioPlayer* utilityPlayer;
|
||||
|
||||
-(void) setVoiceMessageDuration {
|
||||
NSError *error = nil;
|
||||
AVAudioPlayer* utilityPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL URLWithString:_voiceRecordingFile] error:&error]; // Workaround as opening multiple linphone_players at the same time can cause crash (here for example layout refreshed whilst a voice memo is playing
|
||||
_vrTimerLabel.text = [self formattedDuration:utilityPlayer.duration];
|
||||
utilityPlayer = nil;
|
||||
}
|
||||
|
||||
-(void) voicePlayTimerUpdate {
|
||||
CGRect r = _vrWaveMaskPlayback.frame;
|
||||
r.size.width += _vrView.frame.size.width / ((linphone_player_get_duration(voicePlayer) / 500)) ;
|
||||
if (r.size.width > _vrView.frame.size.width) {
|
||||
r.size.width = _vrView.frame.size.width;
|
||||
}
|
||||
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
_vrWaveMaskPlayback.frame = r;
|
||||
}completion:^(BOOL finished) {}];
|
||||
}
|
||||
|
||||
|
||||
-(void) stopPlayer {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
[chatView stopSharedPlayer];
|
||||
[_vrPlayPause setImage:[UIImage imageNamed:@"vr_play"] forState:UIControlStateNormal];
|
||||
[_vrPlayerTimer invalidate];
|
||||
_vrWaveMaskPlayback.frame = CGRectZero;
|
||||
}
|
||||
|
||||
-(NSString *)formattedDuration:(long)valueMs {
|
||||
return [NSString stringWithFormat:@"%02ld:%02ld", valueMs/ 60, (valueMs % 60) ];
|
||||
}
|
||||
|
||||
-(void) startPlayer {
|
||||
[chatView startSharedPlayer:_voiceRecordingFile.UTF8String];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(stopPlayer)
|
||||
name:kLinphoneVoiceMessagePlayerLostFocus
|
||||
object:nil];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(stopPlayer)
|
||||
name:kLinphoneVoiceMessagePlayerEOF
|
||||
object:nil];
|
||||
|
||||
[_vrPlayPause setImage:[UIImage imageNamed:@"vr_stop"] forState:UIControlStateNormal];
|
||||
CGRect r = CGRectZero;
|
||||
r.size.height = _vrView.frame.size.height - 14;
|
||||
r.origin.y = 7;
|
||||
_vrWaveMaskPlayback.frame = r;
|
||||
_vrPlayerTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
|
||||
target:self
|
||||
selector:@selector(voicePlayTimerUpdate)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
[self voicePlayTimerUpdate];
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)onVRPlayPauseClick:(id)sender {
|
||||
if ([chatView sharedPlayedIsPlaying:_voiceRecordingFile.UTF8String])
|
||||
[self stopPlayer];
|
||||
else {
|
||||
[self startPlayer];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@
|
|||
#define CELL_IMAGE_X_MARGIN 100
|
||||
#define IMAGE_DEFAULT_WIDTH 120
|
||||
#define IMAGE_DEFAULT_MARGIN 5
|
||||
#define VOICE_RECORDING_PLAYER_HEIGHT 60
|
||||
#define VOICE_RECORDING_PLAYER_WIDTH 300
|
||||
|
||||
|
||||
@interface UIChatBubbleTextCell : UITableViewCell <UIDocumentPickerDelegate>
|
||||
|
||||
|
|
@ -72,5 +75,6 @@
|
|||
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message;
|
||||
+ (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font;
|
||||
+ (NSString *)ContactDateForChat:(LinphoneChatMessage *)message;
|
||||
+(LinphoneContent *) voiceContent:(LinphoneChatMessage *)message;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -306,6 +306,12 @@
|
|||
}
|
||||
|
||||
- (void)onResend {
|
||||
|
||||
if (!linphone_core_is_network_reachable(LC)) {
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
|
||||
//return;
|
||||
}
|
||||
|
||||
if (_message == nil || !linphone_chat_message_is_outgoing(_message))
|
||||
return;
|
||||
|
||||
|
|
@ -314,7 +320,13 @@
|
|||
return;
|
||||
|
||||
const bctbx_list_t *contents = linphone_chat_message_get_contents(_message);
|
||||
BOOL multiParts = ((linphone_chat_message_get_text_content(self.message) != NULL) ? bctbx_list_size(contents) > 2 : bctbx_list_size(contents) > 1);
|
||||
LinphoneContent *voiceContent = [UIChatBubbleTextCell voiceContent:_message];
|
||||
size_t contentCount = bctbx_list_size(contents);
|
||||
if (voiceContent)
|
||||
contentCount--;
|
||||
|
||||
BOOL multiParts = ((linphone_chat_message_get_text_content(_message) != NULL) ? contentCount > 2 : contentCount > 1);
|
||||
|
||||
if (multiParts) {
|
||||
FileContext *newfileContext = [[FileContext alloc] init];
|
||||
[newfileContext clear];
|
||||
|
|
@ -323,6 +335,9 @@
|
|||
const bctbx_list_t *it;
|
||||
for (it = contents, i=0; it != NULL; it=bctbx_list_next(it)){
|
||||
LinphoneContent *content = (LinphoneContent *)it->data;
|
||||
if (linphone_content_is_voice_recording(content)) {
|
||||
continue;
|
||||
}
|
||||
if (linphone_content_is_file_transfer(content) || linphone_content_is_file(content)){
|
||||
NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)];
|
||||
NSString *filePath = [encrptedFilePaths valueForKey:name];
|
||||
|
|
@ -335,11 +350,11 @@
|
|||
[self onDelete];
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
const char *text = linphone_chat_message_get_text_content(_message);
|
||||
[_chatRoomDelegate resendMultiFiles:newfileContext message: text? [NSString stringWithUTF8String:text]: NULL];
|
||||
[_chatRoomDelegate resendMultiFiles:newfileContext message: text? [NSString stringWithUTF8String:text]: NULL voiceContent:voiceContent];
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (linphone_chat_message_get_file_transfer_information(_message) != NULL) {
|
||||
if (!voiceContent && contentCount == 1 && linphone_chat_message_get_file_transfer_information(_message) != NULL) {
|
||||
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message];
|
||||
NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message];
|
||||
NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:_message];
|
||||
|
|
@ -354,11 +369,11 @@
|
|||
const char *text = linphone_chat_message_get_text_content(_message);
|
||||
NSString *str = text ? [NSString stringWithUTF8String:text] : NULL;
|
||||
if (localImage) {
|
||||
[_chatRoomDelegate resendFile: (data?:[ChatConversationView getFileData:localImage]) withName:localImage type:@"image" key:@"localimage" message:str];
|
||||
[_chatRoomDelegate resendFile: (data?:[ChatConversationView getFileData:localImage]) withName:localImage type:@"image" key:@"localimage" message:str voiceContent:voiceContent];
|
||||
} else if (localVideo) {
|
||||
[_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localVideo]) withName:localVideo type:@"video" key:@"localvideo" message:str];
|
||||
[_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localVideo]) withName:localVideo type:@"video" key:@"localvideo" message:str voiceContent:voiceContent];
|
||||
} else {
|
||||
[_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localFile]) withName:localFile type:@"image" key:@"localfile" message:str];
|
||||
[_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localFile]) withName:localFile type:@"image" key:@"localfile" message:str voiceContent:voiceContent];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
@ -366,7 +381,10 @@
|
|||
double delayInSeconds = 0.4;
|
||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
|
||||
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
|
||||
[_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil];
|
||||
NSString *text = self.textMessage;
|
||||
if (voiceContent && [text isEqualToString:@"🗻"])
|
||||
text = nil;
|
||||
[_chatRoomDelegate resendChat:text withExternalUrl:nil voiceContent:voiceContent];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -457,6 +475,20 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
|
|||
return image;
|
||||
}
|
||||
|
||||
+(LinphoneContent *) voiceContent:(LinphoneChatMessage *)message {
|
||||
for (const bctbx_list_t *it = linphone_chat_message_get_contents(message); it != NULL; it=bctbx_list_next(it)){
|
||||
LinphoneContent *content = (LinphoneContent *)it->data;
|
||||
if (linphone_content_is_voice_recording(content))
|
||||
return content;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
+(CGSize) addVoicePlayerToSize:(CGSize)size withMargins:(BOOL)margins {
|
||||
return CGSizeMake(MAX(size.width,VOICE_RECORDING_PLAYER_WIDTH + (margins ? CELL_MESSAGE_X_MARGIN: 0)), size.height + VOICE_RECORDING_PLAYER_HEIGHT+(margins ? CELL_MESSAGE_Y_MARGIN: 0));
|
||||
|
||||
}
|
||||
|
||||
+ (CGSize)ViewHeightForMessageText:(LinphoneChatMessage *)chat withWidth:(int)width textForImdn:(NSString *)imdnText {
|
||||
NSString *messageText = [UIChatBubbleTextCell TextMessageForChat:chat];
|
||||
|
|
@ -484,14 +516,51 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
|
|||
CGFloat imagesh=0;
|
||||
CGFloat max_imagesw=0;
|
||||
CGFloat max_imagesh=0;
|
||||
LinphoneContent *voiceContent = [self voiceContent:chat];
|
||||
const bctbx_list_t *contents = linphone_chat_message_get_contents(chat);
|
||||
BOOL multiParts = ((linphone_chat_message_get_text_content(chat) != NULL) ? bctbx_list_size(contents) > 2 : bctbx_list_size(contents) > 1);
|
||||
size_t contentCount = bctbx_list_size(contents);
|
||||
if (voiceContent)
|
||||
contentCount--;
|
||||
|
||||
BOOL multiParts = ((linphone_chat_message_get_text_content(chat) != NULL) ? contentCount > 2 : contentCount > 1);
|
||||
|
||||
if (voiceContent && contentCount == 0) {
|
||||
size = CGSizeMake(VOICE_RECORDING_PLAYER_WIDTH, VOICE_RECORDING_PLAYER_HEIGHT);
|
||||
CGSize textSize = CGSizeMake(0, 0);
|
||||
if (![messageText isEqualToString:@"🗻"]) {
|
||||
textSize = [self computeBoundingBox:messageText
|
||||
size:CGSizeMake(max_imagesw , CGFLOAT_MAX)
|
||||
font:messageFont];
|
||||
}
|
||||
|
||||
// add size for message text
|
||||
size.height += textSize.height;
|
||||
size.width = MAX(textSize.width, size.width);
|
||||
size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH);
|
||||
size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT) ;
|
||||
return size;
|
||||
}
|
||||
|
||||
if (multiParts) {
|
||||
const bctbx_list_t *it = contents;
|
||||
NSMutableDictionary<NSString *, NSString *> *encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:chat];
|
||||
|
||||
for (it = contents; it != NULL; it=bctbx_list_next(it)){
|
||||
LinphoneContent *content = (LinphoneContent *)it->data;
|
||||
if (linphone_content_is_voice_recording(content)) {
|
||||
CGSize sSize = CGSizeMake(VOICE_RECORDING_PLAYER_WIDTH, VOICE_RECORDING_PLAYER_HEIGHT);
|
||||
imagesw += sSize.width;
|
||||
if (imagesw > width) {
|
||||
imagesw = sSize.width;
|
||||
max_imagesw = MAX(max_imagesw, imagesw);
|
||||
max_imagesh += imagesh;
|
||||
imagesh = sSize.height;
|
||||
} else {
|
||||
max_imagesw = MAX(max_imagesw, imagesw);
|
||||
imagesh = MAX(imagesh, sSize.height);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
UIImage *image;
|
||||
if(!linphone_chat_message_is_outgoing(chat) && linphone_content_is_file_transfer(content)) {
|
||||
// not yet downloaded
|
||||
|
|
@ -538,14 +607,15 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
|
|||
size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT) ;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LinphoneContent *fileContent = linphone_chat_message_get_file_transfer_information(chat);
|
||||
LinphoneContent *fileContent = linphone_chat_message_get_utf8_text(chat) ? nil : linphone_chat_message_get_file_transfer_information(chat);
|
||||
if (url == nil && fileContent == NULL) {
|
||||
size = [self computeBoundingBox:messageText
|
||||
size:CGSizeMake(width - CELL_MESSAGE_X_MARGIN - 4, CGFLOAT_MAX)
|
||||
font:messageFont];
|
||||
} else {
|
||||
|
||||
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat];
|
||||
NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:chat];
|
||||
NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:chat];
|
||||
|
|
@ -583,27 +653,43 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
|
|||
image = [[UIImage alloc] initWithData:data];
|
||||
}
|
||||
} else {
|
||||
return [self ViewHeightForFile:width];
|
||||
CGSize fileSize = [self ViewHeightForFile:width];
|
||||
if (voiceContent) {
|
||||
fileSize = [self addVoicePlayerToSize:fileSize withMargins:true];
|
||||
}
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
originalImageSize = image.size;
|
||||
} else {
|
||||
if (!localImage && !localVideo) {
|
||||
//We are loading the image
|
||||
return CGSizeMake(CELL_MIN_WIDTH + CELL_MESSAGE_X_MARGIN, CELL_MIN_HEIGHT + CELL_MESSAGE_Y_MARGIN + textSize.height + 20);
|
||||
CGSize baseSize = CGSizeMake(CELL_MIN_WIDTH + CELL_MESSAGE_X_MARGIN, CELL_MIN_HEIGHT + CELL_MESSAGE_Y_MARGIN + textSize.height + 20);
|
||||
if (voiceContent) {
|
||||
baseSize = [self addVoicePlayerToSize:baseSize withMargins:true];
|
||||
}
|
||||
return baseSize;
|
||||
}
|
||||
|
||||
if (localImage && [[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
|
||||
NSData* data = [NSData dataWithContentsOfFile:filePath];
|
||||
UIImage *image = [[UIImage alloc] initWithData:data];
|
||||
if (!image) {
|
||||
return [self ViewHeightForFile:width];
|
||||
CGSize fileSize = [self ViewHeightForFile:width];
|
||||
if (voiceContent) {
|
||||
fileSize = [self addVoicePlayerToSize:fileSize withMargins:true];
|
||||
}
|
||||
return fileSize;
|
||||
}
|
||||
originalImageSize = image.size;
|
||||
} else if (localVideo && [[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
|
||||
UIImage *image = [UIChatBubbleTextCell getImageFromVideoUrl:[NSURL fileURLWithPath:filePath]];
|
||||
if (!image) {
|
||||
return [self ViewHeightForFile:width];
|
||||
CGSize fileSize = [self ViewHeightForFile:width];
|
||||
if (voiceContent) {
|
||||
fileSize = [self addVoicePlayerToSize:fileSize withMargins:true];
|
||||
}
|
||||
return fileSize;
|
||||
}
|
||||
originalImageSize = image.size;
|
||||
} else {
|
||||
|
|
@ -615,7 +701,11 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
|
|||
assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localVideo] options:nil];
|
||||
|
||||
if (![assets firstObject]) {
|
||||
return CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_WIDTH + CELL_MESSAGE_Y_MARGIN + textSize.height);
|
||||
CGSize baseSize = CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_WIDTH + CELL_MESSAGE_Y_MARGIN + textSize.height);
|
||||
if (voiceContent) {
|
||||
baseSize = [self addVoicePlayerToSize:baseSize withMargins:true];
|
||||
}
|
||||
return baseSize;
|
||||
} else {
|
||||
PHAsset *asset = [assets firstObject];
|
||||
originalImageSize = CGSizeMake([asset pixelWidth], [asset pixelHeight]);
|
||||
|
|
@ -627,6 +717,11 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
|
|||
size.height += textSize.height;
|
||||
size.width = MAX(textSize.width, size.width);
|
||||
}
|
||||
|
||||
if (voiceContent) {
|
||||
size.width = MAX(size.width,VOICE_RECORDING_PLAYER_WIDTH);
|
||||
size.height += VOICE_RECORDING_PLAYER_HEIGHT;
|
||||
}
|
||||
|
||||
size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH);
|
||||
size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT);
|
||||
|
|
|
|||
|
|
@ -830,7 +830,7 @@ static RootViewManager *rootViewManagerInstance = nil;
|
|||
}
|
||||
|
||||
if (!linphone_core_is_network_reachable(LC)) {
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView] animated:YES completion:nil];
|
||||
[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
|
||||
@interface FileTransferDelegate : NSObject
|
||||
|
||||
- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom;
|
||||
- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key;
|
||||
- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom andVoiceContent:(LinphoneContent *)voiceContent;
|
||||
- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key voiceContent:(LinphoneContent *)voiceContent;
|
||||
- (void)uploadImage:(UIImage *)image forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality;
|
||||
- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name;
|
||||
- (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom;
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
|
|||
}
|
||||
}
|
||||
|
||||
- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key{
|
||||
- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key voiceContent:(LinphoneContent *)voiceContent{
|
||||
if ([[LinphoneManager.instance fileTransferDelegates] containsObject:self]) {
|
||||
LOGW(@"fileTransferDelegates has already added %p", self);
|
||||
return;
|
||||
|
|
@ -124,12 +124,15 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
|
|||
linphone_chat_message_cbs_set_file_transfer_progress_indication(linphone_chat_message_get_callbacks(_message), file_transfer_progress_indication_send);
|
||||
|
||||
[LinphoneManager setValueInMessageAppData:name forKey:key inMessage:_message];
|
||||
|
||||
if (voiceContent)
|
||||
linphone_chat_message_add_content(_message, voiceContent);
|
||||
|
||||
LOGI(@"%p Uploading content from message %p", self, _message);
|
||||
linphone_chat_message_send(_message);
|
||||
}
|
||||
|
||||
- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom {
|
||||
- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom andVoiceContent:(LinphoneContent *)voiceContent{
|
||||
[LinphoneManager.instance.fileTransferDelegates addObject:self];
|
||||
|
||||
_message = linphone_chat_room_create_empty_message(chatRoom);
|
||||
|
|
@ -162,6 +165,8 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
|
|||
// todo indication progress
|
||||
[LinphoneManager setValueInMessageAppData:names forKey:@"multiparts" inMessage:_message];
|
||||
[LinphoneManager setValueInMessageAppData:types forKey:@"multipartstypes" inMessage:_message];
|
||||
if (voiceContent)
|
||||
linphone_chat_message_add_content(_message, voiceContent);
|
||||
LOGI(@"%p Uploading content from message %p", self, _message);
|
||||
linphone_chat_message_send(_message);
|
||||
}
|
||||
|
|
@ -170,12 +175,12 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
|
|||
- (void)uploadImage:(UIImage *)image forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality {
|
||||
NSString *name = [NSString stringWithFormat:@"%li-%f.jpg", (long)image.hash, [NSDate timeIntervalSinceReferenceDate]];
|
||||
NSData *data = UIImageJPEGRepresentation(image, quality);
|
||||
[self uploadData:data forChatRoom:chatRoom type:@"image" subtype:@"jpg" name:name key:@"localimage"];
|
||||
[self uploadData:data forChatRoom:chatRoom type:@"image" subtype:@"jpg" name:name key:@"localimage" voiceContent:nil];
|
||||
}
|
||||
|
||||
- (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom {
|
||||
NSString *name = [NSString stringWithFormat:@"IMG-%f.MOV", [NSDate timeIntervalSinceReferenceDate]];
|
||||
[self uploadData:data forChatRoom:chatRoom type:@"video" subtype:@"mov" name:name key:@"localvideo"];
|
||||
[self uploadData:data forChatRoom:chatRoom type:@"video" subtype:@"mov" name:name key:@"localvideo" voiceContent:nil];
|
||||
}
|
||||
|
||||
- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name {
|
||||
|
|
@ -184,7 +189,7 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
|
|||
NSString *fileType = [[asset tracksWithMediaType:AVMediaTypeVideo] count] > 0 ? @"video" : @"file";
|
||||
NSString *key = [ChatConversationView getKeyFromFileType:fileType fileName:name];
|
||||
|
||||
[self uploadData:data forChatRoom:chatRoom type:fileType subtype:name.lastPathComponent name:name key:key];
|
||||
[self uploadData:data forChatRoom:chatRoom type:fileType subtype:name.lastPathComponent name:name key:key voiceContent:nil];
|
||||
}
|
||||
|
||||
- (BOOL)download:(LinphoneChatMessage *)message {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
+ (UIImage *)resizeImage:(UIImage *)imageToResize newSize:(CGSize)newSize;
|
||||
|
||||
+ (LinphoneAddress *)normalizeSipOrPhoneAddress:(NSString *)addr;
|
||||
+ (UIAlertController *)networkErrorView;
|
||||
+ (UIAlertController *)networkErrorView:(NSString *)action;
|
||||
|
||||
typedef enum {
|
||||
LinphoneDateHistoryList,
|
||||
|
|
|
|||
|
|
@ -516,12 +516,10 @@
|
|||
return res;
|
||||
}
|
||||
|
||||
+ (UIAlertController *)networkErrorView {
|
||||
+ (UIAlertController *)networkErrorView:(NSString *)action {
|
||||
UIAlertController *errView =
|
||||
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"Network Error", nil)
|
||||
message:NSLocalizedString(@"There is no network connection available, "
|
||||
@"enable WIFI or WWAN prior to place a call",
|
||||
nil)
|
||||
message:NSLocalizedString([@"There is no network connection available, enable WIFI or WWAN prior to " stringByAppendingString:action],nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
BIN
Resources/images/vr_off.png
Normal file
BIN
Resources/images/vr_off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
Resources/images/vr_on.png
Normal file
BIN
Resources/images/vr_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
Resources/images/vr_pause.png
Normal file
BIN
Resources/images/vr_pause.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
Resources/images/vr_play.png
Normal file
BIN
Resources/images/vr_play.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
BIN
Resources/images/vr_stop.png
Normal file
BIN
Resources/images/vr_stop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
BIN
Resources/images/vr_wave.png
Normal file
BIN
Resources/images/vr_wave.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -109,7 +109,7 @@
|
|||
61AE364F20C00B370089D9D3 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AE364E20C00B370089D9D3 /* ShareViewController.m */; };
|
||||
61AE365220C00B370089D9D3 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61AE365020C00B370089D9D3 /* MainInterface.storyboard */; };
|
||||
61AE365620C00B370089D9D3 /* linphoneExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
61AEBEA321906AFC00F35E7F /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
|
||||
61AEBEA321906AFC00F35E7F /* (null) in Frameworks */ = {isa = PBXBuildFile; };
|
||||
61AEBEBD2191990A00F35E7F /* DevicesListView.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AEBEBC2191990A00F35E7F /* DevicesListView.m */; };
|
||||
61AEBEBF2191991F00F35E7F /* DevicesListView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 61AEBEBE2191991F00F35E7F /* DevicesListView.xib */; };
|
||||
61AEBEC62191E47500F35E7F /* chevron_list_close.png in Resources */ = {isa = PBXBuildFile; fileRef = 61AEBEC52191E47500F35E7F /* chevron_list_close.png */; };
|
||||
|
|
@ -622,7 +622,7 @@
|
|||
63E27A321C4FECD000D332AE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63E27A311C4FECD000D332AE /* LaunchScreen.xib */; };
|
||||
63E27A521C50EDB000D332AE /* hold.mkv in Resources */ = {isa = PBXBuildFile; fileRef = 63E27A511C50EB2700D332AE /* hold.mkv */; };
|
||||
63E59A3F1ADE70D900646FB3 /* InAppProductsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E59A3E1ADE70D900646FB3 /* InAppProductsManager.m */; };
|
||||
63E802DB1C625AEF000D5509 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
|
||||
63E802DB1C625AEF000D5509 /* (null) in Resources */ = {isa = PBXBuildFile; };
|
||||
63EC8D391D7438660066547B /* AssistantLinkView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63EC8D3B1D7438660066547B /* AssistantLinkView.xib */; };
|
||||
63F1DF441BCE618E00EDED90 /* UIAddressTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF431BCE618E00EDED90 /* UIAddressTextField.m */; };
|
||||
63F1DF4B1BCE983200EDED90 /* CallConferenceTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF4A1BCE983200EDED90 /* CallConferenceTableView.m */; };
|
||||
|
|
@ -675,6 +675,12 @@
|
|||
C61B1BF22667D075001A4E4A /* menu_security_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF12667D075001A4E4A /* menu_security_default.png */; };
|
||||
C61B1BF42667D202001A4E4A /* more_menu_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF32667D202001A4E4A /* more_menu_default.png */; };
|
||||
C61B1BF72667EC6B001A4E4A /* ephemeral_messages_color_A.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */; };
|
||||
C622E3EF26A81290004F5434 /* vr_stop.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3E926A8128F004F5434 /* vr_stop.png */; };
|
||||
C622E3F026A81290004F5434 /* vr_wave.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EA26A8128F004F5434 /* vr_wave.png */; };
|
||||
C622E3F126A81290004F5434 /* vr_on.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EB26A8128F004F5434 /* vr_on.png */; };
|
||||
C622E3F226A81290004F5434 /* vr_off.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EC26A8128F004F5434 /* vr_off.png */; };
|
||||
C622E3F326A81290004F5434 /* vr_pause.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3ED26A8128F004F5434 /* vr_pause.png */; };
|
||||
C622E3F426A81290004F5434 /* vr_play.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EE26A81290004F5434 /* vr_play.png */; };
|
||||
C64A854E2667B67200252AD2 /* EphemeralSettingsView.m in Sources */ = {isa = PBXBuildFile; fileRef = C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */; };
|
||||
C64A85502667B67A00252AD2 /* EphemeralSettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */; };
|
||||
C64A85522667B74100252AD2 /* ephemeral_messages_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C64A85512667B74100252AD2 /* ephemeral_messages_default.png */; };
|
||||
|
|
@ -1714,6 +1720,12 @@
|
|||
C61B1BF12667D075001A4E4A /* menu_security_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_security_default.png; sourceTree = "<group>"; };
|
||||
C61B1BF32667D202001A4E4A /* more_menu_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = more_menu_default.png; sourceTree = "<group>"; };
|
||||
C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ephemeral_messages_color_A.png; sourceTree = "<group>"; };
|
||||
C622E3E926A8128F004F5434 /* vr_stop.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_stop.png; sourceTree = "<group>"; };
|
||||
C622E3EA26A8128F004F5434 /* vr_wave.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_wave.png; sourceTree = "<group>"; };
|
||||
C622E3EB26A8128F004F5434 /* vr_on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_on.png; sourceTree = "<group>"; };
|
||||
C622E3EC26A8128F004F5434 /* vr_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_off.png; sourceTree = "<group>"; };
|
||||
C622E3ED26A8128F004F5434 /* vr_pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_pause.png; sourceTree = "<group>"; };
|
||||
C622E3EE26A81290004F5434 /* vr_play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_play.png; sourceTree = "<group>"; };
|
||||
C64A854C2667B66900252AD2 /* EphemeralSettingsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EphemeralSettingsView.h; sourceTree = "<group>"; };
|
||||
C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EphemeralSettingsView.m; sourceTree = "<group>"; };
|
||||
C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EphemeralSettingsView.xib; sourceTree = "<group>"; };
|
||||
|
|
@ -1951,7 +1963,7 @@
|
|||
files = (
|
||||
61DD7E1F2372E88F001BDD01 /* CoreLocation.framework in Frameworks */,
|
||||
6180D6FE21EE41A800AD9CB6 /* QuickLook.framework in Frameworks */,
|
||||
61AEBEA321906AFC00F35E7F /* BuildFile in Frameworks */,
|
||||
61AEBEA321906AFC00F35E7F /* (null) in Frameworks */,
|
||||
D37DC7181594AF3400B2A5EB /* MessageUI.framework in Frameworks */,
|
||||
61F1997520C6B1D5006B069A /* AVKit.framework in Frameworks */,
|
||||
249660951FD6A35F001D55AA /* Photos.framework in Frameworks */,
|
||||
|
|
@ -2285,7 +2297,7 @@
|
|||
path = LinphoneUI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29B97314FDCFA39411CA2CEA = {
|
||||
29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C23BCB71D82AAC3005F19BB /* linphone.entitlements */,
|
||||
|
|
@ -2447,6 +2459,12 @@
|
|||
633FEBE11D3CD5570014B822 /* images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C622E3EC26A8128F004F5434 /* vr_off.png */,
|
||||
C622E3EB26A8128F004F5434 /* vr_on.png */,
|
||||
C622E3ED26A8128F004F5434 /* vr_pause.png */,
|
||||
C622E3EE26A81290004F5434 /* vr_play.png */,
|
||||
C622E3E926A8128F004F5434 /* vr_stop.png */,
|
||||
C622E3EA26A8128F004F5434 /* vr_wave.png */,
|
||||
C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */,
|
||||
C61B1BF32667D202001A4E4A /* more_menu_default.png */,
|
||||
C61B1BF12667D075001A4E4A /* menu_security_default.png */,
|
||||
|
|
@ -3357,7 +3375,7 @@
|
|||
fr,
|
||||
hu,
|
||||
);
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA;
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
|
||||
productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
|
|
@ -3408,6 +3426,7 @@
|
|||
615A2817217F280C0060F920 /* chat_list_indicator.png in Resources */,
|
||||
633FEEFF1D3CD55A0014B822 /* options_add_call_disabled@2x.png in Resources */,
|
||||
633FEF091D3CD55A0014B822 /* options_start_conference_disabled@2x.png in Resources */,
|
||||
C622E3F326A81290004F5434 /* vr_pause.png in Resources */,
|
||||
633FEE051D3CD5590014B822 /* cancel_edit_disabled@2x.png in Resources */,
|
||||
633FEE5F1D3CD5590014B822 /* edit_list_default@2x.png in Resources */,
|
||||
633FEEB61D3CD55A0014B822 /* numpad_3_over@2x.png in Resources */,
|
||||
|
|
@ -3418,7 +3437,7 @@
|
|||
633FEED41D3CD55A0014B822 /* numpad_7_default@2x.png in Resources */,
|
||||
633FEEE01D3CD55A0014B822 /* numpad_8_over~ipad@2x.png in Resources */,
|
||||
633FEDDC1D3CD5590014B822 /* call_start_body_disabled~ipad.png in Resources */,
|
||||
63E802DB1C625AEF000D5509 /* BuildFile in Resources */,
|
||||
63E802DB1C625AEF000D5509 /* (null) in Resources */,
|
||||
633FEE2E1D3CD5590014B822 /* color_F.png in Resources */,
|
||||
633FEDC51D3CD5590014B822 /* call_hangup_disabled@2x.png in Resources */,
|
||||
633FEEDF1D3CD55A0014B822 /* numpad_8_over~ipad.png in Resources */,
|
||||
|
|
@ -3453,6 +3472,7 @@
|
|||
633FEDD91D3CD5590014B822 /* call_start_body_default~ipad@2x.png in Resources */,
|
||||
633FEE401D3CD5590014B822 /* contacts_all_selected.png in Resources */,
|
||||
633FEE0C1D3CD5590014B822 /* chat_attachment_disabled.png in Resources */,
|
||||
C622E3EF26A81290004F5434 /* vr_stop.png in Resources */,
|
||||
633FEF001D3CD55A0014B822 /* options_default.png in Resources */,
|
||||
CF15F21F20E4F9A3008B1DE6 /* UIImageViewDeletable.xib in Resources */,
|
||||
633FEE951D3CD55A0014B822 /* micro_default@2x.png in Resources */,
|
||||
|
|
@ -3478,6 +3498,7 @@
|
|||
633FEE7A1D3CD5590014B822 /* history_missed_default.png in Resources */,
|
||||
633FEF121D3CD55A0014B822 /* pause_big_over_selected.png in Resources */,
|
||||
633FED9D1D3CD5590014B822 /* add_field_default@2x.png in Resources */,
|
||||
C622E3F426A81290004F5434 /* vr_play.png in Resources */,
|
||||
639E9CB01C0DB83000019A75 /* SideMenuView.xib in Resources */,
|
||||
633FEDBB1D3CD5590014B822 /* call_audio_start_default@2x.png in Resources */,
|
||||
633FEF1A1D3CD55A0014B822 /* presence_away.png in Resources */,
|
||||
|
|
@ -3505,6 +3526,7 @@
|
|||
615A283E2180A2560060F920 /* invite_linphone.png in Resources */,
|
||||
633FEF281D3CD55A0014B822 /* route_earpiece_default.png in Resources */,
|
||||
633FEE4F1D3CD5590014B822 /* delete_field_over@2x.png in Resources */,
|
||||
C622E3F226A81290004F5434 /* vr_off.png in Resources */,
|
||||
633FEE531D3CD5590014B822 /* dialer_alt_back@2x.png in Resources */,
|
||||
633FEE3E1D3CD5590014B822 /* contacts_all_disabled.png in Resources */,
|
||||
633FEEF31D3CD55A0014B822 /* numpad_over_background.png in Resources */,
|
||||
|
|
@ -3740,6 +3762,7 @@
|
|||
633FEE191D3CD5590014B822 /* chat_send_over@2x.png in Resources */,
|
||||
633FEF181D3CD55A0014B822 /* pause_small_over_selected.png in Resources */,
|
||||
633FEE001D3CD5590014B822 /* camera_switch_over.png in Resources */,
|
||||
C622E3F126A81290004F5434 /* vr_on.png in Resources */,
|
||||
633FEF401D3CD55A0014B822 /* select_all_default.png in Resources */,
|
||||
633FEDF01D3CD5590014B822 /* call_transfer_disabled.png in Resources */,
|
||||
633FEE351D3CD5590014B822 /* conference_exit_default@2x.png in Resources */,
|
||||
|
|
@ -3772,6 +3795,7 @@
|
|||
633FEEFA1D3CD55A0014B822 /* numpad_star~ipad.png in Resources */,
|
||||
D38187B915FE342200C3EDCA /* ContactDetailsView.xib in Resources */,
|
||||
633FEE921D3CD55A0014B822 /* menu.png in Resources */,
|
||||
C622E3F026A81290004F5434 /* vr_wave.png in Resources */,
|
||||
633FEDE41D3CD5590014B822 /* call_status_incoming~ipad.png in Resources */,
|
||||
633FEE4C1D3CD5590014B822 /* delete_field_default.png in Resources */,
|
||||
633FEE391D3CD5590014B822 /* contact_add_default@2x.png in Resources */,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue