Add MessageListView & MessageView
This commit is contained in:
parent
077686d0fd
commit
7ced062950
|
@ -1,6 +1,15 @@
|
|||
import CoreData
|
||||
|
||||
extension Room {
|
||||
var messagesRequest: NSFetchRequest<Message> {
|
||||
let request = Message.fetchRequest()
|
||||
|
||||
request.predicate = NSPredicate(format: "room == %@", self)
|
||||
request.sortDescriptors = [NSSortDescriptor(keyPath: \Message.ts, ascending: true)]
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
var lastMessage: Message? {
|
||||
let request = Message.fetchRequest()
|
||||
|
||||
|
|
|
@ -52,3 +52,14 @@ public final class Server: NSManagedObject {
|
|||
extension Server: Identifiable {
|
||||
|
||||
}
|
||||
|
||||
extension Server {
|
||||
var roomsRequest: NSFetchRequest<Room> {
|
||||
let request = Room.fetchRequest()
|
||||
|
||||
request.predicate = NSPredicate(format: "archived == false")
|
||||
request.sortDescriptors = [NSSortDescriptor(keyPath: \Room.ts, ascending: false)]
|
||||
|
||||
return request
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
extension Date {
|
||||
static func - (lhs: Date, rhs: Date) -> TimeInterval {
|
||||
return lhs.timeIntervalSinceReferenceDate - rhs.timeIntervalSinceReferenceDate
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
import Foundation
|
||||
|
||||
final class MessageFormatter {
|
||||
private let message: Message
|
||||
private let previousMessage: Message?
|
||||
|
||||
init(message: Message, previousMessage: Message?) {
|
||||
self.message = message
|
||||
self.previousMessage = previousMessage
|
||||
}
|
||||
|
||||
func hasDateSeparator() -> Bool {
|
||||
if let previousMessage,
|
||||
let previousMessageTS = previousMessage.ts,
|
||||
let messageTS = message.ts,
|
||||
Calendar.current.isDate(previousMessageTS, inSameDayAs: messageTS) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isHeader() -> Bool {
|
||||
if let previousMessage,
|
||||
let previousMessageTS = previousMessage.ts,
|
||||
let messageTS = message.ts,
|
||||
Calendar.current.isDate(previousMessageTS, inSameDayAs: messageTS),
|
||||
previousMessage.user?.username == message.user?.username,
|
||||
!(previousMessage.groupable == false || message.groupable == false || message.room?.broadcast == true),
|
||||
messageTS - previousMessageTS < 300,
|
||||
message.t != "rm",
|
||||
previousMessage.t != "rm" {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func info() -> String? {
|
||||
switch message.t {
|
||||
case "rm":
|
||||
return "Message Removed"
|
||||
case "e2e":
|
||||
return "Encrypted message"
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func date() -> String? {
|
||||
guard let ts = message.ts else { return nil }
|
||||
|
||||
let dateFormatter = DateFormatter()
|
||||
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeZone = TimeZone.current
|
||||
dateFormatter.timeStyle = .none
|
||||
dateFormatter.dateStyle = .long
|
||||
|
||||
return dateFormatter.string(from: ts)
|
||||
}
|
||||
|
||||
func time() -> String? {
|
||||
guard let ts = message.ts else { return nil }
|
||||
|
||||
let dateFormatter = DateFormatter()
|
||||
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeZone = TimeZone.current
|
||||
dateFormatter.timeStyle = .short
|
||||
dateFormatter.dateStyle = .none
|
||||
|
||||
return dateFormatter.string(from: ts)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
import Foundation
|
||||
|
||||
final class RoomFormatter {
|
||||
private let room: Room
|
||||
private let server: Server
|
||||
|
||||
init(room: Room, server: Server) {
|
||||
self.room = room
|
||||
self.server = server
|
||||
}
|
||||
|
||||
var title: String? {
|
||||
if isGroupChat, (room.name == nil || room.name?.isEmpty == true), let usernames = room.usernames {
|
||||
return usernames
|
||||
.filter { $0 == server.loggedUser.username }
|
||||
.sorted()
|
||||
.joined(separator: ", ")
|
||||
}
|
||||
|
||||
if room.t != "d" {
|
||||
if let fname = room.fname {
|
||||
return fname
|
||||
} else if let name = room.name {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
if room.prid != nil || server.useRealName {
|
||||
return room.fname
|
||||
}
|
||||
|
||||
return room.name
|
||||
}
|
||||
|
||||
var isGroupChat: Bool {
|
||||
if let uids = room.uids, uids.count > 2 {
|
||||
return true
|
||||
}
|
||||
|
||||
if let usernames = room.usernames, usernames.count > 2 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,12 +1,18 @@
|
|||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"Message" : {
|
||||
|
||||
},
|
||||
"Rooms" : {
|
||||
|
||||
},
|
||||
"Servers" : {
|
||||
"comment" : "View title for ServerList.",
|
||||
"extractionState" : "manual"
|
||||
},
|
||||
"This room is read only" : {
|
||||
|
||||
},
|
||||
"Try Again" : {
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import Combine
|
||||
import Foundation
|
||||
|
||||
final class MessageComposerViewModel: ObservableObject {
|
||||
var isReadOnly: Bool {
|
||||
room.isReadOnly
|
||||
}
|
||||
|
||||
private let room: Room
|
||||
private let client: RocketChatClientProtocol
|
||||
private let database: RocketChatDatabase
|
||||
private let server: Server
|
||||
|
||||
init(client: RocketChatClientProtocol, database: RocketChatDatabase, room: Room, server: Server) {
|
||||
self.client = client
|
||||
self.database = database
|
||||
self.room = room
|
||||
self.server = server
|
||||
}
|
||||
|
||||
func sendMessage(_ msg: String) {
|
||||
guard let rid = room.id else { return }
|
||||
|
||||
let messageID = database.createTempMessage(msg: msg, in: room, for: server.loggedUser)
|
||||
|
||||
client.sendMessage(id: messageID, rid: rid, msg: msg)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.subscribe(Subscribers.Sink { completion in
|
||||
if case .failure(let error) = completion {
|
||||
print(error)
|
||||
}
|
||||
} receiveValue: { [weak self] messageResponse in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let message = messageResponse.message
|
||||
|
||||
database.process(updatedMessage: message, in: room)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol MessageListViewModeling {
|
||||
func composerViewModel() -> MessageComposerViewModel
|
||||
func messageViewModel(for message: Message, and previousMessage: Message?) -> MessageViewModel
|
||||
|
||||
func loadMessages(completionHandler: (() -> Void)?)
|
||||
func markAsRead()
|
||||
func stop()
|
||||
}
|
||||
|
||||
final class MessageListViewModel: ObservableObject {
|
||||
@Published private var server: Server
|
||||
|
||||
@Published private(set) var room: Room
|
||||
@Published private(set) var lastMessageID: String?
|
||||
|
||||
private let client: RocketChatClientProtocol
|
||||
private let database: RocketChatDatabase
|
||||
private let formatter: RoomFormatter
|
||||
|
||||
private var timer: Timer?
|
||||
|
||||
private var syncCancellable: AnyCancellable?
|
||||
|
||||
var title: String {
|
||||
formatter.title ?? ""
|
||||
}
|
||||
|
||||
init(
|
||||
client: RocketChatClientProtocol,
|
||||
database: RocketChatDatabase,
|
||||
room: Room,
|
||||
server: Server
|
||||
) {
|
||||
self.client = client
|
||||
self.database = database
|
||||
self.room = room
|
||||
self.server = server
|
||||
self.formatter = RoomFormatter(room: room, server: server)
|
||||
}
|
||||
|
||||
deinit {
|
||||
print("MessageListViewModel.deinit \(room.fname ?? "")")
|
||||
}
|
||||
|
||||
private func scheduledSync(in room: Room) -> Timer {
|
||||
Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { [weak self] _ in
|
||||
self?.syncMessages(in: room)
|
||||
}
|
||||
}
|
||||
|
||||
private func syncMessages(in room: Room) {
|
||||
guard let rid = room.id else { return }
|
||||
|
||||
syncCancellable = client.syncMessages(rid: rid, updatedSince: room.updatedSince ?? Date())
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { completion in
|
||||
if case .failure(let error) = completion {
|
||||
print(error)
|
||||
}
|
||||
} receiveValue: { messagesResponse in
|
||||
let messages = messagesResponse.result.updated
|
||||
|
||||
for message in messages {
|
||||
self.database.process(updatedMessage: message, in: room)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadMessages(in room: Room, latest: Date?) {
|
||||
guard let rid = room.id else { return }
|
||||
|
||||
room.updatedSince = latest
|
||||
|
||||
client.getHistory(rid: rid, t: room.t ?? "", latest: latest ?? Date())
|
||||
.receive(on: DispatchQueue.main)
|
||||
.subscribe(Subscribers.Sink { completion in
|
||||
if case .failure(let error) = completion {
|
||||
print(error)
|
||||
}
|
||||
} receiveValue: { messagesResponse in
|
||||
let messages = messagesResponse.messages
|
||||
|
||||
for message in messages {
|
||||
self.database.process(updatedMessage: message, in: room)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extension MessageListViewModel: MessageListViewModeling {
|
||||
func composerViewModel() -> MessageComposerViewModel {
|
||||
MessageComposerViewModel(client: client, database: database, room: room, server: server)
|
||||
}
|
||||
|
||||
func messageViewModel(for message: Message, and previousMessage: Message?) -> MessageViewModel {
|
||||
MessageViewModel(message: message, previousMessage: previousMessage, server: server)
|
||||
}
|
||||
|
||||
func loadMessages(completionHandler: (() -> Void)? = nil) {
|
||||
loadMessages(in: room, latest: room.lastMessage?.ts)
|
||||
}
|
||||
|
||||
func markAsRead() {
|
||||
guard (room.unread > 0 || room.alert), let rid = room.id else {
|
||||
return
|
||||
}
|
||||
|
||||
client.sendRead(rid: rid)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.subscribe(Subscribers.Sink { completion in
|
||||
if case .failure(let error) = completion {
|
||||
print(error)
|
||||
}
|
||||
} receiveValue: { _ in
|
||||
self.database.markRead(in: rid)
|
||||
})
|
||||
}
|
||||
|
||||
func stop() {
|
||||
syncCancellable?.cancel()
|
||||
timer?.invalidate()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import Foundation
|
||||
|
||||
final class MessageViewModel: ObservableObject {
|
||||
@Published private(set) var server: Server?
|
||||
@Published private(set) var message: Message
|
||||
@Published private(set) var previousMessage: Message?
|
||||
|
||||
let messageFormatter: MessageFormatter
|
||||
|
||||
init(message: Message, previousMessage: Message? = nil, server: Server?) {
|
||||
self.message = message
|
||||
self.previousMessage = previousMessage
|
||||
self.messageFormatter = MessageFormatter(message: message, previousMessage: previousMessage)
|
||||
self.server = server
|
||||
}
|
||||
|
||||
var sender: String? {
|
||||
server?.useRealName == true ? message.user?.name : message.user?.username
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
import Combine
|
||||
import CoreData
|
||||
import Foundation
|
||||
|
||||
protocol RoomListViewModeling {
|
||||
func viewModel(for room: Room) -> RoomViewModel
|
||||
func roomViewModel(for room: Room) -> RoomViewModel
|
||||
func messageListViewModel(for room: Room) -> MessageListViewModel
|
||||
|
||||
func loadRooms()
|
||||
func logout()
|
||||
|
@ -16,6 +18,10 @@ final class RoomListViewModel: ObservableObject {
|
|||
let server: Server
|
||||
}
|
||||
|
||||
var viewContext: NSManagedObjectContext {
|
||||
dependencies.database.viewContext
|
||||
}
|
||||
|
||||
private let dependencies: Dependencies
|
||||
|
||||
private var loadCancellable: AnyCancellable?
|
||||
|
@ -45,8 +51,20 @@ final class RoomListViewModel: ObservableObject {
|
|||
// MARK: - RoomListViewModeling
|
||||
|
||||
extension RoomListViewModel: RoomListViewModeling {
|
||||
func viewModel(for room: Room) -> RoomViewModel {
|
||||
RoomViewModel(room: room, server: dependencies.server)
|
||||
func roomViewModel(for room: Room) -> RoomViewModel {
|
||||
RoomViewModel(
|
||||
room: room,
|
||||
server: dependencies.server
|
||||
)
|
||||
}
|
||||
|
||||
func messageListViewModel(for room: Room) -> MessageListViewModel {
|
||||
MessageListViewModel(
|
||||
client: dependencies.client,
|
||||
database: dependencies.database,
|
||||
room: room,
|
||||
server: dependencies.server
|
||||
)
|
||||
}
|
||||
|
||||
func loadRooms() {
|
||||
|
|
|
@ -4,32 +4,12 @@ final class RoomViewModel: ObservableObject {
|
|||
@Published var room: Room
|
||||
@Published var server: Server
|
||||
|
||||
let formatter: RoomFormatter
|
||||
|
||||
init(room: Room, server: Server) {
|
||||
self.room = room
|
||||
self.server = server
|
||||
}
|
||||
|
||||
var title: String? {
|
||||
if isGroupChat, (room.name == nil || room.name?.isEmpty == true), let usernames = room.usernames {
|
||||
return usernames
|
||||
.filter { $0 == server.loggedUser.username }
|
||||
.sorted()
|
||||
.joined(separator: ", ")
|
||||
}
|
||||
|
||||
if room.t != "d" {
|
||||
if let fname = room.fname {
|
||||
return fname
|
||||
} else if let name = room.name {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
if room.prid != nil || server.useRealName {
|
||||
return room.fname
|
||||
}
|
||||
|
||||
return room.name
|
||||
self.formatter = RoomFormatter(room: room, server: server)
|
||||
}
|
||||
|
||||
var iconName: String? {
|
||||
|
@ -43,7 +23,7 @@ final class RoomViewModel: ObservableObject {
|
|||
return "channel-private"
|
||||
} else if room.t == "c" {
|
||||
return "channel-public"
|
||||
} else if room.t == "d", isGroupChat {
|
||||
} else if room.t == "d", formatter.isGroupChat {
|
||||
return "message"
|
||||
}
|
||||
|
||||
|
@ -82,18 +62,6 @@ final class RoomViewModel: ObservableObject {
|
|||
return "\(username): \(message)"
|
||||
}
|
||||
|
||||
var isGroupChat: Bool {
|
||||
if let uids = room.uids, uids.count > 2 {
|
||||
return true
|
||||
}
|
||||
|
||||
if let usernames = room.usernames, usernames.count > 2 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var updatedAt: String? {
|
||||
guard let ts = room.ts else {
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MessageComposerView: View {
|
||||
@ObservedObject private var viewModel: MessageComposerViewModel
|
||||
|
||||
init(viewModel: MessageComposerViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
@State private var message = ""
|
||||
|
||||
var body: some View {
|
||||
if viewModel.isReadOnly {
|
||||
HStack {
|
||||
Spacer()
|
||||
Text("This room is read only")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
.foregroundStyle(.white)
|
||||
.multilineTextAlignment(.center)
|
||||
Spacer()
|
||||
}
|
||||
} else {
|
||||
TextField("Message", text: $message)
|
||||
.submitLabel(.send)
|
||||
.onSubmit(send)
|
||||
}
|
||||
}
|
||||
|
||||
func send() {
|
||||
guard !message.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
||||
viewModel.sendMessage(message)
|
||||
message = ""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MessageListView: View {
|
||||
@StateObject private var viewModel: MessageListViewModel
|
||||
|
||||
@FetchRequest<Message> private var messages: FetchedResults<Message>
|
||||
|
||||
init(viewModel: MessageListViewModel) {
|
||||
_viewModel = StateObject(wrappedValue: viewModel)
|
||||
_messages = FetchRequest(fetchRequest: viewModel.room.messagesRequest, animation: .none)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ScrollViewReader { reader in
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
ForEach(messages.indices, id: \.self) { index in
|
||||
let message = messages[index]
|
||||
let previousMessage = messages.indices.contains(index - 1) ? messages[index - 1] : nil
|
||||
|
||||
MessageView(viewModel: viewModel.messageViewModel(for: message, and: previousMessage))
|
||||
.id(message.id)
|
||||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
|
||||
MessageComposerView(viewModel: viewModel.composerViewModel())
|
||||
.padding(.top)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
.navigationTitle(viewModel.title)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.onAppear {
|
||||
viewModel.loadMessages {
|
||||
reader.scrollTo(messages.last?.id, anchor: .bottom)
|
||||
}
|
||||
|
||||
viewModel.markAsRead()
|
||||
}
|
||||
.onDisappear {
|
||||
viewModel.stop()
|
||||
}
|
||||
.onReceive(messages.publisher) { _ in
|
||||
viewModel.markAsRead()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import SwiftUI
|
||||
|
||||
struct MessageView: View {
|
||||
@ObservedObject private var viewModel: MessageViewModel
|
||||
|
||||
init(viewModel: MessageViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
if viewModel.messageFormatter.hasDateSeparator() {
|
||||
HStack(alignment: .center) {
|
||||
VStack(alignment: .center) {
|
||||
Divider()
|
||||
.overlay(.gray)
|
||||
}
|
||||
Text(viewModel.messageFormatter.date() ?? "")
|
||||
.lineLimit(1)
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.gray)
|
||||
.layoutPriority(1)
|
||||
VStack(alignment: .center) {
|
||||
Divider()
|
||||
.overlay(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
if viewModel.messageFormatter.isHeader() {
|
||||
HStack(alignment: .center) {
|
||||
Text(viewModel.sender ?? "")
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
.foregroundStyle(.primary)
|
||||
Text(viewModel.messageFormatter.time() ?? "")
|
||||
.lineLimit(1)
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
if let text = viewModel.messageFormatter.info() {
|
||||
Text(text)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.white)
|
||||
.italic()
|
||||
} else if let text = viewModel.message.msg {
|
||||
Text(text)
|
||||
.font(.caption)
|
||||
.foregroundStyle(viewModel.message.status == "temp" ? .secondary : .primary)
|
||||
}
|
||||
// if let attachments = message.attachments?.allObjects as? Array<Attachment> {
|
||||
// ForEach(attachments) { attachment in
|
||||
// AttachmentView(attachment: attachment)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +1,21 @@
|
|||
import SwiftUI
|
||||
|
||||
struct RoomListView: View {
|
||||
@StateObject var viewModel: RoomListViewModel
|
||||
@StateObject private var viewModel: RoomListViewModel
|
||||
|
||||
@FetchRequest(
|
||||
entity: Room.entity(),
|
||||
sortDescriptors: [
|
||||
NSSortDescriptor(keyPath: \Room.ts, ascending: false)
|
||||
],
|
||||
predicate: NSPredicate(format: "archived == false"),
|
||||
animation: .default
|
||||
)
|
||||
private var rooms: FetchedResults<Room>
|
||||
@FetchRequest<Room> private var rooms: FetchedResults<Room>
|
||||
|
||||
init(dependencies: RoomListViewModel.Dependencies) {
|
||||
_viewModel = StateObject(wrappedValue: RoomListViewModel(dependencies: dependencies))
|
||||
_rooms = FetchRequest(fetchRequest: dependencies.server.roomsRequest)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
ForEach(rooms) { room in
|
||||
RoomView(viewModel: viewModel.viewModel(for: room))
|
||||
NavigationLink(value: room) {
|
||||
RoomView(viewModel: viewModel.roomViewModel(for: room))
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
|
@ -28,6 +23,10 @@ struct RoomListView: View {
|
|||
}
|
||||
.navigationTitle("Rooms")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationDestination(for: Room.self) { room in
|
||||
MessageListView(viewModel: viewModel.messageListViewModel(for: room))
|
||||
.environment(\.managedObjectContext, viewModel.viewContext)
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .automatic) {
|
||||
Button("Servers") {
|
||||
|
|
|
@ -16,7 +16,7 @@ struct RoomView: View {
|
|||
.frame(width: 16, height: 16)
|
||||
.scaledToFit()
|
||||
}
|
||||
Text(viewModel.title ?? "")
|
||||
Text(viewModel.formatter.title ?? "")
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.fontWeight(isUnread ? .bold : .medium)
|
||||
|
|
|
@ -46,7 +46,6 @@ struct ServerListView: View {
|
|||
}
|
||||
}
|
||||
.navigationTitle("Servers")
|
||||
.padding()
|
||||
.onAppear {
|
||||
viewModel.loadServers()
|
||||
}
|
||||
|
|
|
@ -67,6 +67,15 @@
|
|||
1E29A30E2B58608C0093C03C /* LoggedUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A30D2B58608C0093C03C /* LoggedUser.swift */; };
|
||||
1E29A3102B5865B80093C03C /* RoomViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A30F2B5865B80093C03C /* RoomViewModel.swift */; };
|
||||
1E29A3122B5866090093C03C /* Room.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3112B5866090093C03C /* Room.swift */; };
|
||||
1E29A3142B5868D80093C03C /* MessageListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3132B5868D80093C03C /* MessageListViewModel.swift */; };
|
||||
1E29A3162B5868DF0093C03C /* MessageListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3152B5868DF0093C03C /* MessageListView.swift */; };
|
||||
1E29A3182B5868E50093C03C /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3172B5868E50093C03C /* MessageView.swift */; };
|
||||
1E29A31A2B5868EE0093C03C /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3192B5868EE0093C03C /* MessageViewModel.swift */; };
|
||||
1E29A31D2B5871B60093C03C /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A31C2B5871B60093C03C /* Date+Extensions.swift */; };
|
||||
1E29A3202B5871C80093C03C /* RoomFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A31F2B5871C80093C03C /* RoomFormatter.swift */; };
|
||||
1E29A3222B5871CE0093C03C /* MessageFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3212B5871CE0093C03C /* MessageFormatter.swift */; };
|
||||
1E29A3242B5874FF0093C03C /* MessageComposerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3232B5874FF0093C03C /* MessageComposerView.swift */; };
|
||||
1E29A3262B58752D0093C03C /* MessageComposerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E29A3252B58752D0093C03C /* MessageComposerViewModel.swift */; };
|
||||
1E2F615B25128F9A00871711 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F615A25128F9A00871711 /* API.swift */; };
|
||||
1E2F615D25128FA300871711 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F615C25128FA300871711 /* Response.swift */; };
|
||||
1E2F61642512955D00871711 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F61632512955D00871711 /* HTTPMethod.swift */; };
|
||||
|
@ -361,6 +370,15 @@
|
|||
1E29A30D2B58608C0093C03C /* LoggedUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedUser.swift; sourceTree = "<group>"; };
|
||||
1E29A30F2B5865B80093C03C /* RoomViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomViewModel.swift; sourceTree = "<group>"; };
|
||||
1E29A3112B5866090093C03C /* Room.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Room.swift; sourceTree = "<group>"; };
|
||||
1E29A3132B5868D80093C03C /* MessageListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListViewModel.swift; sourceTree = "<group>"; };
|
||||
1E29A3152B5868DF0093C03C /* MessageListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListView.swift; sourceTree = "<group>"; };
|
||||
1E29A3172B5868E50093C03C /* MessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageView.swift; sourceTree = "<group>"; };
|
||||
1E29A3192B5868EE0093C03C /* MessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewModel.swift; sourceTree = "<group>"; };
|
||||
1E29A31C2B5871B60093C03C /* Date+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
|
||||
1E29A31F2B5871C80093C03C /* RoomFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomFormatter.swift; sourceTree = "<group>"; };
|
||||
1E29A3212B5871CE0093C03C /* MessageFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageFormatter.swift; sourceTree = "<group>"; };
|
||||
1E29A3232B5874FF0093C03C /* MessageComposerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageComposerView.swift; sourceTree = "<group>"; };
|
||||
1E29A3252B58752D0093C03C /* MessageComposerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageComposerViewModel.swift; sourceTree = "<group>"; };
|
||||
1E2F615A25128F9A00871711 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
|
||||
1E2F615C25128FA300871711 /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = "<group>"; };
|
||||
1E2F61632512955D00871711 /* HTTPMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = "<group>"; };
|
||||
|
@ -628,6 +646,23 @@
|
|||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1E29A31B2B5871AC0093C03C /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E29A31C2B5871B60093C03C /* Date+Extensions.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1E29A31E2B5871BE0093C03C /* Formatters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E29A31F2B5871C80093C03C /* RoomFormatter.swift */,
|
||||
1E29A3212B5871CE0093C03C /* MessageFormatter.swift */,
|
||||
);
|
||||
path = Formatters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1E2F61622512954500871711 /* Requests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -731,6 +766,9 @@
|
|||
1ED033B92B55B5F6004F4930 /* ServerView.swift */,
|
||||
1E29A2CB2B5857F50093C03C /* RoomListView.swift */,
|
||||
1E29A2CF2B58582F0093C03C /* RoomView.swift */,
|
||||
1E29A3152B5868DF0093C03C /* MessageListView.swift */,
|
||||
1E29A3172B5868E50093C03C /* MessageView.swift */,
|
||||
1E29A3232B5874FF0093C03C /* MessageComposerView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
|
@ -741,6 +779,9 @@
|
|||
1ED033B72B55B4BE004F4930 /* ServerListViewModel.swift */,
|
||||
1E29A2CD2B5857FC0093C03C /* RoomListViewModel.swift */,
|
||||
1E29A30F2B5865B80093C03C /* RoomViewModel.swift */,
|
||||
1E29A3132B5868D80093C03C /* MessageListViewModel.swift */,
|
||||
1E29A3192B5868EE0093C03C /* MessageViewModel.swift */,
|
||||
1E29A3252B58752D0093C03C /* MessageComposerViewModel.swift */,
|
||||
);
|
||||
path = ViewModels;
|
||||
sourceTree = "<group>";
|
||||
|
@ -748,6 +789,8 @@
|
|||
1ED0388F2B507B4C00C007D4 /* RocketChat Watch App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E29A31E2B5871BE0093C03C /* Formatters */,
|
||||
1E29A31B2B5871AC0093C03C /* Extensions */,
|
||||
1E29A2D12B585B070093C03C /* Client */,
|
||||
1ED033B42B55B495004F4930 /* ViewModels */,
|
||||
1ED033B12B55B47F004F4930 /* Views */,
|
||||
|
@ -1488,7 +1531,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "SOURCE_MAP=\"$TMPDIR/$(md5 -qs \"$CONFIGURATION_BUILD_DIR\")-main.jsbundle.map\" ../node_modules/@bugsnag/react-native/bugsnag-react-native-xcode.sh\n";
|
||||
shellScript = "# SOURCE_MAP=\"$TMPDIR/$(md5 -qs \"$CONFIGURATION_BUILD_DIR\")-main.jsbundle.map\" ../node_modules/@bugsnag/react-native/bugsnag-react-native-xcode.sh\n";
|
||||
};
|
||||
7F13D807CA5B7E43CE899DB3 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
@ -1762,19 +1805,25 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1E29A3242B5874FF0093C03C /* MessageComposerView.swift in Sources */,
|
||||
1EB375892B55DBFB00AEC3D7 /* Server.swift in Sources */,
|
||||
1E29A3162B5868DF0093C03C /* MessageListView.swift in Sources */,
|
||||
1E29A2F42B585B070093C03C /* SubscriptionsResponse.swift in Sources */,
|
||||
1E29A3142B5868D80093C03C /* MessageListViewModel.swift in Sources */,
|
||||
1E29A2F92B585B070093C03C /* SubscriptionsRequest.swift in Sources */,
|
||||
1E29A2F22B585B070093C03C /* HistoryResponse.swift in Sources */,
|
||||
1ED033BA2B55B5F6004F4930 /* ServerView.swift in Sources */,
|
||||
1E29A2D02B58582F0093C03C /* RoomView.swift in Sources */,
|
||||
1E29A2FD2B585B070093C03C /* RoomsRequest.swift in Sources */,
|
||||
1ED038CA2B50A58400C007D4 /* WatchConnection.swift in Sources */,
|
||||
1E29A3222B5871CE0093C03C /* MessageFormatter.swift in Sources */,
|
||||
1E29A3002B585B070093C03C /* JSONAdapter.swift in Sources */,
|
||||
1E29A3022B585B070093C03C /* DateCodingStrategy.swift in Sources */,
|
||||
1ED033B62B55B4A5004F4930 /* ServerListView.swift in Sources */,
|
||||
1E29A3202B5871C80093C03C /* RoomFormatter.swift in Sources */,
|
||||
1E29A3102B5865B80093C03C /* RoomViewModel.swift in Sources */,
|
||||
1E29A2FC2B585B070093C03C /* SendMessageRequest.swift in Sources */,
|
||||
1E29A3262B58752D0093C03C /* MessageComposerViewModel.swift in Sources */,
|
||||
1E29A30C2B585D1D0093C03C /* String+Extensions.swift in Sources */,
|
||||
1ED033CD2B55D671004F4930 /* RocketChatDatabase.swift in Sources */,
|
||||
1E29A3122B5866090093C03C /* Room.swift in Sources */,
|
||||
|
@ -1784,10 +1833,12 @@
|
|||
1E29A3072B585B070093C03C /* RocketChatError.swift in Sources */,
|
||||
1E29A2F12B585B070093C03C /* SendMessageResponse.swift in Sources */,
|
||||
1E29A30E2B58608C0093C03C /* LoggedUser.swift in Sources */,
|
||||
1E29A3182B5868E50093C03C /* MessageView.swift in Sources */,
|
||||
1E29A2FF2B585B070093C03C /* TokenAdapter.swift in Sources */,
|
||||
1E29A3052B585B070093C03C /* Request.swift in Sources */,
|
||||
1E29A2EF2B585B070093C03C /* RocketChatClient.swift in Sources */,
|
||||
1E29A2FB2B585B070093C03C /* MessagesRequest.swift in Sources */,
|
||||
1E29A31D2B5871B60093C03C /* Date+Extensions.swift in Sources */,
|
||||
1E29A2F62B585B070093C03C /* UserResponse.swift in Sources */,
|
||||
1ED033AE2B55B1CC004F4930 /* Default.xcdatamodeld in Sources */,
|
||||
1ED033BF2B55BF94004F4930 /* Storage.swift in Sources */,
|
||||
|
@ -1802,6 +1853,7 @@
|
|||
1E29A2F02B585B070093C03C /* AttachmentResponse.swift in Sources */,
|
||||
1ED038912B507B4C00C007D4 /* RocketChatApp.swift in Sources */,
|
||||
1E29A2CC2B5857F50093C03C /* RoomListView.swift in Sources */,
|
||||
1E29A31A2B5868EE0093C03C /* MessageViewModel.swift in Sources */,
|
||||
1ED033B82B55B4BE004F4930 /* ServerListViewModel.swift in Sources */,
|
||||
1ED033C42B55C65C004F4930 /* RocketChatAppRouter.swift in Sources */,
|
||||
1ED033B02B55B25A004F4930 /* Database.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue