Permalink
Browse files

Initial commit

  • Loading branch information...
JussiSuojanen authored and Jussi Suojanen committed Feb 12, 2017
0 parents commit 7a2500952535d5d332e81e7c88c82ccbff3b5ffb
Showing with 13,405 additions and 0 deletions.
  1. +8 −0 .gitignore
  2. +714 −0 Friends.xcodeproj/project.pbxproj
  3. +7 −0 Friends.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  4. +10 −0 Friends.xcworkspace/contents.xcworkspacedata
  5. +125 −0 Friends/AddFriendViewController.swift
  6. +101 −0 Friends/AddFriendViewModel.swift
  7. +19 −0 Friends/Alert.swift
  8. +44 −0 Friends/AppDelegate.swift
  9. +133 −0 Friends/AppServerClient.swift
  10. +38 −0 Friends/Assets.xcassets/AppIcon.appiconset/Contents.json
  11. +31 −0 Friends/Base.lproj/LaunchScreen.storyboard
  12. +259 −0 Friends/Base.lproj/Main.storyboard
  13. +32 −0 Friends/Bindable.swift
  14. +32 −0 Friends/Friend.swift
  15. +25 −0 Friends/FriendCellViewModel.swift
  16. +27 −0 Friends/FriendTableViewCell.swift
  17. +109 −0 Friends/FriendsTableViewController.swift
  18. +86 −0 Friends/FriendsTableViewModel.swift
  19. +43 −0 Friends/Info.plist
  20. +9 −0 Friends/JSON.swift
  21. +17 −0 Friends/Result.swift
  22. +98 −0 Friends/UpdateFriendViewModel.swift
  23. +32 −0 FriendsTests/FriendsTests.swift
  24. +22 −0 FriendsTests/Info.plist
  25. +36 −0 FriendsUITests/FriendsUITests.swift
  26. +22 −0 FriendsUITests/Info.plist
  27. +8 −0 Podfile
  28. +15 −0 Podfile.lock
  29. +19 −0 Pods/Alamofire/LICENSE
  30. +1,764 −0 Pods/Alamofire/README.md
  31. +460 −0 Pods/Alamofire/Source/AFError.swift
  32. +465 −0 Pods/Alamofire/Source/Alamofire.swift
  33. +37 −0 Pods/Alamofire/Source/DispatchQueue+Alamofire.swift
  34. +581 −0 Pods/Alamofire/Source/MultipartFormData.swift
  35. +230 −0 Pods/Alamofire/Source/NetworkReachabilityManager.swift
  36. +52 −0 Pods/Alamofire/Source/Notifications.swift
  37. +433 −0 Pods/Alamofire/Source/ParameterEncoding.swift
  38. +647 −0 Pods/Alamofire/Source/Request.swift
  39. +345 −0 Pods/Alamofire/Source/Response.swift
  40. +714 −0 Pods/Alamofire/Source/ResponseSerialization.swift
  41. +102 −0 Pods/Alamofire/Source/Result.swift
  42. +307 −0 Pods/Alamofire/Source/ServerTrustPolicy.swift
  43. +721 −0 Pods/Alamofire/Source/SessionDelegate.swift
  44. +891 −0 Pods/Alamofire/Source/SessionManager.swift
  45. +453 −0 Pods/Alamofire/Source/TaskDelegate.swift
  46. +136 −0 Pods/Alamofire/Source/Timeline.swift
  47. +309 −0 Pods/Alamofire/Source/Validation.swift
  48. +15 −0 Pods/Manifest.lock
  49. +21 −0 Pods/PKHUD/LICENSE
  50. +63 −0 Pods/PKHUD/PKHUD/FrameView.swift
  51. +104 −0 Pods/PKHUD/PKHUD/HUD.swift
  52. +6 −0 Pods/PKHUD/PKHUD/Images.xcassets/Contents.json
  53. +12 −0 Pods/PKHUD/PKHUD/Images.xcassets/checkmark.imageset/Contents.json
  54. BIN Pods/PKHUD/PKHUD/Images.xcassets/checkmark.imageset/checkmark.pdf
  55. +12 −0 Pods/PKHUD/PKHUD/Images.xcassets/cross.imageset/Contents.json
  56. BIN Pods/PKHUD/PKHUD/Images.xcassets/cross.imageset/cross.pdf
  57. +12 −0 Pods/PKHUD/PKHUD/Images.xcassets/progress_activity.imageset/Contents.json
  58. BIN Pods/PKHUD/PKHUD/Images.xcassets/progress_activity.imageset/progress.pdf
  59. +15 −0 Pods/PKHUD/PKHUD/Images.xcassets/progress_circular.imageset/Contents.json
  60. BIN Pods/PKHUD/PKHUD/Images.xcassets/progress_circular.imageset/progress_circular.pdf
  61. +16 −0 Pods/PKHUD/PKHUD/PKHUD.h
  62. +193 −0 Pods/PKHUD/PKHUD/PKHUD.swift
  63. +16 −0 Pods/PKHUD/PKHUD/PKHUDAnimating.swift
  64. +61 −0 Pods/PKHUD/PKHUD/PKHUDAnimation.swift
  65. +29 −0 Pods/PKHUD/PKHUD/PKHUDAssets.swift
  66. +86 −0 Pods/PKHUD/PKHUD/PKHUDErrorView.swift
  67. +30 −0 Pods/PKHUD/PKHUD/PKHUDProgressView.swift
  68. +22 −0 Pods/PKHUD/PKHUD/PKHUDRotatingImageView.swift
  69. +80 −0 Pods/PKHUD/PKHUD/PKHUDSquareBaseView.swift
  70. +57 −0 Pods/PKHUD/PKHUD/PKHUDSuccessView.swift
  71. +51 −0 Pods/PKHUD/PKHUD/PKHUDSystemActivityIndicatorView.swift
  72. +46 −0 Pods/PKHUD/PKHUD/PKHUDTextView.swift
  73. +28 −0 Pods/PKHUD/PKHUD/PKHUDWideBaseView.swift
  74. +103 −0 Pods/PKHUD/PKHUD/Window.swift
  75. +46 −0 Pods/PKHUD/PKHUD/WindowRootViewController.swift
  76. +149 −0 Pods/PKHUD/README.md
  77. +849 −0 Pods/Pods.xcodeproj/project.pbxproj
  78. +5 −0 Pods/Target Support Files/Alamofire/Alamofire-dummy.m
  79. +4 −0 Pods/Target Support Files/Alamofire/Alamofire-prefix.pch
  80. +6 −0 Pods/Target Support Files/Alamofire/Alamofire-umbrella.h
  81. +6 −0 Pods/Target Support Files/Alamofire/Alamofire.modulemap
  82. +9 −0 Pods/Target Support Files/Alamofire/Alamofire.xcconfig
  83. +26 −0 Pods/Target Support Files/Alamofire/Info.plist
  84. +26 −0 Pods/Target Support Files/PKHUD/Info.plist
  85. +5 −0 Pods/Target Support Files/PKHUD/PKHUD-dummy.m
  86. +4 −0 Pods/Target Support Files/PKHUD/PKHUD-prefix.pch
  87. +7 −0 Pods/Target Support Files/PKHUD/PKHUD-umbrella.h
  88. +6 −0 Pods/Target Support Files/PKHUD/PKHUD.modulemap
  89. +9 −0 Pods/Target Support Files/PKHUD/PKHUD.xcconfig
  90. +26 −0 Pods/Target Support Files/Pods-Friends/Info.plist
  91. +50 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends-acknowledgements.markdown
  92. +84 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends-acknowledgements.plist
  93. +5 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends-dummy.m
  94. +93 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends-frameworks.sh
  95. +102 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends-resources.sh
  96. +6 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends-umbrella.h
  97. +10 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends.debug.xcconfig
  98. +6 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends.modulemap
  99. +10 −0 Pods/Target Support Files/Pods-Friends/Pods-Friends.release.xcconfig
  100. +10 −0 README.md
