Refactor ServerListView
This commit is contained in:
parent
91968be958
commit
16b2a123be
|
@ -5,25 +5,17 @@ protocol AppRouting {
|
|||
}
|
||||
|
||||
final class AppRouter: ObservableObject {
|
||||
@Storage(.currentServer) private var currentURL: URL?
|
||||
|
||||
@Published private(set) var route: Route = .serverList
|
||||
@Published private(set) var route: Route = .loading
|
||||
}
|
||||
|
||||
extension AppRouter: AppRouting {
|
||||
func route(to route: Route) {
|
||||
switch route {
|
||||
case .roomList(let server):
|
||||
currentURL = server.url
|
||||
case .serverList:
|
||||
break
|
||||
}
|
||||
|
||||
self.route = route
|
||||
}
|
||||
}
|
||||
|
||||
enum Route {
|
||||
enum Route: Equatable {
|
||||
case loading
|
||||
case serverList
|
||||
case roomList(Server)
|
||||
}
|
|
@ -3,8 +3,7 @@ import SwiftUI
|
|||
struct AppView: View {
|
||||
@Dependency private var database: Database
|
||||
@Dependency private var serversDB: ServersDatabase
|
||||
|
||||
@Storage(.currentServer) private var currentURL: URL?
|
||||
@Dependency private var stateProvider: StateProviding
|
||||
|
||||
@StateObject private var router: AppRouter
|
||||
|
||||
|
@ -15,12 +14,22 @@ struct AppView: View {
|
|||
var body: some View {
|
||||
NavigationStack {
|
||||
switch router.route {
|
||||
case .roomList(let server):
|
||||
RoomListView(server: server)
|
||||
.environment(\.managedObjectContext, database.viewContext)
|
||||
case .serverList:
|
||||
ServerListView(viewModel: ServerListViewModel())
|
||||
.environment(\.managedObjectContext, serversDB.viewContext)
|
||||
case .loading:
|
||||
ProgressView()
|
||||
case .roomList(let server):
|
||||
RoomListView(server: server)
|
||||
.environment(\.managedObjectContext, database.viewContext)
|
||||
case .serverList:
|
||||
ServerListView()
|
||||
.environment(\.managedObjectContext, serversDB.viewContext)
|
||||
}
|
||||
}
|
||||
.onChange(of: router.route) { newValue in
|
||||
switch newValue {
|
||||
case .roomList(let server):
|
||||
stateProvider.update(to: .loggedIn(server))
|
||||
case .serverList, .loading:
|
||||
stateProvider.update(to: .loggedOut)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
|
@ -29,11 +38,10 @@ struct AppView: View {
|
|||
}
|
||||
|
||||
private func loadRoute() {
|
||||
if let currentURL, let server = serversDB.server(url: currentURL) {
|
||||
switch stateProvider.state {
|
||||
case .loggedIn(let server):
|
||||
router.route(to: .roomList(server))
|
||||
} else if serversDB.servers().count == 1, let server = serversDB.servers().first {
|
||||
router.route(to: .roomList(server))
|
||||
} else {
|
||||
case .loggedOut:
|
||||
router.route(to: .serverList)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ final class RocketChatClient: NSObject {
|
|||
@Dependency private var serverProvider: ServerProviding
|
||||
|
||||
private var server: Server {
|
||||
serverProvider.current()
|
||||
serverProvider.server
|
||||
}
|
||||
|
||||
private lazy var session = URLSession(
|
||||
|
|
|
@ -29,7 +29,7 @@ final class RocketChatDatabase: Database {
|
|||
}()
|
||||
|
||||
private lazy var container: NSPersistentContainer = {
|
||||
let name = serverProvider.current().url.host ?? "default"
|
||||
let name = serverProvider.server.url.host ?? "default"
|
||||
|
||||
let container = NSPersistentContainer(name: name, managedObjectModel: Self.model)
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ extension MessageSender: MessageSending {
|
|||
func sendMessage(_ msg: String, in room: Room) {
|
||||
guard let rid = room.id else { return }
|
||||
|
||||
let messageID = database.createTempMessage(msg: msg, in: room, for: serverProvider.current().loggedUser)
|
||||
let messageID = database.createTempMessage(msg: msg, in: room, for: serverProvider.server.loggedUser)
|
||||
|
||||
client.sendMessage(id: messageID, rid: rid, msg: msg)
|
||||
.receive(on: DispatchQueue.main)
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
import Combine
|
||||
import Foundation
|
||||
import WatchConnectivity
|
||||
|
||||
enum ServersLoadingError: Error, Equatable {
|
||||
case unactive
|
||||
case unreachable
|
||||
case locked
|
||||
case undecodable(Error)
|
||||
|
||||
static func == (lhs: ServersLoadingError, rhs: ServersLoadingError) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.unactive, .unactive), (.unreachable, .unreachable), (.locked, .locked), (.undecodable, .undecodable):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protocol ServersLoading {
|
||||
func loadServers() -> AnyPublisher<Void, ServersLoadingError>
|
||||
}
|
||||
|
||||
final class ServersLoader: NSObject {
|
||||
@Dependency private var database: ServersDatabase
|
||||
|
||||
private let session: WCSession
|
||||
|
||||
init(session: WCSession) {
|
||||
self.session = session
|
||||
super.init()
|
||||
session.delegate = self
|
||||
session.activate()
|
||||
}
|
||||
|
||||
private func sendMessage(completionHandler: @escaping (Result<WatchMessage, ServersLoadingError>) -> Void) {
|
||||
print("sendMessage")
|
||||
|
||||
guard session.activationState == .activated else {
|
||||
completionHandler(.failure(.unactive))
|
||||
return
|
||||
}
|
||||
|
||||
guard !session.iOSDeviceNeedsUnlockAfterRebootForReachability else {
|
||||
completionHandler(.failure(.locked))
|
||||
return
|
||||
}
|
||||
|
||||
guard session.isReachable else {
|
||||
completionHandler(.failure(.unreachable))
|
||||
return
|
||||
}
|
||||
|
||||
session.sendMessage([:]) { dictionary in
|
||||
do {
|
||||
let data = try JSONSerialization.data(withJSONObject: dictionary)
|
||||
let message = try JSONDecoder().decode(WatchMessage.self, from: data)
|
||||
|
||||
completionHandler(.success(message))
|
||||
} catch {
|
||||
completionHandler(.failure(.undecodable(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - WCSessionDelegate
|
||||
|
||||
extension ServersLoader: WCSessionDelegate {
|
||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ServersLoading
|
||||
|
||||
extension ServersLoader: ServersLoading {
|
||||
func loadServers() -> AnyPublisher<Void, ServersLoadingError> {
|
||||
Future<Void, ServersLoadingError> { [self] promise in
|
||||
sendMessage { result in
|
||||
switch result {
|
||||
case .success(let message):
|
||||
for server in message.servers {
|
||||
self.database.process(updatedServer: server)
|
||||
}
|
||||
|
||||
promise(.success(()))
|
||||
case .failure(let error):
|
||||
promise(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
.retryWithDelay(retries: 3, delay: 1, scheduler: DispatchQueue.global())
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import Foundation
|
||||
|
||||
protocol ServerProviding {
|
||||
var server: Server { get }
|
||||
}
|
||||
|
||||
final class ServerProvider {
|
||||
@Dependency private var stateProvider: StateProviding
|
||||
}
|
||||
|
||||
extension ServerProvider: ServerProviding {
|
||||
var server: Server {
|
||||
switch stateProvider.state {
|
||||
case .loggedIn(let server):
|
||||
return server
|
||||
case .loggedOut:
|
||||
fatalError("Attempt to get server while logged out.")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import Foundation
|
||||
|
||||
enum AppState {
|
||||
case loggedIn(Server)
|
||||
case loggedOut
|
||||
}
|
||||
|
||||
protocol StateProviding {
|
||||
var state: AppState { get }
|
||||
|
||||
func update(to state: AppState)
|
||||
}
|
||||
|
||||
final class StateProvider: StateProviding {
|
||||
@Storage(.currentServer) private var currentURL: URL?
|
||||
|
||||
@Dependency private var database: ServersDatabase
|
||||
|
||||
var state: AppState {
|
||||
if let currentURL, let server = database.server(url: currentURL) {
|
||||
return .loggedIn(server)
|
||||
} else if database.servers().count == 1, let server = database.servers().first {
|
||||
return .loggedIn(server)
|
||||
} else {
|
||||
return .loggedOut
|
||||
}
|
||||
}
|
||||
|
||||
func update(to state: AppState) {
|
||||
switch state {
|
||||
case .loggedIn(let server):
|
||||
currentURL = server.url
|
||||
case .loggedOut:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,15 +9,16 @@ struct RocketChat_Watch_AppApp: App {
|
|||
}
|
||||
|
||||
private func registerDependencies() {
|
||||
Store.register(AppRouting.self, factory: router)
|
||||
Store.register(ServersDatabase.self, factory: DefaultDatabase())
|
||||
Store.register(StateProviding.self, factory: StateProvider())
|
||||
Store.register(ServerProviding.self, factory: ServerProvider())
|
||||
Store.register(Connection.self, factory: WatchConnection(session: .default))
|
||||
Store.register(ServersLoading.self, factory: ServersLoader(session: .default))
|
||||
Store.register(RocketChatClientProtocol.self, factory: RocketChatClient())
|
||||
Store.register(Database.self, factory: RocketChatDatabase())
|
||||
Store.register(MessagesLoading.self, factory: MessagesLoader())
|
||||
Store.register(MessageSending.self, factory: MessageSender())
|
||||
Store.register(RoomsLoading.self, factory: RoomsLoader())
|
||||
Store.register(AppRouting.self, factory: router)
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
protocol ServerProviding {
|
||||
func current() -> Server
|
||||
}
|
||||
|
||||
final class ServerProvider {
|
||||
@Storage(.currentServer) private var currentURL: URL?
|
||||
@Dependency private var database: ServersDatabase
|
||||
}
|
||||
|
||||
extension ServerProvider: ServerProviding {
|
||||
func current() -> Server {
|
||||
if let currentURL, let server = database.server(url: currentURL) {
|
||||
return server
|
||||
} else {
|
||||
fatalError("Attempt to get server before it was not set.")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
enum ServerListState {
|
||||
case loading
|
||||
case loaded
|
||||
case error(ConnectionError)
|
||||
}
|
||||
|
||||
final class ServerListViewModel: ObservableObject {
|
||||
@Dependency private var connection: Connection
|
||||
@Dependency private var database: ServersDatabase
|
||||
@Dependency private var router: AppRouting
|
||||
|
||||
@Published private(set) var state: ServerListState = .loading
|
||||
|
||||
private func handleSuccess(message: WatchMessage) {
|
||||
message.servers.forEach(database.process(updatedServer:))
|
||||
state = .loaded
|
||||
}
|
||||
|
||||
private func handleFailure(error: Error) {
|
||||
guard let connectionError = error as? ConnectionError else {
|
||||
return
|
||||
}
|
||||
|
||||
state = .error(connectionError)
|
||||
}
|
||||
|
||||
func loadServers() {
|
||||
connection.sendMessage { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .success(let message):
|
||||
DispatchQueue.main.async { self.handleSuccess(message: message) }
|
||||
case .failure(let error):
|
||||
DispatchQueue.main.async { self.handleFailure(error: error) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func didTap(server: Server) {
|
||||
router.route(to: .roomList(server))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import SwiftUI
|
||||
|
||||
struct RetryView: View {
|
||||
private let label: String
|
||||
private let action: () -> Void
|
||||
|
||||
init(_ label: String, action: @escaping () -> Void) {
|
||||
self.label = label
|
||||
self.action = action
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text(label)
|
||||
.multilineTextAlignment(.center)
|
||||
Button("Try Again", action: action)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
|
@ -1,53 +1,80 @@
|
|||
import Combine
|
||||
import CoreData
|
||||
import SwiftUI
|
||||
|
||||
struct ServerListView: View {
|
||||
@StateObject var viewModel: ServerListViewModel
|
||||
@Dependency private var router: AppRouting
|
||||
@Dependency private var serversLoader: ServersLoading
|
||||
|
||||
@FetchRequest(entity: Server.entity(), sortDescriptors: [], animation: .default)
|
||||
private var servers: FetchedResults<Server>
|
||||
@State private var state: ViewState = .loading
|
||||
|
||||
init(viewModel: ServerListViewModel) {
|
||||
_viewModel = StateObject(wrappedValue: viewModel)
|
||||
@FetchRequest<Server> private var servers: FetchedResults<Server>
|
||||
|
||||
init() {
|
||||
let fetchRequest = Server.fetchRequest()
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Server.updatedSince, ascending: true)]
|
||||
|
||||
_servers = FetchRequest(fetchRequest: fetchRequest)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func errorView(_ text: String) -> some View {
|
||||
VStack(alignment: .center) {
|
||||
Text(text)
|
||||
Button("Try Again") {
|
||||
viewModel.loadServers()
|
||||
private var serverList: some View {
|
||||
List {
|
||||
ForEach(servers) { server in
|
||||
ServerView(server: server)
|
||||
.onTapGesture {
|
||||
router.route(to: .roomList(server))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
switch viewModel.state {
|
||||
case .loading:
|
||||
ProgressView()
|
||||
case .loaded where servers.count > 0:
|
||||
List {
|
||||
ForEach(servers) { server in
|
||||
ServerView(server: server)
|
||||
.onTapGesture {
|
||||
viewModel.didTap(server: server)
|
||||
}
|
||||
}
|
||||
}
|
||||
case .loaded:
|
||||
errorView("There are no servers connected.")
|
||||
case .error(let connectionError):
|
||||
switch connectionError {
|
||||
case .needsUnlock:
|
||||
errorView("You need to unlock your iPhone.")
|
||||
case .decoding:
|
||||
errorView("We can't read servers information.")
|
||||
}
|
||||
switch state {
|
||||
case .loading:
|
||||
ProgressView()
|
||||
case .loaded:
|
||||
serverList
|
||||
case .loaded where servers.isEmpty:
|
||||
RetryView("No Connected servers.", action: loadServers)
|
||||
case .error(let error) where error == .locked:
|
||||
RetryView("Please unlock your iPhone.", action: loadServers)
|
||||
case .error(let error) where error == .unactive:
|
||||
RetryView("Could not connect to your iPhone.", action: loadServers)
|
||||
case .error(let error) where error == .unreachable:
|
||||
RetryView("Could not reach your iPhone.", action: loadServers)
|
||||
case .error(let error) where error == .undecodable(error):
|
||||
RetryView("Could not read servers from iPhone.", action: loadServers)
|
||||
default:
|
||||
RetryView("Unexpected error.", action: loadServers)
|
||||
}
|
||||
}
|
||||
.navigationTitle("Servers")
|
||||
.onAppear {
|
||||
viewModel.loadServers()
|
||||
loadServers()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadServers() {
|
||||
state = .loading
|
||||
|
||||
serversLoader.loadServers()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.subscribe(Subscribers.Sink { completion in
|
||||
if case .failure(let error) = completion {
|
||||
state = .error(error)
|
||||
}
|
||||
} receiveValue: { _ in
|
||||
state = .loaded
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerListView {
|
||||
enum ViewState {
|
||||
case loading
|
||||
case loaded
|
||||
case error(ServersLoadingError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
import Foundation
|
||||
import WatchConnectivity
|
||||
|
||||
enum ConnectionError: Error {
|
||||
case needsUnlock
|
||||
case decoding(Error)
|
||||
}
|
||||
|
||||
protocol Connection {
|
||||
func sendMessage(completionHandler: @escaping (Result<WatchMessage, ConnectionError>) -> Void)
|
||||
}
|
||||
|
||||
final class WatchConnection: NSObject {
|
||||
private let session: WCSession
|
||||
|
||||
init(session: WCSession) {
|
||||
self.session = session
|
||||
super.init()
|
||||
session.delegate = self
|
||||
session.activate()
|
||||
}
|
||||
|
||||
private func scheduledSendMessage(completionHandler: @escaping (Result<WatchMessage, ConnectionError>) -> Void) {
|
||||
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [weak self] _ in
|
||||
self?.sendMessage(completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - WCSessionDelegate
|
||||
|
||||
extension WatchConnection: WCSessionDelegate {
|
||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Connection
|
||||
|
||||
extension WatchConnection: Connection {
|
||||
func sendMessage(completionHandler: @escaping (Result<WatchMessage, ConnectionError>) -> Void) {
|
||||
guard session.activationState == .activated else {
|
||||
scheduledSendMessage(completionHandler: completionHandler)
|
||||
return
|
||||
}
|
||||
|
||||
guard !session.iOSDeviceNeedsUnlockAfterRebootForReachability else {
|
||||
completionHandler(.failure(.needsUnlock))
|
||||
return
|
||||
}
|
||||
|
||||
guard session.isReachable else {
|
||||
scheduledSendMessage(completionHandler: completionHandler)
|
||||
return
|
||||
}
|
||||
|
||||
session.sendMessage([:]) { dictionary in
|
||||
do {
|
||||
let data = try JSONSerialization.data(withJSONObject: dictionary)
|
||||
let message = try JSONDecoder().decode(WatchMessage.self, from: data)
|
||||
|
||||
completionHandler(.success(message))
|
||||
} catch {
|
||||
completionHandler(.failure(.decoding(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -82,6 +82,8 @@
|
|||
1E4AFC1B2B5AFC6A00E2AA7D /* Publisher+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AFC1A2B5AFC6A00E2AA7D /* Publisher+Extensions.swift */; };
|
||||
1E4AFC1F2B5B0D0500E2AA7D /* ServerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AFC1E2B5B0D0500E2AA7D /* ServerProvider.swift */; };
|
||||
1E4AFC212B5B1AA000E2AA7D /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AFC202B5B1AA000E2AA7D /* AppView.swift */; };
|
||||
1E4AFC252B5B1DA300E2AA7D /* StateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AFC242B5B1DA300E2AA7D /* StateProvider.swift */; };
|
||||
1E4AFC272B5B23C600E2AA7D /* RetryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4AFC262B5B23C600E2AA7D /* RetryView.swift */; };
|
||||
1E51D962251263CD00DC95DE /* MessageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E51D961251263CD00DC95DE /* MessageType.swift */; };
|
||||
1E51D965251263D600DC95DE /* NotificationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E51D964251263D600DC95DE /* NotificationType.swift */; };
|
||||
1E598AE42515057D002BDFBD /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E598AE32515057D002BDFBD /* Date+Extensions.swift */; };
|
||||
|
@ -127,11 +129,10 @@
|
|||
1ED033AE2B55B1CC004F4930 /* Default.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033AC2B55B1CC004F4930 /* Default.xcdatamodeld */; };
|
||||
1ED033B02B55B25A004F4930 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033AF2B55B25A004F4930 /* Database.swift */; };
|
||||
1ED033B62B55B4A5004F4930 /* ServerListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033B52B55B4A5004F4930 /* ServerListView.swift */; };
|
||||
1ED033B82B55B4BE004F4930 /* ServerListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033B72B55B4BE004F4930 /* ServerListViewModel.swift */; };
|
||||
1ED033BA2B55B5F6004F4930 /* ServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033B92B55B5F6004F4930 /* ServerView.swift */; };
|
||||
1ED033BF2B55BF94004F4930 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033BE2B55BF94004F4930 /* Storage.swift */; };
|
||||
1ED033C12B55C190004F4930 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 1ED033C02B55C190004F4930 /* Localizable.xcstrings */; };
|
||||
1ED033C42B55C65C004F4930 /* RocketChatAppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033C32B55C65C004F4930 /* RocketChatAppRouter.swift */; };
|
||||
1ED033C42B55C65C004F4930 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033C32B55C65C004F4930 /* AppRouter.swift */; };
|
||||
1ED033CB2B55D4F0004F4930 /* RocketChat.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033C92B55D4F0004F4930 /* RocketChat.xcdatamodeld */; };
|
||||
1ED033CD2B55D671004F4930 /* RocketChatDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED033CC2B55D671004F4930 /* RocketChatDatabase.swift */; };
|
||||
1ED038912B507B4C00C007D4 /* RocketChatApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED038902B507B4C00C007D4 /* RocketChatApp.swift */; };
|
||||
|
@ -159,7 +160,7 @@
|
|||
1ED038C42B50A1F500C007D4 /* WatchMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED038C32B50A1F500C007D4 /* WatchMessage.swift */; };
|
||||
1ED038C52B50A1F500C007D4 /* WatchMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED038C32B50A1F500C007D4 /* WatchMessage.swift */; };
|
||||
1ED038C62B50A21800C007D4 /* WatchMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED038C32B50A1F500C007D4 /* WatchMessage.swift */; };
|
||||
1ED038CA2B50A58400C007D4 /* WatchConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED038C92B50A58400C007D4 /* WatchConnection.swift */; };
|
||||
1ED038CA2B50A58400C007D4 /* ServersLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED038C92B50A58400C007D4 /* ServersLoader.swift */; };
|
||||
1ED59D4C22CBA77D00C54289 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1ED59D4B22CBA77D00C54289 /* GoogleService-Info.plist */; };
|
||||
1EDFD0FA2B589B8F002FEE5F /* MessagesLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EDFD0F92B589B8F002FEE5F /* MessagesLoader.swift */; };
|
||||
1EDFD1062B58A66E002FEE5F /* CancelBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EDFD1052B58A66E002FEE5F /* CancelBag.swift */; };
|
||||
|
@ -394,6 +395,8 @@
|
|||
1E4AFC1A2B5AFC6A00E2AA7D /* Publisher+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publisher+Extensions.swift"; sourceTree = "<group>"; };
|
||||
1E4AFC1E2B5B0D0500E2AA7D /* ServerProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerProvider.swift; sourceTree = "<group>"; };
|
||||
1E4AFC202B5B1AA000E2AA7D /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
|
||||
1E4AFC242B5B1DA300E2AA7D /* StateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateProvider.swift; sourceTree = "<group>"; };
|
||||
1E4AFC262B5B23C600E2AA7D /* RetryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetryView.swift; sourceTree = "<group>"; };
|
||||
1E51D961251263CD00DC95DE /* MessageType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageType.swift; sourceTree = "<group>"; };
|
||||
1E51D964251263D600DC95DE /* NotificationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationType.swift; sourceTree = "<group>"; };
|
||||
1E598AE32515057D002BDFBD /* Date+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
|
||||
|
@ -418,11 +421,10 @@
|
|||
1ED033AD2B55B1CC004F4930 /* Default.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Default.xcdatamodel; sourceTree = "<group>"; };
|
||||
1ED033AF2B55B25A004F4930 /* Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = "<group>"; };
|
||||
1ED033B52B55B4A5004F4930 /* ServerListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListView.swift; sourceTree = "<group>"; };
|
||||
1ED033B72B55B4BE004F4930 /* ServerListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListViewModel.swift; sourceTree = "<group>"; };
|
||||
1ED033B92B55B5F6004F4930 /* ServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerView.swift; sourceTree = "<group>"; };
|
||||
1ED033BE2B55BF94004F4930 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
|
||||
1ED033C02B55C190004F4930 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
1ED033C32B55C65C004F4930 /* RocketChatAppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RocketChatAppRouter.swift; sourceTree = "<group>"; };
|
||||
1ED033C32B55C65C004F4930 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; };
|
||||
1ED033CA2B55D4F0004F4930 /* RocketChat.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = RocketChat.xcdatamodel; sourceTree = "<group>"; };
|
||||
1ED033CC2B55D671004F4930 /* RocketChatDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RocketChatDatabase.swift; sourceTree = "<group>"; };
|
||||
1ED0388E2B507B4B00C007D4 /* Rocket.Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Rocket.Chat.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -437,7 +439,7 @@
|
|||
1ED038BD2B50A1D400C007D4 /* DBServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBServer.swift; sourceTree = "<group>"; };
|
||||
1ED038C02B50A1E400C007D4 /* DBUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBUser.swift; sourceTree = "<group>"; };
|
||||
1ED038C32B50A1F500C007D4 /* WatchMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchMessage.swift; sourceTree = "<group>"; };
|
||||
1ED038C92B50A58400C007D4 /* WatchConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConnection.swift; sourceTree = "<group>"; };
|
||||
1ED038C92B50A58400C007D4 /* ServersLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersLoader.swift; sourceTree = "<group>"; };
|
||||
1ED59D4B22CBA77D00C54289 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = SOURCE_ROOT; };
|
||||
1EDFD0F92B589B8F002FEE5F /* MessagesLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesLoader.swift; sourceTree = "<group>"; };
|
||||
1EDFD1052B58A66E002FEE5F /* CancelBag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelBag.swift; sourceTree = "<group>"; };
|
||||
|
@ -690,6 +692,15 @@
|
|||
path = Requests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1E4AFC232B5B1D9C00E2AA7D /* Providers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E4AFC1E2B5B0D0500E2AA7D /* ServerProvider.swift */,
|
||||
1E4AFC242B5B1DA300E2AA7D /* StateProvider.swift */,
|
||||
);
|
||||
path = Providers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1E76CBC425152A7F0067298C /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -790,6 +801,7 @@
|
|||
1E29A3172B5868E50093C03C /* MessageView.swift */,
|
||||
1E29A3232B5874FF0093C03C /* MessageComposerView.swift */,
|
||||
1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */,
|
||||
1E4AFC262B5B23C600E2AA7D /* RetryView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
|
@ -797,7 +809,6 @@
|
|||
1ED033B42B55B495004F4930 /* ViewModels */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1ED033B72B55B4BE004F4930 /* ServerListViewModel.swift */,
|
||||
1E29A30F2B5865B80093C03C /* RoomViewModel.swift */,
|
||||
1E29A3192B5868EE0093C03C /* MessageViewModel.swift */,
|
||||
);
|
||||
|
@ -807,6 +818,7 @@
|
|||
1ED0388F2B507B4C00C007D4 /* RocketChat Watch App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E4AFC232B5B1D9C00E2AA7D /* Providers */,
|
||||
1EDFD0FB2B589FC4002FEE5F /* DependencyInjection */,
|
||||
1EDFD0F82B589B82002FEE5F /* Loaders */,
|
||||
1E29A31E2B5871BE0093C03C /* Formatters */,
|
||||
|
@ -816,14 +828,12 @@
|
|||
1ED033B12B55B47F004F4930 /* Views */,
|
||||
1ED033AB2B55B1C2004F4930 /* Database */,
|
||||
1ED038902B507B4C00C007D4 /* RocketChatApp.swift */,
|
||||
1ED033C32B55C65C004F4930 /* RocketChatAppRouter.swift */,
|
||||
1ED033C32B55C65C004F4930 /* AppRouter.swift */,
|
||||
1E4AFC202B5B1AA000E2AA7D /* AppView.swift */,
|
||||
1ED038C92B50A58400C007D4 /* WatchConnection.swift */,
|
||||
1ED033BE2B55BF94004F4930 /* Storage.swift */,
|
||||
1ED038942B507B4D00C007D4 /* Assets.xcassets */,
|
||||
1ED038962B507B4D00C007D4 /* Preview Content */,
|
||||
1ED033C02B55C190004F4930 /* Localizable.xcstrings */,
|
||||
1E4AFC1E2B5B0D0500E2AA7D /* ServerProvider.swift */,
|
||||
);
|
||||
path = "RocketChat Watch App";
|
||||
sourceTree = "<group>";
|
||||
|
@ -858,6 +868,7 @@
|
|||
1EDFD0F82B589B82002FEE5F /* Loaders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1ED038C92B50A58400C007D4 /* ServersLoader.swift */,
|
||||
1EDFD0F92B589B8F002FEE5F /* MessagesLoader.swift */,
|
||||
1EDFD1052B58A66E002FEE5F /* CancelBag.swift */,
|
||||
1EDFD1072B58AA77002FEE5F /* RoomsLoader.swift */,
|
||||
|
@ -1858,12 +1869,13 @@
|
|||
1ED033BA2B55B5F6004F4930 /* ServerView.swift in Sources */,
|
||||
1E29A2D02B58582F0093C03C /* RoomView.swift in Sources */,
|
||||
1E29A2FD2B585B070093C03C /* RoomsRequest.swift in Sources */,
|
||||
1ED038CA2B50A58400C007D4 /* WatchConnection.swift in Sources */,
|
||||
1ED038CA2B50A58400C007D4 /* ServersLoader.swift in Sources */,
|
||||
1E29A3222B5871CE0093C03C /* MessageFormatter.swift in Sources */,
|
||||
1E9A716F2B59CBCA00477BA2 /* AttachmentView.swift in Sources */,
|
||||
1E29A3002B585B070093C03C /* JSONAdapter.swift in Sources */,
|
||||
1E29A3022B585B070093C03C /* DateCodingStrategy.swift in Sources */,
|
||||
1E4AFC1B2B5AFC6A00E2AA7D /* Publisher+Extensions.swift in Sources */,
|
||||
1E4AFC272B5B23C600E2AA7D /* RetryView.swift in Sources */,
|
||||
1ED033B62B55B4A5004F4930 /* ServerListView.swift in Sources */,
|
||||
1E29A3202B5871C80093C03C /* RoomFormatter.swift in Sources */,
|
||||
1EDFD0FA2B589B8F002FEE5F /* MessagesLoader.swift in Sources */,
|
||||
|
@ -1903,8 +1915,8 @@
|
|||
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 */,
|
||||
1ED033C42B55C65C004F4930 /* AppRouter.swift in Sources */,
|
||||
1E4AFC252B5B1DA300E2AA7D /* StateProvider.swift in Sources */,
|
||||
1ED033B02B55B25A004F4930 /* Database.swift in Sources */,
|
||||
1E9A71712B59CC1300477BA2 /* Attachment.swift in Sources */,
|
||||
1E29A30A2B585B370093C03C /* Data+Extensions.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue