[MOD] Touch gesture actions, proof of concept

Suggestions/requests/ideas for RuneAudio core features and functions

[MOD] Touch gesture actions, proof of concept

Postby waves » 23 Feb 2015, 14:32

mod: touch gestures for smartphone: switch tab, play/pause, toggle webradio and more

updated 2016-09-03

Caveats
- This presupposes that you SSH in to your Rune device and edit files there.
- It is a good idea to first make a backup of the files you modify.
- this is a proof of concept. But it is already quite useful.
- tested on runeaudio updated to latest git version.
- only tested on an android smartphone

The mod adds many touch gestures (tap, longpress, swipe, pan) using hammer.js

Features
1 swipe left/right to switch tab (on main screen area or bottom menu buttons)
2 tap bottom menu playback button when playback screen is active to toggle play/pause
3 swipe up from bottom menu playback button to show volume wheel on top for two seconds (quicker than manual scroll down to volume wheel)

123 makes it easy to control RuneAudio on a smartphone with only the thumb.

4 tap title/artist/album or tap time wheel to toggle play/pause (play/stop if webstream)
5 swipe up on time wheel to show volume wheel on top for 2 seconds
6 longpress title/artist/album for quick webradios mode:
- one webradio station starts playing
- swipe left/right to switch webradios from a quicklist (that you choose). This overrides feature 1.
7 longpress cover art to search Discogs for artist and album in a new browser tab

The mod also makes the bottom menu button row higher, for easier touch navigation

Steps
Download hammer.min.js from http://hammerjs.github.io/
and move it to /srv/http/assets/js/hammer.min.js

Edit this file
Code: Select all
/srv/http/app/templates/playback.php

and add this as a new line below line 5:
Code: Select all
<script type="text/javascript" src="../../assets/js/hammer.min.js"></script>


Then edit the file
Code: Select all
/srv/http/assets/js/runeui.js


find the lines
Code: Select all
// update info and status on Playback tab
function refreshState() {


and add this large code block above those lines

Code: Select all
// HAMMERJS SECTION START
// required: include hammer.min.js in playback.php

// edit radioarr with webradios you want quick access to through swipeleft/swiperight on title
// must match the name on your webradios library page   // you can add any number of webradios
var radioarr = ["bbc_radio_one", "bbc_radio_two", "bbc_radio_three"];

var timehidden;  //for temphidetime function
var timer;       //for temphidetime function

//only on playback.php pages -- without this conditional some menu pages fail
if (getid('currentsong') != null || getid('currentartist') != null || getid('currentalbum') != null )
{  //START CONDITIONAL

// first way to set up hammer
var mc = new Hammer.Manager(getid('currentsong'), {
recognizers: [ [Hammer.Press], [Hammer.Tap], [Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.03, threshold: 15}], ] });
var mc3 = new Hammer.Manager(getid('currentalbum'), {
recognizers: [ [Hammer.Press], [Hammer.Tap], [Hammer.Swipe, {direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.03, threshold: 15}], ] });
var mc4 = new Hammer.Manager(getid('cover-art'), { recognizers: [ [Hammer.Press] ] });

//second way to set up hammer
var mc2 = new Hammer.Manager( getid('currentartist') );
mc2.add( new Hammer.Swipe( {velocity: 0.03, threshold: 15}) );
mc2.add( new Hammer.Tap() );
mc2.add( new Hammer.Press() );

//playback , queue , library pages
var mc5 = new Hammer.Manager(getid('playback'), { recognizers: [ [Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.03, threshold: 50}] ] });
var mc6 = new Hammer.Manager(getid('panel-dx'), { recognizers: [ [Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.03, threshold: 70}] ] });
var mc7 = new Hammer.Manager(getid('panel-sx'), { recognizers: [ [Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.03, threshold: 70}] ] });
//note: swiperight = swipe from left to right on screen (gesture name describes gesture end position)

//time countdown/total texts
var mc8 = new Hammer.Manager(getid('countdown-display'), { recognizers: [ [Hammer.Tap, { enable: true } ], [Hammer.Swipe, { direction: Hammer.DIRECTION_VERTICAL, velocity: 0.05, threshold: 20}] ] });
var mc9 = new Hammer.Manager(getid('total'), { recognizers: [ [Hammer.Tap, { enable: true } ] ] });

//bottom menu buttons  playback, queue, library
var mc10 = new Hammer.Manager(getid('open-playback'), {
recognizers: [ [Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.04, threshold: 15}], [Hammer.Pan, { direction: Hammer.DIRECTION_VERTICAL, pointers: 1, threshold: 20}] ] });
var mc12 = new Hammer.Manager(getid('open-panel-dx'), { recognizers: [ [Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.04, threshold: 40}] ] });
var mc11 = new Hammer.Manager(getid('open-panel-sx'), { recognizers: [ [Hammer.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.04, threshold: 40}] ] });

