diff --git a/chrome/app/OWNERS b/chrome/app/OWNERS index c2830d10bdc84..06808ac41b3ce 100644 --- a/chrome/app/OWNERS +++ b/chrome/app/OWNERS @@ -16,6 +16,8 @@ per-file extensions_strings.grdp=* per-file os_settings_strings.grdp=* per-file os_settings_search_tag_strings.grdp=file://chrome/browser/resources/settings/chromeos/OWNERS +per-file access_code_cast_strings.grdp=file://chrome/browser/ui/webui/access_code_cast/OWNERS + per-file app_management_strings.grdp=file://chrome/browser/ui/webui/app_management/OWNERS per-file web_time_limit_error_page_strings.grdp=file://chrome/browser/ash/child_accounts/OWNERS diff --git a/chrome/app/access_code_cast_strings.grdp b/chrome/app/access_code_cast_strings.grdp new file mode 100644 index 0000000000000..5fc1301190190 --- /dev/null +++ b/chrome/app/access_code_cast_strings.grdp @@ -0,0 +1,16 @@ + + + + + Back + + + Cast + + + Cast to a new display + + + Use the camera to scan QR code + + \ No newline at end of file diff --git a/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_BACK.png.sha1 b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_BACK.png.sha1 new file mode 100644 index 0000000000000..dcb1c6ca3ef12 --- /dev/null +++ b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_BACK.png.sha1 @@ -0,0 +1 @@ +91687f84bc741017567a8e2ac9f6678066b0b877 \ No newline at end of file diff --git a/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_CAST.png.sha1 b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_CAST.png.sha1 new file mode 100644 index 0000000000000..b49ce4829efb2 --- /dev/null +++ b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_CAST.png.sha1 @@ -0,0 +1 @@ +cb57fa67c57448a6862dcac40af6059e8a8a20e9 \ No newline at end of file diff --git a/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_DIALOG_TITLE.png.sha1 b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_DIALOG_TITLE.png.sha1 new file mode 100644 index 0000000000000..b49ce4829efb2 --- /dev/null +++ b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_DIALOG_TITLE.png.sha1 @@ -0,0 +1 @@ +cb57fa67c57448a6862dcac40af6059e8a8a20e9 \ No newline at end of file diff --git a/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_USE_CAMERA.png.sha1 b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_USE_CAMERA.png.sha1 new file mode 100644 index 0000000000000..b49ce4829efb2 --- /dev/null +++ b/chrome/app/access_code_cast_strings_grdp/IDS_ACCESS_CODE_CAST_USE_CAMERA.png.sha1 @@ -0,0 +1 @@ +cb57fa67c57448a6862dcac40af6059e8a8a20e9 \ No newline at end of file diff --git a/chrome/app/access_code_cast_strings_grdp/OWNERS b/chrome/app/access_code_cast_strings_grdp/OWNERS new file mode 100644 index 0000000000000..ccb161db3bcd5 --- /dev/null +++ b/chrome/app/access_code_cast_strings_grdp/OWNERS @@ -0,0 +1 @@ +file://chrome/browser/ui/webui/access_code_cast/OWNERS \ No newline at end of file diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index dcac1852427df..d298caf8d2a1d 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -277,6 +277,9 @@ are declared in tools/grit/grit_rule.gni. + + + diff --git a/chrome/browser/media/router/discovery/access_code/OWNERS b/chrome/browser/media/router/discovery/access_code/OWNERS index 21a5668e33669..d6072ff770495 100644 --- a/chrome/browser/media/router/discovery/access_code/OWNERS +++ b/chrome/browser/media/router/discovery/access_code/OWNERS @@ -1,5 +1 @@ -# ChromeOS EDU Team Members -gbj@google.com -bzielinski@google.com -bmalcolm@google.com -jacqueli@googlle.com +file://chrome/browser/ui/webui/access_code_cast/OWNERS diff --git a/chrome/browser/resources/access_code_cast/BUILD.gn b/chrome/browser/resources/access_code_cast/BUILD.gn index 155fe27c7b98f..08c53a44fba2c 100644 --- a/chrome/browser/resources/access_code_cast/BUILD.gn +++ b/chrome/browser/resources/access_code_cast/BUILD.gn @@ -12,7 +12,10 @@ assert(!is_android, "access_code_cast is not for android.") resources_grd_file = "$target_gen_dir/resources.grd" html_to_js("web_components") { - js_files = [ "access_code_cast.ts" ] + js_files = [ + "access_code_cast.ts", + "code_input/code_input.ts", + ] } copy("copy_browser_proxy") { @@ -50,9 +53,10 @@ ts_library("build_ts") { out_dir = "$target_gen_dir/tsc" tsconfig_base = "tsconfig_base.json" in_files = [ - "browser_proxy.ts", "access_code_cast.mojom-webui.js", "access_code_cast.ts", + "browser_proxy.ts", + "code_input/code_input.ts", "route_request_result_code.mojom-webui.js", ] } diff --git a/chrome/browser/resources/access_code_cast/OWNERS b/chrome/browser/resources/access_code_cast/OWNERS index 85d2109ad8b48..ccb161db3bcd5 100644 --- a/chrome/browser/resources/access_code_cast/OWNERS +++ b/chrome/browser/resources/access_code_cast/OWNERS @@ -1,4 +1 @@ -gbj@google.com -bmalcolm@chromium.org -bzielinski@google.com -jacqueli@google.com \ No newline at end of file +file://chrome/browser/ui/webui/access_code_cast/OWNERS \ No newline at end of file diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.html b/chrome/browser/resources/access_code_cast/access_code_cast.html index 5b6a4228981d4..6aed44b204540 100644 --- a/chrome/browser/resources/access_code_cast/access_code_cast.html +++ b/chrome/browser/resources/access_code_cast/access_code_cast.html @@ -1,4 +1,4 @@ - -

