Skip to content

Commit

Permalink
[Cast2Class] Add basic code input, add i18n
Browse files Browse the repository at this point in the history
Add code_input.ts and code_input.html with a basic input box for typing
access code. Handle input events and transform them into custom events,
which will be useful in the future once the input is stylized and more
complicated. Transform all inputs to uppercase.

Add unit test for code_input value handling.

Additionally, add internationalization for the WebUI. This includes
adding access_code_cast_strings.grdp with the few strings we already
have, and adding translation screenshots. Add OWNERS to relevant file
and directory.

Bug: b/209046365
Change-Id: Ia1ad05fa2630d2e7a9440776f33ee80ad32adddc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3315427
Reviewed-by: Takumi Fujimoto <takumif@chromium.org>
Reviewed-by: Ken Rockot <rockot@google.com>
Commit-Queue: Benjamin Zielinski <bzielinski@google.com>
Cr-Commit-Position: refs/heads/main@{#949201}
  • Loading branch information
Benjamin Zielinski authored and Chromium LUCI CQ committed Dec 7, 2021
1 parent bf26cc6 commit 5f6ea93
Show file tree
Hide file tree
Showing 19 changed files with 209 additions and 20 deletions.
2 changes: 2 additions & 0 deletions chrome/app/OWNERS
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions chrome/app/access_code_cast_strings.grdp
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Access Code Cast-specific strings (included from generated_resources.grd). -->
<grit-part>
<message name="IDS_ACCESS_CODE_CAST_BACK" desc="Label for the 'back' button to return to the previous screen">
Back
</message>
<message name="IDS_ACCESS_CODE_CAST_CAST" desc="Label for the button to start casting">
Cast
</message>
<message name="IDS_ACCESS_CODE_CAST_DIALOG_TITLE" desc="Title for access code cast dialog">
Cast to a new display
</message>
<message name="IDS_ACCESS_CODE_CAST_USE_CAMERA" desc="Label for the button to use the device camera to scan a QR code">
Use the camera to scan QR code
</message>
</grit-part>
@@ -0,0 +1 @@
91687f84bc741017567a8e2ac9f6678066b0b877
@@ -0,0 +1 @@
cb57fa67c57448a6862dcac40af6059e8a8a20e9
@@ -0,0 +1 @@
cb57fa67c57448a6862dcac40af6059e8a8a20e9
@@ -0,0 +1 @@
cb57fa67c57448a6862dcac40af6059e8a8a20e9
1 change: 1 addition & 0 deletions chrome/app/access_code_cast_strings_grdp/OWNERS
@@ -0,0 +1 @@
file://chrome/browser/ui/webui/access_code_cast/OWNERS
3 changes: 3 additions & 0 deletions chrome/app/generated_resources.grd
Expand Up @@ -277,6 +277,9 @@ are declared in tools/grit/grit_rule.gni.
</translations>
<release seq="1">
<messages fallback_to_english="true">
<!-- Access Code Cast specific strings -->
<part file="access_code_cast_strings.grdp" />

<!-- Bookmarks specific strings -->
<part file="bookmarks_strings.grdp" />

Expand Down
6 changes: 1 addition & 5 deletions 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
8 changes: 6 additions & 2 deletions chrome/browser/resources/access_code_cast/BUILD.gn
Expand Up @@ -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") {
Expand Down Expand Up @@ -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",
]
}
Expand Down
5 changes: 1 addition & 4 deletions chrome/browser/resources/access_code_cast/OWNERS
@@ -1,4 +1 @@
gbj@google.com
bmalcolm@chromium.org
bzielinski@google.com
jacqueli@google.com
file://chrome/browser/ui/webui/access_code_cast/OWNERS
20 changes: 13 additions & 7 deletions chrome/browser/resources/access_code_cast/access_code_cast.html
@@ -1,4 +1,4 @@
<style>
<style include="cr-shared-style">
.button-image {
margin-inline-end: 8px;
}
Expand All @@ -18,19 +18,25 @@
margin: 32px 0;
}
</style>
<h1>Cast to a new display</h1>
<h1>$i18n{dialogTitle}</h1>
<div id="codeInputView">
<p>Typed input view</p>
<c2c-code-input length="6" value="" id="codeInput"></c2c-code-input>
<cr-button on-click="switchToQrInput" class="text-button">
<iron-icon class="button-image" icon="cr:videocam"></iron-icon>
Use camera instead
$i18n{useCamera}
</cr-button>
</div>
<div id="qrInputView">
<p>Camera input view</p>
</div>
<div id="button-container">
<cr-button on-click="close">Close</cr-button>
<cr-button id="castButton" class="action-button">Cast</cr-button>
<cr-button id="backButton" on-click="switchToCodeInput" class="action-button">Back</cr-button>
<cr-button on-click="close">$i18n{close}</cr-button>
<cr-button id="castButton" class="action-button"
disabled="[[castButtonDisabled]]">
$i18n{cast}
</cr-button>
<cr-button id="backButton" on-click="switchToCodeInput"
class="action-button">
$i18n{back}
</cr-button>
</div>
22 changes: 22 additions & 0 deletions chrome/browser/resources/access_code_cast/access_code_cast.ts
Expand Up @@ -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';
Expand All @@ -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;

Expand All @@ -25,6 +28,7 @@ interface AccessCodeCastElement {
backButton: CrButtonElement;
castButton: CrButtonElement;
codeInputView: HTMLDivElement;
codeInput: CodeInputElement;
qrInputView: HTMLDivElement;
}
}
Expand All @@ -41,15 +45,24 @@ class AccessCodeCastElement extends PolymerElement {
private listenerIds: Array<number>;
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() {
Expand Down Expand Up @@ -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;
}
}

Expand Down
@@ -0,0 +1,14 @@
<style>
cr-input {
font-size: 50px;
margin: auto;
width: 300px;
}
</style>
<cr-input
type="text"
minlength="[[length]]"
maxlength="[[length]]"
id="accessCodeInput"
value="{{value}}">
</cr-input>
64 changes: 64 additions & 0 deletions 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);
3 changes: 1 addition & 2 deletions chrome/browser/resources/access_code_cast/index.html
Expand Up @@ -3,8 +3,7 @@

<head>
<meta charset="utf-8">
<title>Cast Receiver</title>
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
<script type="module" src="access_code_cast.js"></script>
</head>

Expand Down
13 changes: 13 additions & 0 deletions chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc
Expand Up @@ -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:
Expand Down Expand Up @@ -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());

This comment has been minimized.

Copy link
@junaidfarhan94
Expand Down
Expand Up @@ -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();
});
32 changes: 32 additions & 0 deletions 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());
});
});

0 comments on commit 5f6ea93

Please sign in to comment.