Commit 52fdc039 authored by Steven Bennetts's avatar Steven Bennetts Committed by Commit Bot

Settings: Change Picture: Add cr-picture-preview

This moves the preview pane into a separate element in
preparation for sharing UI between Settings and login/oobe.

Bug: 730031
Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: I7dae1a01579e89ca8f4b8fdc3be7393b2310c869
Reviewed-on: https://chromium-review.googlesource.com/557462Reviewed-by: default avatarTommy Li <tommycli@chromium.org>
Commit-Queue: Steven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#485434}
parent a02c0cd8
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/change_picture/cr_camera.html"> <link rel="import" href="chrome://resources/cr_elements/chromeos/change_picture/cr_picture_preview.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/change_picture/cr_picture_types.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/html/util.html"> <link rel="import" href="chrome://resources/html/util.html">
...@@ -65,32 +66,11 @@ ...@@ -65,32 +66,11 @@
color: var(--paper-grey-600); color: var(--paper-grey-600);
} }
#previewPane { cr-picture-preview {
-webkit-margin-end: 10px; -webkit-margin-end: 10px;
flex-shrink: 0; flex-shrink: 0;
width: 228px; width: 228px;
} }
#previewPane img {
display: block;
height: 228px;
width: 228px;
}
#discardControlBar {
background-color: var(--paper-grey-800);
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
padding: 8px;
}
#discardOldImage {
--iron-icon-fill-color: white;
background-color: var(--paper-red-500);
border-radius: 50%;
display: block;
margin: 0 auto 0 auto;
}
</style> </style>
<div id="container" class="settings-box" tabindex="0"> <div id="container" class="settings-box" tabindex="0">
<iron-a11y-keys keys="up down left right space enter" <iron-a11y-keys keys="up down left right space enter"
...@@ -115,7 +95,7 @@ ...@@ -115,7 +95,7 @@
title="$i18n{oldPhoto}"> title="$i18n{oldPhoto}">
<template is="dom-repeat" items="[[defaultImages_]]"> <template is="dom-repeat" items="[[defaultImages_]]">
<img data-type$="[[selectionTypesEnum_.DEFAULT]]" role="radio" <img data-type$="[[selectionTypesEnum_.DEFAULT]]" role="radio"
data-default-image-index$="[[index]]" src="[[item.url]]" data-index$="[[index]]" src="[[item.url]]"
title="[[item.title]]"> title="[[item.title]]">
</template> </template>
</iron-selector> </iron-selector>
...@@ -130,24 +110,15 @@ ...@@ -130,24 +110,15 @@
</div> </div>
</template> </template>
</div> </div>
<div id="previewPane"> <cr-picture-preview id="picturePreview"
<img alt="$i18n{previewAltText}" src="[[selectedItem_.src]]" camera-present="[[cameraPresent_]]",
hidden="[[isPreviewImageHidden_(selectedItem_)]]"> image-src="[[getImageSrc_(selectedItem_)]]"
<div id="discardControlBar" image-type="[[getImageType_(selectedItem_)]]"
hidden="[[isDiscardHidden_(selectedItem_)]]"> discard-image-label="$i18n{discardPhoto}"
<button is="paper-icon-button-light" id="discardOldImage" flip-photo-label="$i18n{flipPhoto}"
class="icon-delete" title="$i18n{discardPhoto}" preview-alt-text="$i18n{previewAltText}"
on-tap="onTapDiscardOldImage_"> take-photo-label="$i18n{takePhoto}">
</button> </cr-picture-preview>
</div>
<cr-camera id="camera"
camera-active="[[isCameraActive_(cameraPresent_, selectedItem_)]]"
on-photo-taken="onPhotoTaken_"
on-photo-flipped="onPhotoFlipped_"
flip-photo-label="$i18n{flipPhoto}"
take-photo-label="$i18n{takePhoto}">
</cr-camera>
</div>
</div> </div>
</template> </template>
<script src="change_picture.js"></script> <script src="change_picture.js"></script>
......
...@@ -2,30 +2,6 @@ ...@@ -2,30 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
/**
* Contains the possible types of Change Picture selections.
* @enum {string}
*/
var ChangePictureSelectionTypes = {
CAMERA: 'camera',
FILE: 'file',
PROFILE: 'profile',
OLD: 'old',
DEFAULT: 'default',
};
/**
* An image element.
* @typedef {{
* dataset: {
* type: !ChangePictureSelectionTypes,
* defaultImageIndex: ?number,
* },
* src: string,
* }}
*/
var ChangePictureImageElement;
/** /**
* @fileoverview * @fileoverview
* 'settings-change-picture' is the settings subpage containing controls to * 'settings-change-picture' is the settings subpage containing controls to
...@@ -54,7 +30,7 @@ Polymer({ ...@@ -54,7 +30,7 @@ Polymer({
* The currently selected item. This property is bound to the iron-selector * The currently selected item. This property is bound to the iron-selector
* and never directly assigned. This may be undefined momentarily as * and never directly assigned. This may be undefined momentarily as
* the selection changes due to iron-selector implementation details. * the selection changes due to iron-selector implementation details.
* @private {?ChangePictureImageElement} * @private {?CrPicture.ImageElement}
*/ */
selectedItem_: Object, selectedItem_: Object,
...@@ -93,18 +69,24 @@ Polymer({ ...@@ -93,18 +69,24 @@ Polymer({
/** @private */ /** @private */
selectionTypesEnum_: { selectionTypesEnum_: {
type: Object, type: Object,
value: ChangePictureSelectionTypes, value: CrPicture.SelectionTypes,
readOnly: true, readOnly: true,
}, },
}, },
listeners: {
'discard-image': 'onDiscardImage_',
'photo-flipped': 'onPhotoFlipped_',
'photo-taken': 'onPhotoTaken_',
},
/** @private {?settings.ChangePictureBrowserProxy} */ /** @private {?settings.ChangePictureBrowserProxy} */
browserProxy_: null, browserProxy_: null,
/** /**
* The fallback image to be selected when the user discards the Old image. * The fallback image to be selected when the user discards the Old image.
* This may be null if the user started with the Old image. * This may be null if the user started with the Old image.
* @private {?ChangePictureImageElement} * @private {?CrPicture.ImageElement}
*/ */
fallbackImage_: null, fallbackImage_: null,
...@@ -170,7 +152,7 @@ Polymer({ ...@@ -170,7 +152,7 @@ Polymer({
*/ */
receiveSelectedImage_: function(imageUrl) { receiveSelectedImage_: function(imageUrl) {
var index = this.$.selector.items.findIndex(function(image) { var index = this.$.selector.items.findIndex(function(image) {
return image.dataset.type == ChangePictureSelectionTypes.DEFAULT && return image.dataset.type == CrPicture.SelectionTypes.DEFAULT &&
image.src == imageUrl; image.src == imageUrl;
}); });
assert(index != -1, 'Default image not found: ' + imageUrl); assert(index != -1, 'Default image not found: ' + imageUrl);
...@@ -179,7 +161,7 @@ Polymer({ ...@@ -179,7 +161,7 @@ Polymer({
// If user is currently taking a photo, do not steal the focus. // If user is currently taking a photo, do not steal the focus.
if (!this.selectedItem_ || if (!this.selectedItem_ ||
this.selectedItem_.dataset.type != ChangePictureSelectionTypes.CAMERA) { this.selectedItem_.dataset.type != CrPicture.SelectionTypes.CAMERA) {
this.$.selector.select(index); this.$.selector.select(index);
} }
}, },
...@@ -214,7 +196,7 @@ Polymer({ ...@@ -214,7 +196,7 @@ Polymer({
// If user is currently taking a photo, do not steal the focus. // If user is currently taking a photo, do not steal the focus.
if (!this.selectedItem_ || if (!this.selectedItem_ ||
this.selectedItem_.dataset.type != ChangePictureSelectionTypes.CAMERA) { this.selectedItem_.dataset.type != CrPicture.SelectionTypes.CAMERA) {
this.$.selector.select(this.$.selector.indexOf(this.$.profileImage)); this.$.selector.select(this.$.selector.indexOf(this.$.profileImage));
} }
}, },
...@@ -230,24 +212,24 @@ Polymer({ ...@@ -230,24 +212,24 @@ Polymer({
/** /**
* Selects an image element. * Selects an image element.
* @param {!ChangePictureImageElement} image * @param {!CrPicture.ImageElement} image
* @private * @private
*/ */
selectImage_: function(image) { selectImage_: function(image) {
switch (image.dataset.type) { switch (image.dataset.type) {
case ChangePictureSelectionTypes.CAMERA: case CrPicture.SelectionTypes.CAMERA:
// Nothing needs to be done. // Nothing needs to be done.
break; break;
case ChangePictureSelectionTypes.FILE: case CrPicture.SelectionTypes.FILE:
this.browserProxy_.chooseFile(); this.browserProxy_.chooseFile();
break; break;
case ChangePictureSelectionTypes.PROFILE: case CrPicture.SelectionTypes.PROFILE:
this.browserProxy_.selectProfileImage(); this.browserProxy_.selectProfileImage();
break; break;
case ChangePictureSelectionTypes.OLD: case CrPicture.SelectionTypes.OLD:
this.browserProxy_.selectOldImage(); this.browserProxy_.selectOldImage();
break; break;
case ChangePictureSelectionTypes.DEFAULT: case CrPicture.SelectionTypes.DEFAULT:
this.browserProxy_.selectDefaultImage(image.src); this.browserProxy_.selectDefaultImage(image.src);
break; break;
default: default:
...@@ -284,7 +266,7 @@ Polymer({ ...@@ -284,7 +266,7 @@ Polymer({
selector.selectPrevious(); selector.selectPrevious();
} while (this.selectedItem_.hidden); } while (this.selectedItem_.hidden);
if (this.selectedItem_.dataset.type != ChangePictureSelectionTypes.FILE) if (this.selectedItem_.dataset.type != CrPicture.SelectionTypes.FILE)
this.selectImage_(this.selectedItem_); this.selectImage_(this.selectedItem_);
this.lastSelectedImageType_ = this.selectedItem_.dataset.type; this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
...@@ -299,7 +281,7 @@ Polymer({ ...@@ -299,7 +281,7 @@ Polymer({
selector.selectNext(); selector.selectNext();
} while (this.selectedItem_.hidden); } while (this.selectedItem_.hidden);
if (this.selectedItem_.dataset.type != ChangePictureSelectionTypes.FILE) if (this.selectedItem_.dataset.type != CrPicture.SelectionTypes.FILE)
this.selectImage_(this.selectedItem_); this.selectImage_(this.selectedItem_);
this.lastSelectedImageType_ = this.selectedItem_.dataset.type; this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
...@@ -309,17 +291,14 @@ Polymer({ ...@@ -309,17 +291,14 @@ Polymer({
case 'enter': case 'enter':
case 'space': case 'space':
if (this.selectedItem_.dataset.type == if (this.selectedItem_.dataset.type ==
ChangePictureSelectionTypes.CAMERA) { CrPicture.SelectionTypes.CAMERA) {
var /** CrCameraElement */ camera = this.$.camera; /** CrPicturePreviewElement */ (this.$.picturePreview).takePhoto();
camera.takePhoto();
} else if ( } else if (
this.selectedItem_.dataset.type == this.selectedItem_.dataset.type == CrPicture.SelectionTypes.FILE) {
ChangePictureSelectionTypes.FILE) {
this.browserProxy_.chooseFile(); this.browserProxy_.chooseFile();
} else if ( } else if (
this.selectedItem_.dataset.type == this.selectedItem_.dataset.type == CrPicture.SelectionTypes.OLD) {
ChangePictureSelectionTypes.OLD) { this.onDiscardImage_();
this.onTapDiscardOldImage_();
} }
break; break;
} }
...@@ -359,14 +338,14 @@ Polymer({ ...@@ -359,14 +338,14 @@ Polymer({
}, },
/** /**
* Discard currently selected Old image. Selects the first default icon. * Discard currently selected image. Selects the first default icon.
* Returns to the camera stream if the user had just taken a picture. * Returns to the camera stream if the user had just taken a picture.
* @private * @private
*/ */
onTapDiscardOldImage_: function() { onDiscardImage_: function() {
this.oldImageUrl_ = ''; this.oldImageUrl_ = '';
if (this.lastSelectedImageType_ == ChangePictureSelectionTypes.CAMERA) if (this.lastSelectedImageType_ == CrPicture.SelectionTypes.CAMERA)
this.$.selector.select(this.$.selector.indexOf(this.$.cameraImage)); this.$.selector.select(this.$.selector.indexOf(this.$.cameraImage));
if (this.fallbackImage_ != null) { if (this.fallbackImage_ != null) {
...@@ -383,63 +362,36 @@ Polymer({ ...@@ -383,63 +362,36 @@ Polymer({
}, },
/** /**
* @param {string} oldImageUrl * @param {CrPicture.ImageElement} selectedItem
* @return {boolean} True if there is no Old image and the Old image icon * @return {string}
* should be hidden.
* @private
*/
isOldImageHidden_: function(oldImageUrl) {
return oldImageUrl.length == 0;
},
/**
* @param {ChangePictureImageElement} selectedItem
* @return {boolean} True if the preview image should be hidden.
* @private
*/
isPreviewImageHidden_: function(selectedItem) {
if (!selectedItem)
return true;
var type = selectedItem.dataset.type;
return type != ChangePictureSelectionTypes.DEFAULT &&
type != ChangePictureSelectionTypes.PROFILE &&
type != ChangePictureSelectionTypes.OLD;
},
/**
* @param {boolean} cameraPresent
* @param {ChangePictureImageElement} selectedItem
* @return {boolean} True if the camera is selected in the image grid.
* @private * @private
*/ */
isCameraActive_: function(cameraPresent, selectedItem) { getImageSrc_: function(selectedItem) {
return cameraPresent && !!selectedItem && return (selectedItem && selectedItem.src) || '';
selectedItem.dataset.type == ChangePictureSelectionTypes.CAMERA;
}, },
/** /**
* @param {ChangePictureImageElement} selectedItem * @param {CrPicture.ImageElement} selectedItem
* @return {boolean} True if the discard controls should be hidden. * @return {string}
* @private * @private
*/ */
isDiscardHidden_: function(selectedItem) { getImageType_: function(selectedItem) {
return !selectedItem || return (selectedItem && selectedItem.dataset.type) ||
selectedItem.dataset.type != ChangePictureSelectionTypes.OLD; CrPicture.SelectionTypes.NONE;
}, },
/** /**
* @param {ChangePictureImageElement} selectedItem * @param {CrPicture.ImageElement} selectedItem
* @return {boolean} True if the author credit text is shown. * @return {boolean} True if the author credit text is shown.
* @private * @private
*/ */
isAuthorCreditShown_: function(selectedItem) { isAuthorCreditShown_: function(selectedItem) {
return !!selectedItem && return !!selectedItem &&
selectedItem.dataset.type == ChangePictureSelectionTypes.DEFAULT; selectedItem.dataset.type == CrPicture.SelectionTypes.DEFAULT;
}, },
/** /**
* @param {!ChangePictureImageElement} selectedItem * @param {!CrPicture.ImageElement} selectedItem
* @param {!Array<!settings.DefaultImage>} defaultImages * @param {!Array<!settings.DefaultImage>} defaultImages
* @return {string} The author name for the selected default image. An empty * @return {string} The author name for the selected default image. An empty
* string is returned if there is no valid author name. * string is returned if there is no valid author name.
...@@ -450,13 +402,13 @@ Polymer({ ...@@ -450,13 +402,13 @@ Polymer({
return ''; return '';
assert( assert(
selectedItem.dataset.defaultImageIndex !== null && selectedItem.dataset.index !== null &&
selectedItem.dataset.defaultImageIndex < defaultImages.length); selectedItem.dataset.index < defaultImages.length);
return defaultImages[selectedItem.dataset.defaultImageIndex].author; return defaultImages[selectedItem.dataset.index].author;
}, },
/** /**
* @param {!ChangePictureImageElement} selectedItem * @param {!CrPicture.ImageElement} selectedItem
* @param {!Array<!settings.DefaultImage>} defaultImages * @param {!Array<!settings.DefaultImage>} defaultImages
* @return {string} The author website for the selected default image. An * @return {string} The author website for the selected default image. An
* empty string is returned if there is no valid author name. * empty string is returned if there is no valid author name.
...@@ -467,8 +419,8 @@ Polymer({ ...@@ -467,8 +419,8 @@ Polymer({
return ''; return '';
assert( assert(
selectedItem.dataset.defaultImageIndex !== null && selectedItem.dataset.index !== null &&
selectedItem.dataset.defaultImageIndex < defaultImages.length); selectedItem.dataset.index < defaultImages.length);
return defaultImages[selectedItem.dataset.defaultImageIndex].website; return defaultImages[selectedItem.dataset.index].website;
}, },
}); });
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
{ {
'target_name': 'change_picture', 'target_name': 'change_picture',
'dependencies': [ 'dependencies': [
'<(DEPTH)/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp:cr_camera', '<(DEPTH)/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp:cr_picture_preview',
'<(DEPTH)/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp:cr_picture_types',
'<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-selector/compiled_resources2.gyp:iron-selector-extracted', '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-selector/compiled_resources2.gyp:iron-selector-extracted',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
......
...@@ -82,8 +82,7 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -82,8 +82,7 @@ cr.define('settings_people_page_change_picture', function() {
suite('ChangePictureTests', function() { suite('ChangePictureTests', function() {
var changePicture = null; var changePicture = null;
var browserProxy = null; var browserProxy = null;
var crCamera = null; var crPicturePreview = null;
var discardControlBar = null;
suiteSetup(function() { suiteSetup(function() {
loadTimeData.overrideValues({ loadTimeData.overrideValues({
...@@ -98,10 +97,8 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -98,10 +97,8 @@ cr.define('settings_people_page_change_picture', function() {
changePicture = document.createElement('settings-change-picture'); changePicture = document.createElement('settings-change-picture');
document.body.appendChild(changePicture); document.body.appendChild(changePicture);
crCamera = changePicture.$$('cr-camera'); crPicturePreview = changePicture.$$('cr-picture-preview');
assertTrue(!!crCamera); assertTrue(!!crPicturePreview);
discardControlBar = changePicture.$.discardControlBar;
assertTrue(!!discardControlBar);
changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE); changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE);
...@@ -120,27 +117,44 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -120,27 +117,44 @@ cr.define('settings_people_page_change_picture', function() {
cr.webUIListenerCallback('camera-presence-changed', false); cr.webUIListenerCallback('camera-presence-changed', false);
Polymer.dom.flush(); Polymer.dom.flush();
expectTrue(cameraIcon.hidden); return new Promise(function(resolve) {
expectFalse(crCamera.cameraActive); changePicture.async(resolve);
}).then(function() {
expectTrue(cameraIcon.hidden);
expectFalse(crPicturePreview.cameraPresent);
expectFalse(crPicturePreview.cameraActive_);
cr.webUIListenerCallback('camera-presence-changed', true); cr.webUIListenerCallback('camera-presence-changed', true);
Polymer.dom.flush(); Polymer.dom.flush();
return new Promise(function(resolve) {
expectFalse(cameraIcon.hidden); changePicture.async(resolve);
expectFalse(crCamera.cameraActive); });
}).then(function() {
MockInteractions.tap(cameraIcon); expectFalse(cameraIcon.hidden);
expectTrue(crPicturePreview.cameraPresent);
Polymer.dom.flush(); expectFalse(crPicturePreview.cameraActive_);
expectFalse(cameraIcon.hidden);
expectTrue(crCamera.cameraActive); MockInteractions.tap(cameraIcon);
expectEquals(ChangePictureSelectionTypes.CAMERA, Polymer.dom.flush();
changePicture.selectedItem_.dataset.type); return new Promise(function(resolve) {
expectTrue(discardControlBar.hidden); changePicture.async(resolve);
});
}).then(function() {
expectFalse(cameraIcon.hidden);
expectTrue(crPicturePreview.cameraActive_);
expectEquals(CrPicture.SelectionTypes.CAMERA,
changePicture.selectedItem_.dataset.type);
var discard = crPicturePreview.$$('#discard');
expectTrue(!discard || discard.hidden);
// Ensure that the camera is deactivated if user navigates away. // Ensure that the camera is deactivated if user navigates away.
changePicture.currentRouteChanged(settings.routes.BASIC); changePicture.currentRouteChanged(settings.routes.BASIC);
expectFalse(crCamera.cameraActive); return new Promise(function(resolve) {
changePicture.async(resolve);
});
}).then(function() {
expectFalse(crPicturePreview.cameraActive_);
});
}); });
test('ChangePictureProfileImage', function() { test('ChangePictureProfileImage', function() {
...@@ -153,16 +167,17 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -153,16 +167,17 @@ cr.define('settings_people_page_change_picture', function() {
return browserProxy.whenCalled('selectProfileImage').then(function() { return browserProxy.whenCalled('selectProfileImage').then(function() {
Polymer.dom.flush(); Polymer.dom.flush();
expectEquals(ChangePictureSelectionTypes.PROFILE, expectEquals(CrPicture.SelectionTypes.PROFILE,
changePicture.selectedItem_.dataset.type); changePicture.selectedItem_.dataset.type);
expectFalse(crCamera.cameraActive); expectFalse(crPicturePreview.cameraActive_);
expectTrue(discardControlBar.hidden); var discard = crPicturePreview.$$('#discard');
expectTrue(!discard || discard.hidden);
// Ensure that the selection is restored after navigating away and // Ensure that the selection is restored after navigating away and
// then back to the subpage. // then back to the subpage.
changePicture.currentRouteChanged(settings.routes.BASIC); changePicture.currentRouteChanged(settings.routes.BASIC);
changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE); changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE);
expectEquals(ChangePictureSelectionTypes.PROFILE, expectEquals(CrPicture.SelectionTypes.PROFILE,
changePicture.selectedItem_.dataset.type); changePicture.selectedItem_.dataset.type);
}); });
}); });
...@@ -178,11 +193,13 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -178,11 +193,13 @@ cr.define('settings_people_page_change_picture', function() {
// Expect the old image to be selected once an old image is sent via // Expect the old image to be selected once an old image is sent via
// the native interface. // the native interface.
expectEquals(ChangePictureSelectionTypes.OLD, expectEquals(CrPicture.SelectionTypes.OLD,
changePicture.selectedItem_.dataset.type); changePicture.selectedItem_.dataset.type);
expectFalse(oldImage.hidden); expectFalse(oldImage.hidden);
expectFalse(crCamera.cameraActive); expectFalse(crPicturePreview.cameraActive_);
expectFalse(discardControlBar.hidden); var discard = crPicturePreview.$$('#discard');
assertTrue(!!discard);
expectFalse(discard.hidden);
}); });
test('ChangePictureSelectFirstDefaultImage', function() { test('ChangePictureSelectFirstDefaultImage', function() {
...@@ -196,11 +213,12 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -196,11 +213,12 @@ cr.define('settings_people_page_change_picture', function() {
expectEquals('chrome://foo/1.png', args[0]); expectEquals('chrome://foo/1.png', args[0]);
Polymer.dom.flush(); Polymer.dom.flush();
expectEquals(ChangePictureSelectionTypes.DEFAULT, expectEquals(CrPicture.SelectionTypes.DEFAULT,
changePicture.selectedItem_.dataset.type); changePicture.selectedItem_.dataset.type);
expectEquals(firstDefaultImage, changePicture.selectedItem_); expectEquals(firstDefaultImage, changePicture.selectedItem_);
expectFalse(crCamera.cameraActive); expectFalse(crPicturePreview.cameraActive_);
expectTrue(discardControlBar.hidden); var discard = crPicturePreview.$$('#discard');
expectTrue(!discard || discard.hidden);
// Now verify that arrow keys actually select the new image. // Now verify that arrow keys actually select the new image.
browserProxy.resetResolver('selectDefaultImage'); browserProxy.resetResolver('selectDefaultImage');
...@@ -215,8 +233,6 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -215,8 +233,6 @@ cr.define('settings_people_page_change_picture', function() {
test('ChangePictureRestoreImageAfterDiscard', function() { test('ChangePictureRestoreImageAfterDiscard', function() {
var firstDefaultImage = changePicture.$$('img[data-type="default"]'); var firstDefaultImage = changePicture.$$('img[data-type="default"]');
assertTrue(!!firstDefaultImage); assertTrue(!!firstDefaultImage);
var discardOldImage = changePicture.$.discardOldImage;
assertTrue(!!discardOldImage);
MockInteractions.tap(firstDefaultImage); MockInteractions.tap(firstDefaultImage);
...@@ -227,10 +243,12 @@ cr.define('settings_people_page_change_picture', function() { ...@@ -227,10 +243,12 @@ cr.define('settings_people_page_change_picture', function() {
cr.webUIListenerCallback('old-image-changed', 'fake-old-image.jpg'); cr.webUIListenerCallback('old-image-changed', 'fake-old-image.jpg');
Polymer.dom.flush(); Polymer.dom.flush();
expectEquals(ChangePictureSelectionTypes.OLD, expectEquals(CrPicture.SelectionTypes.OLD,
changePicture.selectedItem_.dataset.type); changePicture.selectedItem_.dataset.type);
MockInteractions.tap(discardOldImage); var discardButton = crPicturePreview.$$('#discard button');
assertTrue(!!discardButton);
MockInteractions.tap(discardButton);
Polymer.dom.flush(); Polymer.dom.flush();
expectEquals(firstDefaultImage, changePicture.selectedItem_); expectEquals(firstDefaultImage, changePicture.selectedItem_);
......
...@@ -5,10 +5,18 @@ ...@@ -5,10 +5,18 @@
'targets': [ 'targets': [
{ {
'target_name': 'cr_camera', 'target_name': 'cr_camera',
'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
'dependencies': [ 'dependencies': [
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', 'cr_camera',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util', 'cr_picture_types',
], ],
'target_name': 'cr_picture_preview',
'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
'target_name': 'cr_picture_types',
'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'], 'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'],
}, },
], ],
......
...@@ -64,24 +64,22 @@ ...@@ -64,24 +64,22 @@
margin: 0 auto 0 auto; margin: 0 auto 0 auto;
} }
</style> </style>
<div hidden="[[!cameraActive]]"> <div id="perspectiveBox">
<div id="perspectiveBox"> <div id="userImageStreamCrop">
<div id="userImageStreamCrop"> <video id="cameraVideo" autoplay hidden="[[!cameraOnline_]]"></video>
<video id="cameraVideo" autoplay hidden="[[!cameraOnline_]]"></video> <paper-spinner active="[[!cameraOnline_]]"></paper-spinner>
<paper-spinner active="[[!cameraOnline_]]"></paper-spinner>
</div>
</div>
<div id="cameraControls">
<button is="paper-icon-button-light" id="flipPhoto" tabindex="2"
title="[[flipPhotoLabel]]" on-tap="onTapFlipPhoto_"
disabled="[[!cameraOnline_]]">
</button>
<button is="paper-icon-button-light" id="takePhoto" tabindex="1"
title="[[takePhotoLabel]]" on-tap="takePhoto"
disabled="[[!cameraOnline_]]">
</button>
</div> </div>
</div> </div>
<div id="cameraControls">
<button is="paper-icon-button-light" id="flipPhoto" tabindex="2"
title="[[flipPhotoLabel]]" on-tap="onTapFlipPhoto_"
disabled="[[!cameraOnline_]]">
</button>
<button is="paper-icon-button-light" id="takePhoto" tabindex="1"
title="[[takePhotoLabel]]" on-tap="takePhoto"
disabled="[[!cameraOnline_]]">
</button>
</div>
</template> </template>
<script src="cr_camera.js"></script> <script src="cr_camera.js"></script>
</dom-module> </dom-module>
...@@ -19,16 +19,6 @@ Polymer({ ...@@ -19,16 +19,6 @@ Polymer({
is: 'cr-camera', is: 'cr-camera',
properties: { properties: {
/**
* True if the user has selected the camera as the user image source.
* @type {boolean}
*/
cameraActive: {
type: Boolean,
observer: 'cameraActiveChanged_',
value: false,
},
/** Strings provided by host */ /** Strings provided by host */
flipPhotoLabel: String, flipPhotoLabel: String,
takePhotoLabel: String, takePhotoLabel: String,
...@@ -58,13 +48,12 @@ Polymer({ ...@@ -58,13 +48,12 @@ Polymer({
this.$.cameraVideo.addEventListener('canplay', function() { this.$.cameraVideo.addEventListener('canplay', function() {
this.cameraOnline_ = true; this.cameraOnline_ = true;
}.bind(this)); }.bind(this));
if (this.cameraActive) this.startCamera();
this.startCamera_();
}, },
/** @override */ /** @override */
detached: function() { detached: function() {
this.stopCamera_(); this.stopCamera();
}, },
/** /**
...@@ -88,20 +77,9 @@ Polymer({ ...@@ -88,20 +77,9 @@ Polymer({
this.fire('photo-taken', {photoDataUrl: photoDataUrl}); this.fire('photo-taken', {photoDataUrl: photoDataUrl});
}, },
/** @private */ /** Tries to start the camera stream capture. */
cameraActiveChanged_: function() { startCamera: function() {
if (this.cameraActive) this.stopCamera();
this.startCamera_();
else
this.stopCamera_();
},
/**
* Tries to start the camera stream capture.
* @private
*/
startCamera_: function() {
this.stopCamera_();
this.cameraStartInProgress_ = true; this.cameraStartInProgress_ = true;
var successCallback = function(stream) { var successCallback = function(stream) {
...@@ -122,11 +100,8 @@ Polymer({ ...@@ -122,11 +100,8 @@ Polymer({
navigator.webkitGetUserMedia({video: true}, successCallback, errorCallback); navigator.webkitGetUserMedia({video: true}, successCallback, errorCallback);
}, },
/** /** Stops the camera stream capture if it's currently active. */
* Stops camera capture, if it's currently active. stopCamera: function() {
* @private
*/
stopCamera_: function() {
this.cameraOnline_ = false; this.cameraOnline_ = false;
this.$.cameraVideo.src = ''; this.$.cameraVideo.src = '';
if (this.cameraStream_) if (this.cameraStream_)
......
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="cr_camera.html">
<link rel="import" href="cr_picture_types.html">
<dom-module id="cr-picture-preview">
<template>
<style include="cr-shared-style">
img {
display: block;
width: 100%;
}
#discard {
background-color: var(--paper-grey-800);
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
padding: 8px;
}
#discard button {
--iron-icon-fill-color: white;
background-color: var(--paper-red-500);
border-radius: 50%;
display: block;
margin: 0 auto 0 auto;
}
</style>
<template is="dom-if"
if="[[showImagePreview_(cameraActive_, imageSrc)]]">
<img alt="[[previewAltText]]" src="[[imageSrc]]">
<div id="discard" hidden="[[!showDiscard_(imageType)]]">
<button is="paper-icon-button-light" id="discardImage"
class="icon-delete" title="[[discardImageLabel]]"
on-tap="onTapDiscardImage_">
</button>
</div>
</template>
<template is="dom-if" if="[[cameraActive_]]">
<cr-camera id="camera"
flip-photo-label="[[flipPhotoLabel]]"
take-photo-label="[[takePhotoLabel]]">
</cr-camera>
</template>
</template>
<script src="cr_picture_preview.js"></script>
</dom-module>
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* 'cr-picture-preview' is a Polymer element used to show either a profile
* picture or a camera image preview.
*/
Polymer({
is: 'cr-picture-preview',
properties: {
/** Whether the camera is present / available */
cameraPresent: Boolean,
/** Image source to show when imageType != CAMERA. */
imageSrc: String,
/**
* The type of image to display in the preview.
* @type {CrPicture.SelectionTypes}
*/
imageType: {
type: String,
value: CrPicture.SelectionTypes.NONE,
},
/** Strings provided by host */
discardImageLabel: String,
flipPhotoLabel: String,
previewAltText: String,
takePhotoLabel: String,
/** Whether the camera should be shown and active (started). */
cameraActive_: {
type: Boolean,
computed: 'getCameraActive_(cameraPresent, imageType)',
observer: 'cameraActiveChanged_',
},
},
/**
* Tells the camera to take a photo; the camera will fire a 'photo-taken'
* event when the photo is completed.
*/
takePhoto: function() {
var camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
if (camera)
camera.takePhoto();
},
/**
* @return {boolean}
* @private
*/
getCameraActive_() {
return this.cameraPresent &&
this.imageType == CrPicture.SelectionTypes.CAMERA;
},
/** @private */
cameraActiveChanged_: function() {
var camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
if (!camera)
return; // Camera will be started when attached.
if (this.cameraActive_)
camera.startCamera();
else
camera.stopCamera();
},
/**
* @return {boolean}
* @private
*/
showImagePreview_: function() {
return !this.cameraActive_ && !!this.imageSrc;
},
/**
* @return {boolean}
* @private
*/
showDiscard_: function() {
return this.imageType == CrPicture.SelectionTypes.OLD;
},
/** @private */
onTapDiscardImage_: function() {
this.fire('discard-image');
},
});
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var CrPicture = {};
/**
* Contains the possible types for picture list image elements.
* @enum {string}
*/
CrPicture.SelectionTypes = {
CAMERA: 'camera',
FILE: 'file',
PROFILE: 'profile',
OLD: 'old',
DEFAULT: 'default',
NONE: '',
};
/**
* An picture list image element.
* @typedef {{
* dataset: {
* type: !CrPicture.SelectionTypes,
* index: (number|undefined),
* },
* src: string,
* }}
*/
CrPicture.ImageElement;
...@@ -48,6 +48,18 @@ ...@@ -48,6 +48,18 @@
<structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__CAMERA_JS" <structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__CAMERA_JS"
file="../../webui/resources/cr_elements/chromeos/change_picture/cr_camera.js" file="../../webui/resources/cr_elements/chromeos/change_picture/cr_camera.js"
type="chrome_html" /> type="chrome_html" />
<structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR_PICTURE_PREVIEW_HTML"
file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.html"
type="chrome_html" />
<structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__PICTURE_PREVIEW_JS"
file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.js"
type="chrome_html" />
<structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR_PICTURE_TYPES_HTML"
file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.html"
type="chrome_html" />
<structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__PICTURE_TYPES_JS"
file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.js"
type="chrome_html" />
<structure name="IDR_CR_ELEMENTS_CHROMEOS_CR_NETWORK_ICON_HTML" <structure name="IDR_CR_ELEMENTS_CHROMEOS_CR_NETWORK_ICON_HTML"
file="../../webui/resources/cr_elements/chromeos/network/cr_network_icon.html" file="../../webui/resources/cr_elements/chromeos/network/cr_network_icon.html"
type="chrome_html" /> type="chrome_html" />
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment