Completely rework the chatroom tutorial to make it more intuitive : you now interact with an existing Linphone on a second phone

This commit is contained in:
QuentinArguillere
2020-10-07 15:49:17 +02:00
parent 3db5eb4912
commit ae825689a2
2 changed files with 112 additions and 161 deletions

View File

@@ -25,29 +25,28 @@ class ChatRoomExampleContext : ObservableObject
/*-------- Chatroom tutorial related variables ---------------
-------- "A" always initiates the chat, "B" answers --------*/
let mIdA = "sip:peche5@sip.linphone.org", mIdB = "sip:jehan-iphone@sip.linphone.org"
var mPasswordA = "peche5", mPasswordB = "cotcot"
let mFactoryUri = "sip:conference-factory@sip.linphone.org"
var mProxyConfigA, mProxyConfigB : ProxyConfig!
var mProxyConfig : ProxyConfig!
var mChatMessage : ChatMessage?
let mCoreChatDelegate = LinphoneCoreChatDelegate()
let mLinphoneCoreDelegate = LinphoneCoreDelegate()
let mChatMessageDelegate = LinphoneChatMessageTracker()
let mChatRoomDelegate = LinphoneChatRoomStateTracker()
let mRegistrationConfirmDelegate = LinphoneRegistrationConfirmDelegate()
var mChatRoomA, mChatRoomB : ChatRoom?
@Published var chatroomState = ChatroomExampleState.Unstarted
var mChatRoom : ChatRoom?
@Published var proxyConfigARegistered : Bool = false
@Published var proxyConfigBRegistered : Bool = false
@Published var chatroomState = ChatroomExampleState.Unstarted
@Published var isFlexiSip : Bool = true
@Published var textToSend: String = "msg to send"
@Published var sReplyText: String = "msg to reply"
@Published var sReceivedMessagesA : String = ""
@Published var sReceivedMessagesB: String = ""
@Published var sReceivedMessages : String = ""
@Published var dest : String = "sip:arguillq@sip.linphone.org"
@Published var id : String = "sip:quentindev@sip.linphone.org"
@Published var passwd : String = "dev"
@Published var loggedIn: Bool = false
//var fileFolderUrl : URL?
//var fileUrl : URL?
func getStateAsString() -> String
{
switch (chatroomState)
@@ -61,8 +60,7 @@ class ChatRoomExampleContext : ObservableObject
init()
{
mChatRoomDelegate.tutorialContext = self
mCoreChatDelegate.tutorialContext = self
mRegistrationConfirmDelegate.tutorialContext = self
mLinphoneCoreDelegate.tutorialContext = self
// Initialize Linphone Core
try? mCore = Factory.Instance.createCore(configPath: "", factoryConfigPath: "", systemContext: nil)
@@ -72,97 +70,61 @@ class ChatRoomExampleContext : ObservableObject
try? mCore.start()
// Important ! Will notify when config are registered so that we can proceed with the chatroom creations
mCore.addDelegate(delegate: mRegistrationConfirmDelegate)
// Handle chat message reception
mCore.addDelegate(delegate: mCoreChatDelegate)
// Also handles chat message reception
mCore.addDelegate(delegate: mLinphoneCoreDelegate)
/*
let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let myFiles = documentsPath.appendingPathComponent("TutorialFiles")
fileUrl = myFiles?.appendingPathComponent("file_to_transfer.txt")
do{
try FileManager.default.createDirectory(atPath: myFiles!.path, withIntermediateDirectories: true, attributes: nil)
try String("My file content").write(to: fileUrl!, atomically: false, encoding: .utf8)
}catch let error as NSError{
print("Unable to create directory",error)
}
*/
}
func createProxyConfigAndRegister(identity sId : String, password sPwd : String, factoryUri fUri : String) -> ProxyConfig?
{
let factory = Factory.Instance
do {
let proxy_cfg = try mCore.createProxyConfig()
let address = try factory.createAddress(addr: sId)
let info = try factory.createAuthInfo(username: address.username, userid: "", passwd: sPwd, ha1: "", realm: "", domain: address.domain)
mCore.addAuthInfo(info: info)
try proxy_cfg.setIdentityaddress(newValue: address)
let server_addr = "sip:" + address.domain + ";transport=tls"
try proxy_cfg.setServeraddr(newValue: server_addr)
proxy_cfg.registerEnabled = true
proxy_cfg.conferenceFactoryUri = fUri
try mCore.addProxyConfig(config: proxy_cfg)
if ( mCore.defaultProxyConfig == nil)
{
// IMPORTANT : default proxy config setting MUST be done AFTER adding the config to the core !
mCore.defaultProxyConfig = proxy_cfg
}
return proxy_cfg
} catch {
print(error)
}
return nil
}
/*
func createProxyConfigAndRegister(identity sId : String, password sPwd : String, factoryUri fUri : String) -> ProxyConfig?
func createProxyConfigAndRegister()
{
do {
let proxy_cfg = try createAndInitializeProxyConfig(core : mCore, identity: sId, password: sPwd)
proxy_cfg.conferenceFactoryUri = fUri
try mCore.addProxyConfig(config: proxy_cfg)
mProxyConfig = try createAndInitializeProxyConfig(core : mCore, identity: id, password: passwd)
mProxyConfig.conferenceFactoryUri = mFactoryUri
try mCore.addProxyConfig(config: mProxyConfig)
if ( mCore.defaultProxyConfig == nil) {
// IMPORTANT : default proxy config setting MUST be done AFTER adding the config to the core !
mCore.defaultProxyConfig = proxy_cfg
mCore.defaultProxyConfig = mProxyConfig
}
return proxy_cfg
} catch {
print(error)
}
return nil
}*/
func registerChatRoomsProxyConfigurations()
{
mProxyConfigA = createProxyConfigAndRegister(identity : mIdA, password : mPasswordA, factoryUri: mFactoryUri)!
mProxyConfigB = createProxyConfigAndRegister(identity : mIdB, password : mPasswordB, factoryUri: mFactoryUri)!
}
func createChatRoom()
{
// proxy configuration must first be initialized and registered
if (!proxyConfigARegistered || !proxyConfigBRegistered || mChatRoomA != nil) { return }
if (!loggedIn || mChatRoom != nil) { return }
do {
let chatDest = [mProxyConfigB.contact!]
let chatDest = [try Factory.Instance.createAddress(addr: dest)]
let chatParams = try mCore.createDefaultChatRoomParams()
if (isFlexiSip)
{
if (isFlexiSip) {
chatParams.backend = ChatRoomBackend.FlexisipChat
chatParams.encryptionEnabled = false
chatParams.groupEnabled = false
chatParams.subject = "Tutorial Chatroom"
mChatRoomA = try mCore.createChatRoom(params: chatParams
, localAddr: mProxyConfigA.contact!
, participants: chatDest)
mChatRoomA!.addDelegate(delegate: mChatRoomDelegate)
mChatRoom = try mCore.createChatRoom(params: chatParams, localAddr: mProxyConfig.contact!, participants: chatDest)
mChatRoom!.addDelegate(delegate: mChatRoomDelegate)
// Flexisip chatroom requires a setup time. The delegate will set the state to started when it is ready.
chatroomState = ChatroomExampleState.Starting
}
else
{
else {
chatParams.backend = ChatRoomBackend.Basic
mChatRoomA = try mCore.createChatRoom(params: chatParams
, localAddr: mProxyConfigA.contact!
, participants: chatDest)
mChatRoom = try mCore.createChatRoom(params: chatParams, localAddr: mProxyConfig.contact!, participants: chatDest)
// Basic chatroom do not require setup time
chatroomState = ChatroomExampleState.Started
}
} catch {
print(error)
}
@@ -176,7 +138,7 @@ class ChatRoomExampleContext : ObservableObject
usleep(100000)
}
if let chatRoom = self.mChatRoomA
if let chatRoom = self.mChatRoom
{
do
{
@@ -200,67 +162,60 @@ class ChatRoomExampleContext : ObservableObject
print(error)
}
}
func sendMsg()
{
if let chatRoom = mChatRoomA {
if let chatRoom = mChatRoom {
send(room: chatRoom, msg: textToSend)
}
}
func sendReply()
{
if let chatRoom = mChatRoomB {
send(room: chatRoom, msg: sReplyText)
}
}
/*
func sendFile()
{
do {
let content = try mCore.createContent()
content.filePath = fileUrl!.absoluteString
//mChatRoomA?.createFileTransferMessage(initialContent: <#T##Content#>)
print(try String(contentsOf: fileUrl!, encoding: .utf8))
}catch let error as NSError {
print("Unable to create directory",error)
}
}*/
}
class LinphoneRegistrationConfirmDelegate: CoreDelegate {
class LinphoneCoreDelegate: CoreDelegate {
var tutorialContext : ChatRoomExampleContext!
override func onRegistrationStateChanged(core lc: Core, proxyConfig cfg: ProxyConfig, state cstate: RegistrationState, message: String?) {
print("New registration state \(cstate) for user id \( String(describing: cfg.identityAddress?.asString()))\n")
if (cstate == RegistrationState.Ok)
{
if (cfg === tutorialContext.mProxyConfigA)
{
tutorialContext.proxyConfigARegistered = true
}
else if (cfg === tutorialContext.mProxyConfigB)
{
tutorialContext.proxyConfigBRegistered = true
}
}
}
}
class LinphoneCoreChatDelegate: CoreDelegate {
var tutorialContext : ChatRoomExampleContext!
override func onMessageReceived(core lc: Core, chatRoom room: ChatRoom, message: ChatMessage) {
if (tutorialContext.mChatRoomB == nil)
{
tutorialContext.mChatRoomB = room
}
if (message.contentType == "text/plain")
{
if (room === tutorialContext.mChatRoomA) {
tutorialContext.sReceivedMessagesA += "\n\(message.textContent)"
} else {
tutorialContext.sReceivedMessagesB += "\n\(message.textContent)"
}
}
func onRegistrationStateChanged(core: Core, proxyConfig: ProxyConfig, state: RegistrationState, message: String) {
print("New registration state \(state) for user id \( String(describing: proxyConfig.identityAddress?.asString()))\n")
if (state == RegistrationState.Ok) {
tutorialContext.loggedIn = true
}
}
func onMessageReceived(core lc: Core, chatRoom room: ChatRoom, message: ChatMessage) {
if (tutorialContext.mChatRoom == nil) {
tutorialContext.mChatRoom = room
tutorialContext.chatroomState = ChatroomExampleState.Started
}
if (message.contentType == "text/plain") {
tutorialContext.sReceivedMessages += "\n\(message.textContent)"
}
print(message.contents.count)
}
}
class LinphoneChatRoomStateTracker: ChatRoomDelegate {
var tutorialContext : ChatRoomExampleContext!
override func onStateChanged(chatRoom cr: ChatRoom, newState: ChatRoom.State) {
func onStateChanged(chatRoom cr: ChatRoom, newState: ChatRoom.State) {
if (newState == ChatRoom.State.Created)
{
// This will only have sense when WE are creating a flexisip chatroom.
print("ChatRoomTrace - Chatroom ready to start")
tutorialContext.chatroomState = ChatroomExampleState.Started
}
@@ -268,7 +223,7 @@ class LinphoneChatRoomStateTracker: ChatRoomDelegate {
}
class LinphoneChatMessageTracker: ChatMessageDelegate {
override func onMsgStateChanged(message msg: ChatMessage, state: ChatMessage.State) {
func onMsgStateChanged(message msg: ChatMessage, state: ChatMessage.State) {
print("MessageTrace - msg state changed: \(state)\n")
}
}

View File

@@ -15,25 +15,41 @@ struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
HStack{
Button(action: tutorialContext.registerChatRoomsProxyConfigurations)
{
Text("Chat Login")
Group {
HStack {
Text("Identity :")
.font(.subheadline)
TextField("", text : $tutorialContext.id)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
HStack {
Text("Password :")
.font(.subheadline)
TextField("", text : $tutorialContext.passwd)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
HStack {
Button(action: tutorialContext.createProxyConfigAndRegister)
{
Text("Login")
.font(.largeTitle)
.foregroundColor(Color.white)
.frame(width: 190.0, height: 42.0)
.frame(width: 90.0, height: 42.0)
.background(Color.gray)
}.disabled(tutorialContext.proxyConfigBRegistered && tutorialContext.proxyConfigBRegistered)
VStack{
Text(tutorialContext.proxyConfigARegistered ? "A logged in" :"A not registered")
.font(.footnote)
.foregroundColor(tutorialContext.proxyConfigARegistered ? Color.green : Color.black)
Text(tutorialContext.proxyConfigBRegistered ? "B logged in" :"B not registered")
.font(.footnote)
.foregroundColor(tutorialContext.proxyConfigBRegistered ? Color.green : Color.black)
}
Text("Login State : ")
.font(.footnote)
Text(tutorialContext.loggedIn ? "Logged in" : "Unregistered")
.font(.footnote)
.foregroundColor(tutorialContext.loggedIn ? Color.green : Color.black)
}
}
HStack {
Text("Call destination :")
TextField("", text : $tutorialContext.dest)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
.padding(.top, 5)
HStack {
VStack() {
Toggle(isOn: $tutorialContext.isFlexiSip) {
@@ -55,13 +71,13 @@ struct ContentView: View {
.foregroundColor(Color.white)
.frame(width: 100.0, height: 82.0)
.background(Color.gray)
}.disabled(!tutorialContext.proxyConfigBRegistered || !tutorialContext.proxyConfigBRegistered)
}.disabled(!tutorialContext.loggedIn)
}
HStack {
VStack {
Text("Chat received by A").bold()
Text("Chat received").bold()
ScrollView {
Text(tutorialContext.sReceivedMessagesA)
Text(tutorialContext.sReceivedMessages)
.font(.footnote)
.frame(width : 160)
}.border(Color.gray)
@@ -79,26 +95,6 @@ struct ContentView: View {
}
}
Spacer()
VStack {
Text("Chat received by B").bold()
ScrollView {
Text(tutorialContext.sReceivedMessagesB)
.font(.footnote)
.frame(width : 160)
}.border(Color.gray)
HStack {
TextField("Reply text", text : $tutorialContext.sReplyText)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: tutorialContext.sendReply)
{
Text("Reply")
.font(.callout)
.foregroundColor(Color.white)
.frame(width: 50.0, height: 30.0)
.background(Color.gray)
}.disabled(!tutorialContext.proxyConfigBRegistered || !tutorialContext.proxyConfigBRegistered)
}
}
}.padding(.top)
Group {
Spacer()