@@ -0,0 +1,8 @@
# Xcode
build/
*.pbxuser
xcuserdata
*.xccheckout
DerivedData
*.ipa
*.xcuserstate

Large diffs are not rendered by default.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -0,0 +1,125 @@
//
// AddFriendViewController.swift
// Friends
//
// Created by Jussi Suojanen on 06/01/17.
// Copyright © 2017 Jimmy. All rights reserved.
//
import UIKit
import PKHUD
protocol RefreshFriendData {
var updateFriends: (() -> Void)? { get set }
}
final class AddFriendViewController: UIViewController, RefreshFriendData {
@IBOutlet weak var textFieldFirstname: UITextField! {
didSet {
textFieldFirstname.delegate = self
textFieldFirstname.addTarget(self, action:
#selector(firstnameTextFieldDidChange),
for: .editingChanged)
}
}
@IBOutlet weak var textFieldLastname: UITextField! {
didSet {
textFieldLastname.delegate = self
textFieldLastname.addTarget(self, action:
#selector(lastnameTextFieldDidChange),
for: .editingChanged)
}
}
@IBOutlet weak var textFieldPhoneNumber: UITextField! {
didSet {
textFieldPhoneNumber.delegate = self
textFieldPhoneNumber.addTarget(self, action:
#selector(phoneNumberTextFieldDidChange),
for: .editingChanged)
}
}
@IBOutlet weak var buttonSubmit: UIButton!
var updateFriends: (() -> Void)?
var viewModel: FriendViewModel?
fileprivate var activeTextField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
if viewModel == nil {
viewModel = AddFriendViewModel()
}
bindViewModel()
}
func firstnameTextFieldDidChange(textField: UITextField){
viewModel?.firstname = textField.text ?? ""
}
func lastnameTextFieldDidChange(textField: UITextField){
viewModel?.lastname = textField.text ?? ""
}
func phoneNumberTextFieldDidChange(textField: UITextField){
viewModel?.phonenumber = textField.text ?? ""
}
func bindViewModel() {
title = viewModel?.title
textFieldFirstname?.text = viewModel?.firstname ?? ""
textFieldLastname?.text = viewModel?.lastname ?? ""
textFieldPhoneNumber?.text = viewModel?.phonenumber ?? ""
viewModel?.showLoadingHud.bind {
PKHUD.sharedHUD.contentView = PKHUDSystemActivityIndicatorView()
$0 ? PKHUD.sharedHUD.show() : PKHUD.sharedHUD.hide()
}
viewModel?.updateSubmitButtonState = { [weak self] state in
self?.buttonSubmit?.isEnabled = state
}
viewModel?.navigateBack = { [weak self] in
self?.updateFriends?()
let _ = self?.navigationController?.popViewController(animated: true)
}
viewModel?.onShowError = { [weak self] alert in
let alertController = UIAlertController(title: alert.title,
message: alert.message,
preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: alert.action.buttonTitle,
style: .default,
handler: { _ in alert.action.handler?() }))
self?.present(alertController, animated: true, completion: nil)
}
}
}
// MARK: - Actions
extension AddFriendViewController {
@IBAction func rootViewTapped(_ sender: Any) {
activeTextField?.resignFirstResponder()
}
@IBAction func submitButtonTapped(_ sender: Any) {
viewModel?.submitFriend()
}
}
extension AddFriendViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false
}
func textFieldDidBeginEditing(_ textField: UITextField) {
activeTextField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
activeTextField = nil
}
}
@@ -0,0 +1,101 @@
//
// AddFriendViewModel.swift
// Friends
//
// Created by Jussi Suojanen on 06/01/17.
// Copyright © 2017 Jimmy. All rights reserved.
//
protocol FriendViewModel {
var title: String { get }
var firstname: String? { get set }
var lastname: String? { get set }
var phonenumber: String? { get set }
var showLoadingHud: Bindable<Bool> { get set }
var updateSubmitButtonState: ((Bool) -> ())? { get set }
var navigateBack: (() -> ())? { get set }
var onShowError: ((_ alert: SingleButtonAlert) -> Void)? { get set }
func submitFriend()
}
final class AddFriendViewModel: FriendViewModel {
var title: String {
return "Add Friend"
}
var firstname: String? {
didSet {
validateInput()
}
}
var lastname: String? {
didSet {
validateInput()
}
}
var phonenumber: String? {
didSet {
validateInput()
}
}
var showLoadingHud: Bindable = Bindable(false)
var updateSubmitButtonState: ((Bool) -> ())?
var navigateBack: (() -> ())?
var onShowError: ((_ alert: SingleButtonAlert) -> Void)?
private let appServerClient = AppServerClient()
private var validInputData: Bool = false {
didSet {
if oldValue != validInputData {
updateSubmitButtonState?(validInputData)
}
}
}
func submitFriend() {
guard let firstname = firstname,
let lastname = lastname,
let phonenumber = phonenumber else {
return
}
updateSubmitButtonState?(false)
showLoadingHud.value = true
appServerClient.postFriend(firstname: firstname, lastname: lastname, phonenumber: phonenumber) { [weak self] result in
self?.showLoadingHud.value = false
self?.updateSubmitButtonState?(true)
switch result {
case .success(_):
self?.navigateBack?()
case .failure(let error):
let okAlert = SingleButtonAlert(
title: error?.getErrorMessage() ?? "Could not connect to server. Check your network and try again later.",
message: "Could not add \(firstname) \(lastname).",
action: AlertAction(buttonTitle: "OK", handler: { print("Ok pressed!") })
)
self?.onShowError?(okAlert)
}
}
}
func validateInput() {
let validData = [firstname, lastname, phonenumber].filter {
($0?.characters.count ?? 0) < 1
}
validInputData = (validData.count == 0) ? true : false
}
}
extension AppServerClient.PostFriendFailureReason {
func getErrorMessage() -> String? {
switch self {
case .unAuthorized:
return "Please login to add friends friends."
case .notFound:
return "Failed to add friend. Please try again."
}
}
}
@@ -0,0 +1,19 @@
//
// Alert.swift
// Friends
//
// Created by Jussi Suojanen on 09/01/17.
// Copyright © 2017 Jimmy. All rights reserved.
//
import UIKit
struct AlertAction {
let buttonTitle: String
let handler: (() -> Void)?
}
struct SingleButtonAlert {
let title: String
let message: String?
let action: AlertAction
}
@@ -0,0 +1,44 @@
//
// AppDelegate.swift
// Friends
//
// Created by Jussi Suojanen on 07/11/16.
// Copyright © 2016 Jimmy. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
Oops, something went wrong.

0 comments on commit 7a25009

Please sign in to comment.