//hammer functions
mc8.on("swipeup swipedown", function(ev) {temphidetime(ev)} );  //countdown-display

mc10.on("panup", function(ev) {
if (ev.distance > 50 && ev.distance < 65 && !timehidden) { //only trigger once, after some distance
temphidetime(ev);
if (!$('#open-playback').hasClass('active')) $('a', '#open-playback').click();  //activate playback tab if inactive
window.scrollTo(0, 0);
}
});

mc11.on("swiperight swipeleft", function(ev) { tab(ev) });  //bottom menu button swipe
mc12.on("swiperight swipeleft", function(ev) { tab(ev) });
mc10.on("swiperight swipeleft", function(ev) { tab(ev) });

mc6.on("swiperight swipeleft", function(ev) { tab(ev)} );  //page swipe
mc7.on("swiperight swipeleft", function(ev) { tab(ev)} );
mc5.on("swiperight swipeleft", function(ev) {              //playback page
if (ev.target.id.indexOf('current') > -1) { if ( ev.type.indexOf('right') >= 0 ) $("#previous").click(); else $("#next").click(); }
else if (document.getElementById(ev.target.id).parentElement.Name != 'time-knob') tab(ev);}
//Avoid accidental tab switch when draggging time wheel. This GetElement conditional blocks that (for some reason)
);

function tab(ev) {   //swipe to switch tab
var tabarr = ["#open-panel-sx", "#open-playback", "#open-panel-dx"];
var newtab
tabarr.forEach(function (val,i) {
if ( $(val).hasClass('active') ) newtab = ev.type == "swipeleft" ? tabarr[i==2?0:i+1] : tabarr[i==0?2:i-1]
})
$('a', newtab).click();
};

function temphidetime(ev) {
$('#time-knob, #cover-art').addClass('hide'); $('#volume-knob').css('margin-top', '5px');
var timer = window.setTimeout(unhidetime,2500);
timehidden = 1;
}

function unhidetime(){
timehidden = "";
$('#time-knob, #cover-art').removeClass('hide'); $('#volume-knob').css('margin-top', '30px');
}

mc8.on("tap", function(ev) {toggleplay() } );  //tap on time countdown, total
mc9.on("tap", function(ev) {toggleplay() } );
//

function toggleplay() {
if (GUI.stream === 'radio' || jQuery.inArray( $('#currentsong').text(), radioarr) >= 0 ) {
if (GUI.state === 'play') $("#stop").click(); else $("#play").click();  // radio stop/play
}
else $("#play").click();
};

// longpress cover --> Discogs search artist + album
mc4.on("press", function(ev) {searchcover(ev)} );
function searchcover(ev) {
var miniurl = "http://www.discogs.com/search/?q=" + $("#currentartist").text() + " " + $("#currentalbum").text();
window.open(miniurl);
}

mc.on("press", function(ev) {toggleradio(ev)} );  //title artist album
mc2.on("press", function(ev) {toggleradio(ev)} );
mc3.on("press", function(ev) {toggleradio(ev)} );

mc.on("tap", function(ev) {toggleplay() } );  //title artist album
mc2.on("tap", function(ev) {toggleplay() } );
mc3.on("tap", function(ev) {toggleplay() } );

mc.on("swipeleft swiperight", function(ev) {switchtrack(ev) } );  //title artist album
mc2.on("swipeleft swiperight", function(ev) {switchtrack(ev) } );
mc3.on("swipeleft swiperight", function(ev) {switchtrack(ev) } );

function toggleradio(ev) { //longpress artist/album/song --> play hamradio1
$(':focus').blur();
if (GUI.stream != 'radio') {
  hamlistlen = GUI.json.playlistlength;
  sendCmd('load Webradio/' + radioarr[0] + '.pls');
  sendCmd('play ' + hamlistlen);
  }
}

