Browse Source

Combine all managers into one controller

Sergey 2 years ago
parent
commit
b0114bb89d

+ 0 - 24
Chat.xcodeproj/project.pbxproj

@@ -21,11 +21,7 @@
 		2F6045B3288EA0E6008F005E /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F6045B2288EA0E6008F005E /* LoginView.swift */; };
 		2F6045B6288EA10B008F005E /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F6045B5288EA10B008F005E /* LoginViewModel.swift */; };
 		2F6E936828F8714600FAF0E5 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F6E936728F8714600FAF0E5 /* Message.swift */; };
-		2F81974128ACD9A6008D8C45 /* StreamManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F81974028ACD9A6008D8C45 /* StreamManager.swift */; };
-		2F81974328ACDBC4008D8C45 /* RoomManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F81974228ACDBC4008D8C45 /* RoomManager.swift */; };
-		2F81974528ACDBCF008D8C45 /* RosterManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F81974428ACDBCF008D8C45 /* RosterManager.swift */; };
 		2F81974828ACEDC8008D8C45 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F81974728ACEDC8008D8C45 /* User.swift */; };
-		2F81974A28ACF91E008D8C45 /* MUCManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F81974928ACF91E008D8C45 /* MUCManager.swift */; };
 		2F81974C28ACFDEA008D8C45 /* Room.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F81974B28ACFDEA008D8C45 /* Room.swift */; };
 		2FCB75E728A425580097BD1D /* RoomsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCB75E628A425580097BD1D /* RoomsListView.swift */; };
 		2FCB75EA28A425900097BD1D /* RoomsListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCB75E928A425900097BD1D /* RoomsListViewModel.swift */; };
@@ -48,11 +44,7 @@
 		2F6045B2288EA0E6008F005E /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
 		2F6045B5288EA10B008F005E /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
 		2F6E936728F8714600FAF0E5 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
-		2F81974028ACD9A6008D8C45 /* StreamManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamManager.swift; sourceTree = "<group>"; };
-		2F81974228ACDBC4008D8C45 /* RoomManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomManager.swift; sourceTree = "<group>"; };
-		2F81974428ACDBCF008D8C45 /* RosterManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RosterManager.swift; sourceTree = "<group>"; };
 		2F81974728ACEDC8008D8C45 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
-		2F81974928ACF91E008D8C45 /* MUCManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MUCManager.swift; sourceTree = "<group>"; };
 		2F81974B28ACFDEA008D8C45 /* Room.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Room.swift; sourceTree = "<group>"; };
 		2FCB75E628A425580097BD1D /* RoomsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomsListView.swift; sourceTree = "<group>"; };
 		2FCB75E928A425900097BD1D /* RoomsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomsListViewModel.swift; sourceTree = "<group>"; };
@@ -131,7 +123,6 @@
 			children = (
 				2F24E94328F2FA29007ECE97 /* Main */,
 				2F81974628ACEDB6008D8C45 /* Models */,
-				2FCB762528AA59620097BD1D /* Managers */,
 				2F24E94428F2FAB2007ECE97 /* UI */,
 			);
 			path = Chat;
@@ -182,17 +173,6 @@
 			path = Auth;
 			sourceTree = "<group>";
 		};
-		2FCB762528AA59620097BD1D /* Managers */ = {
-			isa = PBXGroup;
-			children = (
-				2F81974028ACD9A6008D8C45 /* StreamManager.swift */,
-				2F81974428ACDBCF008D8C45 /* RosterManager.swift */,
-				2F81974928ACF91E008D8C45 /* MUCManager.swift */,
-				2F81974228ACDBC4008D8C45 /* RoomManager.swift */,
-			);
-			path = Managers;
-			sourceTree = "<group>";
-		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -271,18 +251,14 @@
 			files = (
 				2FFCDFBC28F6EA1800D9FA9D /* XMPPController.swift in Sources */,
 				2FCB75ED28A42B1E0097BD1D /* ChatViewModel.swift in Sources */,
-				2F81974328ACDBC4008D8C45 /* RoomManager.swift in Sources */,
 				2F24E94828F2FC8A007ECE97 /* AppDelegate.swift in Sources */,
 				2F81974C28ACFDEA008D8C45 /* Room.swift in Sources */,
 				2F60459C288D8000008F005E /* MessageView.swift in Sources */,
 				2F6E936828F8714600FAF0E5 /* Message.swift in Sources */,
-				2F81974128ACD9A6008D8C45 /* StreamManager.swift in Sources */,
 				2F6045B0288E9D3E008F005E /* ChatListViewModel.swift in Sources */,
 				2FCB75EA28A425900097BD1D /* RoomsListViewModel.swift in Sources */,
-				2F81974A28ACF91E008D8C45 /* MUCManager.swift in Sources */,
 				2F81974828ACEDC8008D8C45 /* User.swift in Sources */,
 				2FCB75E728A425580097BD1D /* RoomsListView.swift in Sources */,
-				2F81974528ACDBCF008D8C45 /* RosterManager.swift in Sources */,
 				2F6045B3288EA0E6008F005E /* LoginView.swift in Sources */,
 				2F60459F288D869B008F005E /* ChatListView.swift in Sources */,
 				2F6045A5288E19ED008F005E /* KeyboardReadable.swift in Sources */,

+ 23 - 4
Chat/Main/XMPPController.swift

@@ -8,7 +8,7 @@
 import XMPPFramework
 import XMPPFrameworkSwift
 
-final class XMPPController {
+final class XMPPController: NSObject {
 	static let shared: XMPPController = XMPPController()
 
 	let xmppStream: XMPPStream
@@ -18,7 +18,7 @@ final class XMPPController {
 
 	var xmppAuth: XMPPPlainAuthentication
 
-	private init() {
+	private override init() {
 		self.xmppStream = XMPPStream()
 
 		self.xmppRosterStorage = XMPPRosterMemoryStorage()
@@ -31,7 +31,12 @@ final class XMPPController {
 
 		self.xmppAuth = XMPPPlainAuthentication()
 
+		super.init()
+
+		self.xmppStream.addDelegate(self, delegateQueue: .main)
 		self.xmppReconnect.addDelegate(self, delegateQueue: .main)
+
+		setupStream()
 	}
 
 	func setupStream() {
@@ -43,13 +48,12 @@ final class XMPPController {
 	func login(with login: String, and password: String) {
 		self.xmppStream.myJID = XMPPJID(string: login)
 		self.xmppAuth = XMPPPlainAuthentication(stream: xmppStream, password: password)
-		connect()
 	}
 
 	func connect() {
 		if self.xmppStream.isDisconnected {
 			do {
-				try self.xmppStream.authenticate(xmppAuth)
+				try xmppStream.connect(withTimeout: XMPPStreamTimeoutNone)
 			} catch {
 
 			}
@@ -63,3 +67,18 @@ extension XMPPController: XMPPReconnectDelegate {
 		return true
 	}
 }
+
+extension XMPPController: XMPPStreamDelegate {
+	func xmppStreamDidConnect(_ sender: XMPPStream) {
+		do {
+			try self.xmppStream.authenticate(xmppAuth)
+		} catch {
+
+		}
+	}
+
+	func xmppStreamDidAuthenticate(_ sender: XMPPStream) {
+		sender.send(XMPPPresence())
+		print("Stream: Authenticated")
+	}
+}

+ 0 - 36
Chat/Managers/MUCManager.swift

@@ -1,36 +0,0 @@
-//
-//  MUCManager.swift
-//  Chat (iOS)
-//
-//  Created by Sergey Tarasov on 17.08.2022.
-//
-
-import Foundation
-import XMPPFramework
-import XMPPFrameworkSwift
-
-final class MUCManager: NSObject {
-    var muc: XMPPMUCLight
-
-    var rooms: [Room] = []
-
-    override init() {
-        self.muc = XMPPMUCLight()
-
-        super.init()
-
-        self.muc.activate(StreamManager.shared.stream)
-        self.muc.addDelegate(self, delegateQueue: .main)
-    }
-
-    func fetchRooms() {
-        _ = self.muc.discoverRooms(forServiceNamed: "chat.msg.sharix-app.org")
-    }
-}
-
-extension MUCManager: XMPPMUCLightDelegate {
-    func xmppMUCLight(_ sender: XMPPMUCLight, didDiscoverRooms rooms: [DDXMLElement], forServiceNamed serviceName: String) {
-        debugPrint(rooms)
-        self.rooms = rooms.map({ Room(jidString: $0.attributeStringValue(forName: "jid") ?? "", name: $0.attributeStringValue(forName: "name") ?? "") })
-    }
-}

+ 0 - 97
Chat/Managers/RoomManager.swift

@@ -1,97 +0,0 @@
-//
-//  RoomManager.swift
-//  Chat (iOS)
-//
-//  Created by Sergey Tarasov on 17.08.2022.
-//
-
-import Foundation
-import XMPPFramework
-import XMPPFrameworkSwift
-
-final class RoomManager: NSObject {
-    var room: XMPPRoom
-    var storage: XMPPRoomMemoryStorage
-    var mam: XMPPMessageArchiveManagement
-
-    var jid: XMPPJID?
-
-    var messages: [XMPPMessage] = []
-
-    init(with jidString: String) {
-        self.storage = XMPPRoomMemoryStorage()
-        self.room = XMPPRoom(roomStorage: self.storage, jid: XMPPJID(string: jidString)!)
-        self.mam = XMPPMessageArchiveManagement()
-
-        super.init()
-
-        self.room.activate(StreamManager.shared.stream)
-        self.mam.activate(StreamManager.shared.stream)
-        self.room.join(usingNickname: StreamManager.shared.stream.myJID?.user ?? "Test", history: nil)
-
-        self.room.addDelegate(self, delegateQueue: DispatchQueue.main)
-        self.mam.addDelegate(self, delegateQueue: DispatchQueue.main)
-    }
-
-    func fetchMessages() {
-        self.messages.removeAll()
-
-        if self.room.isJoined {
-            self.mam.retrieveMessageArchive(at: self.room.roomJID.bareJID, withFields: nil, with: nil)
-        } else {
-            let field = DDXMLElement(name: "field")
-            field.addAttribute(withName: "var", stringValue: "with")
-            field.addChild(DDXMLElement(name: "value", stringValue: self.room.roomJID.bare))
-
-            self.mam.retrieveMessageArchive(at: nil, withFields: [field], with: nil)
-        }
-    }
-
-    func sendMessage(_ text: String) {
-        let xmppMessage = XMPPMessage(messageType: room.isJoined ? .chat : .normal, to: self.room.roomJID.bareJID)
-        xmppMessage.addBody(text)
-        if self.room.isJoined {
-            self.room.send(xmppMessage)
-        } else {
-            StreamManager.shared.stream.send(xmppMessage)
-        }
-    }
-}
-
-extension RoomManager: XMPPRoomMemoryStorageDelegate {
-    func xmppRoomMemoryStorage(
-        _ sender: XMPPRoomMemoryStorage!,
-        didReceiveMessage message: XMPPRoomMessageMemoryStorageObject!,
-        fromOccupant occupant: XMPPRoomOccupantMemoryStorageObject!,
-        at index: UInt,
-        in allMessages: [Any]!
-    ) {
-        debugPrint(message.debugDescription)
-    }
-}
-
-extension RoomManager: XMPPRoomDelegate {
-    func xmppRoomDidJoin(_ sender: XMPPRoom) {
-
-    }
-}
-
-extension RoomManager: XMPPMessageArchiveManagementDelegate {
-    func xmppMessageArchiveManagement(
-        _ xmppMessageArchiveManagement: XMPPMessageArchiveManagement,
-        didReceiveMAMMessage message: XMPPMessage
-    ) {
-        if let result = message.children?.first,
-           let forwarded = result.children?.first,
-           let msg = forwarded.children?.first as? DDXMLElement {
-            let xmppmsg = XMPPMessage(from: msg)
-            if xmppmsg.isMessageWithBody {
-                self.messages.append(xmppmsg)
-            }
-        }
-    }
-
-    func xmppMessageArchiveManagement(_ xmppMessageArchiveManagement: XMPPMessageArchiveManagement, didFinishReceivingMessagesWith resultSet: XMPPResultSet) {
-        debugPrint("FINISH MAM")
-    }
-}

+ 0 - 21
Chat/Managers/RosterManager.swift

@@ -1,21 +0,0 @@
-//
-//  RosterManager.swift
-//  Chat (iOS)
-//
-//  Created by Sergey Tarasov on 17.08.2022.
-//
-
-import Foundation
-import XMPPFramework
-import XMPPFrameworkSwift
-
-final class RosterManager {
-    var roster: XMPPRoster
-    var storage: XMPPRosterMemoryStorage
-
-    init() {
-        self.storage = XMPPRosterMemoryStorage()
-        self.roster = XMPPRoster(rosterStorage: self.storage)
-        self.roster.activate(StreamManager.shared.stream)
-    }
-}

+ 0 - 54
Chat/Managers/StreamManager.swift

@@ -1,54 +0,0 @@
-//
-//  StreamManager.swift
-//  Chat (iOS)
-//
-//  Created by Sergey Tarasov on 17.08.2022.
-//
-
-import Foundation
-import XMPPFramework
-import XMPPFrameworkSwift
-
-final class StreamManager: NSObject {
-    static let shared = StreamManager()
-
-    var stream: XMPPStream
-    var delegate: XMPPStreamDelegate?
-
-    var password: String
-
-    private override init() {
-        self.stream = XMPPStream()
-
-        self.password = ""
-
-        super.init()
-        
-        self.stream.addDelegate(self, delegateQueue: DispatchQueue.main)
-    }
-
-    func setupStream(with login: String, password: String) {
-        self.stream.hostName = "msg.sharix-app.org"
-        self.stream.hostPort = 5222
-        self.stream.myJID = XMPPJID(string: login)
-        self.stream.startTLSPolicy = XMPPStreamStartTLSPolicy.allowed
-        self.password = password
-    }
-
-    func connect() {
-        if !self.stream.isDisconnected { return }
-        try! self.stream.connect(withTimeout: XMPPStreamTimeoutNone)
-    }
-}
-
-extension StreamManager: XMPPStreamDelegate {
-    func xmppStreamDidConnect(_ stream: XMPPStream) {
-        print("Stream: Connected")
-        try! stream.authenticate(withPassword: self.password)
-    }
-
-    func xmppStreamDidAuthenticate(_ sender: XMPPStream) {
-        self.stream.send(XMPPPresence())
-        print("Stream: Authenticated")
-    }
-}

+ 7 - 1
Chat/Models/Message.swift

@@ -8,7 +8,13 @@
 import Foundation
 
 struct Message {
-	let messageID: String
+	let id: String
 	let body: String
 	let fromID: String
 }
+
+extension Message: Equatable {
+	static func == (lhs: Message, rhs: Message) -> Bool {
+		return lhs.id == rhs.id
+	}
+}

+ 1 - 1
Chat/UI/Auth/LoginView.swift

@@ -19,7 +19,7 @@ struct LoginView: View {
                 .textFieldStyle(.roundedBorder)
                 .textContentType(.password)
             Button {
-                viewModel.didTouchLogIn { success in
+                viewModel.login { success in
                     if success {
                         authStatus = true
                     }

+ 5 - 6
Chat/UI/Auth/LoginViewModel.swift

@@ -6,18 +6,17 @@
 //
 
 import Foundation
+import XMPPFramework
+import XMPPFrameworkSwift
 
 final class LoginViewModel: ObservableObject {
-    let manager = StreamManager.shared
-
     @Published var login: String = "test11@msg.sharix-app.org"
     @Published var password: String = "test11_-"
 
-    var isShowError: String? = nil
+    func login(_ completion: @escaping (Bool) -> Void) {
+		XMPPController.shared.login(with: login, and: password)
+		XMPPController.shared.connect()
 
-    func didTouchLogIn(_ completion: @escaping (Bool) -> Void) {
-        self.manager.setupStream(with: login, password: password)
-        self.manager.connect()
         completion(true)
     }
 }

+ 3 - 3
Chat/UI/Chat/ChatView.swift

@@ -25,9 +25,9 @@ struct ChatView: View, KeyboardReadable {
                 ScrollViewReader { value in
                     VStack {
                         withAnimation {
-                            ForEach(viewModel.messages, id: \.self) { message in
+							ForEach(viewModel.messages, id: \.id) { message in
                                 HStack {
-                                    if message.from?.bare == StreamManager.shared.stream.myJID?.bare {
+                                    if message.fromID == XMPPController.shared.xmppStream.myJID?.bare {
                                         Spacer(minLength: 40)
                                         MessageView(text: message.body ?? "-", time: "", isSelf: true)
                                     } else {
@@ -77,7 +77,7 @@ struct ChatView: View, KeyboardReadable {
             .padding(.vertical, 6)
             .background()
         }
-        .navigationTitle(viewModel.manager.room.roomJID.user ?? "Room")
+        .navigationTitle(viewModel.room.roomJID.user ?? "Room")
         .navigationBarTitleDisplayMode(.inline)
         .toolbar {
             ToolbarItem(placement: .navigationBarTrailing) {

+ 71 - 13
Chat/UI/Chat/ChatViewModel.swift

@@ -14,30 +14,55 @@ final class ChatViewModelExample {
 }
 
 final class ChatViewModel: NSObject, ObservableObject {
-    let manager: RoomManager
+	let room: XMPPRoom
+	let storage: XMPPRoomMemoryStorage
+	let mam: XMPPMessageArchiveManagement
+
+	let jid: XMPPJID?
 
     @Published var messageText: String = ""
-    @Published var messages: [XMPPMessage] = []
+    @Published var messages: [Message] = []
 
     init(with jidString: String) {
-        self.manager = RoomManager(with: jidString)
-        super.init()
+		self.storage = XMPPRoomMemoryStorage()
+		self.room = XMPPRoom(roomStorage: self.storage, jid: XMPPJID(string: jidString)!)
+		self.mam = XMPPMessageArchiveManagement()
+
+		self.jid = XMPPJID(string: jidString)
+
+		super.init()
+
+		self.room.activate(XMPPController.shared.xmppStream)
+		self.mam.activate(XMPPController.shared.xmppStream)
+		self.room.join(usingNickname: XMPPController.shared.xmppStream.myJID?.user ?? "Test", history: nil)
+
+		self.room.addDelegate(self, delegateQueue: DispatchQueue.main)
+		self.mam.addDelegate(self, delegateQueue: DispatchQueue.main)
     }
 
     func fetchMessages() {
-        self.manager.fetchMessages()
-        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
-            self?.messages = self?.manager.messages ?? ChatViewModelExample.messages.map { text in
-                let message = XMPPMessage()
-                message.addBody(text)
-                return message
-            }
-        }
+		self.messages.removeAll()
+
+		if self.room.isJoined {
+			self.mam.retrieveMessageArchive(at: self.room.roomJID.bareJID, withFields: nil, with: nil)
+		} else {
+			let field = DDXMLElement(name: "field")
+			field.addAttribute(withName: "var", stringValue: "with")
+			field.addChild(DDXMLElement(name: "value", stringValue: self.room.roomJID.bare))
+
+			self.mam.retrieveMessageArchive(at: nil, withFields: [field], with: nil)
+		}
     }
 
     func sendMessage() {
         if !self.messageText.isEmpty {
-            manager.sendMessage(self.messageText)
+			let xmppMessage = XMPPMessage(messageType: room.isJoined ? .chat : .normal, to: self.room.roomJID.bareJID)
+			xmppMessage.addBody(messageText)
+			if self.room.isJoined {
+				self.room.send(xmppMessage)
+			} else {
+				XMPPController.shared.xmppStream.send(xmppMessage)
+			}
             self.messageText = ""
         }
     }
@@ -48,3 +73,36 @@ extension ChatViewModel: XMPPRoomDelegate {
         print(message.debugDescription)
     }
 }
+
+extension ChatViewModel: XMPPRoomMemoryStorageDelegate {
+	func xmppRoomMemoryStorage(
+		_ sender: XMPPRoomMemoryStorage!,
+		didReceiveMessage message: XMPPRoomMessageMemoryStorageObject!,
+		fromOccupant occupant: XMPPRoomOccupantMemoryStorageObject!,
+		at index: UInt,
+		in allMessages: [Any]!
+	) {
+		debugPrint(message.debugDescription)
+	}
+}
+
+extension ChatViewModel: XMPPMessageArchiveManagementDelegate {
+	func xmppMessageArchiveManagement(
+		_ xmppMessageArchiveManagement: XMPPMessageArchiveManagement,
+		didReceiveMAMMessage message: XMPPMessage
+	) {
+		if let result = message.children?.first,
+		   let forwarded = result.children?.first,
+		   let msg = forwarded.children?.first as? DDXMLElement {
+			let xmppmsg = XMPPMessage(from: msg)
+			if xmppmsg.isMessageWithBody, let body = xmppmsg.body, let from = xmppmsg.from?.bare {
+				let readyMessage = Message(id: UUID().uuidString, body: body, fromID: from)
+				self.messages.append(readyMessage)
+			}
+		}
+	}
+
+	func xmppMessageArchiveManagement(_ xmppMessageArchiveManagement: XMPPMessageArchiveManagement, didFinishReceivingMessagesWith resultSet: XMPPResultSet) {
+		debugPrint("FINISH MAM")
+	}
+}

+ 15 - 20
Chat/UI/ChatList/ChatListViewModel.swift

@@ -9,8 +9,8 @@ import Foundation
 import XMPPFramework
 import XMPPFrameworkSwift
 
-final class ChatListViewModel: ObservableObject {
-    let manager = RosterManager()
+final class ChatListViewModel: NSObject, ObservableObject {
+	let manager = XMPPController.shared
 
     @Published var users: [User] = []
 
@@ -20,26 +20,21 @@ final class ChatListViewModel: ObservableObject {
 
     var timer: Timer?
 
-    init() {
-        self.timer = Timer.scheduledTimer(
-            timeInterval: 2,
-            target: self,
-            selector: #selector(fetchChatList),
-            userInfo: nil,
-            repeats: true
-        )
+    override init() {
+		super.init()
+		self.timer = Timer(timeInterval: 2, repeats: true, block: { [weak self] timer in
+			self?.fetchChatList()
+			if !(self?.users.isEmpty ?? true) {
+				timer.invalidate()
+			}
+		})
     }
 
-    @objc
     public func fetchChatList() {
-        if users.isEmpty {
-            let xmppUsers = manager.storage.sortedUsersByAvailabilityName() as? [XMPPUser]
-            guard let users = xmppUsers?.compactMap({ User(jidString: $0.jid.bare, nickname: $0.nickname) }) else {
-                return
-            }
-            self.users = users
-        } else {
-            self.timer?.invalidate()
-        }
+		let xmppUsers = manager.xmppRosterStorage.sortedUsersByAvailabilityName() as? [XMPPUser]
+		guard let users = xmppUsers?.compactMap({ User(jidString: $0.jid.bare, nickname: $0.nickname) }) else {
+			return
+		}
+		self.users = users
     }
 }

+ 12 - 4
Chat/UI/ContentView.swift

@@ -22,14 +22,14 @@ struct ContentView: View {
                         ChatListView(viewModel: contactsViewModel)
                             .navigationViewStyle(StackNavigationViewStyle())
                             .tabItem {
-                                Label("Контакты", systemImage: "person.crop.circle")
+								Label(Tab.contacts.string, systemImage: "person.crop.circle")
                             }
                             .tag(Tab.contacts)
 
                         RoomsListView(viewModel: roomsViewModel)
                             .navigationViewStyle(StackNavigationViewStyle())
                             .tabItem {
-                                Label("Чаты", systemImage: "bubble.left.and.bubble.right")
+								Label(Tab.rooms.string, systemImage: "bubble.left.and.bubble.right")
                             }
                             .tag(Tab.rooms)
 
@@ -37,7 +37,7 @@ struct ContentView: View {
                             .navigationBarTitleDisplayMode(.inline)
                             .navigationViewStyle(StackNavigationViewStyle())
                             .tabItem {
-                                Label("Настройки", systemImage: "gear")
+								Label(Tab.settings.string, systemImage: "gear")
                             }
                             .tag(Tab.settings)
                     }
@@ -60,7 +60,15 @@ struct ContentView: View {
     enum Tab {
         case contacts
         case rooms
-        case settings
+		case settings
+
+		var string: String {
+			switch self {
+			case .contacts: return "Контакты"
+			case .rooms: return "Чаты"
+			case .settings: return "Настройки"
+			}
+		}
     }
 }
 

+ 1 - 1
Chat/UI/Rooms/RoomsListView.swift

@@ -69,7 +69,7 @@ struct RoomsListView: View {
         .toolbar {
             ToolbarItem(placement: .navigationBarTrailing) {
                 Button {
-                    viewModel.fetchChatList()
+                    viewModel.fetchRooms()
                 } label: {
                     Image(systemName: "arrow.counterclockwise")
                 }

+ 27 - 22
Chat/UI/Rooms/RoomsListViewModel.swift

@@ -9,29 +9,34 @@ import Foundation
 import XMPPFramework
 import XMPPFrameworkSwift
 
-final class RoomsListViewModel: ObservableObject {
-    let manager = MUCManager()
+final class RoomsListViewModel: NSObject, ObservableObject {
+	let muc: XMPPMUCLight = XMPPMUCLight()
 
-    @Published var rooms: [Room] = []
-    var timer: Timer?
+	@Published var rooms: [Room] = []
+	var timer: Timer?
 
-    init() {
-        self.timer = Timer.scheduledTimer(
-            timeInterval: 2,
-            target: self,
-            selector: #selector(fetchChatList),
-            userInfo: nil,
-            repeats: true
-        )
-    }
+	override init() {
+		super.init()
+		self.muc.activate(XMPPController.shared.xmppStream)
+		self.muc.addDelegate(self, delegateQueue: .main)
 
-    @objc
-    public func fetchChatList() {
-        if rooms.isEmpty {
-            self.manager.fetchRooms()
-            self.rooms = self.manager.rooms
-        } else {
-            self.timer?.invalidate()
-        }
-    }
+		self.timer = Timer(timeInterval: 2, repeats: true, block: { [weak self] timer in
+			self?.fetchRooms()
+			if !(self?.rooms.isEmpty ?? false) {
+				timer.invalidate()
+			}
+		})
+	}
+
+	func fetchRooms() {
+		let success = self.muc.discoverRooms(forServiceNamed: "chat.msg.sharix-app.org")
+		print(success)
+	}
+}
+
+extension RoomsListViewModel: XMPPMUCLightDelegate {
+	func xmppMUCLight(_ sender: XMPPMUCLight, didDiscoverRooms rooms: [DDXMLElement], forServiceNamed serviceName: String) {
+		debugPrint(rooms)
+		self.rooms = rooms.map({ Room(jidString: $0.attributeStringValue(forName: "jid") ?? "", name: $0.attributeStringValue(forName: "name") ?? "") })
+	}
 }