Ind.ie is now Small Technology Foundation.
Commit 5df15862 authored by Aral Balkan's avatar Aral Balkan

Implemented non-visual accessibility hint feature in messages (progress towards #28, #31, and #32).

parent 636c640f
......@@ -45,6 +45,7 @@
A7A14C691A83A9C100586EAD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A7A14C6B1A83A9C100586EAD /* InfoPlist.strings */; };
A7A14C6E1A83A9C200586EAD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A7A14C701A83A9C200586EAD /* InfoPlist.strings */; };
A7A14C731A83D7DC00586EAD /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A7A14C751A83D7DC00586EAD /* Localizable.strings */; };
A7A14C791A83FBBF00586EAD /* NSString+Matcher.m in Sources */ = {isa = PBXBuildFile; fileRef = A7A14C781A83FBBF00586EAD /* NSString+Matcher.m */; };
A7CC1FFA1A6C8FEB00B49AA9 /* MASShortcut.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7CC1FF91A6C8FEB00B49AA9 /* MASShortcut.framework */; };
A7CC20071A6C992F00B49AA9 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7CC20061A6C992F00B49AA9 /* SwiftyJSON.swift */; };
A7CD7F121A6FBB2400BE31D6 /* node.js in Resources */ = {isa = PBXBuildFile; fileRef = A7CD7F111A6FBB2400BE31D6 /* node.js */; };
......@@ -130,6 +131,8 @@
A7A14C6A1A83A9C100586EAD /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
A7A14C6F1A83A9C200586EAD /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
A7A14C741A83D7DC00586EAD /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
A7A14C771A83FBBF00586EAD /* NSString+Matcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Matcher.h"; sourceTree = "<group>"; };
A7A14C781A83FBBF00586EAD /* NSString+Matcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Matcher.m"; sourceTree = "<group>"; };
A7CC1FF91A6C8FEB00B49AA9 /* MASShortcut.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MASShortcut.framework; path = "../../../../../Library/Developer/Xcode/DerivedData/Heartbeat-bwptofoniwaoqzcgkxzhjtbmtjak/Build/Products/Debug/MASShortcut.framework"; sourceTree = "<group>"; };
A7CC1FFB1A6C8FF700B49AA9 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = ../../sandbox/SwiftyJSON/build/Debug/SwiftyJSON.framework; sourceTree = "<group>"; };
A7CC1FFD1A6C901400B49AA9 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = ../../sandbox/SwiftyJSON/build/Debug/SwiftyJSON.framework; sourceTree = "<group>"; };
......@@ -352,6 +355,7 @@
A78DAE781A7FCA46009FDB15 /* Libraries — Objective C */ = {
isa = PBXGroup;
children = (
A7A14C761A83FBA600586EAD /* github.com/damienromito */,
A78DAE7A1A7FCA60009FDB15 /* NoodleCustomImageRep.h */,
A78DAE7B1A7FCA60009FDB15 /* NoodleCustomImageRep.m */,
);
......@@ -370,6 +374,15 @@
name = "Images for testing";
sourceTree = "<group>";
};
A7A14C761A83FBA600586EAD /* github.com/damienromito */ = {
isa = PBXGroup;
children = (
A7A14C771A83FBBF00586EAD /* NSString+Matcher.h */,
A7A14C781A83FBBF00586EAD /* NSString+Matcher.m */,
);
name = github.com/damienromito;
sourceTree = "<group>";
};
A7E7D7AA1A616AA9003501C1 /* Classes */ = {
isa = PBXGroup;
children = (
......@@ -630,6 +643,7 @@
A7E7D7B51A616B0B003501C1 /* IndieSplitView.swift in Sources */,
A70634BC1A63114200A75BC0 /* StepTwoViewController.swift in Sources */,
A760C9901A75A51100E84890 /* IndieNameFormatter.swift in Sources */,
A7A14C791A83FBBF00586EAD /* NSString+Matcher.m in Sources */,
A7E7D7B61A616B0B003501C1 /* IndieSplitViewController.swift in Sources */,
A7E7D7B41A616B0B003501C1 /* IndieWindow.swift in Sources */,
A70634B61A6310E900A75BC0 /* SetupViewController.swift in Sources */,
......
......@@ -1041,7 +1041,7 @@
<rect key="frame" x="20" y="64" width="550" height="1"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="line" id="zaa-m8-SHT"/>
</imageView>
<containerView translatesAutoresizingMaskIntoConstraints="NO" id="cSn-Q6-cHP">
<containerView translatesAutoresizingMaskIntoConstraints="NO" id="cSn-Q6-cHP" userLabel="Message View (embedded)">
<rect key="frame" x="20" y="73" width="550" height="71"/>
<constraints>
<constraint firstAttribute="height" constant="71" id="tmW-Ym-Ygx"/>
......@@ -1050,16 +1050,6 @@
<segue destination="Qan-DR-1cn" kind="embed" identifier="embedSetupMessageViewController" id="VhE-2A-YA3"/>
</connections>
</containerView>
<containerView translatesAutoresizingMaskIntoConstraints="NO" id="RMv-Dw-7b5">
<rect key="frame" x="205" y="23" width="180" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="GJS-rr-gRx"/>
<constraint firstAttribute="width" constant="180" id="SLL-o5-ySA"/>
</constraints>
<connections>
<segue destination="Eet-Dy-v40" kind="embed" identifier="embedSetupProgressIndicator" id="yXc-2k-L0R"/>
</connections>
</containerView>
<button hidden="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="m3X-EL-LpT">
<rect key="frame" x="277" y="18" width="36" height="25"/>
<buttonCell key="cell" type="roundTextured" title="Yes" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uQp-V1-vRe">
......@@ -1112,17 +1102,29 @@ DQ
</textFieldCell>
<accessibility help="Accepts and moves to the next step of the setup process."/>
</textField>
<containerView ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RMv-Dw-7b5" userLabel="Progress indicator (embedded)">
<rect key="frame" x="205" y="23" width="180" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="GJS-rr-gRx"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" priority="750" constant="180" id="SLL-o5-ySA"/>
</constraints>
<connections>
<segue destination="Eet-Dy-v40" kind="embed" identifier="embedSetupProgressIndicator" id="yXc-2k-L0R"/>
</connections>
</containerView>
</subviews>
<constraints>
<constraint firstItem="azA-4A-JHj" firstAttribute="top" secondItem="ge6-cT-KvW" secondAttribute="bottom" constant="21" id="00p-wl-Z2f"/>
<constraint firstItem="LTp-3R-cwj" firstAttribute="top" secondItem="ge6-cT-KvW" secondAttribute="bottom" constant="21" id="1Bn-oS-NCx"/>
<constraint firstAttribute="centerX" secondItem="RMv-Dw-7b5" secondAttribute="centerX" id="2ib-ig-xdf"/>
<constraint firstAttribute="trailing" secondItem="azA-4A-JHj" secondAttribute="trailing" constant="20" id="6sK-az-Dbo"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="RMv-Dw-7b5" secondAttribute="trailing" constant="20" id="8LV-6f-Sr8"/>
<constraint firstItem="jzL-oE-aZr" firstAttribute="leading" secondItem="gId-Q7-H7g" secondAttribute="leading" constant="20" id="BJ6-sF-qcJ"/>
<constraint firstItem="RMv-Dw-7b5" firstAttribute="top" secondItem="ge6-cT-KvW" secondAttribute="bottom" constant="24" id="EAi-MF-UnS"/>
<constraint firstItem="ge6-cT-KvW" firstAttribute="leading" secondItem="gId-Q7-H7g" secondAttribute="leading" constant="20" id="Kaa-WW-SWp"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="379" id="NnO-jJ-mNJ"/>
<constraint firstItem="m3X-EL-LpT" firstAttribute="top" secondItem="ge6-cT-KvW" secondAttribute="bottom" constant="22" id="UNd-yz-sYs"/>
<constraint firstItem="RMv-Dw-7b5" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gId-Q7-H7g" secondAttribute="leading" constant="20" id="YHc-6a-P1Y"/>
<constraint firstItem="cSn-Q6-cHP" firstAttribute="top" secondItem="gId-Q7-H7g" secondAttribute="top" constant="343" id="bIv-yR-We9"/>
<constraint firstAttribute="centerX" secondItem="LTp-3R-cwj" secondAttribute="centerX" id="hCh-H5-NVB"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="480" id="lfb-YH-bp1"/>
......
......@@ -13,5 +13,6 @@
#import <MASShortcut/Shortcut.h>
#import "NoodleCustomImageRep.h"
#import "NSString+Matcher.h"
#endif
//
// NSString+Matcher.h
// Whyd
//
// Created by Damien Romito on 29/01/15.
// Copyright (c) 2015 Damien Romito. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface NSString(Matcher)
- (NSArray *)matchWithRegex:(NSString *)regex;
- (NSString *)matchWithRegex:(NSString *)regex atIndex:(NSUInteger)index;
- (NSString *)firstMatchedGroupWithRegex:(NSString *)regex;
- (NSTextCheckingResult *)firstMatchedResultWithRegex:(NSString *)regex;
@end
//
// NSString+Matcher.m
// Whyd
//
// Created by Damien Romito on 29/01/15.
// Copyright (c) 2015 Damien Romito. All rights reserved.
//
#import "NSString+Matcher.h"
@implementation NSString(Matcher)
- (NSArray *)matchWithRegex:(NSString *)regex
{
NSTextCheckingResult *result = [self firstMatchedResultWithRegex:regex];
NSMutableArray *mArray = [[NSMutableArray alloc] initWithCapacity:[result numberOfRanges]];
for (int i = 0 ; i < [result numberOfRanges]; i ++ ) {
[mArray addObject:[self substringWithRange:[result rangeAtIndex:i]]];
}
return mArray;
}
- (NSString *)matchWithRegex:(NSString *)regex atIndex:(NSUInteger)index
{
NSTextCheckingResult *result = [self firstMatchedResultWithRegex:regex];
return [self substringWithRange:[result rangeAtIndex:index]];
}
- (NSString *)firstMatchedGroupWithRegex:(NSString *)regex
{
NSTextCheckingResult *result = [self firstMatchedResultWithRegex:regex];
return [self substringWithRange:[result rangeAtIndex:1]];
}
- (NSTextCheckingResult *)firstMatchedResultWithRegex:(NSString *)regex
{
NSRegularExpression *regexExpression = [NSRegularExpression regularExpressionWithPattern:regex options:(NSRegularExpressionOptions)0 error:NULL];
NSRange range = {0, self.length};
return [regexExpression firstMatchInString:self options:(NSMatchingOptions)0 range:range];
}
@end
......@@ -14,6 +14,8 @@ class SetupMessageViewController: NSViewController
@IBOutlet weak var titleLabel: NSTextField!
@IBOutlet weak var messageLabel: NSTextField!
var accessibilityHint:String?
override func accessibilityIsIgnored() -> Bool {
return false
}
......@@ -48,10 +50,24 @@ class SetupMessageViewController: NSViewController
set (str)
{
messageLabel.stringValue = str
// Anything after // in the string, if it exists, is a keypress instruction to be presented only to VoiceOver.
let matches = (NSString(string: str)).matchWithRegex("(.*?)//(.*?)$")
if matches.count == 0
{
// No matches, just pass the string along.
self.messageLabel.stringValue = str
}
else
{
self.messageLabel.stringValue = matches[1] as String
self.accessibilityHint = matches[2] as? String
}
}
}
func show(title:String, body:String)
{
messageTitle = title
......@@ -59,14 +75,18 @@ class SetupMessageViewController: NSViewController
show()
}
override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
override func animationDidStop(anim: CAAnimation!, finished flag: Bool)
{
println("Animation did stop: \(anim). Finished? \(flag)")
}
func show() {
// Make accessibility announcement.
func show()
{
//
// Make accessibility announcement about transition.
//
let localisedDash = NSLocalizedString("-dash-", comment:"Pronunciation hint for use when speaking out URLs in VoiceOver")
let localisedDot = NSLocalizedString("-dot-", comment:"Pronunciation hint for use when speaking out URLs in VoiceOver")
let localisedForwardSlash = NSLocalizedString("-forward-slash-", comment:"Pronunciation hint for use when speaking out URLs in VoiceOver")
......@@ -74,9 +94,21 @@ class SetupMessageViewController: NSViewController
var messageBodyToRead = messageBody.stringByReplacingOccurrencesOfString("-", replacement: localisedDash) // Help with pronunciation (TODO: localise)
messageBodyToRead = messageBodyToRead.stringByReplacingOccurrencesOfString("ind.ie", replacement: "i.n.d" + localisedDot + "i.e") // (Question: will this make it harder for people with Braille?)
messageBodyToRead = messageBodyToRead.stringByReplacingOccurrencesOfString("/", replacement: localisedForwardSlash) //
let messageToRead:String = "\(messageTitle) \(messageBodyToRead)"
var messageToRead:String = "\(messageTitle) \(messageBodyToRead)"
// If an accessibility hint (e.g., an instruction to press a certain keyboard shortcut) exists, add it to the message to be spoken.
if let accessibilityHint = self.accessibilityHint
{
println("Adding accessibility hint: \(self.accessibilityHint)")
messageToRead = messageToRead.stringByAppendingString(accessibilityHint)
}
makeAccessibilityAnnouncement(messageToRead)
//
// Make visual transition
//
let fade = CABasicAnimation(keyPath: "opacity")
fade.fromValue = 0.0
fade.toValue = 1.0
......@@ -87,7 +119,9 @@ class SetupMessageViewController: NSViewController
self.view.hidden = false
}
func hide() {
func hide()
{
self.view.hidden = true
}
......
......@@ -129,7 +129,7 @@ class SetupViewController: NSViewController, SetupDelegate {
}
func showNextButton(title:String="Next")
func showNextButton(title:String=NSLocalizedString("Next", comment:"Button label"))
{
nextButton.title = title
showNextButton(true)
......@@ -148,7 +148,7 @@ class SetupViewController: NSViewController, SetupDelegate {
}
func showBackButton(title:String="Back")
func showBackButton(title:String=NSLocalizedString("Back", comment:"Button label"))
{
backButton.title = title
showBackButton(true)
......@@ -185,7 +185,7 @@ class SetupViewController: NSViewController, SetupDelegate {
prepareInterfaceForChangeToStep(self.currentStep)
// Accessibility — update user on what is happening.
makeAccessibilityAnnouncement("Handle accepted. Transitioning to second step of the setup process: Setup bio.")
makeAccessibilityAnnouncement(NSLocalizedString("Handle accepted. Transitioning to second step of the setup process.", comment:"VoiceOver screen transition announcement."))
// Delay to allow voiceover a chance to read the transition
// TODO: Detect voiceover and only introduce delay if it exists.
......@@ -231,7 +231,7 @@ class SetupViewController: NSViewController, SetupDelegate {
prepareInterfaceForChangeToStep(self.currentStep)
// Accesibility
makeAccessibilityAnnouncement("Returning to first step of the setup process: select handle.")
makeAccessibilityAnnouncement(NSLocalizedString("Returning to first step of the setup process: select handle.", comment:"VoiceOver screen transition announcement."))
// Delay to allow voiceover a chance to read the transition
// TODO: Detect voiceover and only introduce delay if it exists.
delay(1.5)
......
......@@ -167,7 +167,7 @@ class StepOneViewController: SetupStepViewController
func showHandleIsAvailableMessage()
{
let title = String.localizedStringWithFormat(NSLocalizedString("The handle %@ is available!", comment: "Title of message"), self.nameTextField.stringValue)
let body = String.localizedStringWithFormat(NSLocalizedString("Would you like to sign up as ind.ie/%@? Press enter for yes.", comment: "Body of message"), self.nameTextField.stringValue)
let body = String.localizedStringWithFormat(NSLocalizedString("Would you like to sign up as ind.ie/%@? //Press enter for yes.", comment: "Body of message"), self.nameTextField.stringValue)
self.delegate?.showMessage(title, body: body, nextButtonTitle: NSLocalizedString("Yes", comment: "Button title"))
}
......
......@@ -59,7 +59,7 @@ class StepTwoViewController: SetupStepViewController
})
// Show the progress indicator
self.delegate?.showProgress("Creating account…")
self.delegate?.showProgress(NSLocalizedString("Creating account…", comment:"Progress indicator text."))
}
......@@ -76,7 +76,7 @@ class StepTwoViewController: SetupStepViewController
override func viewWillAppear() {
super.viewWillAppear()
self.delegate?.showTip("Create a public profile with your full name, bio, and photo.")
self.delegate?.showTip(NSLocalizedString("Create a public profile with your full name, bio, and photo.", comment:"Setup screen usage tip."))
if personName == nil {
var nameToDisplay = indieAccountName as String
......
......@@ -7,20 +7,38 @@
/* Pronunciation hint for use when speaking out URLs in VoiceOver */
"-forward-slash-" = "-bölü-";
/* Button label */
"Back" = "Geri";
/* Progress indicator text */
"Checking if account exists…" = "Üye ismi var mı diye bakıyorum…";
/* Setup screen usage tip. */
"Create a public profile with your full name, bio, and photo." = "Tüm ismin, biografin ve fotografınla umumi profilini yarat.";
/* Progress indicator text. */
"Creating account…" = "Hesabın yaratılıyor…";
/* VoiceOver screen transition announcement. */
"Handle accepted. Transitioning to second step of the setup process." = "Üye ismi kabul edildi. Kurumun ikinci adımına geçiyoruz.";
/* Button label */
"Next" = "İleri";
/* First setup step instructions. */
"Pick a handle to use on Ind.ie, or enter your existing one." = "Ind.ie üye ismini seç veya daha onceden varsa gir.";
/* Default text for progress indicator. Mostly overriden. */
"Please wait, loading…" = "Lütfen bekleyin, yükleniyor…";
/* VoiceOver screen transition announcement. */
"Returning to first step of the setup process: select handle." = "Kurumun ilk adımına geçiyoruz.";
/* Title of message */
"The handle %@ is available!" = "Üye ismi %@ müsait!";
/* Body of message */
"Would you like to sign up as ind.ie/%@? Press enter for yes." = "ind.ie/%@ olarak üye olmak istiyormusun? Evet için enter’e bas.";
"Would you like to sign up as ind.ie/%@? //Press enter for yes." = "ind.ie/%@ olarak üye olmak istermisin? //Evet için enter’a bas.";
/* Button title */
"Yes" = "Evet";
......
......@@ -416,7 +416,7 @@
"ijk-EB-dga.title" = "Baseline";
/* Class = "NSButtonCell"; title = "Back"; ObjectID = "j1j-a1-fYz"; */
"j1j-a1-fYz.title" = "Back";
"j1j-a1-fYz.title" = "Geri";
/* Class = "NSMenuItem"; title = "Kern"; ObjectID = "jBQ-r6-VK2"; */
"jBQ-r6-VK2.title" = "Kern";
......@@ -440,7 +440,7 @@
"mrP-7w-Klg.title" = "Checking if account exists…";
/* Class = "NSButtonCell"; title = "Done"; ObjectID = "nca-gP-mb3"; */
"nca-gP-mb3.title" = "Done";
"nca-gP-mb3.title" = "Bitir";
/* Class = "(null)"; title = "Window"; ObjectID = "njZ-4z-UZW"; */
"njZ-4z-UZW.title" = "Window";
......
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