function switchtrack(ev) {   //swipe horizontal on title artist album

if (GUI.stream === 'radio' || jQuery.inArray( $('#currentsong').text(), radioarr) >= 0 ) {
//switch next/prev miniarr list of radio streams (wraps around)
var hamsong = parseInt(GUI.json.song);  //this playlist position, first = 0
var hamlistlen = GUI.json.playlistlength;  // count items in playlist
//NOTE only works *if* webstream name in Rune Library is a substring of the currentartist or currentsong string
//( currentsong == Library webstream name until Rune loads proper artist/song strings )
var currart = $('#currentartist').text().toLowerCase()
var currsong = $('#currentsong').text()
var newradio
radioarr.forEach(function (val,i) {
if (currart.indexOf(val.toLowerCase()) > -1 || currsong == val)
 if (!newradio)
  newradio = ev.type == "swipeleft" ? radioarr[i==radioarr.length-1 ? 0 : i+1] : radioarr[i==0  ? radioarr.length-1 : i-1]  // next/prev in radioarr (note: i starts at 0)
});
//alert(ev.type + '\nnewradio=' + newradio + '\ncurrart=' + currart + '\ncurrsong=' + currsong);

//cmd load, not add, see 653 in runeaudio.php
if (newradio) sendCmd('load ' + "\"Webradio/" + newradio + ".pls\"");  // add to queue
if (newradio) setTimeout(function() { sendCmd('play ' + hamlistlen); sendCmd('delete ' + hamsong); }, 100);
//play last in queue  //remove old radiostream from queue   //wait 100
}
else if ( ev.type.indexOf('right') >= 0 ) $("#previous").click(); else $("#next").click();  //non webradio track
};

}  //END CONDITIONAL
// HAMMERJS SECTION END


Note: you must in the beginning of the big code block edit this line
Code: Select all
var radioarr = ["bbc_radio_one", "bbc_radio_two", "bbc_radio_three"];

and edit the quoted strings (and/or add more) to match names of webradios you have set up in your runeaudio webradios library. These webstream touch gestures only work if the name strings you edit in are included in the title shown on the playback tab during playback of the webstream. A simple test setup is to use these BBC radio streams and name them bbc_radio_one and so on when you add them to your webstream library.
Code: Select all
http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p
http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio2_mf_p
http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio3_mf_p


Next find these lines

Code: Select all
        // play/pause when clicking on the counter or total time inside the progress knob
        $('#countdown-display').click(function(){
            sendCmd('pause');
        });
        $('#total').click(function(){
            sendCmd('pause');
        });


and replace them with

Code: Select all
        // play/pause when clicking on the counter or total time inside the progress knob
        /*
        $('#countdown-display').click(function(){
            sendCmd('pause');
        });
        $('#total').click(function(){
            sendCmd('pause');
        });
        */   //mod use hammer instead, to better handle webstreams


Next make the lower menu buttons higher for easier swipe gestures.
Edit this file
Code: Select all
/srv/http/assets/css/runeui.css


find the string
Code: Select all
menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px

and replace with replace
Code: Select all
menu-bottom{position:fixed;left:0;right:0;height:60px;line-height:60px


find the string
Code: Select all
menu-bottom a{display:block;float:left;width:33.333%;line-height:40px

and replace with
Code: Select all
menu-bottom a{display:block;float:left;width:33.333%;line-height:60px


find the string
Code: Select all
btnlist-bottom{bottom:40px;padding:0 10px}

and replace with
Code: Select all
btnlist-bottom{bottom:60px;padding:0 10px}


find the string
Code: Select all
database{padding:80px 0}

and replace with
Code: Select all
database{padding:100px 0}



Necessary steps to apply the modifications
First, when you are done editing, save playback.php , runeui.js and runeui.css

Next we must minify the runeui.js file (i.e. convert it into a more compact file that RuneAudio normally uses, only needed for runeui.js)
- Copy all the contents of your modified runeui.js file to the clipboard
- Paste into the editbox at http://gpbmike.github.io/refresh-sf/
- Click the button Javascript on the right side of the editbox. The content is now minified
- Copy all the minified text in the editbox
- Edit the file runeui.min.js (make a backup of it first!) and replace all its contents with the minified text from the clipboard. Then save.

- Next go to the runeaudio /dev page. Click "clear OPcache". Click "phprestart".
- Finally, reload RuneAudio in the browser on your android smartphone and try out the gestures
Last edited by waves on 03 Sep 2016, 12:39, edited 5 times in total.
waves
 
Posts: 125
Joined: 31 Dec 2014, 10:33

Re: [MOD] Touch gesture actions, proof of concept

Postby ACX » 24 Feb 2015, 12:44

Hi waves,
thank you for submitting your mod. Touch gestures are an interesting added value, so they could be considered in the future (we'll test them once we complete the frontend refactor).
User avatar
ACX
RuneAudio co-founder
 
Posts: 1692
Joined: 29 Nov 2013, 02:25
Location: Udine, Italy

support RuneAudio Donate with PayPal


Return to Feature request

Who is online

Users browsing this forum: No registered users and 7 guests