diff --git a/example/MultipeerKitExample/MultipeerKitExample.xcodeproj/project.pbxproj b/example/MultipeerKitExample/MultipeerKitExample.xcodeproj/project.pbxproj index 8c7eed1..60dde52 100644 --- a/example/MultipeerKitExample/MultipeerKitExample.xcodeproj/project.pbxproj +++ b/example/MultipeerKitExample/MultipeerKitExample.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ DDADA0A2240A83B400842749 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DDADA0A0240A83B400842749 /* LaunchScreen.storyboard */; }; DDADA0AC240A83FF00842749 /* MultipeerKit in Frameworks */ = {isa = PBXBuildFile; productRef = DDADA0AB240A83FF00842749 /* MultipeerKit */; }; DDADA0AE240A844B00842749 /* ExamplePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDADA0AD240A844B00842749 /* ExamplePayload.swift */; }; + DE13AA43284414DF008C3C54 /* ChatPeerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE13AA42284414DF008C3C54 /* ChatPeerDataSource.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -22,13 +23,14 @@ DDADA092240A83B300842749 /* MultipeerKitExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MultipeerKitExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; DDADA095240A83B300842749 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DDADA097240A83B300842749 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - DDADA099240A83B300842749 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + DDADA099240A83B300842749 /* ContentView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; DDADA09B240A83B400842749 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DDADA09E240A83B400842749 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; DDADA0A1240A83B400842749 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; DDADA0A3240A83B400842749 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DDADA0A9240A83F800842749 /* MultipeerKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = MultipeerKit; path = ../..; sourceTree = ""; }; DDADA0AD240A844B00842749 /* ExamplePayload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExamplePayload.swift; sourceTree = ""; }; + DE13AA42284414DF008C3C54 /* ChatPeerDataSource.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = ChatPeerDataSource.swift; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,6 +71,7 @@ DDADA095240A83B300842749 /* AppDelegate.swift */, DDADA097240A83B300842749 /* SceneDelegate.swift */, DDADA099240A83B300842749 /* ContentView.swift */, + DE13AA42284414DF008C3C54 /* ChatPeerDataSource.swift */, DDADA09B240A83B400842749 /* Assets.xcassets */, DDADA0A0240A83B400842749 /* LaunchScreen.storyboard */, DDADA0A3240A83B400842749 /* Info.plist */, @@ -170,6 +173,7 @@ DDADA0AE240A844B00842749 /* ExamplePayload.swift in Sources */, DDADA098240A83B300842749 /* SceneDelegate.swift in Sources */, DDADA09A240A83B300842749 /* ContentView.swift in Sources */, + DE13AA43284414DF008C3C54 /* ChatPeerDataSource.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/example/MultipeerKitExample/MultipeerKitExample/ChatPeerDataSource.swift b/example/MultipeerKitExample/MultipeerKitExample/ChatPeerDataSource.swift new file mode 100644 index 0000000..077c8e1 --- /dev/null +++ b/example/MultipeerKitExample/MultipeerKitExample/ChatPeerDataSource.swift @@ -0,0 +1,56 @@ +// +// ChatPeerDataSource.swift +// MultipeerKitExample +// + +import Foundation +import MultipeerKit + +public struct ChatPeer: Hashable, Identifiable { + public var id: String { peer.id } + let peer: Peer + var history: [String] +} + +public final class ChatPeerDataSource: ObservableObject { + + private let transceiver: MultipeerTransceiver + + public init(transceiver: MultipeerTransceiver) { + self.transceiver = transceiver + + transceiver.availablePeersDidChange = { [weak self] peers in + guard let self = self else { return } + + self.availablePeers = peers.map { peer in + if let resultPeer = self.availablePeers.first(where: { $0.peer == peer }) { + return resultPeer + } + else { + return ChatPeer(peer: peer, history: []) + } + + } + } + + availablePeers = transceiver.availablePeers.map { ChatPeer(peer: $0, history: []) } + } + + @Published public private(set) var availablePeers: [ChatPeer] = [] + + func send(_ message: String, to peers: [ChatPeer]) { + let payload = ExamplePayload(message: message) + transceiver.send(payload, to: peers.map { $0.peer }) + + availablePeers = availablePeers.map { chatPeer in + if var resultPeer = availablePeers.first(where: { $0.peer == chatPeer.peer }) { + resultPeer.history.append(message) + return resultPeer + } + else { + return chatPeer + } + + } + } +} diff --git a/example/MultipeerKitExample/MultipeerKitExample/ContentView.swift b/example/MultipeerKitExample/MultipeerKitExample/ContentView.swift index 95fccb0..bbd967b 100644 --- a/example/MultipeerKitExample/MultipeerKitExample/ContentView.swift +++ b/example/MultipeerKitExample/MultipeerKitExample/ContentView.swift @@ -7,25 +7,24 @@ // import SwiftUI -import MultipeerKit import Combine final class ViewModel: ObservableObject { @Published var message: String = "" - @Published var selectedPeers: [Peer] = [] + @Published var selectedPeers: [ChatPeer] = [] - func toggle(_ peer: Peer) { - if selectedPeers.contains(peer) { - selectedPeers.remove(at: selectedPeers.firstIndex(of: peer)!) + func toggle(_ chatPeer: ChatPeer) { + if selectedPeers.contains(chatPeer) { + selectedPeers.remove(at: selectedPeers.firstIndex(of: chatPeer)!) } else { - selectedPeers.append(peer) + selectedPeers.append(chatPeer) } } } struct ContentView: View { @ObservedObject private(set) var viewModel = ViewModel() - @EnvironmentObject var dataSource: MultipeerDataSource + @EnvironmentObject var dataSource: ChatPeerDataSource @State private var showErrorAlert = false @@ -37,27 +36,30 @@ struct ContentView: View { Button(action: { self.sendToSelectedPeers(self.viewModel.message) }) { Text("SEND") } + + Text("\(dataSource.availablePeers.reduce(0, { $0 + $1.history.count })) message(s) sent") + .foregroundColor(.secondary) } VStack(alignment: .leading) { Text("Peers").font(.system(.headline)).padding() List { - ForEach(dataSource.availablePeers) { peer in + ForEach(dataSource.availablePeers) { chatPeer in HStack { Circle() .frame(width: 12, height: 12) - .foregroundColor(peer.isConnected ? .green : .gray) + .foregroundColor(chatPeer.peer.isConnected ? .green : .gray) - Text(peer.name) + Text(chatPeer.peer.name) Spacer() - if self.viewModel.selectedPeers.contains(peer) { + if viewModel.selectedPeers.map({ $0.peer }).contains(chatPeer.peer) { Image(systemName: "checkmark") } }.onTapGesture { - self.viewModel.toggle(peer) + viewModel.toggle(chatPeer) } } } @@ -73,8 +75,7 @@ struct ContentView: View { return } - let payload = ExamplePayload(message: self.viewModel.message) - dataSource.transceiver.send(payload, to: viewModel.selectedPeers) + dataSource.send(message, to: viewModel.selectedPeers) } } diff --git a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift index 9de1890..bc2aa57 100644 --- a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift +++ b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift @@ -33,8 +33,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { return t }() - private lazy var dataSource: MultipeerDataSource = { - MultipeerDataSource(transceiver: transceiver) + private lazy var dataSource: ChatPeerDataSource = { + ChatPeerDataSource(transceiver: transceiver) }() private func notify(with payload: ExamplePayload, peer: Peer) {