diff --git a/EyeTypeChat.xcodeproj/project.pbxproj b/EyeTypeChat.xcodeproj/project.pbxproj index 919804e..6397e15 100644 --- a/EyeTypeChat.xcodeproj/project.pbxproj +++ b/EyeTypeChat.xcodeproj/project.pbxproj @@ -7,14 +7,26 @@ objects = { /* Begin PBXBuildFile section */ + 231A94151A72AE38008CD10E /* ChatTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 231A94141A72AE38008CD10E /* ChatTableViewCell.swift */; }; + 232CE5321A3A3D6100C94EE8 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 232CE5311A3A3D6100C94EE8 /* Account.swift */; }; + 232CE5341A3A3D9300C94EE8 /* TelegramAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 232CE5331A3A3D9300C94EE8 /* TelegramAccount.swift */; }; + 232CE5361A3A3DCF00C94EE8 /* Conversation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 232CE5351A3A3DCF00C94EE8 /* Conversation.swift */; }; + 232CE5381A3A3E4D00C94EE8 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 232CE5371A3A3E4D00C94EE8 /* Message.swift */; }; + 2333C0A21A51A0F900784BEA /* ChatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2333C0A11A51A0F900784BEA /* ChatViewModel.swift */; }; + 2338BB451A794B5D00901026 /* Contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2338BB441A794B5D00901026 /* Contact.swift */; }; + 236ACA281A44B8B2003D1F53 /* EyeControllable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A759AB1A2F9D4D0005B04C /* EyeControllable.swift */; }; + 237E24601A56E4E90031B30A /* ChatControllable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 237E245F1A56E4E90031B30A /* ChatControllable.swift */; }; + 23C120CE1A4340F8004D7B5E /* MockedData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23C120CD1A4340F8004D7B5E /* MockedData.swift */; }; + 23E593011A7BC78E003DCE61 /* UIImage+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23E593001A7BC78E003DCE61 /* UIImage+Color.swift */; }; + 23FAF5451A52EDED00ADD423 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23FAF5441A52EDED00ADD423 /* ChatViewController.swift */; }; 5E9B341BA996967017148759 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A49492BC4CA902EDA58BC35 /* libPods.a */; }; - 8823D7AE1A30E3D200271406 /* ConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8823D7AD1A30E3D200271406 /* ConversationViewController.swift */; }; + 8823D7AE1A30E3D200271406 /* ConversationListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8823D7AD1A30E3D200271406 /* ConversationListViewController.swift */; }; 8823D7B11A30E8B500271406 /* UIViewController+EyeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8823D7B01A30E8B500271406 /* UIViewController+EyeType.swift */; }; 8823D7B31A30F65E00271406 /* BaseMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8823D7B21A30F65E00271406 /* BaseMenuViewController.swift */; }; 8856809F1A374B2D005F2BB0 /* fixedMenus.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8856809E1A374B2D005F2BB0 /* fixedMenus.plist */; }; 885680A21A374BB8005F2BB0 /* FixedMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885680A11A374BB8005F2BB0 /* FixedMenuViewController.swift */; }; 885680A51A376E47005F2BB0 /* SwiftBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 885680A41A376E47005F2BB0 /* SwiftBridge.m */; }; - 885680A71A378E55005F2BB0 /* FixedMenuViewController+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885680A61A378E55005F2BB0 /* FixedMenuViewController+Commands.swift */; }; + 885680A71A378E55005F2BB0 /* BaseMenuViewController+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885680A61A378E55005F2BB0 /* BaseMenuViewController+Commands.swift */; }; 885D57611A25062D00912290 /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = 885D57601A25062D00912290 /* Podfile */; }; 885D576A1A2513FF00912290 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 885D57691A2513FF00912290 /* CoreLocation.framework */; }; 885D57701A25159000912290 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 885D576F1A25159000912290 /* SystemConfiguration.framework */; }; @@ -26,7 +38,6 @@ 887A2CD21A0BDB4500094E3C /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 887A2CD01A0BDB4500094E3C /* LaunchScreen.xib */; }; 887A2CDE1A0BDB4500094E3C /* EyeTypeChatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887A2CDD1A0BDB4500094E3C /* EyeTypeChatTests.swift */; }; 88A759A11A2F7B070005B04C /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A759A01A2F7B070005B04C /* MainViewModel.swift */; }; - 88A759AC1A2F9D4D0005B04C /* EyeControllable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A759AB1A2F9D4D0005B04C /* EyeControllable.swift */; }; 88A759B11A2F9FC10005B04C /* KeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88A759B01A2F9FC10005B04C /* KeyboardViewController.swift */; }; 88BC6E7D1A12A6F600D3A54E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88BC6E7C1A12A6F600D3A54E /* CoreGraphics.framework */; }; 88BC6E801A12A78C00D3A54E /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88BC6E7F1A12A78C00D3A54E /* MediaPlayer.framework */; }; @@ -58,7 +69,18 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 8823D7AD1A30E3D200271406 /* ConversationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConversationViewController.swift; sourceTree = ""; }; + 231A94141A72AE38008CD10E /* ChatTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatTableViewCell.swift; sourceTree = ""; }; + 232CE5311A3A3D6100C94EE8 /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Account.swift; path = model/Account.swift; sourceTree = ""; }; + 232CE5331A3A3D9300C94EE8 /* TelegramAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TelegramAccount.swift; path = model/TelegramAccount.swift; sourceTree = ""; }; + 232CE5351A3A3DCF00C94EE8 /* Conversation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Conversation.swift; path = model/Conversation.swift; sourceTree = ""; }; + 232CE5371A3A3E4D00C94EE8 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Message.swift; path = model/Message.swift; sourceTree = ""; }; + 2333C0A11A51A0F900784BEA /* ChatViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatViewModel.swift; sourceTree = ""; }; + 2338BB441A794B5D00901026 /* Contact.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Contact.swift; path = model/Contact.swift; sourceTree = ""; }; + 237E245F1A56E4E90031B30A /* ChatControllable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatControllable.swift; sourceTree = ""; }; + 23C120CD1A4340F8004D7B5E /* MockedData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockedData.swift; sourceTree = ""; }; + 23E593001A7BC78E003DCE61 /* UIImage+Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Color.swift"; sourceTree = ""; }; + 23FAF5441A52EDED00ADD423 /* ChatViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = ""; wrapsLines = 1; }; + 8823D7AD1A30E3D200271406 /* ConversationListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConversationListViewController.swift; sourceTree = ""; }; 8823D7B01A30E8B500271406 /* UIViewController+EyeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+EyeType.swift"; sourceTree = ""; }; 8823D7B21A30F65E00271406 /* BaseMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseMenuViewController.swift; sourceTree = ""; }; 883793181A278BDB00AA856D /* libstdc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.dylib"; path = "usr/lib/libstdc++.dylib"; sourceTree = SDKROOT; }; @@ -66,7 +88,7 @@ 885680A11A374BB8005F2BB0 /* FixedMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FixedMenuViewController.swift; sourceTree = ""; }; 885680A31A376E1F005F2BB0 /* SwiftBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftBridge.h; sourceTree = ""; }; 885680A41A376E47005F2BB0 /* SwiftBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SwiftBridge.m; sourceTree = ""; }; - 885680A61A378E55005F2BB0 /* FixedMenuViewController+Commands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FixedMenuViewController+Commands.swift"; sourceTree = ""; }; + 885680A61A378E55005F2BB0 /* BaseMenuViewController+Commands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BaseMenuViewController+Commands.swift"; sourceTree = ""; }; 885ABDE41A13E1DD00552B16 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = ""; }; 885D57601A25062D00912290 /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = SOURCE_ROOT; }; 885D57691A2513FF00912290 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; @@ -134,6 +156,42 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2333C0A01A51A0EC00784BEA /* View Model */ = { + isa = PBXGroup; + children = ( + 2333C0A11A51A0F900784BEA /* ChatViewModel.swift */, + 88A759A01A2F7B070005B04C /* MainViewModel.swift */, + ); + name = "View Model"; + sourceTree = ""; + }; + 236ACA291A44BEFB003D1F53 /* Controllers */ = { + isa = PBXGroup; + children = ( + 887A2CC91A0BDB4500094E3C /* MainViewController.swift */, + 8823D7B21A30F65E00271406 /* BaseMenuViewController.swift */, + 885680A11A374BB8005F2BB0 /* FixedMenuViewController.swift */, + 885680A61A378E55005F2BB0 /* BaseMenuViewController+Commands.swift */, + 88A759B01A2F9FC10005B04C /* KeyboardViewController.swift */, + 8823D7AD1A30E3D200271406 /* ConversationListViewController.swift */, + 8823D7B01A30E8B500271406 /* UIViewController+EyeType.swift */, + 23FAF5441A52EDED00ADD423 /* ChatViewController.swift */, + ); + name = Controllers; + sourceTree = ""; + }; + 23BA3E251A38EB1500C5AD4B /* Core Data Model */ = { + isa = PBXGroup; + children = ( + 2338BB441A794B5D00901026 /* Contact.swift */, + 232CE5371A3A3E4D00C94EE8 /* Message.swift */, + 232CE5351A3A3DCF00C94EE8 /* Conversation.swift */, + 232CE5331A3A3D9300C94EE8 /* TelegramAccount.swift */, + 232CE5311A3A3D6100C94EE8 /* Account.swift */, + ); + name = "Core Data Model"; + sourceTree = ""; + }; 887A2CB61A0BDB4400094E3C = { isa = PBXGroup; children = ( @@ -158,26 +216,20 @@ 887A2CC11A0BDB4500094E3C /* EyeTypeChat */ = { isa = PBXGroup; children = ( + 2333C0A01A51A0EC00784BEA /* View Model */, + 23BA3E251A38EB1500C5AD4B /* Core Data Model */, + 236ACA291A44BEFB003D1F53 /* Controllers */, 887A2CC41A0BDB4500094E3C /* AppDelegate.swift */, - 887A2CC91A0BDB4500094E3C /* MainViewController.swift */, - 88A759A01A2F7B070005B04C /* MainViewModel.swift */, + 23C120CD1A4340F8004D7B5E /* MockedData.swift */, + 231A94141A72AE38008CD10E /* ChatTableViewCell.swift */, + 23E593001A7BC78E003DCE61 /* UIImage+Color.swift */, 88A759AB1A2F9D4D0005B04C /* EyeControllable.swift */, - 8823D7B21A30F65E00271406 /* BaseMenuViewController.swift */, - 885680A11A374BB8005F2BB0 /* FixedMenuViewController.swift */, - 885680A61A378E55005F2BB0 /* FixedMenuViewController+Commands.swift */, - 88A759B01A2F9FC10005B04C /* KeyboardViewController.swift */, - 8823D7AD1A30E3D200271406 /* ConversationViewController.swift */, - 8823D7B01A30E8B500271406 /* UIViewController+EyeType.swift */, - 885ABDE41A13E1DD00552B16 /* MyPlayground.playground */, + 237E245F1A56E4E90031B30A /* ChatControllable.swift */, + 8856809E1A374B2D005F2BB0 /* fixedMenus.plist */, 887A2CCB1A0BDB4500094E3C /* Main.storyboard */, 887A2CCE1A0BDB4500094E3C /* Images.xcassets */, - 887A2CD01A0BDB4500094E3C /* LaunchScreen.xib */, 887A2CC61A0BDB4500094E3C /* EyeTypeChat.xcdatamodeld */, 887A2CC21A0BDB4500094E3C /* Supporting Files */, - 88C5237B1A12933E005E0D71 /* EyeTypeChat-Bridging-Header.h */, - 8856809E1A374B2D005F2BB0 /* fixedMenus.plist */, - 885680A31A376E1F005F2BB0 /* SwiftBridge.h */, - 885680A41A376E47005F2BB0 /* SwiftBridge.m */, ); path = EyeTypeChat; sourceTree = ""; @@ -185,6 +237,11 @@ 887A2CC21A0BDB4500094E3C /* Supporting Files */ = { isa = PBXGroup; children = ( + 885ABDE41A13E1DD00552B16 /* MyPlayground.playground */, + 887A2CD01A0BDB4500094E3C /* LaunchScreen.xib */, + 88C5237B1A12933E005E0D71 /* EyeTypeChat-Bridging-Header.h */, + 885680A31A376E1F005F2BB0 /* SwiftBridge.h */, + 885680A41A376E47005F2BB0 /* SwiftBridge.m */, 887A2CC31A0BDB4500094E3C /* Info.plist */, 885D57601A25062D00912290 /* Podfile */, ); @@ -307,6 +364,11 @@ TargetAttributes = { 887A2CBE1A0BDB4500094E3C = { CreatedOnToolsVersion = 6.1; + SystemCapabilities = { + com.apple.Maps.iOS = { + enabled = 0; + }; + }; }; 887A2CD61A0BDB4500094E3C = { CreatedOnToolsVersion = 6.1; @@ -409,18 +471,29 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8823D7AE1A30E3D200271406 /* ConversationViewController.swift in Sources */, + 236ACA281A44B8B2003D1F53 /* EyeControllable.swift in Sources */, + 8823D7AE1A30E3D200271406 /* ConversationListViewController.swift in Sources */, + 2333C0A21A51A0F900784BEA /* ChatViewModel.swift in Sources */, + 232CE5361A3A3DCF00C94EE8 /* Conversation.swift in Sources */, 887A2CCA1A0BDB4500094E3C /* MainViewController.swift in Sources */, + 231A94151A72AE38008CD10E /* ChatTableViewCell.swift in Sources */, + 232CE5341A3A3D9300C94EE8 /* TelegramAccount.swift in Sources */, + 237E24601A56E4E90031B30A /* ChatControllable.swift in Sources */, 88A759B11A2F9FC10005B04C /* KeyboardViewController.swift in Sources */, 887A2CC51A0BDB4500094E3C /* AppDelegate.swift in Sources */, 887A2CC81A0BDB4500094E3C /* EyeTypeChat.xcdatamodeld in Sources */, 88A759A11A2F7B070005B04C /* MainViewModel.swift in Sources */, 8823D7B11A30E8B500271406 /* UIViewController+EyeType.swift in Sources */, + 2338BB451A794B5D00901026 /* Contact.swift in Sources */, 885680A21A374BB8005F2BB0 /* FixedMenuViewController.swift in Sources */, 885680A51A376E47005F2BB0 /* SwiftBridge.m in Sources */, - 88A759AC1A2F9D4D0005B04C /* EyeControllable.swift in Sources */, - 885680A71A378E55005F2BB0 /* FixedMenuViewController+Commands.swift in Sources */, + 23E593011A7BC78E003DCE61 /* UIImage+Color.swift in Sources */, + 885680A71A378E55005F2BB0 /* BaseMenuViewController+Commands.swift in Sources */, 8823D7B31A30F65E00271406 /* BaseMenuViewController.swift in Sources */, + 23C120CE1A4340F8004D7B5E /* MockedData.swift in Sources */, + 232CE5381A3A3E4D00C94EE8 /* Message.swift in Sources */, + 23FAF5451A52EDED00ADD423 /* ChatViewController.swift in Sources */, + 232CE5321A3A3D6100C94EE8 /* Account.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/EyeTypeChat/Base.lproj/LaunchScreen.xib b/EyeTypeChat/Base.lproj/LaunchScreen.xib index 5b94eee..b2230be 100644 --- a/EyeTypeChat/Base.lproj/LaunchScreen.xib +++ b/EyeTypeChat/Base.lproj/LaunchScreen.xib @@ -1,7 +1,8 @@ - + - + + diff --git a/EyeTypeChat/Base.lproj/Main.storyboard b/EyeTypeChat/Base.lproj/Main.storyboard index e06a97a..67a38cd 100644 --- a/EyeTypeChat/Base.lproj/Main.storyboard +++ b/EyeTypeChat/Base.lproj/Main.storyboard @@ -1,8 +1,9 @@ - + + @@ -93,7 +94,7 @@ - + @@ -140,20 +141,67 @@ - + - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -171,11 +219,14 @@ - + + + + - + @@ -212,10 +263,10 @@ - + - + @@ -226,9 +277,6 @@ - - - @@ -326,5 +374,20 @@ + + + + + + + + + + + + + + + diff --git a/EyeTypeChat/BaseMenuViewController+Commands.swift b/EyeTypeChat/BaseMenuViewController+Commands.swift new file mode 100644 index 0000000..9e28cb8 --- /dev/null +++ b/EyeTypeChat/BaseMenuViewController+Commands.swift @@ -0,0 +1,18 @@ +// +// ConversationViewController+Commands.swift +// EyeTypeChat +// +// Created by Emanuel Andrada on 9/12/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import Foundation + +extension BaseMenuViewController { + + func showKeyboard() { + let viewController: KeyboardViewController = self.storyboard!.instantiateViewControllerWithIdentifier("keyboard") as KeyboardViewController! + viewController.chatControllable = mainViewController? + self.navigationController!.pushViewController(viewController, animated: true) + } +} diff --git a/EyeTypeChat/BaseMenuViewController.swift b/EyeTypeChat/BaseMenuViewController.swift index 6024651..de82c18 100644 --- a/EyeTypeChat/BaseMenuViewController.swift +++ b/EyeTypeChat/BaseMenuViewController.swift @@ -33,7 +33,7 @@ class BaseMenuViewController: UITableViewController, EyeControllable { } return cell! } - + func validRow(indexPath: NSIndexPath) -> NSIndexPath { if (indexPath.section >= numberOfSectionsInTableView(tableView)) { return NSIndexPath(forRow: 0, inSection: 0) diff --git a/EyeTypeChat/ChatControllable.swift b/EyeTypeChat/ChatControllable.swift new file mode 100644 index 0000000..8a829fa --- /dev/null +++ b/EyeTypeChat/ChatControllable.swift @@ -0,0 +1,18 @@ +// +// ChatControllable.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 1/2/15. +// Copyright (c) 2015 SCV Soft. All rights reserved. +// + +import Foundation + +@objc +protocol ChatControllable { + + func chatWillType(letter: String) + func chatWillSend() + func chatWillClearAll() + +} \ No newline at end of file diff --git a/EyeTypeChat/ChatTableViewCell.swift b/EyeTypeChat/ChatTableViewCell.swift new file mode 100644 index 0000000..edc2835 --- /dev/null +++ b/EyeTypeChat/ChatTableViewCell.swift @@ -0,0 +1,35 @@ +// +// ChatTableViewCell.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 1/23/15. +// Copyright (c) 2015 SCV Soft. All rights reserved. +// + +import Foundation + +class ChatTableViewCell: UITableViewCell { + + @IBOutlet weak var photoView: UIImageView! + + @IBOutlet weak var fromLabel: UILabel! + + @IBOutlet weak var messageLabel: UILabel! + + @IBOutlet weak var sentDateLabel: UILabel! + + func loadItem(from fromMessage: String, fromContactColor: UIColor, message: String, sentDate: NSDate, imageName: String) { + + fromLabel.text = fromMessage + fromLabel.textColor = fromContactColor + fromLabel.font = UIFont .preferredFontForTextStyle(UIFontTextStyleHeadline) + messageLabel.text = message + messageLabel.font = UIFont .preferredFontForTextStyle(UIFontTextStyleBody) + messageLabel.numberOfLines = 0 + sentDateLabel.text = MockedData.getFormattedDate(sentDate) + sentDateLabel.font = UIFont .preferredFontForTextStyle(UIFontTextStyleSubheadline) + let image = UIImage(named: imageName) + photoView.image = image?.colorizeWith(fromContactColor) + + } +} \ No newline at end of file diff --git a/EyeTypeChat/ChatViewController.swift b/EyeTypeChat/ChatViewController.swift new file mode 100644 index 0000000..f410862 --- /dev/null +++ b/EyeTypeChat/ChatViewController.swift @@ -0,0 +1,176 @@ +// +// ChatViewController.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 12/30/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import Foundation +import UIKit +import CoreData + +class ChatViewController: BaseMenuViewController { + + @IBOutlet weak var writingTextField: UITextField! + + lazy var managedObjectContext : NSManagedObjectContext? = { + let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate + if let managedObjectContext = appDelegate.managedObjectContext { + return managedObjectContext + } + else { + return nil + } + }() + + var selectedConversation: Conversation? + + lazy var chatModel: ChatViewModel = ChatViewModel(currentConversation: self.selectedConversation!) + + var messageItems = [MessageItem]() + + + override func viewDidLoad() { + setupTableView() + loadConversations() + super.viewDidLoad() + } + + override func viewDidAppear(animated: Bool) { + super.viewDidAppear(animated) + goToBottom() + } + + func setupTableView(){ + self.tableView.estimatedRowHeight = 60.0 + self.tableView.rowHeight = UITableViewAutomaticDimension + } + + func loadConversations(){ + let conversationList = MockedData.getConversationList(managedObjectContext!) + loadConversation(conversationList[0] as Conversation) + } + + func loadConversation(chat: Conversation){ + self.selectedConversation = chat + self.navigationItem.title = chat.title + loadMessagesItems(forChat: self.selectedConversation!) + } + + func loadMessagesItems(forChat chat: Conversation) { + messageItems.removeAll(keepCapacity: true) + chatModel = ChatViewModel(currentConversation: chat) + writingTextField.text = chatModel.currentWritingText + self.selectedConversation = chatModel.currentConversation + // load dynamically the mocked conversations + let messages = MockedData.getOrderedMessages(managedObjectContext!, forConversation: chat) + for item in messages! { + let chatItem = MessageItem(item: item as Message) + messageItems.append(chatItem) + } + updateUI(); + + } + + func updateUI(){ + tableView.reloadData() + tableView.layoutIfNeeded() + goToBottom() + } + + override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) { + updateUI() + } + + func addNewMessage(){ + MockedData.addNewMessage(managedObjectContext!, message: self.writingTextField.text, conversation: self.chatModel.currentConversation) + } + + class MessageItem { + + var message: Message + + init (item: Message) { + message = item + } + } + + // MARK: UITableViewController + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section > 0 { + return 1 + } + return messageItems.count + } + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + + var cell:ChatTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("chatCell") as ChatTableViewCell + + //configuring cell + cell.textLabel?.lineBreakMode = .ByWordWrapping + cell.textLabel?.numberOfLines = 0 + cell.selectionStyle = .None + cell.userInteractionEnabled = false + + //getting values for cell + let messageText = messageItems[indexPath.row].message.text + let messageSentDate = messageItems[indexPath.row].message.sentDateTime + var messageFrom:String + var contactColor:UIColor + if let from = messageItems[indexPath.row].message.fromContact{ + messageFrom = "\(from.name)" + contactColor = from.color + }else{ + messageFrom = "\(MockedData.getUserIdentifier(managedObjectContext!)!)" + contactColor = UIColor.blueColor() // default color for user: blue + } + + let userDefaultImage = "user_default.png" + + //loading cell + cell.loadItem(from: messageFrom, fromContactColor: contactColor, message: messageText, sentDate: messageSentDate, imageName: userDefaultImage) + + return cell + } + + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + // Do nothing + } + + + // MARK: Chat + + func type(letter: String) { + chatModel.currentWritingText = chatModel.currentWritingText + letter + writingTextField.text = chatModel.currentWritingText + } + + func sendMessage() { + addNewMessage() + loadConversations() + clearCurrentText() + } + + func clearCurrentText(){ + chatModel.currentWritingText = "" + writingTextField.text = chatModel.currentWritingText + } + + func goToBottom(){ + tableView.scrollToRowAtIndexPath(lastIndexPath(), atScrollPosition: UITableViewScrollPosition.None, animated: false) + } + + func lastIndexPath() -> NSIndexPath{ + let lastRowIndex = tableView.numberOfRowsInSection(0) - 1 + return NSIndexPath(forRow: lastRowIndex, inSection: 0) + } + + +} diff --git a/EyeTypeChat/ChatViewModel.swift b/EyeTypeChat/ChatViewModel.swift new file mode 100644 index 0000000..58de96b --- /dev/null +++ b/EyeTypeChat/ChatViewModel.swift @@ -0,0 +1,26 @@ +// +// ChatViewModel.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 12/29/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import Foundation + +class ChatViewModel { + + var currentConversation: Conversation + var currentWritingText: String + + init(currentConversation conversation: Conversation){ + self.currentConversation = conversation + self.currentWritingText = "" + } + + func clearWrittenText(){ + currentWritingText = "" + } + + +} \ No newline at end of file diff --git a/EyeTypeChat/ConversationListViewController.swift b/EyeTypeChat/ConversationListViewController.swift new file mode 100644 index 0000000..c2134e3 --- /dev/null +++ b/EyeTypeChat/ConversationListViewController.swift @@ -0,0 +1,79 @@ +// +// ConversationViewController.swift +// EyeTypeChat +// +// Created by Emanuel Andrada on 4/12/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import UIKit +import Foundation +import CoreData + +class ConversationListViewController: BaseMenuViewController { + + lazy var managedObjectContext : NSManagedObjectContext? = { + let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate + if let managedObjectContext = appDelegate.managedObjectContext { + return managedObjectContext + } + else { + return nil + } + }() + + var conversationItems = NSOrderedSet() + + override func viewDidLoad() { + loadConversationItems() + super.viewDidLoad() + } + + override func viewWillAppear(animated: Bool) { + loadConversationItems() + self.tableView.reloadData() + super.viewWillAppear(animated) + } + + func loadConversationItems() { + // load dynamically the mocked conversations + conversationItems = MockedData.getConversationList(managedObjectContext!) + + } + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return showCancel ? 2 : 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section > 0 { + return 1 + } + return conversationItems.count + } + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = self.cell() + if indexPath.section > 0 { + cell.textLabel?.text = "Cancel" + } + else { + cell.textLabel?.text = conversationItems[indexPath.row].title + } + return cell + } + + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + if indexPath.section > 0 { + eyeDidCancel() + } + else { + self.mainViewController?.selectConversation(conversationItems[indexPath.row] as Conversation) + let vc = storyboard!.instantiateViewControllerWithIdentifier("fixedMenu") as FixedMenuViewController + vc.menuName = "conversation" + navigationController?.pushViewController(vc, animated: true) + } + } + + +} diff --git a/EyeTypeChat/ConversationViewController.swift b/EyeTypeChat/ConversationViewController.swift deleted file mode 100644 index fcb5377..0000000 --- a/EyeTypeChat/ConversationViewController.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// ConversationViewController.swift -// EyeTypeChat -// -// Created by Emanuel Andrada on 4/12/14. -// Copyright (c) 2014 SCV Soft. All rights reserved. -// - -import UIKit - -class ConversationViewController: UITableViewController { - - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { - return 1 - } - - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 0 - } -} diff --git a/EyeTypeChat/EyeTypeChat.xcdatamodeld/EyeTypeChat.xcdatamodel/contents b/EyeTypeChat/EyeTypeChat.xcdatamodeld/EyeTypeChat.xcdatamodel/contents index 193f33c..c4e2a64 100644 --- a/EyeTypeChat/EyeTypeChat.xcdatamodeld/EyeTypeChat.xcdatamodel/contents +++ b/EyeTypeChat/EyeTypeChat.xcdatamodeld/EyeTypeChat.xcdatamodel/contents @@ -1,4 +1,34 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EyeTypeChat/FixedMenuViewController+Commands.swift b/EyeTypeChat/FixedMenuViewController+Commands.swift deleted file mode 100644 index c5e7a40..0000000 --- a/EyeTypeChat/FixedMenuViewController+Commands.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// FixedMenuViewController+Commands.swift -// EyeTypeChat -// -// Created by Emanuel Andrada on 9/12/14. -// Copyright (c) 2014 SCV Soft. All rights reserved. -// - -import Foundation - -extension FixedMenuViewController { - - func showKeyboard() { - let viewController = self.storyboard!.instantiateViewControllerWithIdentifier("keyboard") as UIViewController! - self.navigationController!.pushViewController(viewController, animated: true) - } -} diff --git a/EyeTypeChat/FixedMenuViewController.swift b/EyeTypeChat/FixedMenuViewController.swift index 3872721..a231e26 100644 --- a/EyeTypeChat/FixedMenuViewController.swift +++ b/EyeTypeChat/FixedMenuViewController.swift @@ -60,7 +60,7 @@ class FixedMenuViewController: BaseMenuViewController { eyeDidCancel() } else { - performSelectorInObject(self, menuItems[indexPath.row].selector) + performSelectorInObject(self, menuItems[indexPath.row].selector, nil) } } diff --git a/EyeTypeChat/Images.xcassets/user_default.imageset/Contents.json b/EyeTypeChat/Images.xcassets/user_default.imageset/Contents.json new file mode 100644 index 0000000..b9825cd --- /dev/null +++ b/EyeTypeChat/Images.xcassets/user_default.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "ic_account_circle_black_48dp-1.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "ic_account_circle_black_48dp.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "ic_account_circle_black_48dp-2.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp-1.png b/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp-1.png new file mode 100644 index 0000000..dba1d58 Binary files /dev/null and b/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp-1.png differ diff --git a/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp-2.png b/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp-2.png new file mode 100644 index 0000000..44f856e Binary files /dev/null and b/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp-2.png differ diff --git a/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp.png b/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp.png new file mode 100644 index 0000000..94ede99 Binary files /dev/null and b/EyeTypeChat/Images.xcassets/user_default.imageset/ic_account_circle_black_48dp.png differ diff --git a/EyeTypeChat/KeyboardViewController.swift b/EyeTypeChat/KeyboardViewController.swift index 3e61382..535c9ac 100644 --- a/EyeTypeChat/KeyboardViewController.swift +++ b/EyeTypeChat/KeyboardViewController.swift @@ -12,18 +12,19 @@ class KeyboardViewController: UIViewController, EyeControllable { @IBOutlet var keyboardContainer: UIView! @IBOutlet var cancelButton: UIButton! + var chatControllable:ChatControllable! = nil var keyButtons = [[UIButton]]() var selectedButton: UIButton? let margin: CGFloat = 8 var keys = [ - ["A", "b", "c", "d", "1", "2"], - ["E", "f", "g", "h", "3", "4"], - ["I", "j", "k", "l", "m", "n"], - ["O", "p", "q", "r", "s", "t"], - ["U", "v", "w", "x", "y", "z"], + ["a", "b", "c", "d", "1", "2"], + ["e", "f", "g", "h", "3", "4"], + ["i", "j", "k", "l", "m", "n"], + ["o", "p", "q", "r", "s", "t"], + ["u", "v", "w", "x", "y", "z"], ["5", "6", "7", "8", "9", "0"], - ["space", "comma", "point"] + ["space", "comma", "point", "clear", "send"] ] var showCancel = false var currentLine = 0 @@ -39,6 +40,7 @@ class KeyboardViewController: UIViewController, EyeControllable { createKeyboard() } + func createKeyboard() { self.keyboardContainer.removeConstraints(self.keyboardContainer.constraints()) var i = 0 @@ -92,7 +94,36 @@ class KeyboardViewController: UIViewController, EyeControllable { } selectedButton!.selected = true } + + func updateWritingText(letter:String) { + chatControllable.chatWillType(letter) + } + func sendWrittenText() { + chatControllable.chatWillSend() + } + + func clearWrittenText() { + chatControllable.chatWillClearAll() + } + + func executeActionAccordingToKeySelection(key: String){ + switch key{ + case "send": + sendWrittenText() + case "clear": + clearWrittenText() + case "point": + updateWritingText(".") + case "comma": + updateWritingText(",") + case "space": + updateWritingText(" ") + default: + updateWritingText(key) + + } + } // MARK: EyeControllable func eyeDidAccept() { @@ -101,11 +132,13 @@ class KeyboardViewController: UIViewController, EyeControllable { eyeDidCancel() } else { - NSLog("key '%@'", selectedButton!.titleForState(UIControlState.Normal)!) + let keySelection = selectedButton!.titleForState(UIControlState.Normal)! + NSLog("key '%@'", keySelection) currentLine = 0 currentRow = 0 lineSelected = false updateSelection() + executeActionAccordingToKeySelection(keySelection) } } else { diff --git a/EyeTypeChat/MainViewController.swift b/EyeTypeChat/MainViewController.swift index 9c3093e..292148d 100644 --- a/EyeTypeChat/MainViewController.swift +++ b/EyeTypeChat/MainViewController.swift @@ -7,25 +7,35 @@ // import UIKit +import CoreData -class MainViewController: ETVideoSourceViewController { +class MainViewController: ETVideoSourceViewController , ChatControllable { var timer: NSTimer? var subNavigationController: UINavigationController! - var conversationNavigationController: UINavigationController! + var chatNavigationController: UINavigationController! var ignoreNextTick = false - - var myModel: MainViewModel { - get { - return self.model as MainViewModel + + lazy var managedObjectContext : NSManagedObjectContext? = { + let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate + if let managedObjectContext = appDelegate.managedObjectContext { + return managedObjectContext } - } - + else { + return nil + } + }() + required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.model = MainViewModel() } + override func viewDidLoad() { + super.viewDidLoad() + createAndPrintMockedData() + } + override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) startDetect() @@ -50,6 +60,19 @@ class MainViewController: ETVideoSourceViewController { self.videoSource.stopRunning() } + + var myModel: MainViewModel { + get { + return self.model as MainViewModel + } + } + + func createAndPrintMockedData(){ + var mockedData = MockedData(dataContext: managedObjectContext!) + // MockedData.printMockedData(managedObjectContext!) + } + + @IBAction func eyeDidAccept() { if let controllable = subNavigationController.topViewController as? EyeControllable { controllable.eyeDidAccept() @@ -73,14 +96,20 @@ class MainViewController: ETVideoSourceViewController { else { ignoreNextTick = false } + } + func selectConversation(chat: Conversation){ + let c = self.chatNavigationController.topViewController as ChatViewController + c.loadConversation(chat) + } + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if (segue.identifier == "subNavigationController") { subNavigationController = segue.destinationViewController as UINavigationController } - else if (segue.identifier == "conversation") { - conversationNavigationController = segue.destinationViewController as UINavigationController + else if (segue.identifier == "chatSegue") { + chatNavigationController = segue.destinationViewController as UINavigationController } } @@ -89,5 +118,22 @@ class MainViewController: ETVideoSourceViewController { return self } } + + // MARK: ChatControllable + + func chatWillType(letter: String) { + let c = self.chatNavigationController.topViewController as ChatViewController + c.type(letter) + } + + func chatWillSend() { + let c = self.chatNavigationController.topViewController as ChatViewController + c.sendMessage() + } + + func chatWillClearAll() { + let c = self.chatNavigationController.topViewController as ChatViewController + c.clearCurrentText() + } } diff --git a/EyeTypeChat/MainViewModel.swift b/EyeTypeChat/MainViewModel.swift index bd352b3..6461b47 100644 --- a/EyeTypeChat/MainViewModel.swift +++ b/EyeTypeChat/MainViewModel.swift @@ -11,6 +11,7 @@ import UIKit class MainViewModel: ETVideoSourceViewModel { var tickInterval: NSTimeInterval = 1 + var inputMessage = "" override func executeOKAction() { } diff --git a/EyeTypeChat/MockedData.swift b/EyeTypeChat/MockedData.swift new file mode 100644 index 0000000..ff5cd2a --- /dev/null +++ b/EyeTypeChat/MockedData.swift @@ -0,0 +1,298 @@ +// +// MockedData.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 12/18/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import Foundation +import CoreData +import UIKit + +class MockedData { + + init(dataContext: NSManagedObjectContext){ + + // create Telegram account + var telegramAccount = TelegramAccount.createTelegramAccount("Me", entity: "TelegramAccount", context: dataContext) + + // create contact list + var contactSet = NSMutableSet() + var firstContact = Contact.createContact("Mary", phoneNumber: 263823827, color: MockedData.randomColor(), account: telegramAccount, entity: "Contact", context: dataContext) + var secondContact = Contact.createContact("Anna", phoneNumber: 1161690000, color: MockedData.randomColor(), account: telegramAccount, entity: "Contact", context: dataContext) + var thirdContact = Contact.createContact("John", phoneNumber: 328378738, color: MockedData.randomColor(), account: telegramAccount, entity: "Contact", context: dataContext) + contactSet.addObjectsFromArray([firstContact, secondContact, thirdContact]) + + // create conversations + var conversationSet = NSMutableSet() + + // create bff chat + var contactsInBffChat = NSMutableSet() + contactsInBffChat.addObject(firstContact) + var bffConversation = Conversation.createConversation(nil, account: telegramAccount, betweenContacts: contactsInBffChat, messages: nil, entity: "Conversation", context: dataContext) + + // create some messages for bff chat + var currentDate: NSDate? = NSDate(); + let yesterdayDate: NSDate? = NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitDay, value: -1, toDate: NSDate(), options: nil) + var msg01 = Message.createMessage("Hi Mary!", sentDateTime: yesterdayDate!, conversation: bffConversation, fromContact: nil, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(-30, date: currentDate) + var msg02 = Message.createMessage("How are you?", sentDateTime: currentDate!, conversation: bffConversation, fromContact: nil, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(2, date: currentDate) + var msg03 = Message.createMessage("Great! and u?", sentDateTime: currentDate!, conversation: bffConversation, fromContact: firstContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg04 = Message.createMessage("How was San Francisco?", sentDateTime: currentDate!, conversation: bffConversation, fromContact: firstContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg05 = Message.createMessage("Fantastic! See u tomorrow?", sentDateTime: currentDate!, conversation: bffConversation, fromContact: nil, entity: "Message", context:dataContext) + + currentDate = MockedData.dateByAddingMinutes(2, date: currentDate) + var msg06 = Message.createMessage("Sure :)", sentDateTime: currentDate!, conversation: bffConversation, fromContact: firstContact, entity: "Message", context: dataContext) + + var messages = NSMutableSet() + messages.addObjectsFromArray([msg01, msg02, msg03, msg04, msg05, msg06]) + bffConversation.messages = messages + conversationSet.addObject(bffConversation) + + // create group chat + var contactsInGroupChat = NSMutableSet() + contactsInGroupChat.addObjectsFromArray([secondContact, thirdContact]) + var groupConversation = Conversation.createConversation(nil, account: telegramAccount, betweenContacts: contactsInGroupChat, messages: nil, entity: "Conversation", context: dataContext) + + // create some messages for group chat + currentDate = MockedData.dateByAddingMinutes(-50, date: NSDate()) + var msg11 = Message.createMessage("Hello everyone!", sentDateTime: currentDate!, conversation: groupConversation, fromContact: secondContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg12 = Message.createMessage("Hi!", sentDateTime: currentDate!, conversation: groupConversation, fromContact: nil, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(0, date: currentDate) + var msg13 = Message.createMessage("Any news from Tom?", sentDateTime: currentDate!, conversation: groupConversation, fromContact: secondContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(2, date: currentDate) + var msg14 = Message.createMessage("He sent a confirmation email", sentDateTime: currentDate!, conversation: groupConversation, fromContact: thirdContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg15 = Message.createMessage("The plane arrives to NY at 10pm 8pm 7278pm shsjjs hsdhsha test testing eyeun 11 34pm hddueok ma shs aew uwi blah bluon uy 66282 syu or s wop ww bb asrsueoq mlq test.", sentDateTime: currentDate!, conversation: groupConversation, fromContact: nil, entity: "Message", context:dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg16 = Message.createMessage("Perfect", sentDateTime: currentDate!, conversation: groupConversation, fromContact: secondContact, entity: "Message", context: dataContext) + + var groupMessages = NSMutableSet() + groupMessages.addObjectsFromArray([msg11, msg12, msg13, msg14, msg15, msg16]) + groupConversation.messages = groupMessages + conversationSet.addObject(groupConversation) + + // create multiple group chat + var contactsInMultipleGroupChat = NSMutableSet() + contactsInMultipleGroupChat.addObjectsFromArray([firstContact, secondContact, thirdContact]) + var multipleGroupConversation = Conversation.createConversation(nil, account: telegramAccount, betweenContacts: contactsInMultipleGroupChat, messages: nil, entity: "Conversation", context: dataContext) + + // create some messages for multiple group chat + currentDate = MockedData.dateByAddingMinutes(-50, date: NSDate()) + var msg17 = Message.createMessage("1, 2, 3", sentDateTime: currentDate!, conversation: multipleGroupConversation, fromContact: secondContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg18 = Message.createMessage("4", sentDateTime: currentDate!, conversation: multipleGroupConversation, fromContact: firstContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(0, date: currentDate) + var msg19 = Message.createMessage("5", sentDateTime: currentDate!, conversation: multipleGroupConversation, fromContact: secondContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(2, date: currentDate) + var msg20 = Message.createMessage("6, 7, 7, 7", sentDateTime: currentDate!, conversation: multipleGroupConversation, fromContact: thirdContact, entity: "Message", context: dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg21 = Message.createMessage("blah blah 8", sentDateTime: currentDate!, conversation: multipleGroupConversation, fromContact: nil, entity: "Message", context:dataContext) + + currentDate = MockedData.dateByAddingMinutes(1, date: currentDate) + var msg22 = Message.createMessage("9Blah! ", sentDateTime: currentDate!, conversation: multipleGroupConversation, fromContact: secondContact, entity: "Message", context: dataContext) + + var multipleGroupMessages = NSMutableSet() + multipleGroupMessages.addObjectsFromArray([msg17, msg18, msg19, msg20, msg21, msg22]) + multipleGroupConversation.messages = multipleGroupMessages + conversationSet.addObject(multipleGroupConversation) + + // associate contact list with the Telegram account + telegramAccount.contacts = contactSet + // associate conversation list with the Telegram account + telegramAccount.conversations = conversationSet + + } + + class func getUserIdentifier(dataContext: NSManagedObjectContext) -> String?{ + let fetchRequest = NSFetchRequest(entityName: "TelegramAccount") + if let fetchResults = dataContext.executeFetchRequest(fetchRequest, error: nil) as? [TelegramAccount] { + + return fetchResults[0].userIdentifier + } + return nil + } + + class func dateByAddingMinutes(value: Int, date: NSDate?) -> NSDate?{ + return NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.CalendarUnitMinute, value: value, toDate: date!, options: NSCalendarOptions.SearchBackwards) + } + + class func getConversationList(dataContext: NSManagedObjectContext) -> NSOrderedSet{ + let fetchRequest = NSFetchRequest(entityName: "Conversation") + var orderedConversation = NSMutableOrderedSet() + if let fetchResults = dataContext.executeFetchRequest(fetchRequest, error: nil) as? [Conversation] + { + var lastMessageInConversations = NSMutableOrderedSet() + for conversation in fetchResults{ + if let lastMessage = MockedData.getLastMessage(dataContext, forConversation: conversation){ + lastMessageInConversations.addObject(lastMessage) + } + } + + let sortDateDescriptor = NSSortDescriptor(key: "sentDateTime", ascending: false) + lastMessageInConversations.sortUsingDescriptors([sortDateDescriptor]) + lastMessageInConversations.enumerateObjectsUsingBlock { (elem, idx, stop) -> Void in + let sms = elem as Message + let chat = sms.conversation as Conversation + orderedConversation.addObject(chat) + } + } + + return orderedConversation + } + + + class func getLastMessage(dataContext: NSManagedObjectContext, forConversation chat: Conversation?) -> Message?{ + let orderedMsgs = MockedData.getOrderedMessages(dataContext, forConversation: chat) + return orderedMsgs?.lastObject as Message? + + } + + class func getOrderedMessages(dataContext: NSManagedObjectContext, forConversation chat: Conversation?) -> NSArray?{ + let fetchRequest = NSFetchRequest(entityName: "Message") + var chatText = chat!.title + let chatPredicate = NSPredicate(format: "SELF.conversation.title = %@", chatText) + fetchRequest.predicate = chatPredicate + var dateDescriptor = NSSortDescriptor(key: "sentDateTime", ascending: true) + fetchRequest.sortDescriptors = [dateDescriptor] + return dataContext.executeFetchRequest(fetchRequest, error: nil) as? [Message] + } + + class func addNewMessage(dataContext: NSManagedObjectContext, message: String, conversation: Conversation){ + var currentDate: NSDate? = NSDate(); + var msg = Message.createMessage(message, sentDateTime: currentDate!, conversation: conversation, fromContact: nil, entity: "Message", context: dataContext) + } + + class func printMockedData(dataContext: NSManagedObjectContext){ + + let fetchRequest = NSFetchRequest(entityName: "TelegramAccount") + if let fetchResults = dataContext.executeFetchRequest(fetchRequest, error: nil) as? [TelegramAccount] { + + let contacts = fetchResults[0].contacts + println("Contact list") + for contact in contacts! { + if let eachContact = contact as? Contact { + println("Contact Name: \(eachContact.name). Phone Number: \(eachContact.phoneNumber)") + } + } + + let conversations = fetchResults[0].conversations + for chat in conversations! { + if let eachChat = chat as? Conversation { + println("Chat: \(eachChat.title)") + let messages = eachChat.messages + var msgsArray = messages?.allObjects as [Message] + + var sortedMsgs : [Message] = msgsArray + sortedMsgs.sort({$0.sentDateTime.timeIntervalSinceNow < $1.sentDateTime.timeIntervalSinceNow}) + + + for msg in sortedMsgs{ + let sentFormattedDate = MockedData.getFormattedDate(msg.sentDateTime) + var messageDetails: String + if let from = msg.fromContact{ + messageDetails = "Message: \(msg.text). From: \(msg.fromContact!.name). Sent: \(sentFormattedDate)." + }else{ + messageDetails = "Message: \(msg.text). From: \(MockedData.getUserIdentifier(dataContext)!) Sent: \(sentFormattedDate)." + } + + println(messageDetails) + } + + } + } + + } + + } + + class func getFormattedDate(dateTime: NSDate)-> String{ + let dateStringFormatter = NSDateFormatter() + if MockedData.isSameDay(dateTime, thanDate: NSDate()){ + dateStringFormatter.dateFormat = "hh:mm" + } + else{ + dateStringFormatter.dateFormat = "MM-dd-yyyy hh:mm" + } + return dateStringFormatter.stringFromDate(dateTime) + } + + class func isSameDay(dateTime: NSDate, thanDate anotherDate: NSDate)-> Bool { + let calendar = NSCalendar.currentCalendar() + let unitFlags: NSCalendarUnit = .YearCalendarUnit | .MonthCalendarUnit | .DayCalendarUnit + let componentDateTime = calendar.components(unitFlags, fromDate: dateTime) + let componentToday = calendar.components(unitFlags, fromDate: anotherDate) + let day = componentDateTime.day == componentToday.day + let month = componentDateTime.month == componentToday.month + let year = componentDateTime.year == componentToday.year + return (day && month && year) + } + + /* + Distributed under The MIT License: + http://opensource.org/licenses/mit-license.php + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + class func randomColor() -> UIColor{ + // from https://gist.github.com/kylefox/1689973 + + let value1 = UInt32(128) + let value2 : Float32 = 256.0 + let value3 : Float32 = 0.5 + + let hueRandom = Float(arc4random() % 256) + let hueValue = hueRandom / 256.0 // 0.0 to 1.0 + let hue = CGFloat(hueValue) + print(hueValue) + + let saturationRandom = arc4random() % value1 + let saturationValue = Float(saturationRandom) / value2 + value3 // 0.5 to 1.0, away from white + let saturation = CGFloat(saturationValue) + print(saturationValue) + + let brightnessRandom = arc4random() % value1 + let brightnessValue = Float(brightnessRandom) / value2 + value3 // 0.5 to 1.0, away from black + let brightness = CGFloat(brightnessValue) + print(brightnessValue) + + let color = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1) + return color + } + +} \ No newline at end of file diff --git a/EyeTypeChat/MyPlayground.playground/section-1.swift b/EyeTypeChat/MyPlayground.playground/section-1.swift index 6266254..2843bed 100644 --- a/EyeTypeChat/MyPlayground.playground/section-1.swift +++ b/EyeTypeChat/MyPlayground.playground/section-1.swift @@ -3,3 +3,4 @@ import UIKit var str = "Hello, playground" +str + "hey" diff --git a/EyeTypeChat/SwiftBridge.h b/EyeTypeChat/SwiftBridge.h index f0ac703..83bfe01 100644 --- a/EyeTypeChat/SwiftBridge.h +++ b/EyeTypeChat/SwiftBridge.h @@ -8,4 +8,5 @@ #import -void performSelectorInObject(id target, SEL selector); +void performSelectorInObject(id target, SEL selector, id object); + diff --git a/EyeTypeChat/SwiftBridge.m b/EyeTypeChat/SwiftBridge.m index 8dff607..1de4977 100644 --- a/EyeTypeChat/SwiftBridge.m +++ b/EyeTypeChat/SwiftBridge.m @@ -8,9 +8,9 @@ #import -void performSelectorInObject(id target, SEL selector) { +void performSelectorInObject(id target, SEL selector, id object) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" - [target performSelector:selector]; + [target performSelector:selector withObject:(id)object]; #pragma clang diagnostic pop } diff --git a/EyeTypeChat/UIImage+Color.swift b/EyeTypeChat/UIImage+Color.swift new file mode 100644 index 0000000..8d2f2df --- /dev/null +++ b/EyeTypeChat/UIImage+Color.swift @@ -0,0 +1,38 @@ +// +// UIImage+Color.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 1/30/15. +// Copyright (c) 2015 SCV Soft. All rights reserved. +// + +import Foundation + +extension UIImage { + + func colorizeWith(color: UIColor) -> UIImage { + + UIGraphicsBeginImageContext(self.size) + let context = UIGraphicsGetCurrentContext() + color.setFill() + CGContextTranslateCTM(context, 0, self.size.height) + CGContextScaleCTM(context, 1.0, -1.0) + + // set the blend mode to color burn, and the original image + CGContextSetBlendMode(context, kCGBlendModeNormal); + let rect = CGRectMake(0, 0, self.size.width, self.size.height); + CGContextDrawImage(context, rect, self.CGImage); + + // set a mask that matches the shape of the image, then draw (color burn) a colored rectangle + CGContextClipToMask(context, rect, self.CGImage); + CGContextAddRect(context, rect); + CGContextDrawPath(context,kCGPathFill); + + // generate a new UIImage from the graphics context we drew onto + let coloredImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return the color-burned image + return coloredImage; + } +} diff --git a/EyeTypeChat/model/Account.swift b/EyeTypeChat/model/Account.swift new file mode 100644 index 0000000..6d81760 --- /dev/null +++ b/EyeTypeChat/model/Account.swift @@ -0,0 +1,18 @@ +// +// EyeTypeChat.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 12/11/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import Foundation +import CoreData + +class Account: NSManagedObject { + + @NSManaged var userIdentifier: String + @NSManaged var contacts: NSSet? + @NSManaged var conversations: NSSet? + +} diff --git a/EyeTypeChat/model/Contact.swift b/EyeTypeChat/model/Contact.swift new file mode 100644 index 0000000..ced0951 --- /dev/null +++ b/EyeTypeChat/model/Contact.swift @@ -0,0 +1,33 @@ +// +// EyeTypeChat.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 1/28/15. +// Copyright (c) 2015 SCV Soft. All rights reserved. +// + +import Foundation +import CoreData + +class Contact: NSManagedObject { + + @NSManaged dynamic var color: UIColor + @NSManaged var name: String + @NSManaged var phoneNumber: NSNumber + @NSManaged var account: EyeTypeChat.Account // TODO: mark as unowned to avoid strong reference cycles + + + class func createContact(name: String, phoneNumber: NSNumber, color: UIColor, account: Account, entity: String, context: NSManagedObjectContext) -> Contact{ + + var contact = NSEntityDescription.insertNewObjectForEntityForName(entity, inManagedObjectContext: context) as Contact + contact.name = name + contact.phoneNumber = phoneNumber + contact.account = account + contact.color = color + + return contact + + } + + +} diff --git a/EyeTypeChat/model/Conversation.swift b/EyeTypeChat/model/Conversation.swift new file mode 100644 index 0000000..128853a --- /dev/null +++ b/EyeTypeChat/model/Conversation.swift @@ -0,0 +1,47 @@ +// +// EyeTypeChat.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 12/11/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import Foundation +import CoreData + +class Conversation: NSManagedObject { + + @NSManaged var title: String + @NSManaged var account: EyeTypeChat.Account // TODO: mark as unowned to avoid strong reference cycles + @NSManaged var betweenContacts: NSSet + @NSManaged var messages: NSSet? + + class func createConversation(title: String?, account: Account, betweenContacts: NSSet, messages: NSSet?, entity: String, context: NSManagedObjectContext) -> Conversation{ + + var defaultTitle = "" + if title == nil{ + defaultTitle = createDefaultTitleConversationBetweenContacts(betweenContacts) + } + var conversation = NSEntityDescription.insertNewObjectForEntityForName(entity, inManagedObjectContext: context) as Conversation + conversation.title = title != nil ? title! : defaultTitle + conversation.account = account + conversation.betweenContacts = betweenContacts; + conversation.messages = messages; + + return conversation + } + + class func createDefaultTitleConversationBetweenContacts(betweenContacts: NSSet) -> NSString{ + var title = "Chat with " + for var i = 0; i Message{ + + var message = NSEntityDescription.insertNewObjectForEntityForName(entity, inManagedObjectContext: context) as Message + message.text = text + message.sentDateTime = sentDateTime + message.conversation = conversation + message.fromContact = fromContact; + + return message + } + +} diff --git a/EyeTypeChat/model/TelegramAccount.swift b/EyeTypeChat/model/TelegramAccount.swift new file mode 100644 index 0000000..c8c67f2 --- /dev/null +++ b/EyeTypeChat/model/TelegramAccount.swift @@ -0,0 +1,24 @@ +// +// EyeTypeChat.swift +// EyeTypeChat +// +// Created by Maria Ines Casadei on 12/11/14. +// Copyright (c) 2014 SCV Soft. All rights reserved. +// + +import Foundation +import CoreData + +class TelegramAccount: EyeTypeChat.Account { + + class func createTelegramAccount(userIdentifier: String, entity: String, context: NSManagedObjectContext) -> TelegramAccount{ + + var telegramAccount = NSEntityDescription.insertNewObjectForEntityForName(entity, inManagedObjectContext: context) as TelegramAccount + telegramAccount.userIdentifier = userIdentifier + + return telegramAccount + } + + + +} diff --git a/TelegraphKit/TelegraphKit-Bridging-Header.h b/TelegraphKit/TelegraphKit-Bridging-Header.h new file mode 100644 index 0000000..1b2cb5d --- /dev/null +++ b/TelegraphKit/TelegraphKit-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// +