Canvas Discussion Visual Separation

(Note: you can click on the images to enlarge for better view)

The Problem/Context:

In the name of “design,” sometimes we choose form over function.  This is my first semester using Canvas for a Penn State World Campus course.  This also happens to be my last class, so I was both happy and annoyed at having to use a different LMS (Learning Management System).

After a couple of weeks of very lively discussion in a graduate level course, it was obvious that the Canvas discussion function did not easily separate multiple levels of discussion.  The left indentation wasn’t enough to easily follow replies of replies of replies.

Screen Shot 2016-02-09 at 1.49.14 PM

You can see in the screenshot above, how the LMS is using left indentations as a visual guide to the hierarchy of the discussion.  It’s honestly not that bad for smaller discussions, but once you have numerous replies, it became hard to follow the conversations.

So what can we do about it?  My first reaction was trying to figure out how to inject CSS or jQuery code.  That could get complicated and messy pretty quickly (and it’s definitely more geared towards a tinkerer/”hacker” rather than a typical student or faculty).  CSS would be a more natural fit, since it’s really a visual problem (not an interaction problem).  However, in doing some quick research, I found that CSS does not have a mechanism to select ancestors/parents.  I learned something new today!

The solution?

Using a Chrome extension to inject very, very, very simple CSS to add a bigger left-padding and color-code for the corresponding “level” of each reply.

Stylish is a pretty straightforward CSS injector that saves custom CSS styles for different web pages.  Link  It’s a Chrome extension, so it’s relatively easy for a non-technical person to use.

After adding the extension, you can add a custom style to the Canvas discussion page.

Screen Shot 2016-02-09 at 1.55.50 PM

Click on the Stylish icon (“S” right of the address bar on Chrome) and choose the last option “Add Style for psu.instructure.com.”  My screen capture already lists the style, because I had already created it.  In that case, you can click  “Edit” and add/change some simple styles:

.replies {
    padding-left: 20px;
    background: yellow;
}
.replies .replies{
    background: red;
}

.replies .replies .replies {
    background: orange;
}

.replies .replies .replies .replies {
    background: purple;
}

 

Screen Shot 2016-02-09 at 2.40.25 PM

Note that on the bottom, there’s a “Applies to…”  field.  I chose instructure.com for now, but may try to be more specific in the future if I don’t want it to apply to basically all pages in the instructure.com domain.  Either way, it’s easy to turn off the custom CSS.

Also, make sure you give it a name that is descriptive – in my case “Canvas (psu.instructure) Discussion.”

Now, you can check/uncheck the custom CSS to show the new visual guides to the replies.

Screen Shot 2016-02-09 at 1.57.38 PM

 

Posted in Class, Technology | Tagged , | Comments Off on Canvas Discussion Visual Separation

JW Media Player Clickable Transcript

Context:

This code controls the media player (http://www.jwplayer.com/) via javascript API.  The inspiration/idea came from Philip Hutchinson’s Easy Captions code (http://pipwerks.com/2010/06/07/for-your-reading-pleasure-easycaptions/) which provides an incredibly elegant solution to captions/transcripts embedded as html (instead of being dynamically loaded).

This code basically serves as a remote control to find a specific spot of a video or audio file when you click on different parts of the transcript.  The code is used as an external trigger for the media player using <span> tags to scrub the playback to a specific timecode.  When the <span> tags are used to match up a text transcript to a audio/video presentation, it becomes a simple but powerful and effective tool that gives the user control over how they can consume the media.

This provides a better experience for all users, but it especially helps screen readers parse content to make it more useful for visually impaired users.

Clickable Transcript Screenshot
Clickable Transcript Screenshot

HTML code sample:

		<div class="clickAudioTranscript" data-playerid="video3">
			<p>
				<span data-begin="0">Niederman v. Brodsky, 261 A.2d 84 (Pa. 1970) </span><br />
				<span data-begin="8">In this case, the parties are Niederman and Brodsky. </span><br />
				<span data-begin="12">Is this case a state case or a federal case? </span><span data-begin="16">You have two signs that it is a state case. </span><span data-begin="20">One is that within the parentheses you see PA, which stands for Pennsylvania,</span><span data-begin="24"> so that tells you that it is a state case. </span><span data-begin="28">But even if you do not know all the states and their abbreviations,</span><span data-begin="32"> you have another sign that it is a state case. </span><span data-begin="36">In the place for the name of the reporter, you see A.2d. </span><span data-begin="40">If it were a federal case, you would see the letter F, standing for federal. </span><span data-begin="46">It might be F. Supp., which is the Federal Supplement, </span><span data-begin="50">containing federal district court cases, </span><span data-begin="53">or it might be F. 2d, which means the second series of the federal reporter, containing cases from the federal courts of appeals, </span><span data-begin="62">or other versions of federal reporters containing the letter F.</span><span data-begin="67"> But instead of F you see A.</span><span data-begin="69"> This means that it is the Atlantic reporter. </span><span data-begin="73">You will see other letters for other geographic references, but without even reading the case you know that it is a case in a state court. </span><br />
				<span data-begin="81">So here we have the case of Niederman v. Brodsky,</span><span data-begin="85"> reported in volume 261 of Atlantic 2d, </span><span data-begin="88">the second series of the Atlantic reporter, beginning at page 84. </span><span data-begin="93">The case was decided by the Pennsylvania Supreme Court in 1970.</span></p>
		</div>
		<div class="clickAudioPlayer" id="video3"> 
		</div>
		<script type="text/javascript">
			jwplayer('video3').setup({
				'id': 'video3',
				'flashplayer': 'https://courses.worldcampus.psu.edu/public/multimedia/videoPlayer/player.swf',
				'width': '640',
				'height': '24',
				'controlbar': 'bottom',
				'streamer':'rtmp://wc-fms.outreach.psu.edu/wc/',
				'file': 'COURSES/LLMLW/LLMLW903/LLMLW903Example1Niederman.mp3'
			})
		</script><!--VIDEO EMBED CODE ENDS HERE-->

Javascript code sample:

$(document).ready(function() {

	$('.playAudio').click(function() {
		var jwPlayerID = $(this).attr('data-playerID');
		jwplayer(jwPlayerID).seek('0');
	});
	$('.clickAudioTranscript span').bind('click', function() {
		var jwPlayerID = $(this).parents('.clickAudioTranscript').attr('data-playerID');
		jwplayer(jwPlayerID).seek($(this).attr('data-begin'));
		return false;
	});
	$('.clickAudioTranscript span').bind('mouseenter', function() {
		$(this).css('background','yellow');
	});
	$('.clickAudioTranscript span').bind('mouseleave', function() {
		$(this).css('background','none');
	});
});

Translator

The clickable transcript code is useful, but does not adhere to captioning standards such as timecoded XML.  The following tool is a simple converter that takes timecoded XML as input and outputs html with embedded <span> tags with the needed attributes for use with my clickable transcript code above.

XML to HTML Caption Converter
XML to HTML Caption Converter

Javascript code sample:

$(document).ready(function() {
	$('#translateButton').click(function() {
		var inputText = $($('#captionInput').val());
		var outputText = "";
		inputText.find('p').each(function(index) {
			var beginSec = parseInt($(this).attr('begin').split(':')[0]*360)
				+ parseInt($(this).attr('begin').split(':')[1]*60)
				+ parseInt($(this).attr('begin').split(':')[2]);
			var endSec = parseInt($(this).attr('end').split(':')[0]*360)
				+ parseInt($(this).attr('end').split(':')[1]*60)
				+ parseInt($(this).attr('end').split(':')[2]);
			outputText +=''
				+ $(this).text() + '\n';
		});
		$('#transcriptOutput').html(outputText);
	});
});


Posted in Projects, Research | Comments Off on JW Media Player Clickable Transcript

Design Studio FA14 Final project and presentation, Swift Calculator

The last few things tweaked in the calculator are mostly related to the logic of the calculator.  It is very, very streamlined compared to where I started.  It was a classic case of I spent about 10 hours to REDUCE the number of lines of code.  This is where the state diagram was worth its weight in gold.

Other than that, there was some minor tweaks to show only 2 decimal points.  There’s still some bugs, but it functions well overall.  The main known bug is if you press operations consecutively, it will perform the operation on the displayed number.  For example, if there’s a 2 on the screen (from a previous calculation), and you press +, it will do 2+2 and display 4.  If you press + again, it will do 4+4 and display 8.

Here’s my final presentation for the coursework I did for the past few months.

Final Presentation Pecha Kucha (20 slides, 20 seconds per slide)

Here is the final project files:

Swift Calculator Final (zip)

And here’s the code for the calculator for viewcontroller.swift (in the zipped project, but included for readability)

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit
import Foundation

class ViewController: UIViewController {
    
    @IBOutlet var calcDisplay1: UITextField!
    @IBOutlet var calcDisplayOp: UITextField!
    
    var clearDisplay:Bool = false
    var firstOp:Bool = true
    var num1:Float = 0.1
    var num2:Float = 0.0
    var numCalc:Float = 0.0
    var prevOp:String = ""
    
    
    @IBOutlet var btn01: UIButton!
    @IBOutlet var btn02: UIButton!
    @IBOutlet var btn03: UIButton!
    @IBOutlet var btn04: UIButton!
    @IBOutlet var btn05: UIButton!
    @IBOutlet var btn06: UIButton!
    @IBOutlet var btn07: UIButton!
    @IBOutlet var btn08: UIButton!
    @IBOutlet var btn09: UIButton!
    @IBOutlet var btnDecimal: UIButton!
    @IBOutlet var btn00: UIButton!
    @IBOutlet var btnEqual: UIButton!
    @IBOutlet var btnClear: UIButton!
    @IBOutlet var btnPlus: UIButton!
    @IBOutlet var btnMinus: UIButton!
    @IBOutlet var btnMultiply: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        btn02.showsTouchWhenHighlighted = true;
        btn03.showsTouchWhenHighlighted = true;
        btn04.showsTouchWhenHighlighted = true;
        btn05.showsTouchWhenHighlighted = true;
        btn06.showsTouchWhenHighlighted = true;
        btn07.showsTouchWhenHighlighted = true;
        btn08.showsTouchWhenHighlighted = true;
        btn09.showsTouchWhenHighlighted = true;
        btn00.showsTouchWhenHighlighted = true;
        btnDecimal.showsTouchWhenHighlighted = true;
        btnEqual.showsTouchWhenHighlighted = true;
        btnClear.showsTouchWhenHighlighted = true;
        btnPlus.showsTouchWhenHighlighted = true;
        btnMinus.showsTouchWhenHighlighted = true;
        btnMultiply.showsTouchWhenHighlighted = true;
        self.view.backgroundColor = UIColor.lightGrayColor()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func digitPressed(buttonPressed: String) {
        if (calcDisplayOp.text != "") {
            firstOp = false
        }
        if (calcDisplayOp.text == "=") {
            firstOp = true
            clearDisplay = true
        }
        if (clearDisplay == true){
            calcDisplay1.text = ""
            clearDisplay = false
        }
        calcDisplay1.text = (calcDisplay1.text as NSString)+buttonPressed
    }
    
    func calculateValue(op: String, n1: Float, n2: Float) -> Float{
        var calculatedValue:Float = 0.0
        switch (op) {
            case "+":
                calculatedValue = n1 + n2
            case "-":
                calculatedValue = n1 - n2
            case "x":
                calculatedValue = n1 * n2
            default:
                calculatedValue = -9999.9999
        }
        return calculatedValue
    }

    
    func operatorPressed(buttonPressed: String) {
        
        calcDisplayOp.text = buttonPressed
      
        if (prevOp == "="){
            firstOp = true
        }

        switch(buttonPressed) {
            
            case "+", "-", "x", "=":
                if (firstOp == true) { // this is the first operation... don't present a calculated value until 2nd input from user
                    num1 = (calcDisplay1.text as NSString).floatValue
                } else { // and operator was pressed and there is already a value present in num1
                    num2 = (calcDisplay1.text as NSString).floatValue
                    numCalc = calculateValue(prevOp, n1: num1, n2: num2)
                    calcDisplay1.text = NSString(format: "%.2f", numCalc)
                    num1=numCalc
                }
        default:
            calcDisplay1.text="?"
            
        }
        prevOp = buttonPressed
        clearDisplay = true
    }
    
    @IBAction func calcEqual(sender: AnyObject) {
        operatorPressed("=")
    }

    @IBAction func calc01(sender: AnyObject) {
        digitPressed("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        digitPressed("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        digitPressed("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        digitPressed("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        digitPressed("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        digitPressed("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        digitPressed("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        digitPressed("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        digitPressed("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        digitPressed(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        digitPressed("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        operatorPressed("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        operatorPressed("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        operatorPressed("x")
   }
    @IBAction func calcClear(sender: AnyObject) {
        calcDisplayOp.text = ""
        calcDisplay1.text = ""
        calcDisplayOp.text = ""
        num1 = 1
        num2 = 0
        numCalc = 0
        firstOp = true
        prevOp = ""
        clearDisplay = false
    }
}


 

Posted in Class, Technology | Tagged , | Comments Off on Design Studio FA14 Final project and presentation, Swift Calculator

Learning Swift: Calculator App, part 5. Revamping the logic/design

This is part 5 of my Learning Swift Calculator App.

This update is mostly about the code structure and design decision about the calculator and its behavior.

Technical lessons learned:

  • Adding variable values in the middle of the string is so much easier using the following format – “blah blah blah and I am going to add /(variable) in the middle of it”  Assuming that variable:String = “some words” then the previous string becomes “blah blah blah and I am going to add some words in the middle of it”
  • Be careful when modifying IBOutlets.  Renaming it in Viewcontroller.swift does not modify the IBOutlet link (in the Storyboard).  You have to relink it.  The error given by xCode is not particular helpful either.

Design lesson learned:

  • Contextual buttons would make the code so much cleaner, but calculators have been around so long that people expect certain behaviors.
    • An example of what I mean by contextual button is this: after pressing = it would make it much clearer to the user what the calculator is actually doing if the equal button disappeared.  However, many of us have come to expect the equal button to mean, repeat last operation.  So, if you press 1+1= (the calculator shows 2), then if you press = again, the calculator will show 3.

After spending a few hours banging my head against some weird behavior, I started from scratch with a state diagram.

The general gist is as follows:

State diagram for calculator
State diagram for calculator

This is generally being modeled after the OS X calculator.  The tricky part is that the operators (+,-,x, etc.) do different things depending on what the user input was previous to pressing the operator buttons.  If a user presses + after a calculation already took place, the calculator is essentially doing a = and then + presenting the user with the calculated value, then getting ready to accept the next input value.  This is completely different from my original design, where I took a string and processed the calculation when the user pressed =.

I’ve already spent a few hours on this logic and it’s much more complicated than I thought.

Here’s the code so far.  Still very buggy.

 

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet var calcDisplay1: UITextField!
    @IBOutlet var calcDisplayOp: UITextField!
    
    var clearDisplay:Bool = false
    var firstOp:Bool = true
    var num1:Float = 0.0
    var num2:Float = 0.0
    
    
    @IBOutlet var btn01: UIButton!
    @IBOutlet var btn02: UIButton!
    @IBOutlet var btn03: UIButton!
    @IBOutlet var btn04: UIButton!
    @IBOutlet var btn05: UIButton!
    @IBOutlet var btn06: UIButton!
    @IBOutlet var btn07: UIButton!
    @IBOutlet var btn08: UIButton!
    @IBOutlet var btn09: UIButton!
    @IBOutlet var btnDecimal: UIButton!
    @IBOutlet var btn00: UIButton!
    @IBOutlet var btnEqual: UIButton!
    @IBOutlet var btnClear: UIButton!
    @IBOutlet var btnPlus: UIButton!
    @IBOutlet var btnMinus: UIButton!
    @IBOutlet var btnMultiply: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        btn02.showsTouchWhenHighlighted = true;
        btn03.showsTouchWhenHighlighted = true;
        btn04.showsTouchWhenHighlighted = true;
        btn05.showsTouchWhenHighlighted = true;
        btn06.showsTouchWhenHighlighted = true;
        btn07.showsTouchWhenHighlighted = true;
        btn08.showsTouchWhenHighlighted = true;
        btn09.showsTouchWhenHighlighted = true;
        btn00.showsTouchWhenHighlighted = true;
        btnDecimal.showsTouchWhenHighlighted = true;
        btnEqual.showsTouchWhenHighlighted = true;
        btnClear.showsTouchWhenHighlighted = true;
        btnPlus.showsTouchWhenHighlighted = true;
        btnMinus.showsTouchWhenHighlighted = true;
        btnMultiply.showsTouchWhenHighlighted = true;
        self.view.backgroundColor = UIColor.lightGrayColor()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func digitPressed(buttonPressed: String) {
        if (calcDisplayOp.text != "") {
            firstOp = false
        }
        if (clearDisplay == true){
            calcDisplay1.text = ""
            clearDisplay = false
        }
        calcDisplay1.text = (calcDisplay1.text as NSString)+buttonPressed
    }
    
    func calculateValue(op: String, n1: Float, n2: Float) -> Float{
        var calculatedValue:Float = 0.0
        switch (op) {
            case "+":
                calculatedValue = n1 + n2
            case "-":
                calculatedValue = n1 - n2
            case "*":
                calculatedValue = n1 * n2
            default:
                calculatedValue = -9999.9999
        }
        return calculatedValue
    }

    
    func operatorPressed(buttonPressed: String) {
        calcDisplayOp.text = buttonPressed
        
        if (calcDisplay1.text == "") { // if user press op before any digits, then assume that num1 = 0
            
        } else { // this means that there is a number on display that the next operation needs to do something against.
            if (firstOp == true) { // this is the first operation... don't present a calculated value until 2nd input from user
                num1 = (calcDisplay1.text as NSString).floatValue
            } else { //
                num2 = (calcDisplay1.text as NSString).floatValue
                calcDisplay1.text = "\(calculateValue(buttonPressed, n1: num1, n2: num2))"
                num1 = num2
            }
        }

        clearDisplay = true
        
        /* CASES

        EXPECTED CASE:
        
        THERE IS A NUMBER ON THE DISPLAY, OPERATOR 
        
        
        ERROR CASES:
    
        NOTHING ON THE DISPLAY, USER PRESSES AN OPERATION (OS X CALCULATOR ASSUMES FIRST NUMBER IS 0)
        
        
        AMBIGUOUS CASES:
        
        USER PRESSES AN OPERATOR FOLLOWING AN OPERATOR (OS X CALCULATOR OVERRIDES OPERATOR WITH LATEST PRESSED)
        
        
        
        */
    }
    
    @IBAction func calcEqual(sender: AnyObject) {
        var currOp:String = calcDisplayOp.text
        calcDisplayOp.text = "="
        
        num2 = (calcDisplay1.text as NSString).floatValue
        calcDisplay1.text = "\(calculateValue(currOp, n1: num1, n2: num2))"
        num1 = num2
        
        firstOp = true
        
        clearDisplay = true
    }

    @IBAction func calc01(sender: AnyObject) {
        digitPressed("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        digitPressed("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        digitPressed("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        digitPressed("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        digitPressed("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        digitPressed("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        digitPressed("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        digitPressed("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        digitPressed("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        digitPressed(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        digitPressed("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        operatorPressed("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        operatorPressed("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        operatorPressed("x")
   }
    @IBAction func calcClear(sender: AnyObject) {
        calcDisplayOp.text = ""
        calcDisplay1.text = ""
        calcDisplayOp.text = ""
        num1 = 0;
        num2 = 0;
        firstOp = true
        clearDisplay = false
    }
}

Posted in Class, Professional Development, Research, Technology | Tagged , , | Comments Off on Learning Swift: Calculator App, part 5. Revamping the logic/design

Learning Swift: Calculator App, part 4. Autolayout

This is part 4 of my Learning Swift Calculator App.

Progress:

  • UI elements will be evenly distributed on any size screen and orientation.

Lessons learned:

Autolayout is a wonderful thing and Apple does their best to help developers who would prefer to develop using the GUI rather than code, but, if you don’t understand the underlying concepts, using the GUI doesn’t help at all.

This tutorial helped me understand the general concepts of Autolayout:

http://www.appcoda.com/introduction-auto-layout/

This tutorial was more helpful with the step by step details on how to distribute components across a screen:

All in all, it was straightforward once I understood what constraints mean and how to define them.  Once I figured it out, there was a lot of repetitive steps applying the same constraints to different elements – I am not sure if there’s an easier way to do so.

The basic premise is actually very simple.  You define the X or Y coordinates of an elements in relation to the view.  You can do it as a decimal value, so my four columns of buttons (1, 2, 3, and C) were 0.2, 0.4, 0.6, and 0.8 respectively.  xCode6 beta does not recognize the value if I put in .2.  You have to put in the zero.

Also, when you ctrl+drag an object, the direction of the drag gives you a contextual menu.  For example, when you drag down, it will let you select “Bottom Space” and when you drag right, it will let you select “Trailing Space.”  This confused me for a while, but it’s a nice touch by Apple.

Contextual menu if ctrl+drag down
Contextual menu if ctrl+drag down
Contextual menu if ctrl+drag right
Contextual menu if ctrl+drag right

I haven’t experimented with the size constraints much, but you can also give elements minimum and/or maximum sizes, so that they will resize properly when the orientation is changed or if the app is run on different screen size devices.

Lastly, again, I am not sure if I am missing something, but when constraints are defined, they are not reflected on the storyboard.  Instead, when you click on an element, you see where the element will go based on constraints in a box with dotted lines.  This is a bit different than what was shown in the video tutorial linked above.  Maybe it is an xCode preference or maybe I just need to change some view setting.

Size and location shown in dotted box.
Size and location shown in dotted box.

Here’s all the project files: download (.zip 71kb)

Here’s the code so far; however, you can’t see all the autolayout work on this code.

 

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    var displayString = ""
    
    @IBOutlet var calcDisplay: UITextField!
    @IBOutlet var btn01: UIButton!
    @IBOutlet var btn02: UIButton!
    @IBOutlet var btn03: UIButton!
    @IBOutlet var btn04: UIButton!
    @IBOutlet var btn05: UIButton!
    @IBOutlet var btn06: UIButton!
    @IBOutlet var btn07: UIButton!
    @IBOutlet var btn08: UIButton!
    @IBOutlet var btn09: UIButton!
    @IBOutlet var btnDecimal: UIButton!
    @IBOutlet var btn00: UIButton!
    @IBOutlet var btnEqual: UIButton!
    @IBOutlet var btnClear: UIButton!
    @IBOutlet var btnPlus: UIButton!
    @IBOutlet var btnMinus: UIButton!
    @IBOutlet var btnMultiply: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        btn02.showsTouchWhenHighlighted = true;
        btn03.showsTouchWhenHighlighted = true;
        btn04.showsTouchWhenHighlighted = true;
        btn05.showsTouchWhenHighlighted = true;
        btn06.showsTouchWhenHighlighted = true;
        btn07.showsTouchWhenHighlighted = true;
        btn08.showsTouchWhenHighlighted = true;
        btn09.showsTouchWhenHighlighted = true;
        btn00.showsTouchWhenHighlighted = true;
        btnDecimal.showsTouchWhenHighlighted = true;
        btnEqual.showsTouchWhenHighlighted = true;
        btnClear.showsTouchWhenHighlighted = true;
        btnPlus.showsTouchWhenHighlighted = true;
        btnMinus.showsTouchWhenHighlighted = true;
        btnMultiply.showsTouchWhenHighlighted = true;
        self.view.backgroundColor = UIColor.lightGrayColor()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func updateCalculatorDisplay(buttonPressed: String) {

        switch (buttonPressed) {
        case ".","1","2","3","4","5","6","7","8","9","0":
            displayString += buttonPressed
        case "-","+","x":
            displayString += " " + buttonPressed + " "
        default:
            displayString += buttonPressed
        }
        calcDisplay.text = displayString
    }

    @IBAction func calc01(sender: AnyObject) {
        updateCalculatorDisplay("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        updateCalculatorDisplay("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        updateCalculatorDisplay("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        updateCalculatorDisplay("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        updateCalculatorDisplay("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        updateCalculatorDisplay("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        updateCalculatorDisplay("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        updateCalculatorDisplay("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        updateCalculatorDisplay("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        updateCalculatorDisplay(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        updateCalculatorDisplay("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        updateCalculatorDisplay("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        updateCalculatorDisplay("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        updateCalculatorDisplay("x")
   }
    @IBAction func calcEqual(sender: AnyObject) {
        var tempArray = displayString.componentsSeparatedByString(" ")
        var currentOperation = "initial"
        var calculatedValue:Float = 0.0;
        for tempValue in tempArray {
            switch (tempValue) {
                case "+":
                    currentOperation = "+"
                case "-":
                    currentOperation = "-"
                case "x":
                    currentOperation = "x"
                case "%":
                    currentOperation = "%"
                default:
                    switch (currentOperation) {
                        case "+":
                            calculatedValue += (tempValue as NSString).floatValue
                        case "-":
                            calculatedValue -= (tempValue as NSString).floatValue
                        case "x":
                            calculatedValue *= (tempValue as NSString).floatValue
                       case "initial":
                            calculatedValue = (tempValue as NSString).floatValue
                        default:
                            calculatedValue += 0.0
                    }
            }
        }
        displayString = "=" + calculatedValue.description
        calcDisplay.text = displayString
    }
    @IBAction func calcClear(sender: AnyObject) {
        displayString = ""
        calcDisplay.text = ""
    }
}


Posted in Class, Professional Development, Technology | Tagged , , | Comments Off on Learning Swift: Calculator App, part 4. Autolayout

Learning Swift: Calculator App, part 3. IBOutlet and button touch highlighting

This is part 3 of my Learning Swift Calculator App.

Progress

  • Working on UIX (visual cue that a button has been touched)

Lessons learned:

Yes – there is only one item on this update.  Adding a state change when a button is touched sent me down a long rabbit hole I did not expect would end where it actually ended up.  Let me explain.

My experience is multimedia development comes largely from Adobe Flash Professional.  This means I was thinking in terms of button states, properties, and id.  Swift and objective C certainly have similar features, but I was stuck on step 1.  How do I reference this button that was created through the GUI/storyboard.  Many of the how to’s/tutorials showed how to create a button programmatically and, then, how to change the property of the button (such as the border of background color).  In Flash, I was used to just creating something, setting an ID, and being able to programmatically manipulate it.

Frustrated, I decided to look at Apple’s documentation instead and found thttps://developer.apple.com/library/IOs/documentation/UIKit/Reference/UIButton_Class/index.html) that there was one simple property that would achieve what I had set out to do – showsTouchWhenHighlighted

This was helpful, but it still didn’t answer how to refer to the button.  So how do I actually set the property for the button that was created via the GUI/Storyboard?

@IBOutletvar btn01: UIButton!

Yes, it was indeed that simple, but if you don’t know what you’re looking for, then you don’t know what to search for.  Getting this far took way longer than I expected.  So with that one line of code, I could change the property.

btn01.showsTouchWhenHighlighted = true;

Lastly, I also had to change the background color of the app so that I could see the highlight (not easy to see on the default white background)

self.view.backgroundColor = UIColor.blackColor()

Those two lines were added to the viewDidLoad function as follows:

    @IBOutlet var btn01: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        
        self.view.backgroundColor = UIColor.blackColor()
    }
Posted in Class, Professional Development, Research | Tagged , | Comments Off on Learning Swift: Calculator App, part 3. IBOutlet and button touch highlighting

Learning Swfit: Calculator App, part 2. Case, Auto Layout, Variable types

This is part 2 of my Learning Swift Calculator App.

Progress:

  • +, -, x operations are now functional
  • decimals also work

Lessons learned:

  • It’s easy to get caught up on a new programming language and forget to use universal concepts of programming that would have made my life a lot easier
    • In my haste (and learning/programming style), I jumped in with both feet, and soon I had one too many else if statements.  I cleaned up the initial logic to use case statements instead.  Not different than any other programming language out there – just common sense and cleaner programming all around.
  • Layout issues – for the first few versions, I will stick with programming for a target device (iPhone5) instead of universal design.  This can be enabled on the view controller file inspector > disable “Use Auto Layout” (thanks Dr. Hooper for pointing me to this setting!)
  • Calculators are very complicated!
    • My initial versions will ignore order of operations
    • Will not check user input for errors (for example, if the user presses + +, it will give unexpected results)
  • I have some issues with decimals (1+1.1=2.0999….) – need to check into how my values are being saved.  Again variable types seem to be haunting me.
  • Break points are super easy to use!  (Apple+”\” to add/delete)  The debug interface is intuitive and clearly shows all the variables.  The debug navigator (6th icon on the 2nd row of icons on the top left… looks like a line, 3 columns, and a line) is also a great snapshot into what’s going on – shows cpu/memory/disk/network usage.

Code as of this writing for ViewController.swift:

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    
    var displayString = ""
    
    @IBOutlet var calcDisplay: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func updateCalculatorDisplay(buttonPressed: String) {

        switch (buttonPressed) {
        case ".","1","2","3","4","5","6","7","8","9","0":
            displayString += buttonPressed
        case "-","+","x":
            displayString += " " + buttonPressed + " "
        default:
            displayString += buttonPressed
        }
        calcDisplay.text = displayString
    }

    @IBAction func calc01(sender: AnyObject) {
        updateCalculatorDisplay("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        updateCalculatorDisplay("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        updateCalculatorDisplay("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        updateCalculatorDisplay("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        updateCalculatorDisplay("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        updateCalculatorDisplay("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        updateCalculatorDisplay("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        updateCalculatorDisplay("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        updateCalculatorDisplay("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        updateCalculatorDisplay(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        updateCalculatorDisplay("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        updateCalculatorDisplay("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        updateCalculatorDisplay("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        updateCalculatorDisplay("x")
   }
    @IBAction func calcEqual(sender: AnyObject) {
        var tempArray = displayString.componentsSeparatedByString(" ")
        var currentOperation = "initial"
        var calculatedValue:Float = 0.0;
        for tempValue in tempArray {
            switch (tempValue) {
                case "+":
                    currentOperation = "+"
                case "-":
                    currentOperation = "-"
                case "x":
                    currentOperation = "x"
                case "%":
                    currentOperation = "%"
                default:
                    switch (currentOperation) {
                        case "+":
                            calculatedValue += (tempValue as NSString).floatValue
                        case "-":
                            calculatedValue -= (tempValue as NSString).floatValue
                        case "x":
                            calculatedValue *= (tempValue as NSString).floatValue
                       case "initial":
                            calculatedValue = (tempValue as NSString).floatValue
                        default:
                            calculatedValue += 0.0
                    }
            }
        }
        displayString = "=" + calculatedValue.description
        calcDisplay.text = displayString
    }
    @IBAction func calcClear(sender: AnyObject) {
        displayString = ""
        calcDisplay.text = ""
    }
}


Posted in Class, Professional Development, Research | Tagged , , | Comments Off on Learning Swfit: Calculator App, part 2. Case, Auto Layout, Variable types

Learning Swift – Calculator App, part 1

As part of my course work for Design Studio (LDT550) at Penn State, I am learning how to program in Swift (Apple’s iOS programming language) using xCode 6 beta.  In particular, I am working with Dr. Simon Hooper to get some of the basics down by programming a simple calculator.

Here is my progress…

First of all, connecting UI elements from storyboard (Main.storyboard) to the code that controls (ViewController.swift) isn’t too difficult.  It’s a bit abstract and there are multiple ways to connect them (ctrl+drag from storyboard or using the connections inspector), but once you figure it out, it seems straightforward.

The actual programming was more challenging than I expected.  I never thought about the intricacies of calculators.  Modern devices have changed our expectations on how calculators work.  Our current expectations are closer to how graphing calculators operate.

For example, in an basic calculator, you can enter a number and as soon as you press an operator, it clears the screen and expects the next number:

Press 1 (display shows “1”)

Press + (display shows “+” and clears old value waiting for new value)

Press 1 (display shows “1”)

Press = (display shows “2”)

However, in a graphing calculator, you can enter an entire expression before calculating

Press 1 (display shows “1”)

Press + (display shows “1 +”)

Press 1 (display shows “1+1”)

Press = (display shows “2” or “1+1=2”)

There are many design decisions to make before programming even a simple calculator – and the design decisions are not simply visual – not by a long shot.

Some technical lessons learned:

  • Type inference and type safety came into play right away (https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html).
  • Converting to and from Strings is a bit tricky (for display onto a Text Field) – I may not be doing it correctly right now – need to learn some more about this.
  • Syntax is very familiar, but it’s unnatural not to end lines with a semi colon.
  • xCode hints and autocomplete feature is very helpful and educational.
  • I am not quite sure how the layout works (with the square View Controller – which I assume it’s for designing apps that will work well for landscape/portrait/different size devices), so I have placed everything close to the top/left to start.

Here’s the app so far (only + works, not thoroughly tested):

Story board and Connections for calculator app
Story board and Connections for calculator app

And here’s the code:

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    
    var displayString = ""
    
    @IBOutlet var calcDisplay: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func updateCalculatorDisplay(buttonPressed: String) {
        displayString += buttonPressed + " "
        calcDisplay.text = displayString
    }

    @IBAction func calc01(sender: AnyObject) {
        updateCalculatorDisplay("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        updateCalculatorDisplay("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        updateCalculatorDisplay("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        updateCalculatorDisplay("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        updateCalculatorDisplay("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        updateCalculatorDisplay("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        updateCalculatorDisplay("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        updateCalculatorDisplay("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        updateCalculatorDisplay("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        updateCalculatorDisplay(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        updateCalculatorDisplay("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        updateCalculatorDisplay("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
    }
    @IBAction func calcMultiply(sender: AnyObject) {
    }
    @IBAction func calcEqual(sender: AnyObject) {
        var tempArray = displayString.componentsSeparatedByString(" ")
        var currentOperation = ""
        var calculatedValue:Float = 0.0;
        for tempValue in tempArray {
            displayString += tempValue
            if tempValue == "+" {
                currentOperation = "+"
            } else if currentOperation == "" {
                calculatedValue = (tempValue as NSString).floatValue
            } else {
                if currentOperation == "+" {
                    calculatedValue += (tempValue as NSString).floatValue
                }
            }
        }
        displayString = "=" + calculatedValue.description
        calcDisplay.text = displayString
    }
    @IBAction func calcClear(sender: AnyObject) {
        displayString = ""
        calcDisplay.text = ""
    }
}


 

Posted in Class | Tagged , , | Comments Off on Learning Swift – Calculator App, part 1

ICON Lab move, VOIP phone logistics, Getting the new building connected

What’s keeping me busy this week?

  • Finalizing the Immersive Construction Lab (ICON Lab) move details
  • Transitioning phone service to VOIP in preparation to the move
  • Getting equipment ready for Comcast to connect the new building (Building 661)

Finalizing the Immersive Construction Lab (ICON Lab) move details

We had our second meeting yesterday with Christie Digital (http://www.christiedigital.com/en-us/pages/default.aspx) regarding the install.  The first meeting was a kick off meeting gathering details.  One of their techs also has come to visit the old and new site to take measurements and figure out egress from the old site (building 101) and ingress into the new site (building 661).  Main takeaways from this experience has been that all parties need to be flexible.  While Christie Digital has been finalizing placement of microphones, speakers, screens, rack, etc. in the new space, a few changes have come up that will require new conduit to be run, ducts to be moved, etc.  Our architect (http://www.kierantimberlake.com/) has been extremely responsive and easy to work with to make sure that all our needs can be met (within reason).  The main changes as we move will driven by the fact that the new space has very high ceilings, so we will not be ceiling mounting speakers, microphones, and videoconferencing cameras.

Transitioning phone service to VOIP in preparation to the move

This has definitely been an interesting project pulling together many things I already knew, but in an unexpected manner.  This project is primarily organized by central IT at the College of Engineering.

As we move into the new building, we will be transitioning from Verizon to VOIP (centrally managed and provided by Penn State Telecommunication and Networking Services – TNS).  There are two particular challenges we needed to overcome – porting the telephone numbers and minimizing interruptions.

The plan is:

  1. Provide new VOIP service in the old building
  2. Port the numbers before we move and disconnect the old analog phones
  3. Take the new phones when we move and they should “automagically” work.

Step 1 was the first big obstacles as our current space was not designed to provide enough data ports.  We are now running a secondary switch sitting under a desk in the cubicle area to be able to provide enough data connections for computers and phones.  Secondly, we had to prioritize what phones we would connect.  Instead of purchasing and running long wires all over the place, we decided that only the phones that are used by staff (instead of visiting researchers) would be connected.

Step 2 is a step of faith.  Since the porting process is completely out of our hands, our staff will have two phones on their desk during this time.  One day, the phones should start ringing in the VOIP phones and the old phones should be disconnected.  The timing of porting numbers is a mystery and we are taking this two phone approach to minimize any interruption of service.

Step 3 is only possible because our network infrastructure is inside Penn State’s network.  Building 101 and Building 661 will both be on fiber optic point-to-point connection back to University Park.  Basically, it’s like we’re all in one physical space and we’re just unplugging the phone from one room and plugging it into another port in the same network.

Voila!  We should have new phone service with the old numbers without any down time.

Getting equipment ready for Comcast to connect the new building

This is just another exercise in communication and patience.  Working with external contractors and vendors can be a challenge.  My only responsibility is that Comcast has everything they need to provide a connection in the new building.  For now, this includes a rack for them to install a modem and switch after the building is connected.

Comcast is responsible for running the conduit from the street into the building.  Then there are a number of different crews pulling cable, splicing, and installing equipment.  Again, I don’t have a big hand in the project other than trying to stay informed, so that we do not get into a situation where our move is delayed due to lack of connectivity.

Posted in Projects | Comments Off on ICON Lab move, VOIP phone logistics, Getting the new building connected

CBEI and long overdue update

My last post was January 2013 when I started working at my, then, new job at the EEB Hub. A lot has happened since. I have been here for 1.5 years and I can honestly say I could not have predicted that this job would shape into what it has become.

First of all, we went through a re-branding/re-naming. It is a bit frustrating, to say the least, since this organization was already re-named once (from GPIC, Greater Philadelphia Innovation Cluster, to EEB Hub, Energy Efficient Buildings Hub). It is now CBEI, the Consortium for Building Energy Innovation). One of the big things I needed to help with was our new website: www.cbei.psu.edu

The new site means we are no longer using an outside contractor to maintain our website. It is now hosted within the College of Engineering at Penn State. There are many challenges now that the site is in-house, but, one thing is for sure, it is much, much, much, much cheaper. This website probably deserves its own post at a later date.

Our new headquarters is still under construction (http://kierantimberlake.com/posts/view/259/) and planning for the move has been a great learning experience. Just today, we received a few of our new VOIP phones. We will be transition to VOIP from analog before the move, so we can port the numbers ahead of time and just “plug and play” once we get to our new offices.

CBEI VOIP phones
CBEI VOIP phones

There’s a lot more I could write about, but one of the biggest news is that our budget from the Department of Energy has been cut by more than 50%, so our staff has been shrinking. This directly impacts my workload, since I am in a support role. This also opens up some time to catch up and think of places to improve or catch up. For example, I have been working on getting Dell KACE set up on our machines for patching and software deployment.

Also, with the extra time, I plan on incorporate blogging into my regular routine, so there should be more consistent updates.

Posted in Projects | Comments Off on CBEI and long overdue update