Commit a0b84e21 authored by Jordy Greenblatt's avatar Jordy Greenblatt Committed by Commit Bot

[CrOS MultiDevice]: Basic individual feature subpage

This is the subpage for the multidevice settings UI. It will contain a
toggle for each individual feature in addition to some feature-specific
infrastructure (e.g. setup button, learn more link, password protection
of features). I will also have a toggle to disable all multidevice
features and a button to forget phone already set up on the account
(the subpage is only reached if there is a phone set).

Note that if the phone is not yet verified for multidevice features,
then individual feature toggles will not be shown.

Bug: 824568
Cq-Include-Trybots: luci.chromium.try:closure_compilation
Change-Id: I29e8f9aa3d2801fb898eabf02adc2e79bd43ef5e
Reviewed-on: https://chromium-review.googlesource.com/1128334
Commit-Queue: Jordy Greenblatt <jordynass@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#574017}
parent be880666
......@@ -8,8 +8,10 @@ js_type_check("closure_compile") {
deps = [
":multidevice_browser_proxy",
":multidevice_constants",
":multidevice_feature_item",
":multidevice_page",
":multidevice_page_container",
":multidevice_subpage",
]
}
......@@ -25,6 +27,14 @@ js_library("multidevice_constants") {
]
}
js_library("multidevice_feature_item") {
deps = [
"..:route",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js:i18n_behavior",
]
}
js_library("multidevice_page") {
deps = [
":multidevice_browser_proxy",
......@@ -42,3 +52,10 @@ js_library("multidevice_page_container") {
"//ui/webui/resources/js:web_ui_listener_behavior",
]
}
js_library("multidevice_subpage") {
deps = [
"..:route",
"//ui/webui/resources/js:i18n_behavior",
]
}
......@@ -26,8 +26,10 @@ cr.define('settings', function() {
// return cr.sendWithPromise('getPageContentData');
// once handler is built.
return Promise.resolve({
mode: settings.MultiDeviceSettingsMode.NO_HOST_SET,
hostDevice: null,
mode: settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED,
hostDevice: {
name: 'Pixel XL',
},
});
}
}
......
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../route.html">
<link rel="import" href="../settings_shared_css.html">
<dom-module id="settings-multidevice-feature-item">
<template>
<style include="settings-shared">
.svg-placeholder {
width: var(--cr-icon-size);
}
.middle {
-webkit-padding-start: 20px;
}
</style>
<div class="settings-box two-line first"
on-click="handleItemClick_"
actionable$="[[hasSubpageClickHandler_(subpageRoute)]]">
<!-- TODO (jordynass): Add iron icon -->
<div class="svg-placeholder"></div>
<div class="middle">
[[getFeatureName_(featureNameId)]]
<div class="secondary"
id="featureSecondary"
inner-h-t-m-l="[[getSubLabelInnerHtml_(featureSummaryId)]]">
</div>
</div>
<template is="dom-if" if="[[hasSubpageClickHandler_(subpageRoute)]]">
<paper-icon-button-light class="subpage-arrow">
<button aria-label="[[getFeatureName_(featureNameId)]]"
aria-describedby="featureSecondary"></button>
</paper-icon-button-light>
<div class="separator"></div>
</template>
<cr-toggle on-change="onChangeToggle_"></cr-toggle>
</div>
</template>
<script src="multidevice_feature_item.js"></script>
</dom-module>
// Copyright 2018 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
* Item for an individual multidevice feature. These features appear in the
* multidevice subpage to allow the user to individually toggle them as long as
* the phone is enabled as a multidevice host. The feature items contain basic
* information relevant to the individual feature, such as a route to the
* feature's autonomous page if there is one.
*/
cr.exportPath('settings');
Polymer({
is: 'settings-multidevice-feature-item',
behaviors: [I18nBehavior],
properties: {
/** @type {string} */
featureNameId: String,
/** @type {string} */
featureSummaryId: String,
/**
* If it is non-null, the item should be actionable and clicking on it
* should navigate there. If it is undefined, the item is simply not
* actionable.
* @type {settings.Route|undefined}
*/
subpageRoute: Object,
},
/** @private @return {string} */
getFeatureName_: function() {
return this.i18nAdvanced(this.featureNameId);
},
/** @private @return {string} */
getSubLabelInnerHtml_: function() {
return this.i18nAdvanced(this.featureSummaryId);
},
/** @private @return {boolean} */
hasSubpageClickHandler_: function() {
return !!this.subpageRoute;
},
onChangeToggle_: function() {
// TODO (jordynass): Trigger the correct workflow.
console.log('Toggle changed');
},
/** @private */
handleItemClick_: function() {
if (!this.subpageRoute)
return;
settings.navigateTo(this.subpageRoute);
}
});
......@@ -4,32 +4,63 @@
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../route.html">
<link rel="import" href="../settings_page/settings_animated_pages.html">
<link rel="import" href="../settings_page/settings_subpage.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="multidevice_browser_proxy.html">
<link rel="import" href="multidevice_constants.html">
<link rel="import" href="multidevice_subpage.html">
<dom-module id="settings-multidevice-page">
<template>
<style include="settings-shared"></style>
<div class="settings-box two-line first">
<div class="start">
<div id="multidevice-label">[[getLabelText_(pageContentData)]]</div>
<div class="secondary"
inner-h-t-m-l="[[getSubLabelInnerHtml_(pageContentData)]]">
<settings-animated-pages id="pages" section="multidevice"
focus-config="[[focusConfig_]]">
<neon-animatable route-path="default">
<div id="multidevice-item"
class="settings-box two-line first"
on-click="handleItemClick_"
actionable$="[[doesClickOpenSubpage_(pageContentData)]]">
<div class="start">
<div id="multidevice-label">[[getLabelText_(pageContentData)]]</div>
<div class="secondary" id="mutltideviceSubLabel" inner-h-t-m-l=
"[[getSubLabelInnerHtml_(pageContentData, hostEnabled_)]]">
</div>
</div>
<template is="dom-if"
if="[[doesClickOpenSubpage_(pageContentData)]]">
<paper-icon-button-light class="subpage-arrow">
<button aria-label="[[getLabelText_(pageContentData)]]"
aria-describedby="mutltideviceSubLabel"></button>
</paper-icon-button-light>
</template>
<div class="separator"></div>
<template is="dom-if" if="[[showButton_(pageContentData)]]" restamp>
<paper-button class="secondary-button"
on-click="handleButtonClick_">
[[getButtonText_(pageContentData)]]
</paper-button>
</template>
<template is="dom-if" if="[[showToggle_(pageContentData)]]" restamp>
<cr-toggle checked="{{hostEnabled_}}"></cr-toggle>
</template>
</div>
</div>
<div class="separator"></div>
<template is="dom-if" if="[[showButton_(pageContentData)]]" restamp>
<paper-button class="secondary-button" on-click="handleClick_">
[[getButtonText_(pageContentData)]]
</paper-button>
</neon-animatable>
<template is="dom-if" route-path="/multidevice/features">
<settings-subpage associated-control="[[$$('#multidevice-item')]]"
page-title="[[pageContentData.hostDevice.name]]">
<settings-multidevice-subpage prefs="{{prefs}}"
page-content-data="[[pageContentData]]"
host-enabled="{{hostEnabled_}}">
</settings-multidevice-subpage>
</settings-subpage>
</template>
<template is="dom-if" if="[[showToggle_(pageContentData)]]" restamp>
<cr-toggle></cr-toggle>
</template>
</div>
</settings-animated-pages>
</template>
<script src="multidevice_page.js"></script>
</dom-module>
......@@ -6,7 +6,6 @@
* @fileoverview
* Settings page for managing MultiDevice features.
*/
cr.exportPath('settings');
Polymer({
......@@ -27,11 +26,32 @@ Polymer({
// TODO(jordynass): Set this variable once the information is retrieved from
// prefs.
/**
* @type {boolean|undefined}
* If a host has been verified, this is true if that host is and enabled and
* false if it is disabled. Otherwise it is undefined.
* True if the multidevice setup is complete and the paired phone has been
* verified; otherwise, false.
* @private {boolean}
*/
hostEnabled_: {
type: Boolean,
value: true,
},
/**
* A Map specifying which element should be focused when exiting a subpage.
* The key of the map holds a settings.Route path, and the value holds a
* query selector that identifies the desired element.
* @private {!Map<string, string>}
*/
hostEnabled: Boolean,
focusConfig_: {
type: Object,
value: function() {
const map = new Map();
if (settings.routes.MULTIDEVICE_FEATURES)
map.set(
settings.routes.MULTIDEVICE_FEATURES.path,
'#multidevice-item .subpage-arrow');
return map;
},
},
},
/** @private {?settings.MultiDeviceBrowserProxy} */
......@@ -65,8 +85,8 @@ Polymer({
case settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION:
return this.i18nAdvanced('multideviceVerificationText');
default:
return this.hostEnabled ? this.i18n('multideviceEnabled') :
this.i18n('multideviceDisabled');
return this.hostEnabled_ ? this.i18n('multideviceEnabled') :
this.i18n('multideviceDisabled');
}
},
......@@ -105,8 +125,28 @@ Polymer({
settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED;
},
/**
* @return {boolean}
* @private
*/
doesClickOpenSubpage_: function() {
return [
settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER,
settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION,
settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED,
].includes(this.pageContentData.mode);
},
/** @private */
handleItemClick_: function() {
if (!this.doesClickOpenSubpage_())
return;
settings.navigateTo(settings.routes.MULTIDEVICE_FEATURES);
},
/** @private */
handleClick_: function() {
handleButtonClick_: function(event) {
event.stopPropagation();
switch (this.pageContentData.mode) {
case settings.MultiDeviceSettingsMode.NO_HOST_SET:
this.browserProxy_.showMultiDeviceSetupDialog();
......
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../route.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="multidevice_feature_item.html">
<dom-module id="settings-multidevice-subpage">
<template>
<style include="settings-shared iron-flex">
#status-text-container[enabled] {
color: var(--google-green-500);
}
</style>
<div class="settings-box first">
<div id="status-text-container" class="start" enabled$="[[hostEnabled]]">
[[getEnabledOrDiabledText_(hostEnabled)]]
</div>
<cr-toggle id="enable-multidevice" checked="{{hostEnabled}}">
</cr-toggle>
</div>
<template is="dom-if"
if="[[showIndividualFeatures_(pageContentData)]]"
restamp>
<settings-multidevice-feature-item subpage-route="[[routes.LOCK_SCREEN]]"
feature-name-id="multideviceSmartLockItemTitle"
feature-summary-id="multideviceSmsConnectItemSummary">
</settings-multidevice-feature-item>
</template>
</template>
<script src="multidevice_subpage.js"></script>
</dom-module>
// Copyright 2018 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
* Subpage of settings-multidevice-page for managing multidevice features
* individually and for forgetting a host.
*/
cr.exportPath('settings');
Polymer({
is: 'settings-multidevice-subpage',
behaviors: [I18nBehavior],
properties: {
/** SettingsPrefsElement 'prefs' Object reference. See prefs.js. */
prefs: {
type: Object,
notify: true,
},
// TODO(jordynass): Set this based on data in this.prefs.
/**
* If a host has been verified, this is true if that host is and enabled and
* false if it is disabled. Otherwise it is undefined.
* @type {boolean|undefined}
*/
hostEnabled: {
type: Boolean,
notify: true,
},
/** @type {?SettingsRoutes} */
routes: {
type: Object,
value: settings.routes,
},
/** @type {MultiDevicePageContentData} */
pageContentData: Object,
},
showIndividualFeatures_: function() {
return this.pageContentData.mode ===
settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED;
},
/**
* @return {string}
* @private
*/
getEnabledOrDiabledText_: function() {
return this.hostEnabled ? this.i18n('multideviceEnabled') :
this.i18n('multideviceDisabled');
},
});
......@@ -51,6 +51,7 @@
* MANAGE_PROFILE: (undefined|!settings.Route),
* MANAGE_TTS_SETTINGS: (undefined|!settings.Route),
* MULTIDEVICE: (undefined|!settings.Route),
* MULTIDEVICE_FEATURES: (undefined|!settings.Route),
* NETWORK_DETAIL: (undefined|!settings.Route),
* ON_STARTUP: (undefined|!settings.Route),
* PASSWORDS: (undefined|!settings.Route),
......@@ -235,6 +236,7 @@ cr.define('settings', function() {
r.BLUETOOTH_DEVICES = r.BLUETOOTH.createChild('/bluetoothDevices');
r.MULTIDEVICE = r.BASIC.createSection('/multidevice', 'multidevice');
r.MULTIDEVICE_FEATURES = r.MULTIDEVICE.createChild('/multidevice/features');
// </if>
if (pageVisibility.appearance !== false) {
......
......@@ -1306,6 +1306,12 @@
<structure name="IDR_SETTINGS_MULTIDEVICE_CONSTANTS_JS"
file="multidevice_page/multidevice_constants.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_FEATURE_ITEM_HTML"
file="multidevice_page/multidevice_feature_item.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_FEATURE_ITEM_JS"
file="multidevice_page/multidevice_feature_item.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_PAGE_HTML"
file="multidevice_page/multidevice_page.html"
type="chrome_html" />
......@@ -1318,6 +1324,12 @@
<structure name="IDR_SETTINGS_MULTIDEVICE_PAGE_CONTAINER_JS"
file="multidevice_page/multidevice_page_container.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_SUBPAGE_HTML"
file="multidevice_page/multidevice_subpage.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_MULTIDEVICE_SUBPAGE_JS"
file="multidevice_page/multidevice_subpage.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_NETWORK_PROXY_SECTION_HTML"
file="internet_page/network_proxy_section.html"
type="chrome_html" />
......
......@@ -2536,8 +2536,15 @@ void AddMultideviceStrings(content::WebUIDataSource* html_source) {
IDS_SETTINGS_MULTIDEVICE_SETUP_ITEM_HEADING},
{"multideviceEnabled", IDS_SETTINGS_MULTIDEVICE_ENABLED},
{"multideviceDisabled", IDS_SETTINGS_MULTIDEVICE_DISABLED},
{"smsConnect", IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT},
{"smsConnectSummary", IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT_SUMMARY},
{"multideviceSmartLockItemTitle", IDS_SETTINGS_EASY_UNLOCK_SECTION_TITLE},
{"multideviceInstantTetheringItemTitle",
IDS_SETTINGS_MULTIDEVICE_INSTANT_TETHERING},
{"multideviceSmsConnectItemTitle", IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT},
{"multideviceSmsConnectItemSummary",
IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT_SUMMARY},
{"multideviceForgetDevice", IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE},
{"multideviceForgetDeviceSummary",
IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION},
};
AddLocalizedStringsBulk(html_source, localized_strings,
arraysize(localized_strings));
......@@ -2561,6 +2568,11 @@ void AddMultideviceStrings(content::WebUIDataSource* html_source) {
l10n_util::GetStringFUTF16(
IDS_SETTINGS_MULTIDEVICE_SETUP_SUMMARY,
GetHelpUrlWithBoard(chrome::kMultiDeviceLearnMoreURL)));
html_source->AddString(
"multideviceSmartLockItemSummary",
l10n_util::GetStringFUTF16(
IDS_SETTINGS_MULTIDEVICE_SMART_LOCK_SUMMARY,
GetHelpUrlWithBoard(chrome::kEasyUnlockLearnMoreUrl)));
}
#endif
......
......@@ -29,6 +29,14 @@ suite('Multidevice', function() {
name: 'Pixel XL',
};
function setPageContentData(newMode, newHostDevice) {
multidevicePage.pageContentData = {
mode: newMode,
hostDevice: newHostDevice,
};
Polymer.dom.flush();
}
suiteSetup(function() {
HOST_SET_MODES = [
settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER,
......@@ -53,17 +61,11 @@ suite('Multidevice', function() {
multidevicePage.remove();
});
const setPageContentData = function(newMode, newHostDevice) {
multidevicePage.pageContentData = {
mode: newMode,
hostDevice: newHostDevice,
};
Polymer.dom.flush();
};
const getLabel = () => multidevicePage.$$('#multidevice-label').textContent;
test('pressing setup shows multidevice setup dialog', function() {
const getSubpage = () => multidevicePage.$$('settings-multidevice-subpage');
test('clicking setup shows multidevice setup dialog', function() {
setPageContentData(settings.MultiDeviceSettingsMode.NO_HOST_SET, null);
const button = multidevicePage.$$('paper-button');
assertTrue(!!button);
......@@ -90,4 +92,38 @@ suite('Multidevice', function() {
settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED, anotherHost);
assertEquals(getLabel(), anotherHost.name);
});
test('item is actionable if and only if a host is set', function() {
setPageContentData(settings.MultiDeviceSettingsMode.NO_HOST_SET, null);
assertFalse(
multidevicePage.$$('#multidevice-item').hasAttribute('actionable'));
for (let mode of HOST_SET_MODES) {
setPageContentData(mode, HOST_DEVICE);
assertTrue(
multidevicePage.$$('#multidevice-item').hasAttribute('actionable'));
}
});
test(
'clicking item with verified host opens subpage with features',
function() {
setPageContentData(
settings.MultiDeviceSettingsMode.HOST_SET_VERIFIED, HOST_DEVICE);
assertFalse(!!getSubpage());
multidevicePage.$$('#multidevice-item').click();
assertTrue(!!getSubpage());
assertTrue(!!getSubpage().$$('settings-multidevice-feature-item'));
});
test(
'clicking item with unverified set host opens subpage without features',
function() {
setPageContentData(
settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION,
HOST_DEVICE);
assertFalse(!!getSubpage());
multidevicePage.$$('#multidevice-item').click();
assertTrue(!!getSubpage());
assertFalse(!!getSubpage().$$('settings-multidevice-feature-item'));
});
});
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