             return true
         }
         return false
+    }
+    
+    func startJitsiCall(withWidget widget: Widget) {
+        if self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key != nil {
+            //  this Jitsi call is already managed by this class, no need to report the call again
+            return
+        }
+        
+        guard let roomId = widget.roomId else {
+            return
+        }
+        
+        guard let session = sessions.first else {
+            return
+        }
+        
+        guard let room = session.room(withRoomId: roomId) else {
+            return
+        }
+        
+        let newUUID = UUID()
+        let handle = CXHandle(type: .generic, value: roomId)
+        let startCallAction = CXStartCallAction(call: newUUID, handle: handle)
+        let transaction = CXTransaction(action: startCallAction)
+        JMCallKitProxy.request(transaction) { (error) in
+            if error == nil {
+                JMCallKitProxy.reportCallUpdate(with: newUUID,
+                                                handle: roomId,
+                                                displayName: room.summary.displayname,
+                                                hasVideo: true)
+                JMCallKitProxy.reportOutgoingCall(with: newUUID, connectedAt: nil)
+
+                self.jitsiCalls[newUUID] = widget
+            }
+        }
+    }
+    
+    func endJitsiCall(withWidget widget: Widget) {
+        guard let uuid = self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key else {
+            //  this Jitsi call is not managed by this class
+            return
+        }
+        
+        let endCallAction = CXEndCallAction(call: uuid)
+        let transaction = CXTransaction(action: endCallAction)
+        JMCallKitProxy.request(transaction) { (error) in
+            if error == nil {
+                self.jitsiCalls.removeValue(forKey: uuid)
+            }
+        }
+    }
+    
+    func processWidgetEvent(_ event: MXEvent, inSession session: MXSession) {
+        guard JMCallKitProxy.isProviderConfigured() else {
+            //  CallKit proxy is not configured, no benefit in parsing the event
+            return
+        }
+        
+        guard let widget = Widget(widgetEvent: event, inMatrixSession: session) else {
+            return
+        }
+        
+        if self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key != nil {
+            //  this Jitsi call is already managed by this class, no need to report the call again
+            return
+        }
+        
+        if widget.isActive {
+            guard widget.type == kWidgetTypeJitsiV1 || widget.type == kWidgetTypeJitsiV2 else {
+                //  not a Jitsi widget, ignore
+                return
+            }
+            
+            if let jitsiVC = AppDelegate.theDelegate().jitsiViewController,
+               jitsiVC.widget.widgetId == widget.widgetId {
+                //  this is already the Jitsi call we have atm
+                return
+            }
+            
+            if TimeInterval(event.age)/MSEC_PER_SEC > Constants.groupCallInviteLifetime {
+                //  too late to process the event
+                return
+            }
+            
+            //  an active Jitsi widget
+            let newUUID = UUID()
+            
+            //  assume this Jitsi call will survive
+            self.jitsiCalls[newUUID] = widget
+            
+            if event.sender == session.myUserId {
+                //  outgoing call
+                JMCallKitProxy.reportOutgoingCall(with: newUUID, connectedAt: nil)
+            } else {
+                //  incoming call
+                let user = session.user(withUserId: event.sender)
+                let displayName = NSString.localizedUserNotificationString(forKey: "GROUP_CALL_FROM_USER",
+                                                                           arguments: [user?.displayname as Any])
+                JMCallKitProxy.reportNewIncomingCall(UUID: newUUID,
+                                                     handle: widget.roomId,
+                                                     displayName: displayName,
+                                                     hasVideo: true) { (error) in
+                    if error != nil {
+                        self.jitsiCalls.removeValue(forKey: newUUID)
+                    }
+                }
+            }
+        } else {
+            guard let uuid = self.jitsiCalls.first(where: { $0.value.widgetId == widget.widgetId })?.key else {
+                //  this Jitsi call is not managed by this class
+                return
+            }
+            JMCallKitProxy.reportCall(with: uuid, endedAt: nil, reason: .remoteEnded)
+            self.jitsiCalls.removeValue(forKey: uuid)
+        }
     }
     
     //  MARK: - Private

                                                  name: .RoomGroupCallTileTapped,
                                                  object: nil)
        
        isStarted = false
    }
    
    @objc

    }
    
}

#if canImport(JitsiMeetSDK)
//  MARK: - JMCallKitListener

extension CallPresenter: JMCallKitListener {
    
    func providerDidReset() {
        
    }
    
    func performAnswerCall(UUID: UUID) {
        guard let widget = jitsiCalls[UUID] else {
            return
        }
        
        AppDelegate.theDelegate().displayJitsiViewController(with: widget, andVideo: true)
    }
    
    func performEndCall(UUID: UUID) {
        guard let widget = jitsiCalls[UUID] else {
            return
        }
        
        if let jitsiVC = AppDelegate.theDelegate().jitsiViewController, jitsiVC.widget.widgetId == widget.widgetId {
            //  hangup an active call
            jitsiVC.hangup()
            AppDelegate.theDelegate().jitsiViewController(jitsiVC, dismissViewJitsiController: nil)
        } else {
            //  decline incoming call
            JitsiService.shared.declineWidget(withId: widget.widgetId)
        }
    }
    
    func performSetMutedCall(UUID: UUID, isMuted: Bool) {
        guard let widget = jitsiCalls[UUID] else {
            return
        }
        
        if let jitsiVC = AppDelegate.theDelegate().jitsiViewController, jitsiVC.widget.widgetId == widget.widgetId {
            //  mute the active Jitsi call
            jitsiVC.setAudioMuted(isMuted)
        }
    }
    
    func performStartCall(UUID: UUID, isVideo: Bool) {
        
    }
    
    func providerDidActivateAudioSession(session: AVAudioSession) {
        
    }

    func providerDidDeactivateAudioSession(session: AVAudioSession) {
        
    }

    func providerTimedOutPerformingAction(action: CXAction) {
        
    }
    
}
#endif