Cast to a new display

+

$i18n{dialogTitle}

-

Typed input view

+ - Use camera instead + $i18n{useCamera}

Camera input view

- Close - Cast - Back + $i18n{close} + + $i18n{cast} + + + $i18n{back} +
diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.ts b/chrome/browser/resources/access_code_cast/access_code_cast.ts index 7656ceaa87432..e052ab341d150 100644 --- a/chrome/browser/resources/access_code_cast/access_code_cast.ts +++ b/chrome/browser/resources/access_code_cast/access_code_cast.ts @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import './code_input/code_input.js'; + import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/icons.m.js'; import 'chrome://resources/cr_elements/shared_style_css.m.js'; @@ -12,6 +14,7 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/poly import {PageCallbackRouter} from './access_code_cast.mojom-webui.js'; import {BrowserProxy} from './browser_proxy.js'; +import {CodeInputElement} from './code_input/code_input.js'; declare const chrome: any; @@ -25,6 +28,7 @@ interface AccessCodeCastElement { backButton: CrButtonElement; castButton: CrButtonElement; codeInputView: HTMLDivElement; + codeInput: CodeInputElement; qrInputView: HTMLDivElement; } } @@ -41,15 +45,24 @@ class AccessCodeCastElement extends PolymerElement { private listenerIds: Array; private router: PageCallbackRouter; + codeLength: number; + castButtonDisabled: boolean; + constructor() { super(); this.listenerIds = []; this.router = BrowserProxy.getInstance().callbackRouter; + + this.codeLength = 6; + this.castButtonDisabled = true; } ready() { super.ready(); this.setState(PageState.CODE_INPUT); + this.$.codeInput.addEventListener('access-code-input', (e: any) => { + this.handleCodeInput(e); + }); } connectedCallback() { @@ -78,6 +91,15 @@ class AccessCodeCastElement extends PolymerElement { this.$.castButton.hidden = state !== PageState.CODE_INPUT; this.$.qrInputView.hidden = state !== PageState.QR_INPUT; this.$.backButton.hidden = state !== PageState.QR_INPUT; + + if (state === PageState.CODE_INPUT) { + this.$.codeInput.clearInput(); + this.$.codeInput.focusInput(); + } + } + + private handleCodeInput(e: any) { + this.castButtonDisabled = e.detail.value.length !== this.codeLength; } } diff --git a/chrome/browser/resources/access_code_cast/code_input/code_input.html b/chrome/browser/resources/access_code_cast/code_input/code_input.html new file mode 100644 index 0000000000000..6b113108a7cc5 --- /dev/null +++ b/chrome/browser/resources/access_code_cast/code_input/code_input.html @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/chrome/browser/resources/access_code_cast/code_input/code_input.ts b/chrome/browser/resources/access_code_cast/code_input/code_input.ts new file mode 100644 index 0000000000000..67f495114b56c --- /dev/null +++ b/chrome/browser/resources/access_code_cast/code_input/code_input.ts @@ -0,0 +1,64 @@ +// Copyright 2021 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. + +import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; + +import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; +import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +export interface CodeInputElement { + $: { + accessCodeInput: CrInputElement; + } +} + +export class CodeInputElement extends PolymerElement { + static get is() { + return 'c2c-code-input'; + } + + static get template() { + return html`{__html_template__}`; + } + + static get properties() { + return { + length: Number, + value: { + type: String, + value: '', + } + }; + } + + get crInput() { + return this.$.accessCodeInput; + } + + value: string; + + ready() { + super.ready(); + this.$.accessCodeInput.addEventListener('input', () => { + this.handleInput(); + }); + } + + clearInput() { + this.$.accessCodeInput.value = ''; + } + + focusInput() { + this.$.accessCodeInput.focusInput(); + } + + private handleInput() { + this.$.accessCodeInput.value = this.$.accessCodeInput.value.toUpperCase(); + this.dispatchEvent(new CustomEvent('access-code-input', { + detail: {value: this.$.accessCodeInput.value} + })); + } +} + +customElements.define(CodeInputElement.is, CodeInputElement); \ No newline at end of file diff --git a/chrome/browser/resources/access_code_cast/index.html b/chrome/browser/resources/access_code_cast/index.html index c1205849cb783..001fc21bce578 100644 --- a/chrome/browser/resources/access_code_cast/index.html +++ b/chrome/browser/resources/access_code_cast/index.html @@ -3,8 +3,7 @@ - Cast Receiver - + diff --git a/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc b/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc index 936a18db52b6f..7f7b790b49d35 100644 --- a/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc +++ b/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc @@ -14,9 +14,12 @@ #include "chrome/common/webui_url_constants.h" #include "chrome/grit/access_code_cast_resources.h" #include "chrome/grit/access_code_cast_resources_map.h" +#include "chrome/grit/generated_resources.h" +#include "components/strings/grit/components_strings.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/common/bindings_policy.h" +#include "ui/base/webui/web_ui_util.h" /////////////////////////////////////////////////////////////////////////////// // AccessCodeCast dialog: @@ -110,6 +113,16 @@ AccessCodeCastUI::AccessCodeCastUI(content::WebUI* web_ui) base::make_span(kAccessCodeCastResources, kAccessCodeCastResourcesSize), IDR_ACCESS_CODE_CAST_INDEX_HTML); + static constexpr webui::LocalizedString kStrings[] = { + {"back", IDS_ACCESS_CODE_CAST_BACK}, + {"cast", IDS_ACCESS_CODE_CAST_CAST}, + {"close", IDS_CLOSE}, + {"dialogTitle", IDS_ACCESS_CODE_CAST_DIALOG_TITLE}, + {"useCamera", IDS_ACCESS_CODE_CAST_USE_CAMERA}, + }; + + source->AddLocalizedStrings(kStrings); + content::BrowserContext* browser_context = web_ui->GetWebContents()->GetBrowserContext(); content::WebUIDataSource::Add(browser_context, source.release()); diff --git a/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js b/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js index 6d490bd51e483..8af144d1ba2ec 100644 --- a/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js +++ b/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js @@ -43,3 +43,19 @@ var AccessCodeCastAppTest = class extends AccessCodeCastBrowserTest { TEST_F('AccessCodeCastAppTest', 'All', function() { mocha.run(); }); + +// eslint-disable-next-line no-var +var AccessCodeCastCodeInputElementTest = class extends AccessCodeCastBrowserTest { + /** @override */ + get browsePreload() { + return 'chrome://access-code-cast/test_loader.html?module=access_code_cast/code_input_test.js'; + } +}; + +/** + * This browsertest acts as a thin wrapper to run the unit tests found + * at code_input_test.js + */ +TEST_F('AccessCodeCastCodeInputElementTest', 'All', function() { + mocha.run(); +}); diff --git a/chrome/test/data/webui/access_code_cast/code_input_test.js b/chrome/test/data/webui/access_code_cast/code_input_test.js new file mode 100644 index 0000000000000..2d793e3e5d227 --- /dev/null +++ b/chrome/test/data/webui/access_code_cast/code_input_test.js @@ -0,0 +1,32 @@ +// Copyright 2021 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. + +import 'chrome://access-code-cast/code_input/code_input.js'; + +suite('CodeInputElementTest', () => { + /** @type {!CodeInputElement} */ + let c2cInput; + + /** @type {!CrInputElement} */ + let crInput; + + setup(() => { + PolymerTest.clearBody(); + + c2cInput = document.createElement('c2c-code-input'); + document.body.appendChild(c2cInput); + crInput = c2cInput.crInput; + }); + + test('value set correctly', () => { + c2cInput.value = 'hello'; + assertEquals(c2cInput.value, crInput.value); + + // |value| is copied to uppercase when typing triggers inputEvent. + let testString = 'hello world'; + crInput.value = testString; + crInput.dispatchEvent(new InputEvent('input')); + assertEquals(c2cInput.value, testString.toUpperCase()); + }); +}); \ No newline at end of file