Commit 830eec40 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk

fix: memory leak on call

fix memory leak related to call widgets and call model

Change-Id: Icd0f86cc4045deffb1decd88bc88c63bbe890d13
parent c60c32c8
......@@ -51,14 +51,14 @@ class ButtonsContainerView: UIView, NibLoadable {
didSet {
self.viewModel?.observableCallOptions
.observeOn(MainScheduler.instance)
.subscribe(onNext: { (callOptions) in
.subscribe(onNext: { [weak self] callOptions in
switch callOptions {
case .none:
self.withoutOptions()
self?.withoutOptions()
case .optionsWithoutSpeakerphone:
self.optionsWithoutSpeaker()
self?.optionsWithoutSpeaker()
case .optionsWithSpeakerphone:
self.optionsWithSpeaker()
self?.optionsWithSpeaker()
}
}).disposed(by: self.disposeBag)
}
......@@ -76,11 +76,6 @@ class ButtonsContainerView: UIView, NibLoadable {
override open func didMoveToWindow() {
super.didMoveToWindow()
self.cancelButton.backgroundColor = UIColor.red
if #available(iOS 11.0, *) {
guard let window = self.window else {
return
}
}
}
func commonInit() {
......
......@@ -35,7 +35,7 @@ class ButtonsContainerViewModel {
var isAudioOnly: Bool
let avalaibleCallOptions = BehaviorSubject<CallOptions>(value: .none)
lazy var observableCallOptions: Observable<CallOptions> = {
lazy var observableCallOptions: Observable<CallOptions> = { [unowned self] in
return self.avalaibleCallOptions.asObservable()
}()
......@@ -49,38 +49,38 @@ class ButtonsContainerViewModel {
private func checkCallOptions() {
let callIsActive: Observable<Bool> = {
self.callService.currentCall.filter({ [unowned self] call in
return call.state == .current && call.callId == self.callID
self.callService.currentCall.filter({ [weak self] call in
return call.state == .current && call.callId == self?.callID
}).map({_ in
return true
})
}()
callIsActive
.subscribe(onNext: { [unowned self] active in
.subscribe(onNext: { [weak self] active in
if !active {
return
}
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad {
self.avalaibleCallOptions.onNext(.optionsWithoutSpeakerphone)
self?.avalaibleCallOptions.onNext(.optionsWithoutSpeakerphone)
return
}
self.connectToSpeaker()
self?.connectToSpeaker()
}).disposed(by: self.disposeBag)
}
private func connectToSpeaker() {
let speakerIsAvailable: Observable<Bool> = {
let speakerIsAvailable: Observable<Bool> = { [unowned self] in
return self.audioService.enableSwitchAudio.map({ (hide) in
!hide
})
}()
speakerIsAvailable.subscribe(onNext: { [unowned self] available in
speakerIsAvailable.subscribe(onNext: { [weak self] available in
if available {
self.avalaibleCallOptions.onNext(.optionsWithSpeakerphone)
self?.avalaibleCallOptions.onNext(.optionsWithSpeakerphone)
return
}
self.avalaibleCallOptions.onNext(.optionsWithoutSpeakerphone)
self?.avalaibleCallOptions.onNext(.optionsWithoutSpeakerphone)
}).disposed(by: self.disposeBag)
}
}
......@@ -135,16 +135,17 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
@objc func hideCapturedVideo() {
if self.isMenuShowed { return }
UIView.animate(withDuration: 0.3, animations: {
if self.capturedVideoBlurEffect.alpha == 0 {
self.isVideoHidden = true
self.capturedVideoBlurEffect.alpha = 1
UIView.animate(withDuration: 0.3, animations: { [weak self] in
if self?.capturedVideoBlurEffect.alpha == 0 {
self?.isVideoHidden = true
self?.capturedVideoBlurEffect.alpha = 1
} else {
self.isVideoHidden = false
self.capturedVideoBlurEffect.alpha = 0
self?.isVideoHidden = false
self?.capturedVideoBlurEffect.alpha = 0
}
self.resizeCapturedVideo(withInfoContainer: !self.infoContainer.isHidden)
self.view.layoutIfNeeded()
guard let hidden = self?.infoContainer.isHidden else {return}
self?.resizeCapturedVideo(withInfoContainer: !hidden)
self?.view.layoutIfNeeded()
})
}
......@@ -163,13 +164,13 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
func animateCallCircle() {
self.callPulse.alpha = 0.5
self.callPulse.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
UIView.animate(withDuration: 1.5, animations: {
self.callPulse.alpha = 0.0
self.callPulse.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
self.view.layoutIfNeeded()
}, completion: { [unowned self] _ in
if self.viewModel.call?.state == .ringing || self.viewModel.call?.state == .connecting {
self.animateCallCircle()
UIView.animate(withDuration: 1.5, animations: { [weak self] in
self?.callPulse.alpha = 0.0
self?.callPulse.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
self?.view.layoutIfNeeded()
}, completion: { [weak self] _ in
if self?.viewModel.call?.state == .ringing || self?.viewModel.call?.state == .connecting {
self?.animateCallCircle()
}
})
}
......@@ -178,8 +179,8 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
self.buttonsContainer.viewModel = self.viewModel.containerViewModel
self.buttonsContainer.cancelButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.removeFromScreen()
self?.viewModel.cancelCall()
self?.removeFromScreen()
}).disposed(by: self.disposeBag)
self.buttonsContainer.muteAudioButton.rx.tap
......@@ -326,17 +327,17 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
self.viewModel.showCallOptions
.observeOn(MainScheduler.instance)
.subscribe(onNext: { show in
.subscribe(onNext: { [weak self] show in
if show {
self.showContactInfo()
self?.showContactInfo()
}
}).disposed(by: self.disposeBag)
self.viewModel.showCancelOption
.observeOn(MainScheduler.instance)
.subscribe(onNext: { show in
.subscribe(onNext: { [weak self] show in
if show {
self.showCancelButton()
self?.showCancelButton()
}
}).disposed(by: self.disposeBag)
......@@ -362,8 +363,8 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
if !self.viewModel.isAudioOnly {
self.viewModel.callPaused
.observeOn(MainScheduler.instance)
.subscribe(onNext: { show in
self.setAvatarView(show)
.subscribe(onNext: { [weak self] show in
self?.setAvatarView(show)
}).disposed(by: self.disposeBag)
}
......@@ -454,6 +455,9 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
}
func removeFromScreen() {
if !self.infoContainer.isHidden {
task?.cancel()
}
UIDevice.current.isProximityMonitoringEnabled = false
self.dismiss(animated: false)
}
......@@ -485,10 +489,11 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
// Waiting for screen size change
DispatchQueue.global(qos: .background).async {
sleep(UInt32(0.5))
DispatchQueue.main.async {
self.resizeCapturedVideo(withInfoContainer: !self.infoContainer.isHidden)
if UIDevice.current.hasNotch && (UIDevice.current.orientation == .landscapeRight || UIDevice.current.orientation == .landscapeLeft) && self.infoContainer.isHidden == false {
self.buttonsContainerBottomConstraint.constant = 1
DispatchQueue.main.async { [weak self] in
guard let hidden = self?.infoContainer.isHidden else {return}
self?.resizeCapturedVideo(withInfoContainer: !hidden)
if UIDevice.current.hasNotch && (UIDevice.current.orientation == .landscapeRight || UIDevice.current.orientation == .landscapeLeft) && self?.infoContainer.isHidden == false {
self?.buttonsContainerBottomConstraint.constant = 1
}
}
}
......@@ -572,21 +577,21 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
self.infoContainer.isHidden = false
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.2, animations: {
self.capturedVideoBlurEffect.alpha = 0
self.resizeCapturedVideo(withInfoContainer: true)
self.infoContainerTopConstraint.constant = -10
if UIDevice.current.hasNotch && (self.orientation == .landscapeRight || self.orientation == .landscapeLeft) {
self.buttonsContainerBottomConstraint.constant = 1
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.capturedVideoBlurEffect.alpha = 0
self?.resizeCapturedVideo(withInfoContainer: true)
self?.infoContainerTopConstraint.constant = -10
if UIDevice.current.hasNotch && (self?.orientation == .landscapeRight || self?.orientation == .landscapeLeft) {
self?.buttonsContainerBottomConstraint.constant = 1
} else if UIDevice.current.userInterfaceIdiom == .pad {
self.buttonsContainerBottomConstraint.constant = 30
self?.buttonsContainerBottomConstraint.constant = 30
} else {
self.buttonsContainerBottomConstraint.constant = 10
self?.buttonsContainerBottomConstraint.constant = 10
}
self.view.layoutIfNeeded()
self?.view.layoutIfNeeded()
})
task = DispatchWorkItem { self.hideContactInfo() }
task = DispatchWorkItem {[weak self] in self?.hideContactInfo() }
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 7, execute: task!)
}
......
......@@ -93,11 +93,11 @@ class CallViewModel: Stateable, ViewModel {
return callService.currentCall.filter({ [weak self] call in
return call.callId == self?.call?.callId
})
.map({[weak self] call in
.map({ call in
return call.state == .over || call.state == .failure
}).map({ hide in
}).map({ [weak self] hide in
if hide {
self.videoService.setCameraOrientation(orientation: UIDevice.current.orientation)
self?.videoService.setCameraOrientation(orientation: UIDevice.current.orientation)
}
return hide
})
......@@ -154,16 +154,16 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var isActiveVideoCall: Observable<Bool> = {
return self.callService.currentCall
.filter({ [weak self] call in
return call.callId == self?.call?.callId
lazy var isActiveVideoCall: Observable<Bool> = { [unowned self] in
return (self.callService.currentCall
.filter({call in
return call.callId == self.call?.callId
}).map({ call in
return call.state == .current && !self.isAudioOnly
})
}))
}()
lazy var showCallOptions: Observable<Bool> = {
lazy var showCallOptions: Observable<Bool> = { [unowned self] in
return Observable.combineLatest(self.screenTapped.asObservable(),
isActiveVideoCall) { (tapped, shouldRespond) in
if tapped && shouldRespond {
......@@ -173,7 +173,7 @@ class CallViewModel: Stateable, ViewModel {
}
}()
lazy var showCancelOption: Observable<Bool> = {
lazy var showCancelOption: Observable<Bool> = { [unowned self] in
return self.callService.currentCall
.filter({ [weak self] call in
return call.callId == self?.call?.callId &&
......@@ -183,7 +183,7 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var showCapturedFrame: Observable<Bool> = {
lazy var showCapturedFrame: Observable<Bool> = { [unowned self] in
return self.callService.currentCall
.filter({ [weak self] call in
return call.callId == self?.call?.callId &&
......@@ -195,7 +195,7 @@ class CallViewModel: Stateable, ViewModel {
var screenTapped = BehaviorSubject(value: false)
lazy var videoButtonState: Observable<UIImage?> = {
lazy var videoButtonState: Observable<UIImage?> = { [unowned self] in
let onImage = UIImage(asset: Asset.videoRunning)
let offImage = UIImage(asset: Asset.videoMuted)
......@@ -208,7 +208,7 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var videoMuted: Observable<Bool> = {
lazy var videoMuted: Observable<Bool> = { [unowned self] in
return self.callService.currentCall.filter({ [weak self] call in
call.callId == self?.call?.callId &&
call.state == .current
......@@ -217,7 +217,7 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var audioButtonState: Observable<UIImage?> = {
lazy var audioButtonState: Observable<UIImage?> = { [unowned self] in
let onImage = UIImage(asset: Asset.audioRunning)
let offImage = UIImage(asset: Asset.audioMuted)
......@@ -229,7 +229,7 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var speakerButtonState: Observable<UIImage?> = {
lazy var speakerButtonState: Observable<UIImage?> = { [unowned self] in
let offImage = UIImage(asset: Asset.disableSpeakerphone)
let onImage = UIImage(asset: Asset.enableSpeakerphone)
......@@ -242,16 +242,16 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var isOutputToSpeaker: Observable<Bool> = {
lazy var isOutputToSpeaker: Observable<Bool> = { [unowned self] in
return self.audioService.isOutputToSpeaker.asObservable()
}()
lazy var speakerSwitchable: Observable<Bool> = {
lazy var speakerSwitchable: Observable<Bool> = { [unowned self] in
return self.audioService.isHeadsetConnected.asObservable()
.map { value in return !value }
}()
lazy var audioMuted: Observable<Bool> = {
lazy var audioMuted: Observable<Bool> = { [unowned self] in
return self.callService.currentCall.filter({ [weak self] call in
call.callId == self?.call?.callId &&
call.state == .current
......@@ -260,7 +260,7 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var pauseCallButtonState: Observable<UIImage?> = {
lazy var pauseCallButtonState: Observable<UIImage?> = { [unowned self] in
let unpauseCall = UIImage(asset: Asset.unpauseCall)
let pauseCall = UIImage(asset: Asset.pauseCall)
......@@ -272,7 +272,7 @@ class CallViewModel: Stateable, ViewModel {
})
}()
lazy var callPaused: Observable<Bool> = {
lazy var callPaused: Observable<Bool> = { [unowned self] in
return self.callService.currentCall.filter({ [weak self] call in
call.callId == self?.call?.callId &&
(call.state == .hold ||
......@@ -301,10 +301,9 @@ class CallViewModel: Stateable, ViewModel {
return call.callId == self?.call?.callId
}).map({ call in
return call.state == .current
}).subscribe(onNext: { _ in
self.videoService.setCameraOrientation(orientation: UIDevice.current.orientation)
}).subscribe(onNext: { [weak self] _ in
self?.videoService.setCameraOrientation(orientation: UIDevice.current.orientation)
}).disposed(by: self.disposeBag)
}
static func formattedDurationFrom(interval: Int) -> String {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment