Touch “Hold” Function: Button Held Down In NativeScript

Tonight I needed to run a function constantly while a button is being held down in my app.  I found the gestures functionality and it had what I needed but I had to do some work to get it to perform what I was after.

My task was this, when someone puts their finger down on a ‘Record’ button I need to store what the sound level was every 10/1000 of a second.  So here’s what I did.

Using Gestures Touch to Define “Hold”

When the page is loaded I assign the button element to a variable then I add the on touch function.  It’s important to declare that button’s variable at the beginning of your JS so it’s available in all functions.  Also important to require your view module and gesture.  Here’s a snippet that covers all of that:

var viewModule = require("ui/core/view");
var audio = require("nativescript-audio");
var timer = require("timer");
var gestures = require("ui/gestures");
var documents = fs.knownFolders.currentApp();
var recorder = new audio.TNSRecorder();
var isRec = false;
var timeRec;
var currentRecording = new Array();
var page;
var soundlevel;

exports.loaded = function(args) {
    page = args.object;
    soundlevel = viewModule.getViewById(page, "soundlevel");

    soundlevel.on(gestures.GestureTypes.touch, function (args) {
        if(args.action == "down" || args.action == "up") {
            recordVolume( args.action );
        }
    });
}

Now that I’m calling a function, let’s tell that function what to do.  We have our “soundlevel” view which is just a button with id=”soundlevel” and we’ve assigned an action of “on” for it when gesture touch occurs.  The gesture touch passes args that include “action” as a property.  That property can be “down”, “up” amongst other things, but these are what we need.  So now let’s build a function to handle the hold.

function recordVolume(action) {
    var recorderOptions = {
        filename: documents.path + "/recording.caf",
        infoCallback: function() {
            console.log();
        },

        errorCallback: function() {
            console.log();
        }
    };
    if( action == "up" ) {
        recorder.stop();
        isRec = false;
        timer.clearInterval(timeRec);
    } else {
        recorder.start( recorderOptions );
        currentRecording = new Array();
        isRec = true;
        timeRec = timer.setInterval( function() {
            var barWidth = Math.round((160+Number(recorder.getMeters(0, "average")))/160*100);
            currentRecording.push(barWidth);
        }, 10);
    }
}

Note: barWidth is an integer I end up assigning as a percentage of the screen width.  This way I can give a visualization of sound level.

Here we check wether the action is up or down and do our desired functionality based on that.  If it’s “up” that means the finger has been lifted from the screen so we stop everything.

If the action is “down” that means the user has just pressed the button.  So we user the timer library and set an interval.  Basically every 10/1000 of a second we perform a calculation of the sound level and push that to our array of sound levels.  Now we can analyze that and do what we want to do!

 

Monitor Sound Wave Decibels While Recording on iOS

You’re going to laugh at this.  My brother-in-law, David, told me an app idea he wanted me to build YEARS ago.  I had only written one crappy Android app, but when you write an app people start throwing you their ideas like crazy.

His idea, it was funny, but it was beyond my ability so I never really got going on it.  Now that NativeScript is here and I’m spending more time in the app world I decided to give it a go.  His idea? RankMyStank…

Farts

He wanted an app where you fart into the phone and it ranks your fart based on an array of factors: Length, depth, variety, pitch and so on.  I’m still working out that algorithm…

What I love about this idea is it made me really dig into NativeScript and try to figure out how to make this happen.  So I found the plugin nativescript-audio.  This boasted the ability to record and playback sounds easily in NS.

At first I couldn’t get it to work, so I put the project to the side.  After I released my first app into iTunes recently I had learned so much more about the framework and decided to give it another go.

I got the plugin working pretty quick.  As I toyed with it I began to realize there was no way to track the sound wave or get any details about the structure of the sounds being recorded.  You could just record then play.

Contributing

I’ve always wanted to contribute to an open source project but never felt like I was talented enough.  As I dug into figuring out how to accomplish this task I realized if I could figure it out, I could probably add it to the plugin.  This was motivation.  So, I set forth on my venture and here’s what I figured out.

Native Functionality

The cool thing about NativeScript is that you have access to all the native functions of iOS and Android.  Usually you don’t tap into them because there is such a great library of plugins already.  And there’s no way I could build this plugin from scratch at this point so altering the nativescript-audio plugin was my best option.

Inside the nativescript-audio plugin is a directory called src/ios/ and in here you find the functionality that communicates with the iOS native functions for audio.  The file recorder.js was my best bet so I popped it open.  There I saw:

TNSRecorder.prototype.start = function (options) {

As well as

TNSRecorder.prototype.stop = function () {

Amongst others, these guys told me that I found the spot where the functions I’ve been using in my javascript code to use this plugin were being defined.

Monitoring Recording

So I spent quite some time learning about the class I saw being used here: AVAudioRecorder.  This is the iOS class used to record sound.  I found out exactly how to use it to get the dB of sound waves being recorded in real time.  The function is called averagePowerForChannel() though there is also peakPowerForChannel().  From what I understand averagePowerForChannel() is closer to what the human ear hears so I went with that.

I also discovered that in order to use these functions you you must turn metering on.  It’s processor intensive so it is not on bey default.  In the end, this is all the code I added to the plugin to give us two new functions… one to detect if recording is happening and one to get us the current dB of sound being recorded.

TNSRecorder.prototype.isRecording = function () {
    var _this = this;
    return _this._recorder.recording;
};
TNSRecorder.prototype.getMeters = function (channel) {
    var _this = this;
    if (!_this._recorder.meteringEnabled) {
        _this._recorder.meteringEnabled = true;
    }
    _this._recorder.updateMeters();
    return _this._recorder.averagePowerForChannel(channel);
};

I wound up not even using the isRecording function but I figured it could be useful for others so I left it in after testing it.

Rewriting in TypeScript

So TypeScript is how the original plugin was built and it uses a compiler to create the .js files.  Now knowing this I had to write these functions in TS before submitting a pull request to the original plugin.  Fortunately that wasn’t too difficult.

public isRecording() {
  var _this = this;
  return _this._recorder.recording;
}

public getMeters(channel: number) {
  var _this = this;
  if(!_this._recorder.meteringEnabled) {
    _this._recorder.meteringEnabled = true;
  }
  _this._recorder.updateMeters();
  return _this._recorder.averagePowerForChannel(channel);
}

Using In NativeScript

So here’s what I have now just demoing the functions and showing they work.  I update a Label view’s width to show current dB coming in.  It’s fairly straight forward and a decent example of it’s use.

exports.onTap = function(args) {
    var recorderOptions = {
        filename: documents.path + "/recording.caf",
        infoCallback: function() {
            console.log();
        },
        errorCallback: function() {
            console.log();
        }
    };
    if( isRec ) {
        recorder.stop();
        isRec = false;
        timer.clearInterval(timeRec);
    } else {
        recorder.start( recorderOptions );
        isRec = true;
        timeRec = timer.setInterval( function() {
            var barWidth = Math.round((160+Number(recorder.getMeters(0)))/160*100);
            page.css = ".soundlevel { color:#FFF; padding: 10px; background-color: Brown; width:" + barWidth + "%; }";
        }, 10);
    }
}

Don’t Touch Things In /platform/

I learned this the hard way just like every thing else in here related to NativeScript.  It’s a young framework and there is not a ton of documentation or much of a community yet.  But I love it and the slack community is pretty active.

I finally finished an app and needed to get it in iTunes for my boss.  I started following build instructions using Xcode which involved following along with NativeScript’s docs and also getting linked over to Apple’s dev docs a lot.  Somewhere along the way I felt that I needed to make some changes to my app in Xcode so that it would be able to get submitted for review as it kept hitting errors when trying to upload.

Icons

Icons are handled in a way that’s not overly complex but super easy to screw up.  When you open your project that NativeScript generates you will see a lot of stuff going on.  One of those is the “Use Asset Catalog” option for your icons.

If you have any issues with icons when trying to upload to iTunes you will probably start toying with the Asset Catalog and your info.plist.  One word of advice: DON’T!

NativeScript handles this for you just fine.  Make sure you have all required icons in your /app/App_Resources/iOS directory (including your 120px ones! I.e. 40@3x and so on, these are new and screwed me up bad).

tns prepare ios

The point is, when you want to build your app just run tns prepare ios then open the project in Xcode.  You can have it handle some of the automated tasks you might need when it pops up its warnings, but don’t screw with the .plist file or the asset catalog stuff or you will spend an entire day like me trying to figure out what’s wrong.

When you run the prepare CLI command NativeScript builds out a fully functional Xcode project for you.  Other than dealing with setting up your Apple developer account and connecting it to Xcode there’s not much else for you to do.  When you are ready to build and submit to the app store all you have to do is make sure the device selected is “Generic iOS Device” hit Product > Archive then when the Organizer window opens Validate then Upload to iTunes.

Using update_option & get_option Instead of the Complicated Settings API in WordPress Plugin Development

IMPORTANT EDIT: Security is vital, and I’ve been called out by two very respectable WordPress engineers on Advanced WordPress for my lack of security in this post and that using the Settings API is important because it handles this security for you.  I’m adding nonce, capability checks and proper sanitization to this code right now and should be in place shortly.

The code in here is also written for brevity of example.  Copying and pasting will work but it’s best practice to put functionality in the appropriate places.  For example instead of just using sanitize( $_POST[‘var’] ) you should add a filter that’s global.


WOAH that’s a long title.  This isn’t going to be a crazy long post but all those items mentioned are very important to the content.  The WordPress Settings API is powerful and for large plugins or themes it might be the best way to go about managing a large array of settings and options.  But most of my plugins are small scale and I find it overly complicated and bulky.

My Experience With The WP Settings API

If you don’t care about my experience and just want to see my solution click here.

My first plugin where I needed a core admin page just for settings was the WP Name Your Donation plugin.  I’ve all but abandoned that plugin because there are so many awesome plugins out there that cover its functionality and more.  It was a great learning experience building it though.

It allows multiple gateway options for accepting user determined amounts of money, i.e. donations.  So the admin page needed to allow a user to set the api keys for multiple gateways and I was starting off with Stripe, Authorize.Net and PayPal.

Googling admin settings in plugin development while I was building this, which was only my second plugin, referred me to articles on the WP Settings API.  It took a TON of trial and error to get this functioning and I still don’t think it’s implemented right.  Take a look at this:

https://gist.github.com/ChrisFlannagan/5ed116c35b97b601fc6d26dcd7085bca

I start by building out all my options in arrays.  These arrays hold all the info for each setting input I will need for each payment method option.  Then I loop through them all using the Settings API method add_settings_field() after using the methods register_setting() and add_settings_section(), note this is in the admin_init hook:

https://gist.github.com/ChrisFlannagan/1cabe324b70ae0d18921d5277574e62a

I have different functions for different kinds of fields which you can see in the parameters of add_settings_field.

Codex Confusion

Over in the codex for the Settings API you will notice multiple times they have small callout notes saying “make sure this was done first.” The confusion is real because my code does not follow a lot of the directions yet it works.  But when I was playing with it last night in a new plugin I was following directions exactly and it wouldn’t work.  For example:

NOTE: You MUST register any options used by this function with register_setting() or they won’t be saved and updated automatically.

In my code you will see I use the register_setting method, but I use it with the parameters

( self::PLUGIN_ABBR . '-group', self::PLUGIN_ABBR . '-group' )

The PLUGIN_ABBR is just wpnyd so the string “wpnyd-group” is set for both parameters and here’s the kicker: I DON’T USE THAT STRING ANYWHERE ELSE IN MY SETTINGS CODE.  What the hell???  I look back at this and wonder what the hell brought me to the code that’s in place and that works.

I’m not going to expand on this too much but will in comments if we have discussion.  This is just one example of my insane confusion from trying to implement the Settings API for the second time and trying to actually follow directions.

Using update_option and get_option For Admin Settings in a Plugin

These methods are lightweight and serve a simple but awesome purpose.  You set a unique key and a value and those are accessible at any time.  I find it best just to learn by example so I will show what I recently did and explain along the way.

I need the ability to let an admin set a few checkbox options and a color.  For simplicity’s sake in this post I’ll show how I do that with just one checkbox and a text field (I use a color picker but that makes it complicated, so we will just use text).

Here’s the full code, explanation below that:

https://gist.github.com/ChrisFlannagan/26264438230bad687680c8cf61a8f5fa

Let’s look at the form first.  We have two inputs, feature_on and settings_color, a checkbox and a text input respectively.  These represent two settings we want the admin to be able to control.

Now let’s look at the php up top.  The first thing I do is set a default value $settings_color which will be used in case this has not been set by the admin yet.  Then I check if the form has been submitted by detecting if $_REQUEST[‘settings_color’] is set.  If it is, let’s update some settings.

The first method we use is the WordPress method update_option().  I love this method.  If the option doesn’t exist, it creates it, if it does exist then it simply updates it! So simple, so straight forward, so not messy, YES.

NOTE: Option keys MUST be unique so be carful naming as you don’t want to overwrite an option in another plugin.  Here I added “myplugin_” to the beginning but I’m sure you can be more creative than that.

Setting & Getting Text Input Values

This is so straight forward.  First thing we do after checking if the form was submitted is simply set the options value with the (sanitized) submitted value:

update_option( “myplugin_settings_color”, sanitize_hex_color( $_POST[‘settings_color’] ) );

Done! Now we can call this value and use it, overwriting our default set value with:

if( get_option( “myplugin_settings_color” ) !== false ) {
$settings_color = get_option( “myplugin_settings_color” );
}

We must check if the admin has already set this or not by testing if it exists via the !== false or we will throw a php warning.

Sanitizing with pre_update_option

It’s important to sanitize any posted data going into your database.  For options we use pre_update_option filter.  To use this you need to add your option’s key to the end of the filter.  So for my settings_color option it would be like this:

add_filter( 'pre_update_option_settings_color', array( &$this, 'hexcolor_sanitize' ), 10, 2 );

Then a function ‘hexcolor_sanitize’ needs to be defined for handling this.  In this code example below you will see how that is handled.  Side note, sanitize_hex_color is not available outside of the customizer so I just copied the function into my plugin’s code:

https://gist.github.com/ChrisFlannagan/ce8c3152552e7156ad2c892bcc7e85cb

Setting & Getting Checkboxes

If a checkbox is checked when a form is submitted then it’s value is accessible via $_REQUEST[‘checkbox_name’].  If it is NOT checked, then that request variable is not set at all.  So if we don’t need a value from it but simply need to detect if it’s checked or not we just see if it exists:

if( isset( $_REQUEST[feature_on] ) ) {

For my purposes this is all we need so we update our option to either true or false.  Now if we want to set the box to checked or unchecked in the admin interface based on what an admin has or has not set already then we need to check a couple of things.  Has this setting been set previously? If so is this setting true or false? We accomplish this with:

if ( get_option( “myplugin_feature_on” ) !== false && get_option( “myplugin_feature_on” ) ) {
echo ‘checked=”checked” ‘;
}

Conclusion

The purpose of this article isn’t to make the Settings API look like a bad choice.  It’s extremely powerful and a great choice for many applications.  But for simple plugins like mine it’s overkill.  And I will say this, the codex and documentation on the Settings API are fucking horrible and confusing.

Tutorial, Shmutorial, Learn New Stuff By Switching It Up

My new job needs an iPhone and Android app.  I’ve built a few shaky Android apps using java and a LOT of google.  They worked but not being a java developer I know my methods and coding standards were sub-par at best.  I’ve never attempted an iOS app.

Thankfully there are few pretty badass frameworks out now that let you use javascript or something similar to build native apps.  A friend recommended NativeScript.js and so far I’m really liking it.  But I’m learning a brand new technology so I do the same thing most of us do.  I go through the official, beginners tutorial example to build out a sample app.

Make It Your Project

But I like to do it different.  I find this method not only immerses you in the new language or framework but also helps you start solving problems and learning deeper parts of the system at the same time.

I need a fairly basic app.  It needs to let users log some information kind of like MyFitnessPal and keep track with analytics.  Nothing crazy but will include a couple features that dive into some deeper modules like using the camera.

So I start the tutorial going step by step which gets a nice boilerplate up, gives you a hello world and then moves onto building out features for their sample which is a groceries list app.  This is when I start changing things to do what I want them to do.

For Example

Chapter 2 gets into building out a view for the initial screen which is a login or sign up screen.  Hey, we need this in our app! Awesome, so I’m going to follow this part exactly for now.

The tutorial taught me how to implement css stylesheets app wide or specific to individual pages.  We styled up the login inputs and buttons and now I want to side-track a bit.  I want my companies logo at the top.  I leave the tutorial right where it is and I pop open a new tab and find the developers resources on the website.  I find UI Components section, Images is listed in there, I click and now I dive into how images work.

I already know how to put UI components in the layout from the tutorial so this should be easy.

Nope

OK, so I have to load the Image module and I also have to then create an Image instance.  I’ve loaded the main module already and that was in the main app file, so do I do it there or do I do it in the page’s JS file? Let’s experiment!!

This is how I find the learning process really starts getting more intuitive.  I’m forced to solve a problem instead of just following a line by line tutorial on creating an app.  For me, and I suspect for others, this process actually makes learning a lot faster and more in depth.  It might not work for everyone but I have to suggest giving it a go.

Note: They actually show how to add an image not even a section further down the tutorial but I still find the fact I took the time to dig through developer resources for a few a great learning experience.

In Conclusion

This won’t work for everything.  Some languages and frameworks, especially those you have absolutely zero knowledge of, following the initial tutorials exactly is not a bad idea for introducing yourself to the system.  But this comes in handy and again, I do recommend giving it a go sometime.

My First WordCamp Presentation Was Awesome

I’m sitting in a tattoo parlor in St. Louis right now waiting on the artist to sketch up my art.  I love tattoos, I love getting them, I love appreciating other people’s, I can’t get enough of them.  I get tattoos to memorialize events in my life.  I get them for other reasons too but that’s a big one.  I decided to get one that represents my experience this weekend.

haildale-shamrockI’m on stage all the time with my band.  We’ve played in front of 500 people and I didn’t have a single butterfly.  But the day before doing my first WordCamp presentation I was nervous as hell.  I was terrified honestly.  I’ve never spoken as an expert.  I’ve never considered myself an expert.  I was encouraged by my piers to apply for speaker positions though so I decided why not and sent out a few applications.  To my surprise three got back to me and I was actually doing it.

I spoke on Plugin Development 101.  It was a basic introductory to how plugins are built in WordPress and how simple it is to actually make one.  The end of the presentation I build a plugin in just a few minutes to demo the simplicity.  The slides can be found here: http://whoischris.com/slides/plugin-dev-101.pdf

When I got to the conference and was setting up my computer with the projector I felt a lot calmer.  There were only two people in there.  As much as I wanted to have a big group, my nerves were very happy at the tiny turn out.  I was supposed to start at 9, but decided to wait a couple minutes to see if anyone else showed up.  By 9:04 every seat in the room was filled… shit.

I kept my composure and just went at it, started talking, introduced myself and went slide by slide.  I was fast, and I probably rushed a couple of slides because I was finished in 25 minutes when it was supposed to be 40 minutes with a 5 min q & a.  Thankfully everyone seemed to really enjoy it and there were loads of questions to fill the remaining time.  We had an awesome discussion overall and I think people really got some good stuff out of it.

So in a few minutes the tattoo artist will be back to get me.  I’m getting an old school radio microphone with WCSTL in red lettering above it.  I added a pic below, skin is swollen, pink and twisted a little weird, it looks really good though and can’t wait for it to heal.

Up next, June 4th in Asheville, I’ll be presenting on leveling up as a developer.

wcstl

I Won’t Help You, But I Will Teach You

A week doesn’t go by where I don’t get a request from a friend for help with their website.  Typically it’s WordPress related and people know that’s what I do.  I never reply “sure I can help!” Why? Because that’s helping no one.

If a friend doesn’t understand that they have to select “image” as the post format in their theme to get it to display how they want I could easily just tell them “If it’s a picture blog post be sure to select image as the format and make sure you set your featured image and don’t just add it to the post’s body.”  Sure this will fix their current issue but what does that do for future issues?

It makes them come back to me for everything.

It Takes More Time To Teach

Teaching definitely is more of a time investment than doing a quick 2-minute fix for someone.  But when I teach someone I feel like I’m actually helping them not just now but in preparation for future issues.  Say I approach the previous situation by teaching the basics of themes and templates, posts verse pages and rudimentary HTML; Now the friend/student might be able to tackle future, related issues.  Instead of asking me why their page has a side bar when they don’t want it on that page, they could now have the inclination to see there is a “template” option on the page editor, and like many themes there is probably one called “No Sidebar.” Boom, just:

  • Saved us both time by asking me for more help
  • They feel a mental reward of solving something by themselves
  • Internet gets better web pages

It’s a win-win all across the board!

Going All Out

A buddy from high school, who I’ve somewhat reconnected with over the past few years, posted a link to his latest blog post.  His featured image is gorgeous but small and you can’t click to a full size version.  I commented this on his Facebook post and he told me he’s just learning WordPress, I told him to hit me up if he has any questions.  And he did! I’ve offered this to so so so many people and they always say that would be awesome and will do.  Almost never happens.

When I get the opportunity to teach I eat it up.  I’ve loved showing people how the web works since I first got a real understanding of it.  So many people want to have things done but don’t want to take the time to learn.  Code just does not interest them and this blows my mind.  I just don’t get it.  I LOVE code and I think it’s the coolest freaking thing ever.  That said, I don’t get Bruce Springsteen, a lot of people do, so that’s just the way the world turns I guess.

My buddy who responded to my offer and I have a phone call setup for 6pm so I can walk him through how his css file works, how featured images work and how to adjust small items in his theme.  It’s so refreshing to have someone sincerely interested in “getting it.”

In Conclusion, It Ain’t About Money

Teaching is rewarding.  If it paid better I’d absolutely love to be a professor.  Someday, I hope I can pursue a path of being an educator.  Knowing that you aren’t just helping someone past a hump but actually enabling them to do better problem solving on their own isn’t just helping them, or you, but helping society overall.

Full Screen jssor Slider Exact Window Width & Height

I’ve been working on a program for my side job that is supposed to have lots of slider like features between content with LOTS of content.  My favorite slider libray, because it’s got SO much functionality for devs is jssor.

One thing I could not find a proper solution for was making a full screen slider that would work on any screen or device (with a modern browser).  So, I thought and thought and came up with a solution.

So there’s no way to set jssor height by percentage or parent height and keep the width proportional.  I tried everything I could but it absolutely must be pixels.  There are some options that set it but the width is then off.  Seriously, I tried everything.

So What If We Set It By Pixels?

I mean, it is a php site.  So I came up with an interesting solution.  It’s not bullet proof, especially if the user resizes the window, but it works.

My php starts with this:

session_start();
if( isset( $_REQUEST['wslides'] ) ) {
   $_SESSION['wslides'] = $_REQUEST['wslides'];
   $_SESSION['hslides'] = $_REQUEST['hslides'];
}
if( !isset( $_SESSION['wslides'] ) || isset( $_REQUEST['reset'] ) ) {
   header( "Location: set-dimensions.php" );
}

Here we start a session, then, we see if there’s a query variable called ‘wslides.’  If there is, then we have ‘wheight’ too and we know what pixels to set for our slider.  Bam!

So How Do We Get Those Pixel Dimensions?

Look at the next ‘if’ statement.  If we don’t have a session set for width and height we forward to a page called ‘set-dimensions.php’.  Here’s the full code of that page:

<html>
<head>
   <title>Loading</title>
   <script language="javascript" type="text/javascript">
      window.location.href='index.php?wslides=' + window.innerWidth + '&hslides=' + window.innerHeight;
   </script>
</head>
<body></body>
</html>

It’s just used to set dimensions of window very fast then send back with the query variables.  Now we can build our slider to the window’s width!

<div id="slider1_container" style="position: relative; top: 0px; left: 0px; width: <?php echo $_SESSION['wslides']; ?>px; height: <?php echo $_SESSION['hslides']; ?>px;">
 <!-- Slides Container -->
 <div u="slides" style="cursor: move; position: absolute; overflow: hidden; left: 0px; top: 0px; width: <?php echo $_SESSION['wslides']; ?>px; height: <?php echo $_SESSION['hslides']; ?>px;">
  <div id="slide-welcome">hello</div>
  <div id="slide-goodbye">goodbye</div>
 </div>
</div>

The WP Crowd Podcast: Level’ing Up as a WordPress Developer

I’ve joined the team over at The WP Crowd for the most recent podcast.  I’ll also be blogging over there as well, so keep an eye out for my articles!

Episode 029: Level’ing Up as a WordPress Developer