diff --git a/Blink/Blink.xcodeproj/project.pbxproj b/Blink/Blink.xcodeproj/project.pbxproj index 90d705b..952ecd6 100644 --- a/Blink/Blink.xcodeproj/project.pbxproj +++ b/Blink/Blink.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 4F5F130D24B6612E00A7D9E7 /* Multipeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5F130C24B6612E00A7D9E7 /* Multipeer.swift */; }; 4F5F130F24B661D700A7D9E7 /* MenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5F130E24B661D700A7D9E7 /* MenuViewModel.swift */; }; 4F5F131124B6659A00A7D9E7 /* BrainstormingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5F131024B6659A00A7D9E7 /* BrainstormingViewModel.swift */; }; + 4F5F131324B78BCB00A7D9E7 /* VotingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5F131224B78BCB00A7D9E7 /* VotingViewModel.swift */; }; + 4F5F131524B8DDB500A7D9E7 /* VotingViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5F131424B8DDB500A7D9E7 /* VotingViewModelTests.swift */; }; A418231A24B39DDF0082962F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A418231924B39DDF0082962F /* AppDelegate.swift */; }; A418231C24B39DDF0082962F /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A418231B24B39DDF0082962F /* MenuView.swift */; }; A418231E24B39DE10082962F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A418231D24B39DE10082962F /* Assets.xcassets */; }; @@ -70,6 +72,8 @@ 4F5F130C24B6612E00A7D9E7 /* Multipeer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Multipeer.swift; sourceTree = ""; }; 4F5F130E24B661D700A7D9E7 /* MenuViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewModel.swift; sourceTree = ""; }; 4F5F131024B6659A00A7D9E7 /* BrainstormingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrainstormingViewModel.swift; sourceTree = ""; }; + 4F5F131224B78BCB00A7D9E7 /* VotingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingViewModel.swift; sourceTree = ""; }; + 4F5F131424B8DDB500A7D9E7 /* VotingViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VotingViewModelTests.swift; sourceTree = ""; }; A418231624B39DDF0082962F /* Blink.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Blink.app; sourceTree = BUILT_PRODUCTS_DIR; }; A418231924B39DDF0082962F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; A418231B24B39DDF0082962F /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = ""; }; @@ -289,6 +293,7 @@ 4F5F130A24B6610F00A7D9E7 /* ViewModels */ = { isa = PBXGroup; children = ( + 4F5F131224B78BCB00A7D9E7 /* VotingViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -353,6 +358,7 @@ children = ( A418232E24B39DE10082962F /* BlinkTests.swift */, A418233024B39DE10082962F /* Info.plist */, + 4F5F131424B8DDB500A7D9E7 /* VotingViewModelTests.swift */, ); path = BlinkTests; sourceTree = ""; @@ -534,6 +540,7 @@ 4F5F12D424B639FA00A7D9E7 /* SceneDelegate.swift in Sources */, 4F5F130F24B661D700A7D9E7 /* MenuViewModel.swift in Sources */, 4F5F12D624B639FA00A7D9E7 /* ContentView.swift in Sources */, + 4F5F131324B78BCB00A7D9E7 /* VotingViewModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -568,6 +575,7 @@ buildActionMask = 2147483647; files = ( A418232F24B39DE10082962F /* BlinkTests.swift in Sources */, + 4F5F131524B8DDB500A7D9E7 /* VotingViewModelTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Blink/Blink/Brainstorming/ViewModels/BrainstormingViewModel.swift b/Blink/Blink/Brainstorming/ViewModels/BrainstormingViewModel.swift index 0816850..6bc6e96 100644 --- a/Blink/Blink/Brainstorming/ViewModels/BrainstormingViewModel.swift +++ b/Blink/Blink/Brainstorming/ViewModels/BrainstormingViewModel.swift @@ -9,6 +9,7 @@ import Foundation import MultipeerConnectivity + class BrainstormingViewModel: NSObject, ObservableObject { /// Shared instance of the Multipeer Class. diff --git a/Blink/Blink/Voting/ViewModel/VotingViewModel.swift b/Blink/Blink/Voting/ViewModel/VotingViewModel.swift index f68865e..d6e3c07 100644 --- a/Blink/Blink/Voting/ViewModel/VotingViewModel.swift +++ b/Blink/Blink/Voting/ViewModel/VotingViewModel.swift @@ -9,15 +9,52 @@ import Foundation import MultipeerConnectivity -class VotingViewModel: NSObject, MCSessionDelegate { - +class VotingViewModel: NSObject { + typealias Ranking = [(key: String, value: Int)] let multipeerConnection = Multipeer.shared + var ideas: [String] = [] + var votes: [String] = [] + var rank: Ranking = [] + override init() { super.init() multipeerConnection.delegate = self } + func sendIdeas() { + let mcSession = multipeerConnection.mcSession + if mcSession.connectedPeers.count > 0 { + if let ideasData = try? NSKeyedArchiver.archivedData(withRootObject: ideas, requiringSecureCoding: false) { + do { + try mcSession.send(ideasData, toPeers: mcSession.connectedPeers, with: .reliable) + } catch let error as NSError { + let ac = UIAlertController(title: "Send error", message: error.localizedDescription, preferredStyle: .alert) + ac.addAction(UIAlertAction(title: "Ok", style: .default)) +// present(ac, animated: true) + } + } + } + } + + func countVotes(votes: [String], ideas: [String]) -> Ranking { + let votedIdeas = Array(Set(votes)) + var nonVotedIdeas = [String]() + for i in ideas { + if !votedIdeas.contains(i) { + nonVotedIdeas.append(i) + } + } + let votedIdeasArray = votes.map { ($0, 1) } + let ideasFrequency = Dictionary(votedIdeasArray, uniquingKeysWith: +) + let nonVotedIdeasArray = nonVotedIdeas.map { ($0, 0) } + let ideasNonFrequency = Dictionary(nonVotedIdeasArray, uniquingKeysWith: +) + let votingResult = ideasFrequency.merging(ideasNonFrequency) { (_, new) in new } + return votingResult.sorted(by: {($0.value > $1.value)}) + } +} + +extension VotingViewModel: MCSessionDelegate { func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) { switch state { case MCSessionState.connected: @@ -30,16 +67,18 @@ class VotingViewModel: NSObject, MCSessionDelegate { multipeerConnection.connectionStatus = .unknown } } - + func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) { + if let votesList:[String] = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [String] { + votes += votesList } } - + func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) { } - + func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) { } - + func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) { } } diff --git a/Blink/BlinkTests/VotingViewModelTests.swift b/Blink/BlinkTests/VotingViewModelTests.swift new file mode 100644 index 0000000..303edd7 --- /dev/null +++ b/Blink/BlinkTests/VotingViewModelTests.swift @@ -0,0 +1,30 @@ +// +// VotingViewModelTests.swift +// BlinkTests +// +// Created by Edgar Sgroi on 10/07/20. +// Copyright © 2020 Artur Carneiro. All rights reserved. +// + +import XCTest +@testable import Blink + +class VotingViewModelTests: XCTestCase { + + func testCountVotes() { + let viewModel = VotingViewModel() + let ideas = ["preved", "poka", "hola", "yo"] + let votes = ["preved", "hola", "poka", "hola", "poka", "hola"] + + XCTAssertFalse(ideas.isEmpty) + XCTAssertFalse(votes.isEmpty) + + let result = viewModel.countVotes(votes: votes, ideas: ideas) + XCTAssertFalse(result.isEmpty) + let expectedResult = [(key: "hola", value: 3), (key: "poka", value: 2), (key: "preved", value: 1), (key: "yo", value: 0)] + for index in 0.. 0 { + if let votesData = try? NSKeyedArchiver.archivedData(withRootObject: votes, requiringSecureCoding: false) { + do { + try mcSession.send(votesData, toPeers: mcSession.connectedPeers, with: .reliable) + } catch let error as NSError { + let ac = UIAlertController(title: "Send error", message: error.localizedDescription, preferredStyle: .alert) + ac.addAction(UIAlertAction(title: "Ok", style: .default)) +// present(ac, animated: true) + } + } + } + } +} + +extension VotingViewModel: MCSessionDelegate { + func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) { + switch state { + case MCSessionState.connected: + multipeerConnection.connectionStatus = .connected + case MCSessionState.connecting: + multipeerConnection.connectionStatus = .connecting + case MCSessionState.notConnected: + multipeerConnection.connectionStatus = .notConnected + @unknown default: + multipeerConnection.connectionStatus = .unknown + } + } + + func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) { + if let ideasList:[String] = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [String] { + ideas = ideasList + } + } + + func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) { + } + + func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) { + } + + func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) { + } + + +}