Commit 364c5089 authored by Aral Balkan's avatar Aral Balkan

Added some string extensions for easy string replacement. Updated my...

Added some string extensions for easy string replacement. Updated my NSNotificationCenter extension with methods to remove observers. The setup steps now pass data between each other. The second step of setup now tries to present user’s handle in a more human fashion, pre-populated in the name field (progress towards #25).
parent ad392a1c
This diff is collapsed.
......@@ -85,4 +85,63 @@ extension String {
result.replaceCharactersInRange(NSRange(range), withString: withString)
return result
}
}
\ No newline at end of file
}
//
// Thanks to http://sketchytech.blogspot.co.uk/2014/08/pure-swift-stringbyreplacingoccurrences.html
//
extension String {
func rangesOfString(findStr:String) -> [Range<String.Index>] {
var arr = [Range<String.Index>]()
var startInd = self.startIndex
var i = 0
// test first of all whether the string is likely to appear at all
if contains(self, first(findStr)!) {
startInd = find(self,first(findStr)!)!
}
else {
return arr
}
// set starting point for search based on the finding of the first character
i = distance(self.startIndex, startInd)
while i<=countElements(self)-countElements(findStr) {
if self[advance(self.startIndex, i)..<advance(self.startIndex, i+countElements(findStr))] == findStr {
arr.append(Range(start:advance(self.startIndex, i),end:advance(self.startIndex, i+countElements(findStr))))
i = i+countElements(findStr)
}
i++
}
return arr
} // try further optimization by repeating the initial act of finding first character after each found string
func stringByReplacingOccurrencesOfString(string:String, replacement:String) -> String {
// get ranges first using rangesOfString: method, then glue together the string using ranges of existing string and old string
let ranges = self.rangesOfString(string)
// if the string isn't found return unchanged string
if ranges.isEmpty {
return self
}
var newString = ""
var startInd = self.startIndex
for r in ranges {
newString += self[startInd..<minElement(r)]
newString += replacement
if maxElement(r) < self.endIndex {
startInd = advance(maxElement(r),1)
}
}
// add the last part of the string after the final find
if maxElement(ranges.last!) < self.endIndex {
newString += self[advance(maxElement(ranges.last!),1)..<self.endIndex]
}
return newString
}
}
......@@ -86,10 +86,10 @@ class IndieNameFormatter: NSFormatter {
var acceptableString:String = (partialString.componentsSeparatedByCharactersInSet(unacceptableCharactersSet) as NSArray).componentsJoinedByString("")
if acceptableString == partialString {
//Partial string is a valid Ind.ie name
//Partial string is valid enough to be massaged during stringForObjectValue
return true
} else {
// Partial string is not a valid Ind.ie name
// Partial string is not valid
return false
}
}
......@@ -137,6 +137,7 @@ class IndieNameFormatter: NSFormatter {
//
// Normalise using Unicode Campatibility Decomposition (Form KD)
// (See http://www.unicode.org/reports/tr15/)
//
massagedIndieName = massagedIndieName.decomposedStringWithCompatibilityMapping
let marks = NSCharacterSet.nonBaseCharacterSet()
massagedIndieName = "".join(massagedIndieName.componentsSeparatedByCharactersInSet(marks))
......
......@@ -10,11 +10,32 @@ import Foundation
extension NSNotificationCenter {
//
// Syntactic sugar
// Syntactic sugar: let’s make the addObserver call literate.
//
// NSNotificationCenter.defaultCenter().when(DebugNotification.named(.ZoomWindow), call: "myMethod", on
//
// Adding observers
//
public func when(youGet notificationName: String, call selector: Selector, on observer: AnyObject) {
self.addObserver(observer, selector: selector, name: notificationName, object: nil)
}
public func when(youGet notificationName: String, from object:AnyObject?, call selector: Selector, on observer: AnyObject) {
self.addObserver(observer, selector: selector, name: notificationName, object: object)
}
//
// Removing observers
//
public func unsubscribe(#observer: AnyObject, fromNotificationsNamed name: String?) {
self.removeObserver(observer, name: name, object: nil)
}
public func unsubscribe(#observer: AnyObject, fromNotificationsNamed name: String?, sentBy object:AnyObject?) {
self.removeObserver(observer, name: name, object: object)
}
}
\ No newline at end of file
......@@ -129,9 +129,9 @@ public class Node: NSObject, WebSocketDelegate
//
// Node pipe notifications
//
📡.addObserver(self, selector: "pipeHasOutput:", name: NSFileHandleReadCompletionNotification, object: self.nodeTask!.standardOutput.fileHandleForReading)
📡.addObserver(self, selector: "pipeIsClosed:", name: NSFileHandleReadToEndOfFileCompletionNotification, object: self.nodeTask!.standardOutput.fileHandleForReading) // Never gets called
📡.when(youGet: NSFileHandleReadCompletionNotification, from: self.nodeTask!.standardOutput.fileHandleForReading, call: "pipeHasOutput:", on: self)
📡.when(youGet: NSFileHandleReadToEndOfFileCompletionNotification, from: self.nodeTask!.standardOutput.fileHandleForReading, call: "pipeIsClosed:", on: self)
self.nodeTask!.standardOutput.fileHandleForReading.readInBackgroundAndNotify()
self.nodeTask!.launch()
......
......@@ -11,6 +11,12 @@
import Cocoa
protocol SetupDelegate
{
func nextStep()
func previousStep()
}
class SetupStepViewController: NSViewController {
var delegate: SetupDelegate?
......@@ -19,7 +25,9 @@ class SetupStepViewController: NSViewController {
super.viewDidLoad()
// Do view setup here.
}
// MARK - Actions
@IBAction func nextStepButtonPress(sender:NSButton)
{
self.delegate?.nextStep()
......@@ -30,4 +38,15 @@ class SetupStepViewController: NSViewController {
self.delegate?.previousStep()
}
// MARK - Data methods
func dataToPassToNextStep() -> AnyObject?
{
return nil
}
func dataReceivedFromPreviousStep(data: AnyObject?) -> ()
{
println("Data received from previous step: \(data)")
}
}
......@@ -55,12 +55,21 @@ class SetupViewController: NSViewController, SetupDelegate {
//
if self.currentStep != self.numberOfSteps
{
let currentViewController:SetupStepViewController = self.viewControllers[self.currentStep-1]
self.currentStep++
// Get any data the current view controller may want to pass to the next one.
var dataFromCurrentStep:AnyObject? = currentViewController.dataToPassToNextStep()
let nextViewController:SetupStepViewController = self.viewControllers[self.currentStep-1]
self.addChildViewController(nextViewController)
// Pass any data that we got from the current view controller to the next one.
nextViewController.dataReceivedFromPreviousStep(dataFromCurrentStep)
// Transition to the next view controller.
self.transitionFromViewController(self.currentViewController, toViewController: nextViewController, options: .SlideLeft) { () -> Void in
// Update the current view controller to point to the new one.
self.currentViewController.removeFromParentViewController()
......@@ -88,8 +97,8 @@ class SetupViewController: NSViewController, SetupDelegate {
self.addChildViewController(nextViewController)
self.transitionFromViewController(self.currentViewController, toViewController: nextViewController, options: .SlideRight)
{
() -> Void in
{
() -> Void in
// Update the current view controller to point to the new one.
self.currentViewController.removeFromParentViewController()
self.currentViewController = nextViewController
......
......@@ -8,13 +8,6 @@
import Cocoa
protocol SetupDelegate
{
func nextStep()
func previousStep()
}
class StepOneViewController: SetupStepViewController
{
......@@ -23,7 +16,8 @@ class StepOneViewController: SetupStepViewController
@IBOutlet weak var nameTextFieldWidthConstraint: NSLayoutConstraint!
@IBOutlet weak var accountCheckProgressIndicator: NSView!
@IBOutlet weak var yesButton: NSButton!
@IBOutlet weak var instructionsLabel: NSTextField!
// Child view controllers
weak var setupMessageViewController:SetupMessageViewController!
weak var setupAccountCheckProgressViewController:SetupAccountCheckProgressViewController!
......@@ -34,7 +28,9 @@ class StepOneViewController: SetupStepViewController
{
super.viewDidLoad()
NSNotificationCenter.defaultCenter().when(youGet: NSControlTextDidChangeNotification, call: "textDidChange:", on: self)
// NSNotificationCenter.defaultCenter().when(youGet: NSControlTextDidChangeNotification, call: "textDidChange:", on: self)
NSNotificationCenter.defaultCenter().when(youGet: NSControlTextDidChangeNotification, from: nameTextField, call: "textDidChange:", on: self)
// Hide the copy of the text field that we use for measurements.
nameTextFieldCopyForMeasurements.hidden = true
......@@ -45,6 +41,7 @@ class StepOneViewController: SetupStepViewController
// Hide both the Yes button and the account check progress indicator
yesButton.hidden = true
accountCheckProgressIndicator.hidden = true
instructionsLabel.hidden = false
}
......@@ -67,6 +64,19 @@ class StepOneViewController: SetupStepViewController
}
}
// MARK: - Pass data to the next step.
override func dataReceivedFromPreviousStep(data: AnyObject?) {
fatalError("This is step one… there is no previous step. Who the heck is passing us data? Panicing! :)")
}
override func dataToPassToNextStep() -> AnyObject? {
return nameTextField.stringValue
}
// MARK: - Handle checking.
func textDidChange(notification:NSNotification) {
//
......@@ -90,6 +100,7 @@ class StepOneViewController: SetupStepViewController
//
yesButton.hidden = true
accountCheckProgressIndicator.hidden = true
instructionsLabel.hidden = false
self.setupMessageViewController.hide()
timer.invalidate()
self.timer = NSTimer(timeInterval: 0.5, target: self, selector: "checkIfNameExists", userInfo: nil, repeats: false)
......@@ -118,6 +129,7 @@ class StepOneViewController: SetupStepViewController
//
// Show progress
//
instructionsLabel.hidden = true
accountCheckProgressIndicator.hidden = false
self.yesButton.hidden = true
......@@ -127,12 +139,17 @@ class StepOneViewController: SetupStepViewController
Node.sharedInstance.call(remoteFunction.named(remoteFunction.isHandleAvailable), withArguments:[nameText]) { response in
let handleIsAvailable = response["handleIsAvailable"]
println("Retrieved response from Waystone. handleIsAvailable: \(handleIsAvailable)")
if (handleIsAvailable) {
self.accountCheckProgressIndicator.hidden = true
self.yesButton.hidden = false
self.setupMessageViewController.messageBody = "Would you like to sign up as \(self.nameTextField.stringValue).ind.ie?"
self.setupMessageViewController.show()
delay(1.5) {
if (handleIsAvailable) {
self.accountCheckProgressIndicator.hidden = true
self.yesButton.hidden = false
self.setupMessageViewController.messageBody = "Would you like to sign up as \(self.nameTextField.stringValue).ind.ie?"
self.setupMessageViewController.show()
}
}
}
}
}
......
......@@ -10,10 +10,59 @@ import Cocoa
class StepTwoViewController: SetupStepViewController
{
@IBOutlet weak var personNameTextField: NSTextField!
@IBOutlet weak var bioTextField: NSTextField!
private var indieAccountName:String!
var personName:String?
var bio:String?
// MARK: Called by SetupViewController
override func dataReceivedFromPreviousStep(data: AnyObject?) {
indieAccountName = data as String
}
// MARK: - View lifecycle.
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
}
override func viewWillAppear() {
super.viewWillAppear()
if personName == nil {
var nameToDisplay = indieAccountName as String
// Attempt to make a best guess at displaying their name
// (e.g., if I chose aral-balkan as my Ind.ie name, I’d see Aral Balkan.)
// It’s OK if we get it wrong; it can easily be changed and they’ll still see that we made an effort :)
nameToDisplay = nameToDisplay.stringByReplacingOccurrencesOfString("-", replacement: " ")
nameToDisplay = nameToDisplay.capitalizedString
personNameTextField.stringValue = nameToDisplay
personName = nameToDisplay
} else {
personNameTextField.stringValue = personName!
}
NSNotificationCenter.defaultCenter().when(youGet: NSControlTextDidChangeNotification, from: personNameTextField, call: "personNameTextDidChange:", on: self)
}
override func viewWillDisappear() {
// Clean up
NSNotificationCenter.defaultCenter().unsubscribe(observer: self, fromNotificationsNamed: NSControlTextDidChangeNotification, sentBy: personNameTextField)
}
// MARK: - Notification handlers
func personNameTextDidChange(notification:NSNotification) {
personName = personNameTextField.stringValue
println("Updating person name to: \(personName)")
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment