Skip to content

Commit

Permalink
added behaviors
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyapuchka committed Oct 10, 2015
1 parent f298f8e commit 668440c
Show file tree
Hide file tree
Showing 10 changed files with 401 additions and 106 deletions.
60 changes: 52 additions & 8 deletions ViewControllerThinning.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

/* Begin PBXBuildFile section */
098AF8971BC0057E00D43EE0 /* TextFieldTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098AF8961BC0057E00D43EE0 /* TextFieldTheme.swift */; settings = {ASSET_TAGS = (); }; };
099DC0501BC8597D00C61D26 /* FormBehaviour.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099DC04F1BC8597C00C61D26 /* FormBehaviour.swift */; settings = {ASSET_TAGS = (); }; };
099DC0521BC85A3500C61D26 /* AuthFormBehaviour.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099DC0511BC85A3500C61D26 /* AuthFormBehaviour.swift */; settings = {ASSET_TAGS = (); }; };
099DC0541BC85ABC00C61D26 /* BackgroundHighlightableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099DC0531BC85ABC00C61D26 /* BackgroundHighlightableView.swift */; settings = {ASSET_TAGS = (); }; };
099DC0571BC85FC400C61D26 /* ShakeAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099DC0561BC85FC400C61D26 /* ShakeAnimation.swift */; settings = {ASSET_TAGS = (); }; };
099DC05A1BC8673D00C61D26 /* FormTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099DC0581BC8673D00C61D26 /* FormTextField.swift */; settings = {ASSET_TAGS = (); }; };
099DC05B1BC8673D00C61D26 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099DC0591BC8673D00C61D26 /* ViewController.swift */; settings = {ASSET_TAGS = (); }; };
099DC05D1BC8715E00C61D26 /* HighlightableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099DC05C1BC8715E00C61D26 /* HighlightableButton.swift */; settings = {ASSET_TAGS = (); }; };
09BAC98C1BB802BA00B0F90D /* UIImage+Named.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BAC98B1BB802BA00B0F90D /* UIImage+Named.swift */; settings = {ASSET_TAGS = (); }; };
09BAC98E1BB8048700B0F90D /* UIView+InterfaceBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BAC98D1BB8048700B0F90D /* UIView+InterfaceBuilder.swift */; settings = {ASSET_TAGS = (); }; };
09BAC9921BB805A300B0F90D /* UIView+Appearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 09BAC9911BB805A300B0F90D /* UIView+Appearance.m */; settings = {ASSET_TAGS = (); }; };
Expand All @@ -20,12 +27,17 @@
09E2D4251BB7476100DBF6BA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 09E2D4241BB7476100DBF6BA /* Assets.xcassets */; };
09E2D4281BB7476100DBF6BA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 09E2D4261BB7476100DBF6BA /* LaunchScreen.storyboard */; };
09E2D4601BB74AE800DBF6BA /* SwiftNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09E2D45F1BB74AD500DBF6BA /* SwiftNetworking.framework */; };
09E2D46F1BB75ED400DBF6BA /* FormTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E2D46E1BB75ED400DBF6BA /* FormTextField.swift */; settings = {ASSET_TAGS = (); }; };
09E2D4711BB7711400DBF6BA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E2D4701BB7711400DBF6BA /* ViewController.swift */; settings = {ASSET_TAGS = (); }; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
098AF8961BC0057E00D43EE0 /* TextFieldTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTheme.swift; sourceTree = "<group>"; };
099DC04F1BC8597C00C61D26 /* FormBehaviour.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormBehaviour.swift; sourceTree = "<group>"; };
099DC0511BC85A3500C61D26 /* AuthFormBehaviour.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthFormBehaviour.swift; sourceTree = "<group>"; };
099DC0531BC85ABC00C61D26 /* BackgroundHighlightableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundHighlightableView.swift; sourceTree = "<group>"; };
099DC0561BC85FC400C61D26 /* ShakeAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShakeAnimation.swift; sourceTree = "<group>"; };
099DC0581BC8673D00C61D26 /* FormTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTextField.swift; sourceTree = "<group>"; };
099DC0591BC8673D00C61D26 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
099DC05C1BC8715E00C61D26 /* HighlightableButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightableButton.swift; sourceTree = "<group>"; };
09BAC98B1BB802BA00B0F90D /* UIImage+Named.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Named.swift"; sourceTree = "<group>"; };
09BAC98D1BB8048700B0F90D /* UIView+InterfaceBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+InterfaceBuilder.swift"; sourceTree = "<group>"; };
09BAC9901BB805A300B0F90D /* UIView+Appearance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Appearance.h"; sourceTree = "<group>"; };
Expand All @@ -43,8 +55,6 @@
09E2D4291BB7476100DBF6BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
09E2D45D1BB74A9800DBF6BA /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = "<group>"; };
09E2D45F1BB74AD500DBF6BA /* SwiftNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftNetworking.framework; path = Carthage/Build/iOS/SwiftNetworking.framework; sourceTree = "<group>"; };
09E2D46E1BB75ED400DBF6BA /* FormTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTextField.swift; sourceTree = "<group>"; };
09E2D4701BB7711400DBF6BA /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -59,12 +69,42 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
099DC04D1BC8596A00C61D26 /* Models */ = {
isa = PBXGroup;
children = (
099DC04E1BC8596A00C61D26 /* Behaviours */,
);
path = Models;
sourceTree = "<group>";
};
099DC04E1BC8596A00C61D26 /* Behaviours */ = {
isa = PBXGroup;
children = (
099DC04F1BC8597C00C61D26 /* FormBehaviour.swift */,
099DC0511BC85A3500C61D26 /* AuthFormBehaviour.swift */,
099DC0531BC85ABC00C61D26 /* BackgroundHighlightableView.swift */,
);
path = Behaviours;
sourceTree = "<group>";
};
099DC0551BC85FBA00C61D26 /* Animations */ = {
isa = PBXGroup;
children = (
099DC0561BC85FC400C61D26 /* ShakeAnimation.swift */,
);
path = Animations;
sourceTree = "<group>";
};
09BAC9811BB8022400B0F90D /* Views */ = {
isa = PBXGroup;
children = (
099DC0581BC8673D00C61D26 /* FormTextField.swift */,
099DC0591BC8673D00C61D26 /* ViewController.swift */,
099DC0551BC85FBA00C61D26 /* Animations */,
09BAC9A51BB8979600B0F90D /* Auth */,
09BAC9961BB8118800B0F90D /* Themes */,
09BAC98A1BB802BA00B0F90D /* Extensions */,
099DC05C1BC8715E00C61D26 /* HighlightableButton.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -120,10 +160,9 @@
09E2D41C1BB7476100DBF6BA /* ViewControllerThinning */ = {
isa = PBXGroup;
children = (
099DC04D1BC8596A00C61D26 /* Models */,
09BAC9811BB8022400B0F90D /* Views */,
09E2D41D1BB7476100DBF6BA /* AppDelegate.swift */,
09E2D4701BB7711400DBF6BA /* ViewController.swift */,
09E2D46E1BB75ED400DBF6BA /* FormTextField.swift */,
09BAC9931BB805B400B0F90D /* ViewControllerThinning-Bridging-Header.h */,
09E2D4211BB7476100DBF6BA /* Main.storyboard */,
09E2D4241BB7476100DBF6BA /* Assets.xcassets */,
Expand Down Expand Up @@ -234,12 +273,17 @@
files = (
09BAC9951BB809A800B0F90D /* UIView+Extensions.swift in Sources */,
09BAC9A21BB817EC00B0F90D /* FormTextFieldTheme.swift in Sources */,
09E2D46F1BB75ED400DBF6BA /* FormTextField.swift in Sources */,
09E2D4711BB7711400DBF6BA /* ViewController.swift in Sources */,
099DC05D1BC8715E00C61D26 /* HighlightableButton.swift in Sources */,
099DC0541BC85ABC00C61D26 /* BackgroundHighlightableView.swift in Sources */,
099DC0571BC85FC400C61D26 /* ShakeAnimation.swift in Sources */,
099DC05B1BC8673D00C61D26 /* ViewController.swift in Sources */,
09BAC9921BB805A300B0F90D /* UIView+Appearance.m in Sources */,
09BAC98E1BB8048700B0F90D /* UIView+InterfaceBuilder.swift in Sources */,
099DC0501BC8597D00C61D26 /* FormBehaviour.swift in Sources */,
09BAC9A71BB897C000B0F90D /* AuthView.swift in Sources */,
09BAC98C1BB802BA00B0F90D /* UIImage+Named.swift in Sources */,
099DC0521BC85A3500C61D26 /* AuthFormBehaviour.swift in Sources */,
099DC05A1BC8673D00C61D26 /* FormTextField.swift in Sources */,
09E2D41E1BB7476100DBF6BA /* AppDelegate.swift in Sources */,
098AF8971BC0057E00D43EE0 /* TextFieldTheme.swift in Sources */,
);
Expand Down
76 changes: 76 additions & 0 deletions ViewControllerThinning/Models/Behaviours/AuthFormBehaviour.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// AuthFormBehaviour.swift
// ViewControllerThinning
//
// Created by Ilya Puchka on 09.10.15.
// Copyright © 2015 Ilya Puchka. All rights reserved.
//

import UIKit
import SwiftNetworking

class AuthFormBehaviour: NSObject, FormBehaviour {

var apiClient: APIClient = APIClient(baseURL: NSURL(string: "http://localhost")!)

override init() {}

@IBOutlet
var userNameInput: UITextField! {
didSet {
userNameInput.delegate = self
}
}

@IBOutlet
var passwordInput: UITextField! {
didSet {
passwordInput.delegate = self
}
}

@IBOutlet
var formFields: [UIView]!

@IBAction
func submitForm() {
guard let
username = userNameInput.text,
password = passwordInput.text else {
return
}
userNameInput.endEditing(true)
passwordInput.endEditing(true)
login(username, password: password)
}

var onCancel: (()->())?

@IBAction
func cancelForm() {
onCancel?()
}

var onLoggedIn: ((error: NSError?, performedRequest: Bool) -> ())?

func login(username: String, password: String) {
apiClient.login(username, password: password) { [weak self] (error, performedRequest) -> () in
self?.onLoggedIn?(error: error, performedRequest: performedRequest)
}
}

}

extension AuthFormBehaviour: UITextFieldDelegate {

func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == formFields.last {
submitForm()
}
else {
goToNextFormField()
}
return true
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// BackgroundHighlightableView.swift
// ViewControllerThinning
//
// Created by Ilya Puchka on 09.10.15.
// Copyright © 2015 Ilya Puchka. All rights reserved.
//

import UIKit

protocol BackgroundHighlightableView: class {
var backgroundColor: UIColor? {get set}
var backgroundColorForHighlightedState: UIColor? {get}
var backgroundColorForNormalState: UIColor? {get}

var highlighted: Bool {get set}
func setHighlighted(highlighted: Bool, animated: Bool)
func backgroundColor(highlighted: Bool) -> UIColor?
}

extension BackgroundHighlightableView where Self: UIView {

func setHighlighted(highlighted: Bool, animated: Bool) {
let view = self as UIView
guard backgroundColorForHighlightedState != nil &&
view.backgroundColor != nil else {
return
}
changeAnimated(true, options: [.BeginFromCurrentState]) {
view.backgroundColor = self.backgroundColor(highlighted)
}
}

func backgroundColor(highlighted: Bool) -> UIColor? {
return highlighted ? backgroundColorForHighlightedState : backgroundColorForNormalState
}

}

51 changes: 51 additions & 0 deletions ViewControllerThinning/Models/Behaviours/FormBehaviour.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// FormBehaviour.swift
// ViewControllerThinning
//
// Created by Ilya Puchka on 09.10.15.
// Copyright © 2015 Ilya Puchka. All rights reserved.
//

import UIKit

protocol FormBehaviour {
var formFields: [UIView]! {get}
func goToNextFormField() -> UIView?
func currentFormField() -> UIView?
func submitForm()
func cancelForm()
}

extension FormBehaviour {

func currentFormField() -> UIView? {
for field in formFields where field.isFirstResponder() {
return field
}
return nil
}

func goToNextFormField() -> UIView? {
guard let
formFields = self.formFields,
currentField = currentFormField(),
currentFieldIndex = formFields.indexOf(currentField)
where
formFields.count > 1
else {
return nil
}

var nextFormField: UIView! = nil
var nextIndex = currentFieldIndex
repeat {
nextIndex = (nextIndex + 1) % formFields.count
nextFormField = formFields[nextIndex]
} while nextFormField.canBecomeFirstResponder() == false && nextIndex != currentFieldIndex
if nextIndex != currentFieldIndex {
nextFormField.becomeFirstResponder()
}
return nextFormField
}

}
57 changes: 57 additions & 0 deletions ViewControllerThinning/Views/Animations/ShakeAnimation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// ShakeAnimation.swift
// ViewControllerThinning
//
// Created by Ilya Puchka on 09.10.15.
// Copyright © 2015 Ilya Puchka. All rights reserved.
//

import UIKit

@objc
protocol Animation {
var duration: Double {get}
var view: UIView? {get}
}

extension Animation {
func play() {
fatalError("Concrete instances of Animation protocol should provide implementation of this method.")
}
}

@objc
protocol ShakeAnimation: Animation {
var maxOffset: Double {get set}
var keyPath: String {get set}
}

extension ShakeAnimation {
func play() {
guard let view = view else { return }

let animation = CAKeyframeAnimation(keyPath: keyPath)
animation.values = [0, maxOffset, -0.8 * maxOffset, 0.4 * maxOffset, 0]
animation.keyTimes = [ 0, (1 / 6.0), (3 / 6.0), (5 / 6.0), 1 ]
animation.duration = duration ?? view.implicitAnimationDuration
animation.additive = true
view.layer.addAnimation(animation, forKey: "shake")
}
}

class ShakeAnimationImp: NSObject, ShakeAnimation {

@IBInspectable
var duration: Double = 0.2

@IBInspectable
var maxOffset: Double = 10

@IBInspectable
var keyPath: String = "position.x"

@IBOutlet
weak var view: UIView?

}

Loading

0 comments on commit 668440c

Please sign in to comment.