Merge pull request #77 from glyptodon/mobile-issues

GUAC-1044: Fix appearance of menu.
This commit is contained in:
James Muehlner
2015-02-02 17:38:43 -08:00
4 changed files with 246 additions and 138 deletions

View File

@@ -155,23 +155,47 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
remaining: 15
};
// Hide menu by default
$scope.menuShown = false;
/**
* Menu-specific properties.
*/
$scope.menu = {
// Use physical keyboard by default
$scope.inputMethod = 'none';
/**
* Whether the menu is currently shown.
*
* @type Boolean
*/
shown : false,
// Convenience method for closing the menu
$scope.closeMenu = function closeMenu() {
$scope.menuShown = false;
};
/**
* Whether the Guacamole display should be scaled to fit the browser
* window.
*
* @type Boolean
*/
autoFit : true,
/**
* The currently selected input method. This may be either "none",
* "osk", or "text".
*
* @type String
*/
inputMethod : 'none',
/**
* The current scroll state of the menu.
*
* @type ScrollState
*/
$scope.menuScrollState = new ScrollState();
scrollState : new ScrollState()
};
// Convenience method for closing the menu
$scope.closeMenu = function closeMenu() {
$scope.menu.shown = false;
};
// Update the model when clipboard data received from client
$scope.$on('guacClientClipboard', function clientClipboardListener(event, client, mimetype, clipboardData) {
@@ -206,12 +230,12 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
// Hide menu if swipe gesture is detected
if (Math.abs(currentY - startY) < MENU_DRAG_VERTICAL_TOLERANCE
&& startX - currentX >= MENU_DRAG_DELTA)
$scope.menuShown = false;
$scope.menu.shown = false;
// Scroll menu by default
else {
$scope.menuScrollState.left -= deltaX;
$scope.menuScrollState.top -= deltaY;
$scope.menu.scrollState.left -= deltaX;
$scope.menu.scrollState.top -= deltaY;
}
return false;
@@ -226,7 +250,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
if (Math.abs(currentY - startY) < MENU_DRAG_VERTICAL_TOLERANCE
&& currentX - startX >= MENU_DRAG_DELTA)
$scope.menuShown = true;
$scope.menu.shown = true;
}
@@ -294,7 +318,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
currentScale = Math.min(currentScale, $scope.client.clientProperties.maxScale);
// Update scale based on pinch distance
$scope.autoFit = false;
$scope.menu.autoFit = false;
$scope.client.clientProperties.autoFit = false;
$scope.client.clientProperties.scale = currentScale;
@@ -307,7 +331,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
};
// Show/hide UI elements depending on input method
$scope.$watch('inputMethod', function setInputMethod(inputMethod) {
$scope.$watch('menu.inputMethod', function setInputMethod(inputMethod) {
// Show input methods only if selected
$scope.showOSK = (inputMethod === 'osk');
@@ -315,7 +339,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
});
$scope.$watch('menuShown', function menuVisibilityChanged(menuShown, menuShownPreviousState) {
$scope.$watch('menu.shown', function menuVisibilityChanged(menuShown, menuShownPreviousState) {
// Send clipboard data if menu is hidden
if (!menuShown && menuShownPreviousState)
@@ -351,7 +375,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
// Toggle the menu
$scope.$apply(function() {
$scope.menuShown = !$scope.menuShown;
$scope.menu.shown = !$scope.menu.shown;
});
}
}
@@ -372,8 +396,8 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
// Show menu and scroll file transfer into view
if (count > oldCount) {
$scope.menuShown = true;
$scope.fileTransferMarker.scrollIntoView();
$scope.menu.shown = true;
$scope.menu.fileTransferMarker.scrollIntoView();
}
});
@@ -460,7 +484,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
};
$scope.zoomIn = function zoomIn() {
$scope.autoFit = false;
$scope.menu.autoFit = false;
$scope.client.clientProperties.autoFit = false;
$scope.client.clientProperties.scale += 0.1;
};
@@ -470,12 +494,11 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
$scope.client.clientProperties.scale -= 0.1;
};
$scope.autoFit = true;
$scope.changeAutoFit = function changeAutoFit() {
if ($scope.autoFit && $scope.client.clientProperties.minScale) {
if ($scope.menu.autoFit && $scope.client.clientProperties.minScale) {
$scope.client.clientProperties.autoFit = true;
} else {
}
else {
$scope.client.clientProperties.autoFit = false;
$scope.client.clientProperties.scale = 1;
}
@@ -495,7 +518,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
$scope.client.client.disconnect();
// Hide menu
$scope.menuShown = false;
$scope.menu.shown = false;
};

View File

@@ -30,6 +30,11 @@ angular.module('client').factory('guacAudio', [function guacAudio() {
*/
return new (function() {
/**
* Array of codecs to test.
*
* @type String[]
*/
var codecs = [
'audio/ogg; codecs="vorbis"',
'audio/mp4; codecs="mp4a.40.5"',
@@ -38,30 +43,58 @@ angular.module('client').factory('guacAudio', [function guacAudio() {
'audio/wav; codecs=1'
];
/**
* Array of all codecs that are reported as "probably" supported.
*
* @type String[]
*/
var probably_supported = [];
/**
* Array of all codecs that are reported as "maybe" supported.
*
* @type String[]
*/
var maybe_supported = [];
/**
* Internal audio element for the sake of testing codec support. If
* audio is explicitly not supported by the browser, this will instead
* be null.
*
* @type Audio
*/
var audio = null;
// Attempt to create audio element
try {
audio = new Audio();
}
catch (e) {
// If creation fails, allow audio to remain null
}
/**
* Array of all supported audio mimetypes, ordered by liklihood of
* working.
*/
this.supported = [];
// Build array of supported audio formats
// Build array of supported audio formats (if audio supported at all)
if (audio) {
codecs.forEach(function(mimetype) {
var audio = new Audio();
var support_level = audio.canPlayType(mimetype);
// Trim semicolon and trailer
var semicolon = mimetype.indexOf(";");
if (semicolon != -1)
if (semicolon !== -1)
mimetype = mimetype.substring(0, semicolon);
// Partition by probably/maybe
if (support_level == "probably")
if (support_level === "probably")
probably_supported.push(mimetype);
else if (support_level == "maybe")
else if (support_level === "maybe")
maybe_supported.push(mimetype);
});
@@ -73,6 +106,7 @@ angular.module('client').factory('guacAudio', [function guacAudio() {
// Prioritize "maybe" supported types second
Array.prototype.push.apply(
this.supported, maybe_supported);
}
})();

View File

@@ -21,10 +21,10 @@
*/
#menu {
overflow: auto;
overflow: hidden;
position: absolute;
top: 0;
bottom: 0;
height: 100%;
max-width: 100%;
width: 480px;
background: #EEE;
@@ -37,6 +37,43 @@
transition: left 0.125s, opacity 0.125s;
}
.menu-content {
overflow: hidden;
display: table;
table-layout: fixed;
width: 100%;
height: 100%;
}
.menu-header {
display: table-row;
height: 0;
}
.menu-header h2 {
margin-bottom: 0;
}
.menu-body {
display: table-row;
height: 100%;
}
.menu-body-content {
position: relative;
width: 100%;
height: 100%;
}
.menu-body-scroll-region {
overflow: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
#menu h3 {
margin: 1em;
}

View File

@@ -20,8 +20,9 @@
THE SOFTWARE.
-->
<!-- Client view -->
<guac-viewport>
<!-- Client view -->
<div class="client-view">
<!-- Central portion of view -->
@@ -42,24 +43,30 @@
<!-- On-screen keyboard -->
<div class="keyboard-container" ng-show="showOSK">
<guac-osk layout="'CLIENT.URL_OSK_LAYOUT' | translate"/>
<guac-osk layout="'CLIENT.URL_OSK_LAYOUT' | translate"></guac-osk>
</div>
</div>
</div>
</guac-viewport>
<!-- Menu -->
<div ng-class="{open: menuShown}" id="menu" guac-touch-drag="menuDrag" guac-scroll="menuScrollState">
<div ng-class="{open: menu.shown}" id="menu">
<div class="menu-content">
<!-- Stationary header -->
<div class="menu-header">
<div class="logout-panel">
<a class="home button" href="#/">{{'CLIENT.ACTION_NAVIGATE_HOME' | translate}}</a>
<a class="disconnect danger button" ng-click="disconnect()">{{'CLIENT.ACTION_DISCONNECT' | translate}}</a>
</div>
<h2>{{client.name}}</h2>
</div>
<!-- Scrollable body -->
<div class="menu-body">
<div class="menu-body-content">
<div class="menu-body-scroll-region" guac-touch-drag="menuDrag" guac-scroll="menu.scrollState">
<!-- Clipboard -->
<h3>{{'CLIENT.SECTION_HEADER_CLIPBOARD' | translate}}</h3>
@@ -69,7 +76,7 @@
</div>
<!-- File transfers -->
<h3 guac-marker="fileTransferMarker">{{'CLIENT.SECTION_HEADER_FILE_TRANSFERS' | translate}}</h3>
<h3 guac-marker="menu.fileTransferMarker">{{'CLIENT.SECTION_HEADER_FILE_TRANSFERS' | translate}}</h3>
<div class="content" id="file-transfers">
<guac-file-transfer-manager client="client"></guac-file-transfer-manager>
</div>
@@ -80,20 +87,20 @@
<!-- No IME -->
<div class="choice">
<label><input id="ime-none" name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="none"/> {{'CLIENT.NAME_INPUT_METHOD_NONE' | translate}}</label>
<label><input id="ime-none" name="input-method" ng-change="closeMenu()" ng-model="menu.inputMethod" type="radio" value="none"/> {{'CLIENT.NAME_INPUT_METHOD_NONE' | translate}}</label>
<p class="caption"><label for="ime-none">{{'CLIENT.HELP_INPUT_METHOD_NONE' | translate}}</label></p>
</div>
<!-- Text input -->
<div class="choice">
<div class="figure"><label for="ime-text"><img src="images/settings/tablet-keys.png" alt=""/></label></div>
<label><input id="ime-text" name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="text"/> {{'CLIENT.NAME_INPUT_METHOD_TEXT' | translate}}</label>
<label><input id="ime-text" name="input-method" ng-change="closeMenu()" ng-model="menu.inputMethod" type="radio" value="text"/> {{'CLIENT.NAME_INPUT_METHOD_TEXT' | translate}}</label>
<p class="caption"><label for="ime-text">{{'CLIENT.HELP_INPUT_METHOD_TEXT' | translate}} </label></p>
</div>
<!-- Guac OSK -->
<div class="choice">
<label><input id="ime-osk" name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="osk"/> {{'CLIENT.NAME_INPUT_METHOD_OSK' | translate}}</label>
<label><input id="ime-osk" name="input-method" ng-change="closeMenu()" ng-model="menu.inputMethod" type="radio" value="osk"/> {{'CLIENT.NAME_INPUT_METHOD_OSK' | translate}}</label>
<p class="caption"><label for="ime-osk">{{'CLIENT.HELP_INPUT_METHOD_OSK' | translate}}</label></p>
</div>
@@ -132,7 +139,14 @@
<div id="zoom-state">{{formattedScale()}}%</div>
<div ng-click="zoomIn()" id="zoom-in"><img src="images/settings/zoom-in.png" alt="+"/></div>
</div>
<div><label><input ng-model="autoFit" ng-change="changeAutoFit()" ng-disabled="autoFitDisabled()" type="checkbox" id="auto-fit"/> {{'CLIENT.TEXT_ZOOM_AUTO_FIT' | translate}}</label></div>
<div><label><input ng-model="menu.autoFit" ng-change="changeAutoFit()" ng-disabled="autoFitDisabled()" type="checkbox" id="auto-fit"/> {{'CLIENT.TEXT_ZOOM_AUTO_FIT' | translate}}</label></div>
</div>
</div>
</div>
</div>
</div>
</div>
</guac-viewport>