Use flex instead of fixed sizes

Bug: 251087601
Test: npm run and check scaling with different screen sizes
Change-Id: I18efdd1250f0598ca2a01414dfa24e25b2bd6232
This commit is contained in:
Cosmin Băieș
2022-10-07 16:20:35 +02:00
parent a686867301
commit 7fa68d374e
34 changed files with 1184 additions and 1612 deletions

View File

@@ -30,7 +30,7 @@ exports.config = {
args: ["--headless", "--disable-gpu", "--window-size=1280x1024"]
}
},
chromeDriver: "./node_modules/webdriver-manager/selenium/chromedriver_105.0.5195.52",
chromeDriver: "./node_modules/webdriver-manager/selenium/chromedriver_106.0.5249.61",
allScriptsTimeout: 10000,
getPageTimeout: 10000,

View File

@@ -68,7 +68,7 @@ describe("AdbProxyComponent", () => {
it("check correct icon and message displays if unauthorised proxy", () => {
component.proxy.setState(ProxyState.UNAUTH);
fixture.detectChanges();
expect(htmlElement.querySelector(".adb-info")?.innerHTML).toBe("Proxy authorisation required");
expect(htmlElement.querySelector(".adb-info")?.innerHTML).toBe("Proxy authorisation required.");
expect(htmlElement.querySelector(".adb-icon")?.innerHTML).toBe("lock");
});

View File

@@ -19,52 +19,64 @@ import { proxyClient, ProxyClient, ProxyState } from "trace_collection/proxy_cli
@Component({
selector: "adb-proxy",
template: `
<div *ngIf="proxy.state===states.NO_PROXY">
<div class="further-adb-info">
<p>Launch the Winscope ADB Connect proxy to capture traces directly from your browser.<br/>Python 3.5+ and ADB are required.</p>
<p>Run:<br/>python3 $ANDROID_BUILD_TOP/development/tools/winscope-ng/src/adb/winscope_proxy.py</p>
<p>Or get it from the AOSP repository.</p>
</div>
<div *ngIf="proxy.state===states.NO_PROXY" class="further-adb-info">
<p class="mat-body-1">Launch the Winscope ADB Connect proxy to capture traces directly from your browser.</p>
<p class="mat-body-1">Python 3.5+ and ADB are required.</p>
<p class="mat-body-1">Run: <code>python3 $ANDROID_BUILD_TOP/development/tools/winscope-ng/src/adb/winscope_proxy.py</code></p>
<p class="mat-body-1">Or get it from the AOSP repository.</p>
<div>
<button mat-stroked-button (click)="downloadFromAosp()">Download from AOSP</button>
<button mat-stroked-button class="retry" (click)="restart()">Retry</button>
<button color="primary" mat-stroked-button (click)="downloadFromAosp()">Download from AOSP</button>
<button color="primary" mat-stroked-button class="retry" (click)="restart()">Retry</button>
</div>
</div>
<div *ngIf="proxy.state===states.INVALID_VERSION">
<div id="icon-information">
<div *ngIf="proxy.state===states.INVALID_VERSION" class="further-adb-info">
<p class="icon-information mat-body-1">
<mat-icon class="adb-icon">update</mat-icon>
<span class="adb-info">Your local proxy version is incompatible with Winscope.</span>
</div>
<div class="further-adb-info">
<p>Please update the proxy to version {{ proxyVersion }}.</p>
<p>Run:<br/>python3 $ANDROID_BUILD_TOP/development/tools/winscope-ng/src/adb/winscope_proxy.py</p>
<p>Or get it from the AOSP repository.</p>
</div>
</p>
<p class="mat-body-1">Please update the proxy to version {{ proxyVersion }}.</p>
<p class="mat-body-1">Run: <code>python3 $ANDROID_BUILD_TOP/development/tools/winscope-ng/src/adb/winscope_proxy.py</code></p>
<p class="mat-body-1">Or get it from the AOSP repository.</p>
<div>
<button mat-stroked-button (click)="downloadFromAosp()">Download from AOSP</button>
<button mat-stroked-button class="retry" (click)="restart()">Retry</button>
<button color="primary" mat-stroked-button (click)="downloadFromAosp()">Download from AOSP</button>
<button color="primary" mat-stroked-button class="retry" (click)="restart()">Retry</button>
</div>
</div>
<div *ngIf="proxy.state===states.UNAUTH">
<div id="icon-information">
<div *ngIf="proxy.state===states.UNAUTH" class="further-adb-info">
<p class="icon-information mat-body-1">
<mat-icon class="adb-icon">lock</mat-icon>
<span class="adb-info">Proxy authorisation required</span>
</div>
<div class="further-adb-info">
<p>Enter Winscope proxy token:</p>
<mat-form-field class="proxy-key-field">
<input matInput [(ngModel)]="proxyKeyItem" name="proxy-key"/>
</mat-form-field>
<p>The proxy token is printed to console on proxy launch, copy and paste it above.</p>
</div>
<span class="adb-info">Proxy authorisation required.</span>
</p>
<p class="mat-body-1">Enter Winscope proxy token:</p>
<mat-form-field class="proxy-key-field">
<input matInput [(ngModel)]="proxyKeyItem" name="proxy-key"/>
</mat-form-field>
<p class="mat-body-1">The proxy token is printed to console on proxy launch, copy and paste it above.</p>
<div>
<button mat-stroked-button class="retry" (click)="restart()">Connect</button>
<button color="primary" mat-stroked-button class="retry" (click)="restart()">Connect</button>
</div>
</div>
`,
styles: [".proxy-key-field {width: 30rem}"]
styles: [
`
.icon-information {
display: flex;
flex-direction: row;
align-items: center;
}
.further-adb-info {
overflow-wrap: break-word;
}
.further-adb-info p {
margin: 10px 0;
}
.proxy-key-field {
width: 30rem
}
`
]
})
export class AdbProxyComponent {
@Input()

View File

@@ -83,7 +83,7 @@ describe("AppComponent", () => {
component.dataLoaded = false;
fixture.detectChanges();
expect(htmlElement.querySelector(".welcome-info")).toBeTruthy();
expect(htmlElement.querySelector(".viewers.hide")).toBeTruthy();
expect(htmlElement.querySelector("#viewers")).toBeNull();
});
it("displays correct elements when data loaded", async () => {
@@ -91,6 +91,6 @@ describe("AppComponent", () => {
fixture.detectChanges();
expect(htmlElement.querySelector("#collect-traces-card")).toBeFalsy();
expect(htmlElement.querySelector("#upload-traces-card")).toBeFalsy();
expect(htmlElement.querySelector(".viewers.show")).toBeTruthy();
expect(htmlElement.querySelector("#viewers")).toBeTruthy();
});
});

View File

@@ -28,43 +28,41 @@ import { ViewerInputMethodComponent } from "viewers/components/viewer_input_meth
selector: "app-root",
template: `
<mat-toolbar class="app-toolbar">
<span id="app-title">Winscope</span>
<p id="app-title" class="mat-display-1">Winscope</p>
<span class="toolbar-wrapper">
<button mat-stroked-button *ngIf="dataLoaded" (click)="toggleTimestamp()">Start/End Timestamp</button>
<button class="upload-new-btn" mat-stroked-button *ngIf="dataLoaded" (click)="clearData()">Upload New</button>
<button *ngIf="dataLoaded" color="primary" mat-stroked-button (click)="toggleTimestamp()">Start/End Timestamp</button>
<button *ngIf="dataLoaded" color="primary" mat-stroked-button (click)="clearData()">Upload New</button>
</span>
</mat-toolbar>
<div class="welcome-info" *ngIf="!dataLoaded">
<span>Welcome to Winscope. Please select source to view traces.</span>
</div>
<h1 *ngIf="!dataLoaded" class="welcome-info mat-headline">Welcome to Winscope. Please select source to view traces.</h1>
<div *ngIf="!dataLoaded" fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
<mat-card class="homepage-card" id="collect-traces-card">
<collect-traces [traceCoordinator]="traceCoordinator" (dataLoadedChange)="onDataLoadedChange($event)"[store]="store"></collect-traces>
<div *ngIf="!dataLoaded" class="card-grid">
<mat-card id="collect-traces-card" class="homepage-card">
<collect-traces [traceCoordinator]="traceCoordinator" (dataLoadedChange)="onDataLoadedChange($event)" [store]="store"></collect-traces>
</mat-card>
<mat-card class="homepage-card" id="upload-traces-card">
<mat-card id="upload-traces-card" class="homepage-card">
<upload-traces [traceCoordinator]="traceCoordinator" (dataLoadedChange)="onDataLoadedChange($event)"></upload-traces>
</mat-card>
</div>
<div id="viewers" [class]="showViewers()">
<trace-view
<trace-view
*ngIf="dataLoaded"
id="viewers"
[store]="store"
[traceCoordinator]="traceCoordinator"
></trace-view>
</div>
></trace-view>
<div id="timescrub">
<div *ngIf="dataLoaded" id="timescrub">
<mat-slider
*ngIf="dataLoaded"
color="primary"
class="time-slider"
step="1"
min="0"
[max]="this.allTimestamps.length-1"
aria-label="units"
[value]="currentTimestampIndex"
(input)="updateCurrentTimestamp($event)"
class="time-slider"
></mat-slider>
</div>
<div id="timestamps">
@@ -72,36 +70,50 @@ import { ViewerInputMethodComponent } from "viewers/components/viewer_input_meth
`,
styles: [
`
.time-slider {
width: 100%
}
.upload-new-btn {
float: right;
position: relative;
vertical-align: middle;
display: inline-block;
}
.app-toolbar {
background-color: white;
border-bottom: 1px solid var(--default-border);
box-shadow: none;
background-color: rgba(1, 1, 1, 0);
height: 56px;
vertical-align: middle;
position: relative;
display: inline-block;
}
#app-title {
margin: 12px 0;
}
.toolbar-wrapper {
width: 100%;
height: 100%;
vertical-align: middle;
position: relative;
display: inline-block;
align-content: center;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.welcome-info {
margin: 16px 0;
text-align: center;
font: inherit;
padding: 40px;
}
.homepage-card {
flex: 1;
margin: 10px;
overflow: auto;
border: 1px solid var(--default-border);
}
.homepage-card mat-card-content {
display: flex;
flex-direction: column;
overflow: auto;
}
#viewers {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
overflow: auto;
}
#timescrub {
padding: 8px;
border-top: 1px solid var(--default-border);
}
.time-slider {
width: 100%
}
`
],
@@ -157,11 +169,6 @@ export class AppComponent {
proxyClient.adbData = [];
}
public showViewers() {
const isShown = this.dataLoaded ? "show" : "hide";
return `viewers ${isShown}`;
}
public onDataLoadedChange(dataLoaded: boolean) {
if (dataLoaded && !(this.traceCoordinator.getViewers().length > 0)) {
this.allTimestamps = this.traceCoordinator.getTimestamps();

View File

@@ -28,88 +28,90 @@ import { ParserErrorSnackBarComponent } from "./parser_error_snack_bar_component
@Component({
selector: "collect-traces",
template: `
<mat-card-title id="title">Collect Traces</mat-card-title>
<mat-card-content>
<mat-card-title id="title">Collect Traces</mat-card-title>
<mat-card-content>
<div class="connecting-message" *ngIf="connect.isConnectingState()"><span>Connecting...</span></div>
<p *ngIf="connect.isConnectingState()" class="connecting-message mat-body-1">Connecting...</p>
<div class="set-up-adb" *ngIf="!connect.adbSuccess()">
<button id="proxy-tab" mat-stroked-button [ngClass]="tabClass(true)" (click)="displayAdbProxyTab()">ADB Proxy</button>
<!-- <button id="web-tab" mat-raised-button [ngClass]="tabClass(false)" (click)="displayWebAdbTab()">Web ADB</button> -->
<div *ngIf="!connect.adbSuccess()" class="set-up-adb">
<button id="proxy-tab" color="primary" mat-stroked-button [ngClass]="tabClass(true)" (click)="displayAdbProxyTab()">ADB Proxy</button>
<!-- <button id="web-tab" color="primary" mat-raised-button [ngClass]="tabClass(false)" (click)="displayWebAdbTab()">Web ADB</button> -->
<adb-proxy *ngIf="isAdbProxy" [(proxy)]="connect.proxy!" (addKey)="onAddKey($event)"></adb-proxy>
<!-- <web-adb *ngIf="!isAdbProxy"></web-adb> TODO: fix web adb workflow -->
</div>
<div id="devices-connecting" *ngIf="connect.isDevicesState()">
<span> {{ objectKeys(connect.devices()).length > 0 ? "Connected devices:" : "No devices detected" }}</span>
<mat-list class="device-choice">
<mat-list-item *ngFor="let deviceId of objectKeys(connect.devices())" (click)="connect.selectDevice(deviceId)">
<mat-icon class="icon-message">
{{ connect.devices()[deviceId].authorised ? "smartphone" : "screen_lock_portrait" }}
</mat-icon>
<span class="icon-message">
{{ connect.devices()[deviceId].authorised ? connect.devices()[deviceId].model : "unauthorised" }} ({{ deviceId }})
</span>
</mat-list-item>
</mat-list>
<p class="mat-body-1"> {{ objectKeys(connect.devices()).length > 0 ? "Connected devices:" : "No devices detected" }}</p>
<mat-list *ngIf="objectKeys(connect.devices()).length > 0">
<mat-list-item *ngFor="let deviceId of objectKeys(connect.devices())" (click)="connect.selectDevice(deviceId)">
<mat-icon>
{{ connect.devices()[deviceId].authorised ? "smartphone" : "screen_lock_portrait" }}
</mat-icon>
{{ connect.devices()[deviceId].authorised ? connect.devices()[deviceId].model : "unauthorised" }} ({{ deviceId }})
</mat-list-item>
</mat-list>
</div>
<div id="trace-collection-config" *ngIf="connect.isStartTraceState()">
<div class="device-choice">
<mat-list class="device-choice">
<mat-list-item>
<mat-icon class="icon-message">smartphone</mat-icon>
<span class="icon-message">
{{ connect.selectedDevice().model }} ({{ connect.selectedDeviceId() }})
</span>
<button class="change-btn" mat-raised-button (click)="connect.resetLastDevice()">Change device</button>
</mat-list-item>
</mat-list>
</div>
<mat-list>
<mat-list-item>
<mat-icon>smartphone</mat-icon>
{{ connect.selectedDevice().model }} ({{ connect.selectedDeviceId() }})
<button color="primary" class="change-btn" mat-button (click)="connect.resetLastDevice()">Change device</button>
</mat-list-item>
</mat-list>
<div class="trace-section">
<trace-config
[traces]="setTraces.DYNAMIC_TRACES"
></trace-config>
<button class="start-btn" mat-stroked-button (click)="startTracing()">Start trace</button>
<trace-config [traces]="setTraces.DYNAMIC_TRACES"></trace-config>
<button color="primary" mat-stroked-button class="start-btn" (click)="startTracing()">Start trace</button>
</div>
<div class="dump-section">
<p class="subtitle">Dump targets</p>
<h3 class="mat-subheading-2">Dump targets</h3>
<div class="selection">
<mat-checkbox
*ngFor="let dumpKey of objectKeys(setTraces.DUMPS)"
color="primary"
[(ngModel)]="setTraces.DUMPS[dumpKey].run"
>{{setTraces.DUMPS[dumpKey].name}}</mat-checkbox>
<button class="dump-btn" mat-stroked-button (click)="dumpState()">Dump state</button>
<button color="primary" class="dump-btn" mat-stroked-button (click)="dumpState()">Dump state</button>
</div>
</div>
</div>
<div class="unknown-error" *ngIf="connect.isErrorState()">
<mat-icon class="icon-message">error</mat-icon>
<span class="icon-message">Error:</span>
<pre>
{{ connect.proxy?.errorText }}
</pre>
<button class="retry-btn" mat-raised-button (click)="connect.restart()">Retry</button>
<div *ngIf="connect.isErrorState()" class="unknown-error">
<p class="error-wrapper mat-body-1">
<mat-icon>error</mat-icon>
Error:
</p>
<pre> {{ connect.proxy?.errorText }} </pre>
<button color="primary" class="retry-btn" mat-raised-button (click)="connect.restart()">Retry</button>
</div>
<div class="end-tracing" *ngIf="connect.isEndTraceState()">
<span>Tracing...</span>
<div *ngIf="connect.isEndTraceState()" class="end-tracing">
<p class="mat-body-1">Tracing...</p>
<mat-progress-bar md-indeterminate value="{{connect.loadProgress}}"></mat-progress-bar>
<button class="end-btn" mat-raised-button (click)="endTrace()">End trace</button>
<button color="primary" class="end-btn" mat-raised-button (click)="endTrace()">End trace</button>
</div>
<div class="load-data" *ngIf="connect.isLoadDataState()">
<span>Loading data...</span>
<div *ngIf="connect.isLoadDataState()" class="load-data">
<p class="mat-body-1">Loading data...</p>
<mat-progress-bar md-indeterminate></mat-progress-bar>
</div>
</mat-card-content>
</mat-card-content>
`,
styles: [
".device-choice {cursor: pointer}",
`
.change-btn {
margin-left: 5px;
}
.error-wrapper {
display: flex;
flex-direction: row;
align-items: center;
}
`
]
})
export class CollectTracesComponent implements OnInit, OnDestroy {

View File

@@ -21,15 +21,28 @@ import { ParserError, ParserErrorType } from "parsers/parser_factory";
@Component({
selector: "upload-snack-bar",
template: `
<div class="flex">
<div class="message-wrapper">
<p class="data" *ngFor="let msg of errorMessages">{{msg}}</p>
</div>
<button class="icon-button close" (click)="snackBarRef.dismiss()">
<mat-icon class="icon-button close-snackbar">close</mat-icon>
<div class="snack-bar-container">
<p *ngFor="let msg of errorMessages" class="snack-bar-content mat-body-1">{{msg}}</p>
<button color="primary" mat-button class="snack-bar-action" (click)="snackBarRef.dismiss()">
Close
</button>
</div>
`,
styles: [
`
.snack-bar-container {
display: flex;
flex-direction: row;
align-items: center;
}
.snack-bar-content {
color: white;
}
.snack-bar-action {
margin-left: 12px;
}
`
]
})
export class ParserErrorSnackBarComponent {

View File

@@ -20,57 +20,61 @@ import { EnableConfiguration, SelectionConfiguration, TraceConfiguration, TraceC
selector: "trace-config",
template: `
<div class="card-block">
<p class="subtitle">Trace targets</p>
<ul class="checkboxes">
<div *ngFor="let traceKey of objectKeys(traces)">
<h3 class="mat-subheading-2">Trace targets</h3>
<div class="checkboxes">
<mat-checkbox
*ngFor="let traceKey of objectKeys(traces)"
color="primary"
class="trace-box"
[checked]="traces[traceKey].run"
[indeterminate]="traces[traceKey].isTraceCollection ? someTraces(traces[traceKey]) : false"
(change)="changeRunTrace($event.checked, traces[traceKey])"
>{{traces[traceKey].name}}</mat-checkbox>
</div>
<ng-container *ngFor="let traceKey of advancedConfigTraces()">
<h3 class="mat-subheading-2">{{traces[traceKey].name}} configuration</h3>
<div *ngIf="traces[traceKey].config?.enableConfigs" class="config-opt">
<mat-checkbox
class="trace-box"
[checked]="traces[traceKey].run"
[indeterminate]="traces[traceKey].isTraceCollection ? someTraces(traces[traceKey]) : false"
(change)="changeRunTrace($event.checked, traces[traceKey])"
>{{traces[traceKey].name}}</mat-checkbox>
</div>
</ul>
*ngFor="let enableConfig of traceEnableConfigs(traces[traceKey])"
color="primary"
class="enable-config"
[disabled]="!traces[traceKey].run && !traces[traceKey].isTraceCollection"
[(ngModel)]="enableConfig.enabled"
(ngModelChange)="changeTraceCollectionConfig(traces[traceKey])"
>{{enableConfig.name}}</mat-checkbox>
<div *ngFor="let traceKey of advancedConfigTraces()">
<p class="subtitle">{{traces[traceKey].name}} configuration</p>
<div>
<div class="config-opt" *ngIf="traces[traceKey].config?.enableConfigs">
<mat-checkbox
*ngFor="let enableConfig of traceEnableConfigs(traces[traceKey])"
class="enable-config"
[disabled]="!traces[traceKey].run && !traces[traceKey].isTraceCollection"
[(ngModel)]="enableConfig.enabled"
(ngModelChange)="changeTraceCollectionConfig(traces[traceKey])"
>{{enableConfig.name}}</mat-checkbox>
<div class="config-opt" *ngIf="traces[traceKey].config?.selectionConfigs">
<div *ngIf="traces[traceKey].config?.selectionConfigs" class="config-opt">
<mat-form-field
appearance="fill"
class="config-selection"
*ngFor="let selectionConfig of traceSelectionConfigs(traces[traceKey])"
><mat-label>{{selectionConfig.name}}</mat-label>
<mat-select class="selected-value" [(value)]="selectionConfig.value" [disabled]="!traces[traceKey].run">
<mat-option
*ngFor="let option of selectionConfig.options"
value="{{option}}"
>{{ option }}</mat-option>
</mat-select>
*ngFor="let selectionConfig of traceSelectionConfigs(traces[traceKey])"
class="config-selection"
appearance="fill">
<mat-label>{{selectionConfig.name}}</mat-label>
<mat-select class="selected-value" [(value)]="selectionConfig.value" [disabled]="!traces[traceKey].run">
<mat-option
*ngFor="let option of selectionConfig.options"
value="{{option}}"
>{{ option }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
</ng-container>
</div>
`,
styles: [
`
.checkboxes {
columns: 3 10em;
padding: 0;
.card-block {
margin: 15px;
}
.config-opt {
position: relative;
display: inline-block;
.checkboxes {
padding: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.config-selection {
margin: 0 5px;
}
`
]

View File

@@ -27,54 +27,47 @@ import { Viewer } from "viewers/viewer";
@Component({
selector: "trace-view",
template: `
<mat-card class="trace-card">
<mat-card-header class="trace-view-header">
<span class="header-items-wrapper">
<nav mat-tab-nav-bar class="viewer-nav-bar">
<a
mat-tab-link
*ngFor="let tab of viewerTabs"
[active]="isCurrentActiveCard(tab.cardId)"
(click)="showViewer(tab.cardId)"
class="viewer-tab"
>{{tab.label}}</a>
</nav>
<button
mat-stroked-button
class="icon-button save-btn"
(click)="downloadAllTraces()"
>Download all traces</button>
</span>
</mat-card-header>
<mat-card-content class="trace-view-content">
</mat-card-content>
</mat-card>
<div class="header-items-wrapper">
<nav mat-tab-nav-bar class="viewer-nav-bar">
<a
*ngFor="let tab of viewerTabs"
mat-tab-link
[active]="isCurrentActiveCard(tab.cardId)"
(click)="showViewer(tab.cardId)"
class="viewer-tab"
>{{tab.label}}</a>
</nav>
<button
color="primary"
mat-button
class="save-btn"
(click)="downloadAllTraces()"
>Download all traces</button>
</div>
<div class="trace-view-content">
</div>
`,
styles: [
`
:host /deep/ .trace-view-header .mat-card-header-text {
margin: 0;
}
.header-items-wrapper {
width: 100%;
vertical-align: middle;
position: relative;
display: inline-block;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.viewer-nav-bar {
vertical-align: middle;
display: inline-block;
height: 100%;
}
.trace-view-content {
height: 0;
flex-grow: 1;
}
.save-btn {
float: right;
vertical-align: middle;
border: none;
height: 100%;
margin: 0;
display: inline-block;
}
`
]

View File

@@ -24,98 +24,70 @@ import { ParserError } from "parsers/parser_factory";
@Component({
selector: "upload-traces",
template: `
<mat-card-title id="title">Upload Traces</mat-card-title>
<mat-card-content>
<div
class="drop-box"
ref="drop-box"
(dragleave)="onFileDragOut($event)"
(dragover)="onFileDragIn($event)"
(drop)="onHandleFileDrop($event)"
(click)="fileDropRef.click()"
>
<input
hidden
class="input-files"
id="fileDropRef"
type="file"
(change)="onInputFile($event)"
#fileDropRef
multiple
/>
<mat-list
class="uploaded-files"
*ngIf="this.loadedTraces.length > 0"
>
<mat-list-item *ngFor="let trace of loadedTraces" class="listed-file">
<span class="listed-file">
<mat-icon class= "listed-file-item">{{TRACE_INFO[trace.type].icon}}</mat-icon>
<span class="listed-file-item">{{trace.name}} ({{TRACE_INFO[trace.type].name}})</span>
<button
(click)="onRemoveTrace($event, trace)"
class="icon-button close-btn listed-file-item"
><mat-icon>close</mat-icon>
</button>
</span>
</mat-list-item>
</mat-list>
<span *ngIf="this.loadedTraces.length === 0" class="drop-info">Drag your .winscope file(s) or click to upload</span>
</div>
<mat-card-title id="title">Upload Traces</mat-card-title>
<mat-card-content>
<div
class="drop-box"
ref="drop-box"
(dragleave)="onFileDragOut($event)"
(dragover)="onFileDragIn($event)"
(drop)="onHandleFileDrop($event)"
(click)="fileDropRef.click()"
>
<input
id="fileDropRef"
hidden
type="file"
multiple
#fileDropRef
(change)="onInputFile($event)"
/>
<mat-list *ngIf="this.loadedTraces.length > 0" class="uploaded-files">
<mat-list-item *ngFor="let trace of loadedTraces">
<mat-icon>{{TRACE_INFO[trace.type].icon}}</mat-icon>
{{trace.name}} ({{TRACE_INFO[trace.type].name}})
<button
color="primary"
mat-icon-button
class="close-btn"
(click)="onRemoveTrace($event, trace)"
><mat-icon>close</mat-icon>
</button>
</mat-list-item>
</mat-list>
<p *ngIf="this.loadedTraces.length === 0" class="drop-info mat-body-1">Drag your .winscope file(s) or click to upload</p>
</div>
<div class="load-traces-btns" *ngIf="this.loadedTraces.length > 0">
<button mat-raised-button class="load-btn" (click)="onLoadData()">View traces</button>
<button mat-stroked-button for="fileDropRef" (click)="fileDropRef.click()">Upload another file</button>
<button mat-stroked-button (click)="onClearData()">Clear all</button>
</div>
</mat-card-content>
<div *ngIf="this.loadedTraces.length > 0">
<button color="primary" mat-raised-button class="load-btn" (click)="onLoadData()">View traces</button>
<button color="primary" mat-stroked-button for="fileDropRef" (click)="fileDropRef.click()">Upload another file</button>
<button color="primary" mat-stroked-button (click)="onClearData()">Clear all</button>
</div>
</mat-card-content>
`,
styles: [
`
.drop-box {
outline: 2px dashed var(--default-border);
outline-offset: -10px;
background: white;
padding: 10px 10px 10px 10px;
height: 400px;
position: relative;
cursor: pointer;
padding: 10px;
display: flex;
flex-direction: column;
overflow: auto;
text-align: center;
align-items: center;
justify-items: center;
vertical-align: middle;
}
.drop-info {
font-weight: normal;
pointer-events: none;
margin: auto;
}
#inputfile {
margin: auto;
outline: 2px dashed var(--default-border);
outline-offset: -10px;
cursor: pointer;
}
.uploaded-files {
text-align: left;
height: 400px;
overflow: auto;
width: 100%;
}
.listed-file {
width: 100%;
position: relative;
display: inline-block;
height: 100%;
width: 100%;
}
.listed-file-item {
position: relative;
display: inline-block;
vertical-align: middle;
align-items: center;
overflow: auto;
}
.close-btn {
float: right;
margin-left: auto;
}
.drop-info {
pointer-events: none;
margin: auto;
}
`
]

View File

@@ -18,19 +18,23 @@ import {Component} from "@angular/core";
@Component({
selector: "web-adb",
template: `
<div id="info-message">
<p class="text-icon-wrapper mat-body-1">
<mat-icon class="adb-icon">info</mat-icon>
<span class="adb-info">Add new device</span>
</div>
<div>
<p>Click the button below to follow instructions in the Chrome pop-up.</p>
<p>Selecting a device will kill all existing ADB connections.</p>
</div>
<div>
<button mat-raised-button>Select a device</button>
</div>
</p>
<p class="mat-body-1">Click the button below to follow instructions in the Chrome pop-up.</p>
<p class="mat-body-1">Selecting a device will kill all existing ADB connections.</p>
<button color="primary" mat-raised-button>Select a device</button>
`,
styles: [".icon-message {vertical-align: middle;}"]
styles: [
`
.text-icon-wrapper {
display: flex;
flex-direction: row;
align-items: center;
}
`
]
})
export class WebAdbComponent {
adbDevice = null;

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@use '@angular/material' as mat;
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
@import '//fonts.googleapis.com/css2?family=Google+Sans';
$primary: mat.define-palette(mat.$blue-palette, 700);
$accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
$typography: mat.define-typography-config(
$font-family: 'Roboto, sans-serif'
);
@include mat.core($typography);
$theme: mat.define-light-theme((
color: (
primary: $primary,
accent: $accent,
)
));
@include mat.core-theme($theme);
@include mat.button-theme($theme);
@include mat.card-theme($theme);
@include mat.checkbox-theme($theme);
@include mat.form-field-theme($theme);
@include mat.grid-list-theme($theme);
@include mat.icon-theme($theme);
@include mat.input-theme($theme);
@include mat.list-theme($theme);
@include mat.progress-bar-theme($theme);
@include mat.progress-spinner-theme($theme);
@include mat.radio-theme($theme);
@include mat.select-theme($theme);
@include mat.slider-theme($theme);
@include mat.snack-bar-theme($theme);
@include mat.tabs-theme($theme);
@include mat.tooltip-theme($theme);
@include mat.toolbar-theme($theme);

View File

@@ -13,95 +13,46 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
@import '//fonts.googleapis.com/css2?family=Google+Sans';
:root {
html {
height: 100%;
width: 100%;
--default-border: #DADCE0;
--default-blue: #1A73E8;
}
:root .mat-stroked-button {
margin: 10px;
body {
margin: 0;
height: 100%;
width: 100%;
}
.mat-snack-bar-container, .close-snackbar {
color: white;
}
.mat-snack-bar-container .flex {
display: inline-flex;
align-items: baseline;
position: relative;
vertical-align: middle;
justify-content: space-between;
}
.mat-snack-bar-container .data {
display: block;
}
.mat-snack-bar-container .message-wrapper, .mat-snack-bar-container .close {
vertical-align: middle;
position: relative;
display: inline-block;
}
#app-title {
font-family: 'Google Sans', sans-serif;
font-size: 30;
}
#title {
font-family: 'Google Sans', sans-serif;
font-size: 18px;
}
.labels-canvas div {
font-family: 'Google Sans', sans-serif;
}
h1, p, span {
font-family: 'Google Sans Text', sans-serif;
font-weight: 400;
}
button span {
font-family: 'Google Sans', sans-serif;
font-weight: 500;
}
button {
cursor: pointer;
}
.homepage-card {
border: 1px solid var(--default-border);
width: 50%;
height: 48rem;
display: flex;
overflow: auto;
margin: 10px;
}
.homepage-card mat-card-content {
app-root {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
overflow: auto;
}
.trace-card {
padding: 0 !important;
margin: 0 !important;
border: none;
box-shadow: none !important;
height: 100%;
overflow: auto;
display: flex;
.mat-headline, .mat-title, .mat-subheading-2, .mat-body-1, .mat-body-2, .mat-small {
margin: 0;
}
button.mat-raised-button {
margin: 10px;
}
button.mat-stroked-button {
margin: 10px;
}
mat-checkbox {
margin-left: 12px;
}
mat-icon {
margin: 5px;
}
.card-grid {
width: 100%;
height: 100%;
@@ -109,159 +60,3 @@ button {
flex-direction: row;
overflow: auto;
}
mat-checkbox {
margin-left: 5px;
}
.mat-form-field {
margin: 2px;
padding: 0;
}
mat-icon {
margin: 5px;
}
.icon-message, .adb-icon, .adb-info {
vertical-align: middle;
}
.file-icon {
vertical-align: middle;
outline: none;
background: none;
}
.card-block {
margin: 15px;
}
button.mat-raised-button {
background-color: var(--default-blue);
color: white;
margin: 10px;
}
button.mat-raised-button span {
font-weight: 500;
}
.tab.inactive {
background-color:white;
color: black;
}
.input {
opacity: 0;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
}
.subtitle {
font-size: 16px;
line-height: 24px;
font-weight: 500;
}
.file-input-prompt {
color: white;
background-color: var(--default-blue);
border-radius: 21.5px;
cursor: pointer;
}
.viewers.hide {
display: none !important;
}
.icon-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
#trace-collection-config button {
background: none;
box-shadow: none;
color: var(--default-blue);
}
.device-choice button {
border: none;
}
.trace-section button, .dump-section button {
border: 1px solid var(--default-border);
}
/* changing colors of pre-built theme */
.mat-accent .mat-option.mat-selected:not(.mat-option-disabled){color: var(--default-blue)}
.mat-pseudo-checkbox-checked,.mat-pseudo-checkbox-indeterminate,.mat-accent .mat-pseudo-checkbox-checked,.mat-accent .mat-pseudo-checkbox-indeterminate{background:var(--default-blue)}
.mat-badge-accent .mat-badge-content{background:var(--default-blue);}
.mat-button.mat-accent,.mat-icon-button.mat-accent,.mat-stroked-button.mat-accent, .mat-stroked-button{color:var(--default-blue)}
.mat-button.mat-accent .mat-button-focus-overlay,.mat-icon-button.mat-accent .mat-button-focus-overlay,.mat-stroked-button.mat-accent .mat-button-focus-overlay{background-color:var(--default-blue)}
.mat-flat-button.mat-accent,.mat-raised-button.mat-accent,.mat-fab.mat-accent,.mat-mini-fab.mat-accent{background-color:var(--default-blue)}
.mat-checkbox-checked.mat-accent .mat-checkbox-background{background-color:var(--default-blue)}
.mat-checkbox-checked:not(.mat-checkbox-disabled).mat-accent .mat-ripple-element,.mat-checkbox:active:not(.mat-checkbox-disabled).mat-accent .mat-ripple-element{background:var(--default-blue)}
.mat-chip.mat-standard-chip.mat-chip-selected.mat-accent{background-color:var(--default-blue);}
.mat-datepicker-content.mat-accent .mat-calendar-body-selected{background-color:var(--default-blue);}
.mat-datepicker-toggle-active.mat-accent{color:var(--default-blue)}
.mat-form-field.mat-focused .mat-form-field-label.mat-accent{color:var(--default-blue)}
.mat-focused .mat-form-field-required-marker{color:var(--default-blue)}
.mat-form-field.mat-focused .mat-form-field-ripple.mat-accent{background-color:var(--default-blue)}
.mat-form-field-type-mat-native-select.mat-focused:not(.mat-form-field-invalid).mat-accent .mat-form-field-infix::after{color:var(--default-blue)}
.mat-form-field-appearance-outline.mat-focused.mat-accent .mat-form-field-outline-thick{color:var(--default-blue)}
.mat-icon.mat-accent{color:var(--default-blue)}
.mat-form-field.mat-accent .mat-input-element{caret-color:var(--default-blue)}
.mat-progress-bar.mat-accent .mat-progress-bar-fill::after{background-color:var(--default-blue)}
.mat-progress-spinner.mat-accent circle,.mat-spinner.mat-accent circle{stroke:var(--default-blue)}
.mat-radio-button.mat-accent.mat-radio-checked .mat-radio-outer-circle{border-color:var(--default-blue)}
.mat-radio-button.mat-accent .mat-radio-inner-circle,.mat-radio-button.mat-accent .mat-radio-ripple .mat-ripple-element:not(.mat-radio-persistent-ripple),.mat-radio-button.mat-accent.mat-radio-checked .mat-radio-persistent-ripple,.mat-radio-button.mat-accent:active .mat-radio-persistent-ripple{background-color:var(--default-blue)}
.mat-form-field.mat-focused.mat-accent .mat-select-arrow{color:var(--default-blue)}
.mat-slide-toggle.mat-checked .mat-slide-toggle-thumb{background-color:var(--default-blue)}
.mat-slide-toggle.mat-checked .mat-ripple-element{background-color:var(--default-blue)}
.mat-slider.mat-accent .mat-slider-track-fill,.mat-slider.mat-accent .mat-slider-thumb,.mat-slider.mat-accent .mat-slider-thumb-label{background-color:var(--default-blue)}
.mat-step-header.mat-accent .mat-step-icon-selected,.mat-step-header.mat-accent .mat-step-icon-state-done,.mat-step-header.mat-accent .mat-step-icon-state-edit{background-color:var(--default-blue);}
.mat-tab-group.mat-accent .mat-ink-bar,.mat-tab-nav-bar.mat-accent .mat-ink-bar{background-color:var(--default-blue)}
.mat-tab-group.mat-background-accent>.mat-tab-header,.mat-tab-group.mat-background-accent>.mat-tab-link-container,.mat-tab-group.mat-background-accent>.mat-tab-header-pagination,.mat-tab-nav-bar.mat-background-accent>.mat-tab-header,.mat-tab-nav-bar.mat-background-accent>.mat-tab-link-container,.mat-tab-nav-bar.mat-background-accent>.mat-tab-header-pagination{background-color:var(--default-blue)}
.mat-toolbar.mat-accent{background:var(--default-blue);}
.mat-simple-snackbar-action{color:var(--default-blue)}
/* changing fonts of pre-built theme */
.mat-h1,.mat-headline,.mat-typography .mat-h1,.mat-typography .mat-headline,.mat-typography h1{font:400 24px/32px "Google Sans", sans-serif;letter-spacing:normal;margin:0 0 16px}
.mat-h2,.mat-title,.mat-typography .mat-h2,.mat-typography .mat-title,.mat-typography h2{font:500 20px/32px "Google Sans", sans-serif;letter-spacing:normal;margin:0 0 16px}
.mat-h3,.mat-subheading-2,.mat-typography .mat-h3,.mat-typography .mat-subheading-2,.mat-typography h3{font:400 16px/28px "Google Sans", sans-serif;letter-spacing:normal;margin:0 0 16px}
.mat-h4,.mat-subheading-1,.mat-typography .mat-h4,.mat-typography .mat-subheading-1,.mat-typography h4{font:400 15px/24px "Google Sans", sans-serif;letter-spacing:normal;margin:0 0 16px}
.mat-h5,.mat-typography .mat-h5,.mat-typography h5{font:400 calc(14px * 0.83)/20px "Google Sans", sans-serif;margin:0 0 12px}
.mat-h6,.mat-typography .mat-h6,.mat-typography h6{font:400 calc(14px * 0.67)/20px "Google Sans", sans-serif;margin:0 0 12px}
.mat-body-strong,.mat-body-2,.mat-typography .mat-body-strong,.mat-typography .mat-body-2{font:500 14px/24px "Google Sans Text", sans-serif;letter-spacing:normal}
.mat-body,.mat-body-1,.mat-typography .mat-body,.mat-typography .mat-body-1,.mat-typography{font-family:"Google Sans Text", sans-serif;}
.mat-small,.mat-caption,.mat-typography .mat-small,.mat-typography .mat-caption{font:400 12px/20px "Google Sans Text", sans-serif;letter-spacing:normal}
.mat-display-4,.mat-typography .mat-display-4{font:300 112px/112px "Google Sans", sans-serif;letter-spacing:-0.05em;margin:0 0 56px}
.mat-display-3,.mat-typography .mat-display-3{font:400 56px/56px "Google Sans", sans-serif;letter-spacing:-0.02em;margin:0 0 64px}
.mat-display-2,.mat-typography .mat-display-2{font:400 45px/48px "Google Sans", sans-serif;letter-spacing:-0.005em;margin:0 0 64px}
.mat-display-1,.mat-typography .mat-display-1{font:400 34px/40px "Google Sans", sans-serif;letter-spacing:normal;margin:0 0 64px}
.mat-select-trigger{font-family:"Google Sans", sans-serif;}
.mat-radio-button{font-family:"Google Sans", sans-serif}
.mat-select{font-family:"Google Sans", sans-serif}
.mat-slide-toggle-content{font-family:"Google Sans", sans-serif}
.mat-slider-thumb-label-text{font-family:"Google Sans", sans-serif}
.mat-stepper-vertical,.mat-stepper-horizontal{font-family:"Google Sans", sans-serif}
.mat-tab-group{font-family:"Google Sans", sans-serif}
.mat-tab-label,.mat-tab-link{font-family:"Google Sans", sans-serif; font-weight: 500;}
.mat-toolbar,.mat-toolbar h1,.mat-toolbar h2,.mat-toolbar h3,.mat-toolbar h4,.mat-toolbar h5,.mat-toolbar h6{font-family:"Google Sans", sans-serif;}
.mat-tooltip{font-family:"Google Sans", sans-serif;}
.mat-list-item{font-family:"Google Sans", sans-serif}
.mat-list-option{font-family:"Google Sans", sans-serif}
.mat-list-base .mat-subheader{font-family:"Google Sans", sans-serif;}
.mat-list-base[dense] .mat-subheader{font-family:"Google Sans", sans-serif;}
.mat-option{font-family:"Google Sans", sans-serif;}
.mat-optgroup-label{font-family:"Google Sans", sans-serif}
.mat-simple-snackbar{font-family:"Google Sans", sans-serif;}

View File

@@ -18,44 +18,54 @@ import { Component, Input } from "@angular/core";
@Component({
selector: "coordinates-table",
template: `
<span class="coord-null-value" *ngIf="!hasCoordinates()">null</span>
<div class="coord-table-wrapper" *ngIf="hasCoordinates()">
<table class="table">
<tr class="header-row">
<td>Left</td>
<td>Top</td>
<td>Right</td>
<td>Bottom</td>
</tr>
<tr>
<td>{{ coordinates.left }}</td>
<td>{{ coordinates.top }}</td>
<td>{{ coordinates.right }}</td>
<td>{{ coordinates.bottom }}</td>
</tr>
</table>
</div>
<p *ngIf="!hasCoordinates()" class="mat-body-1">null</p>
<table *ngIf="hasCoordinates()" class="table">
<tr class="header-row">
<td>
<p class="mat-body-1">Left</p>
</td>
<td>
<p class="mat-body-1">Top</p>
</td>
<td>
<p class="mat-body-1">Right</p>
</td>
<td>
<p class="mat-body-1">Bottom</p>
</td>
</tr>
<tr>
<td>
<p class="mat-body-1">{{ coordinates.left }}</p>
</td>
<td>
<p class="mat-body-1">{{ coordinates.top }}</p>
</td>
<td>
<p class="mat-body-1">{{ coordinates.right }}</p>
</td>
<td>
<p class="mat-body-1">{{ coordinates.bottom }}</p>
</td>
</tr>
</table>
`,
styles: [
`
.coord-null-value {
color: rgba(0, 0, 0, 0.75);
.table {
width: 100%;
border-collapse: collapse;
}
.coord-table-wrapper {
margin-left: 10px;
display: inline-flex;
padding: 3px 0px;
.table td {
padding: 1px 5px;
border: 1px solid var(--default-border);
text-align: center;
overflow-wrap: anywhere;
}
.coord-table-wrapper td, .coord-table-wrapper th {
height: auto;
border: 1px solid ar(--default-border);
}
.coord-table-wrapper .header-row td {
.header-row td {
color: gray;
font-weight: 600;
}
`
],

View File

@@ -25,10 +25,10 @@ import { TableProperties } from "viewers/common/table_properties";
@Component({
selector: "hierarchy-view",
template: `
<mat-card-header class="view-header">
<div class="view-header">
<div class="title-filter">
<span class="hierarchy-title">Hierarchy</span>
<mat-form-field class="filter-field">
<h2 class="hierarchy-title mat-title">Hierarchy</h2>
<mat-form-field>
<mat-label>Filter...</mat-label>
<input
matInput
@@ -40,6 +40,7 @@ import { TableProperties } from "viewers/common/table_properties";
</div>
<div class="view-controls">
<mat-checkbox
color="primary"
*ngFor="let option of objectKeys(userOptions)"
class="trace-box"
[(ngModel)]="userOptions[option].enabled"
@@ -51,7 +52,7 @@ import { TableProperties } from "viewers/common/table_properties";
class="properties-table"
[properties]="tableProperties"
></properties-table>
<div class="pinned-items" *ngIf="pinnedItems.length > 0">
<div *ngIf="pinnedItems.length > 0" class="pinned-items">
<tree-node
*ngFor="let pinnedItem of pinnedItems"
class="node"
@@ -65,11 +66,10 @@ import { TableProperties } from "viewers/common/table_properties";
(click)="onPinnedNodeClick($event, pinnedItem)"
></tree-node>
</div>
</mat-card-header>
<mat-card-content class="hierarchy-content" [style]="maxHierarchyHeight()">
</div>
<div class="hierarchy-content">
<div class="tree-wrapper">
<tree-view
class="tree-view"
*ngIf="tree"
[isFlattened]="isFlattened()"
[isShaded]="true"
@@ -85,72 +85,48 @@ import { TableProperties } from "viewers/common/table_properties";
(selectedTreeChange)="selectedTreeChange($event)"
></tree-view>
</div>
</mat-card-content>
</div>
`,
styles: [
`
.view-header {
position: relative;
display: block;
width: 100%;
min-height: 3.75rem;
align-items: center;
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--default-border);
padding-bottom: 12px;
}
.title-filter {
position: relative;
display: flex;
align-items: center;
width: 100%;
margin-bottom: 12px;
}
.hierarchy-title {
font-weight: medium;
font-size: 16px;
}
.filter-field {
font-size: 16px;
transform: scale(0.7);
right: 0px;
position: absolute;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.view-controls {
display: inline-block;
font-size: 12px;
font-weight: normal;
margin-left: 5px;
}
.hierarchy-content {
display: flex;
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
}
.tree-view {
white-space: pre-line;
flex: 1 0 0;
height: 100%;
overflow-y: auto;
flex-direction: row;
flex-wrap: wrap;
}
.properties-table {
padding-top: 5px;
position: relative;
display: block;
width: 100%;
}
.hierarchy-content {
height: 0;
flex-grow: 1;
overflow-y: auto;
}
.pinned-items {
border: 2px solid yellow;
position: relative;
display: block;
width: 100%;
box-sizing: border-box;
border: 2px solid yellow;
}
.tree-wrapper {
overflow-y: auto
}
`,
nodeStyles
@@ -179,14 +155,6 @@ export class HierarchyComponent {
return this.userOptions["flat"]?.enabled;
}
public maxHierarchyHeight() {
const headerHeight = this.elementRef.nativeElement.querySelector(".view-header").clientHeight;
const max = this.tableProperties ? 400 : 800;
return {
height: `${max - headerHeight}px`
};
}
public onPinnedNodeClick(event: MouseEvent, pinnedItem: HierarchyTreeNode) {
event.preventDefault();
if (window.getSelection()?.type === "range") {

View File

@@ -21,343 +21,289 @@ import { ViewerEvents } from "viewers/common/viewer_events";
@Component({
selector: "ime-additional-properties",
template: `
<mat-card-header class="view-header">
<div class="title-filter">
<span class="additional-properties-title">WM & SF Properties</span>
</div>
</mat-card-header>
<mat-card-content class="additional-properties-content">
<h2 class="view-header mat-title">WM & SF Properties</h2>
<div class="additional-properties-content">
<div *ngIf="isAllPropertiesNull()" class="group">
There is no corresponding WM / SF additionalProperties for this IME entry
no WM / SF entry is recorded before this IME entry in time.
View later frames for WM & SF properties.
<p class="mat-body-1">
There is no corresponding WM / SF additionalProperties for this IME entry
no WM / SF entry is recorded before this IME entry in time.
View later frames for WM & SF properties.
</p>
</div>
<div *ngIf="isImeManagerService">
<ng-container *ngIf="isImeManagerService">
<div class="group">
<button
class="text-button group-header"
*ngIf="wmProtoOrNull()"
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(wmProtoOrNull()) }"
(click)="onClickShowInPropertiesPanel(wmProtoOrNull(), additionalProperties.wm?.name)">
WMState
</button>
<span class="group-header" *ngIf="!wmProtoOrNull()">WMState</span>
<div class="full-width">
<span class="value" *ngIf="additionalProperties.wm">{{
additionalProperties.wm.name }}</span>
<span *ngIf="!additionalProperties.wm">There is no corresponding WMState entry.</span>
<h3 *ngIf="!wmProtoOrNull()" class="group-header mat-subheading-2">WMState</h3>
<div class="left-column">
<p *ngIf="additionalProperties.wm" class="mat-body-1">
{{ additionalProperties.wm.name }}
</p>
<p *ngIf="!additionalProperties.wm" class="mat-body-1">
There is no corresponding WMState entry.
</p>
</div>
</div>
<div class="group" *ngIf="wmInsetsSourceProviderOrNull()">
<div *ngIf="wmInsetsSourceProviderOrNull()" class="group">
<button
class="text-button group-header"
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(wmInsetsSourceProviderOrNull()) }"
(click)="onClickShowInPropertiesPanel(wmInsetsSourceProviderOrNull(), 'Ime Insets Source Provider')">
IME Insets Source Provider
</button>
<div class="full-width">
<div></div>
<span class="key">Source Frame:</span>
<coordinates-table
[coordinates]="wmInsetsSourceProviderSourceFrameOrNull()"
></coordinates-table>
<div></div>
<span class="key">Source Visible:</span>
<span class="value">{{
wmInsetsSourceProviderSourceVisibleOrNull() }}</span>
<div></div>
<span class="key">Source Visible Frame:</span>
<coordinates-table
[coordinates]="wmInsetsSourceProviderSourceVisibleFrameOrNull()"
></coordinates-table>
<div></div>
<span class="key">Position:</span>
<span class="value">{{ wmInsetsSourceProviderPositionOrNull() }}</span>
<div></div>
<span class="key">IsLeashReadyForDispatching:</span>
<span class="value">{{
wmInsetsSourceProviderIsLeashReadyOrNull() }}</span>
<div></div>
<span class="key">Controllable:</span>
<span class="value">{{
wmInsetsSourceProviderControllableOrNull() }}</span>
<div></div>
<div class="left-column">
<p class="mat-body-2">Source Frame:</p>
<coordinates-table [coordinates]="wmInsetsSourceProviderSourceFrameOrNull()"></coordinates-table>
<p class="mat-body-1">
<span class="mat-body-2">Source Visible:</span>
&ngsp;
{{ wmInsetsSourceProviderSourceVisibleOrNull() }}
</p>
<p class="mat-body-2">Source Visible Frame:</p>
<coordinates-table [coordinates]="wmInsetsSourceProviderSourceVisibleFrameOrNull()"></coordinates-table>
<p class="mat-body-1">
<span class="mat-body-2">Position:</span>
&ngsp;
{{ wmInsetsSourceProviderPositionOrNull() }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">IsLeashReadyForDispatching:</span>
&ngsp;
{{ wmInsetsSourceProviderIsLeashReadyOrNull() }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Controllable:</span>
&ngsp;
{{ wmInsetsSourceProviderControllableOrNull() }}
</p>
</div>
</div>
<div class="group" *ngIf="wmImeControlTargetOrNull()">
<div *ngIf="wmImeControlTargetOrNull()" class="group">
<button
class="text-button group-header"
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(wmImeControlTargetOrNull()) }"
(click)="onClickShowInPropertiesPanel(wmImeControlTargetOrNull(), 'Ime Control Target')">
IME Control Target
</button>
<div class="full-width">
<span class="key" *ngIf="wmImeControlTargetTitleOrNull()">Title:</span>
<span class="value" *ngIf="wmImeControlTargetTitleOrNull()">{{
wmImeControlTargetTitleOrNull() }}</span>
<div class="left-column">
<p *ngIf="wmImeControlTargetTitleOrNull()" class="mat-body-1">
<span class="mat-body-2">Title:</span>
&ngsp;
{{ wmImeControlTargetTitleOrNull() }}
</p>
</div>
</div>
<div class="group" *ngIf="wmImeInputTargetOrNull()">
<div *ngIf="wmImeInputTargetOrNull()" class="group">
<button
class="text-button group-header"
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(wmImeInputTargetOrNull()) }"
(click)="onClickShowInPropertiesPanel(wmImeInputTargetOrNull(), 'Ime Input Target')">
IME Input Target
</button>
<div class="full-width">
<span class="key" *ngIf="wmImeInputTargetTitleOrNull()">Title:</span>
<span class="value" *ngIf="wmImeInputTargetTitleOrNull()">{{
wmImeInputTargetTitleOrNull() }}</span>
<div class="left-column">
<p *ngIf="wmImeInputTargetTitleOrNull()" class="mat-body-1">
<span class="mat-body-2">Title:</span>
&ngsp;
{{ wmImeInputTargetTitleOrNull() }}
</p>
</div>
</div>
<div class="group" *ngIf="wmImeLayeringTargetOrNull()">
<div *ngIf="wmImeLayeringTargetOrNull()" class="group">
<button
class="text-button group-header"
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(wmImeLayeringTargetOrNull()) }"
(click)="onClickShowInPropertiesPanel(wmImeLayeringTargetOrNull(), 'Ime Layering Target')">
IME Layering Target
</button>
<div class="full-width">
<span class="key" *ngIf="wmImeLayeringTargetTitleOrNull()">Title:</span>
<span class="value" *ngIf="wmImeLayeringTargetTitleOrNull()">{{
wmImeLayeringTargetTitleOrNull() }}</span>
<div class="left-column">
<p *ngIf="wmImeLayeringTargetTitleOrNull()" class="mat-body-1">
<span class="mat-body-2">Title:</span>
&ngsp;
{{ wmImeLayeringTargetTitleOrNull() }}
</p>
</div>
</div>
</div>
</ng-container>
<div *ngIf="!isImeManagerService">
<ng-container *ngIf="!isImeManagerService">
<!-- Ime Client or Ime Service -->
<div class="group">
<button
class="text-button group-header"
*ngIf="wmProtoOrNull()"
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(wmProtoOrNull()) }"
(click)="onClickShowInPropertiesPanel(wmProtoOrNull(), additionalProperties.wm?.name)">
WMState
</button>
<span class="group-header" *ngIf="!wmProtoOrNull()">WMState</span>
<div class="full-width">
<span class="value" *ngIf="additionalProperties.wm">{{
additionalProperties.wm.name }}</span>
<span *ngIf="!additionalProperties.wm">There is no corresponding WMState entry.</span>
<h3 *ngIf="!wmProtoOrNull()" class="group-header mat-subheading-2">WMState</h3>
<div class="left-column">
<p *ngIf="additionalProperties.wm" class="mat-body-1">{{
additionalProperties.wm.name
}}</p>
<p *ngIf="!additionalProperties.wm" class="mat-body-1">
There is no corresponding WMState entry.
</p>
</div>
</div>
<div class="group">
<span class="group-header">SFLayer</span>
<div class="full-width">
<span class="value" *ngIf="additionalProperties.sf">{{
additionalProperties.sf.name }}</span>
<span *ngIf="!additionalProperties.sf">There is no corresponding SFLayer entry.</span>
<h3 class="group-header mat-subheading-2">SFLayer</h3>
<div class="left-column">
<p *ngIf="additionalProperties.sf" class="mat-body-1">{{
additionalProperties.sf.name
}}</p>
<p *ngIf="!additionalProperties.sf" class="mat-body-1">
There is no corresponding SFLayer entry.
</p>
</div>
</div>
<div class="group" *ngIf="additionalProperties.wm">
<span class="group-header">Focus</span>
<div class="full-width">
<span class="key">Focused App:</span>
<span class="value">{{ additionalProperties.wm.focusedApp }}</span>
<div></div>
<span class="key">Focused Activity:</span>
<span class="value">{{ additionalProperties.wm.focusedActivity }}</span>
<div></div>
<span class="key">Focused Window:</span>
<span class="value">{{ additionalProperties.wm.focusedWindow }}</span>
<div></div>
<span class="key" *ngIf="additionalProperties.sf">Focused Window Color:</span>
<span class="value" *ngIf="additionalProperties.sf">{{
additionalProperties.sf.focusedWindow.color
}}</span>
<div></div>
<span class="key">Input Control Target Frame:</span>
<coordinates-table
[coordinates]="wmControlTargetFrameOrNull()"
></coordinates-table>
<div></div>
<div *ngIf="additionalProperties.wm" class="group">
<h3 class="group-header mat-subheading-2">Focus</h3>
<div class="left-column">
<p class="mat-body-1">
<span class="mat-body-2">Focused App:</span>
&ngsp;
{{ additionalProperties.wm.focusedApp }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Focused Activity:</span>
&ngsp;
{{ additionalProperties.wm.focusedActivity }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Focused Window:</span>
&ngsp;
{{ additionalProperties.wm.focusedWindow }}
</p>
<p *ngIf="additionalProperties.sf" class="mat-body-1">
<span class="mat-body-2">Focused Window Color:</span>
&ngsp;
{{ additionalProperties.sf.focusedWindow.color }}
</p>
<p class="mat-body-2">Input Control Target Frame:</p>
<coordinates-table [coordinates]="wmControlTargetFrameOrNull()"></coordinates-table>
</div>
</div>
<div class="group">
<span class="group-header">Visibility</span>
<div class="full-width">
<span class="key" *ngIf="additionalProperties.wm">InputMethod Window:</span>
<span class="value" *ngIf="additionalProperties.wm">{{
additionalProperties.wm.isInputMethodWindowVisible
}}</span>
<div></div>
<span class="key" *ngIf="additionalProperties.sf">InputMethod Surface:</span>
<span class="value" *ngIf="additionalProperties.sf">{{
additionalProperties.sf.inputMethodSurface.isInputMethodSurfaceVisible }}</span>
<div></div>
<h3 class="group-header mat-subheading-2">Visibility</h3>
<div class="left-column">
<p *ngIf="additionalProperties.wm" class="mat-body-1">
<span class="mat-body-2">InputMethod Window:</span>
&ngsp;
{{ additionalProperties.wm.isInputMethodWindowVisible }}
</p>
<p *ngIf="additionalProperties.sf" class="mat-body-1">
<span class="mat-body-2">InputMethod Surface:</span>
&ngsp;
{{ additionalProperties.sf.inputMethodSurface.isInputMethodSurfaceVisible }}
</p>
</div>
</div>
<div class="group" *ngIf="additionalProperties.sf">
<div *ngIf="additionalProperties.sf" class="group">
<button
class="text-button group-header"
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(additionalProperties.sf.imeContainer) }"
(click)="onClickShowInPropertiesPanel(additionalProperties.sf.imeContainer)">
Ime Container
</button>
<div class="full-width">
<span class="key">ZOrderRelativeOfId:</span>
<span class="value">{{
additionalProperties.sf.imeContainer.zOrderRelativeOfId
}}</span>
<div></div>
<span class="key">Z:</span>
<span class="value">{{ additionalProperties.sf.imeContainer.z }}</span>
<div></div>
<div class="left-column">
<p class="mat-body-1">
<span class="mat-body-2">ZOrderRelativeOfId:</span>
&ngsp;
{{ additionalProperties.sf.imeContainer.zOrderRelativeOfId }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Z:</span>
&ngsp;
{{ additionalProperties.sf.imeContainer.z }}
</p>
</div>
</div>
<div class="group" *ngIf="additionalProperties.sf">
<div *ngIf="additionalProperties.sf" class="group">
<button
class="text-button group-header"
[class]="{
'selected': isHighlighted(additionalProperties.sf.inputMethodSurface)
}"
(click)="onClickShowInPropertiesPanel(
additionalProperties.sf.inputMethodSurface)">
color="primary"
mat-button
class="group-header"
[class]="{ 'selected': isHighlighted(additionalProperties.sf.inputMethodSurface) }"
(click)="onClickShowInPropertiesPanel(additionalProperties.sf.inputMethodSurface)">
Input Method Surface
</button>
<div class="full-width">
<span class="key">ScreenBounds:</span>
<coordinates-table
[coordinates]="sfImeContainerScreenBoundsOrNull()"
></coordinates-table>
<div></div>
<span class="key">Rect:</span>
<coordinates-table
[coordinates]="sfImeContainerRectOrNull()"
></coordinates-table>
<div></div>
<div class="left-column">
<p class="mat-body-2">ScreenBounds:</p>
<coordinates-table [coordinates]="sfImeContainerScreenBoundsOrNull()"></coordinates-table>
</div>
<div class="right-column">
<p class="mat-body-2">Rect:</p>
<coordinates-table [coordinates]="sfImeContainerRectOrNull()"></coordinates-table>
</div>
</div>
</div>
</mat-card-content>
</ng-container>
</div>
`,
styles: [
`
.view-header {
width: 100%;
height: 2.5rem;
border-bottom: 1px solid var(--default-border);
}
.title-filter {
position: relative;
display: flex;
align-items: center;
width: 100%;
margin-bottom: 12px;
}
.additional-properties-title {
font-weight: medium;
font-size: 16px;
}
.additional-properties-content {
display: flex;
flex-direction: column;
height: 375px;
height: 0;
flex-grow: 1;
overflow-y: auto;
overflow-x: hidden;
}
.container {
overflow: auto;
}
.group {
padding: 0.5rem;
border-bottom: thin solid rgba(0, 0, 0, 0.12);
flex-direction: row;
padding: 8px;
display: flex;
flex-direction: row;
border-bottom: 1px solid var(--default-border);
}
.group .key {
font-weight: bold;
}
.group .value {
color: rgba(0, 0, 0, 0.75);
word-break: break-all !important;
.mat-body-1 {
overflow-wrap: anywhere;
}
.group-header {
justify-content: center;
text-align: left;
padding: 0px 5px;
width: 95px;
display: inline-block;
font-size: bigger;
height: 100%;
width: 80px;
padding: 0;
text-align: center;
line-height: normal;
white-space: normal;
}
p.group-header {
color: grey;
word-break: break-word;
}
.left-column {
width: 320px;
max-width: 100%;
display: inline-block;
vertical-align: top;
overflow: auto;
padding-right: 20px;
flex: 1;
padding: 0 5px;
}
.right-column {
width: 320px;
max-width: 100%;
display: inline-block;
vertical-align: top;
overflow: auto;
flex: 1;
padding: 0 5px;
}
.full-width {
width: 100%;
display: inline-block;
vertical-align: top;
overflow: auto;
}
.column-header {
font-weight: medium;
font-size: smaller;
}
.element-summary {
padding-top: 1rem;
}
.element-summary .key {
font-weight: bold;
}
.element-summary .value {
color: rgba(0, 0, 0, 0.75);
}
.tree-view {
overflow: auto;
}
.text-button {
border: none;
cursor: pointer;
font-size: 14px;
font-family: roboto;
color: blue;
text-decoration: underline;
text-decoration-color: blue;
background-color: inherit;
}
.text-button:focus {
color: purple;
}
.text-button.selected {
color: purple;
}
`
],
})

View File

@@ -22,10 +22,10 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
@Component({
selector: "properties-view",
template: `
<mat-card-header class="view-header">
<div class="view-header">
<div class="title-filter">
<span class="properties-title">Properties</span>
<mat-form-field class="filter-field">
<h2 class="properties-title mat-title">Properties</h2>
<mat-form-field>
<mat-label>Filter...</mat-label>
<input
matInput
@@ -38,92 +38,69 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
<div class="view-controls">
<mat-checkbox
*ngFor="let option of objectKeys(userOptions)"
color="primary"
class="trace-box"
[(ngModel)]="userOptions[option].enabled"
(ngModelChange)="updateTree()"
[matTooltip]="userOptions[option].tooltip ?? ''"
>{{userOptions[option].name}}</mat-checkbox>
</div>
<div *ngIf="itemIsSelected() && propertyGroups" class="element-summary">
<property-groups
[item]="selectedFlickerItem"
></property-groups>
</div>
</mat-card-header>
<mat-card-content class="properties-content" [style]="maxPropertiesHeight()">
<span *ngIf="objectKeys(propertiesTree).length > 0 && isProtoDump" class="properties-title"> Properties - Proto Dump </span>
<property-groups
*ngIf="itemIsSelected() && propertyGroups"
class="property-groups"
[item]="selectedFlickerItem"
></property-groups>
</div>
<div class="properties-content">
<h3 *ngIf="objectKeys(propertiesTree).length > 0 && isProtoDump" class="properties-title mat-subheading-2">Properties - Proto Dump</h3>
<div class="tree-wrapper">
<tree-view
class="tree-view"
*ngIf="objectKeys(propertiesTree).length > 0"
[item]="propertiesTree"
[showNode]="showNode"
[isLeaf]="isLeaf"
*ngIf="objectKeys(propertiesTree).length > 0"
[isAlwaysCollapsed]="true"
></tree-view>
</div>
</mat-card-content>
</div>
`,
styles: [
`
.view-header {
display: block;
width: 100%;
min-height: 3.75rem;
align-items: center;
border-bottom: 1px solid lightgrey;
flex: 1;
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--default-border);
padding-bottom: 12px;
overflow-y: auto;
}
.title-filter {
position: relative;
display: flex;
align-items: center;
width: 100%;
margin-bottom: 12px;
}
.properties-title {
font-size: 16px;
}
.filter-field {
font-size: 16px;
transform: scale(0.7);
right: 0px;
position: absolute;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.view-controls {
display: inline-block;
font-size: 12px;
font-weight: normal;
margin-left: 5px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 16px;
}
.properties-content{
.properties-content {
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
overflow-x:hidden
}
.element-summary {
padding: 1rem;
border-bottom: thin solid rgba(0,0,0,.12);
.property-groups {
overflow-y: auto;
}
.element-summary .key {
font-weight: 500;
}
.element-summary .value {
color: rgba(0, 0, 0, 0.75);
}
.tree-view {
white-space: pre-line;
flex: 1 0 0;
height: 100%;
.tree-wrapper {
overflow-y: auto
}
`,
@@ -144,13 +121,6 @@ export class PropertiesComponent {
@Inject(ElementRef) private elementRef: ElementRef,
) {}
public maxPropertiesHeight() {
const headerHeight = this.elementRef.nativeElement.querySelector(".view-header").clientHeight;
return {
height: `${800 - headerHeight}px`
};
}
public filterTree() {
const event: CustomEvent = new CustomEvent(
ViewerEvents.PropertiesFilterChange,

View File

@@ -19,49 +19,33 @@ import { TableProperties } from "viewers/common/table_properties";
@Component({
selector: "properties-table",
template: `
<div class="properties-table-wrapper">
<table class="table">
<tr *ngFor="let entry of objectEntries(properties)">
<td class="table-cell-name">
<span>{{ entry[0] }}</span>
<p class="mat-body-1">{{ entry[0] }}</p>
</td>
<td class="table-cell-value">
<span>{{ entry[1] != undefined ? entry[1] : 'undefined' }}</span>
<p class="mat-body-1">{{ entry[1] != undefined ? entry[1] : 'undefined' }}</p>
</td>
</tr>
</table>
</div>
`,
styles: [
`
.properties-table-wrapper {
border-bottom: 1px solid var(--default-border);
}
.properties-table-wrapper .table-cell-name {
background-color: rgba(158, 192, 200, 0.281);
border: 1px solid var(--default-border);
height: 20px;
padding: 0;
width: 20%;
}
.properties-table-wrapper .table-cell-value {
overflow-wrap: anywhere;
border: 1px solid var(--default-border);
height: 20px;
padding: 0;
width: 80%;
}
.properties-table-wrapper table {
height: auto;
border-collapse: collapse;
.table {
width: 100%;
border-collapse: collapse;
}
.properties-table-wrapper span {
padding: 5px;
.table-cell-name, .table-cell-value {
padding: 1px 5px;
border: 1px solid var(--default-border);
overflow-wrap: anywhere;
}
.table-cell-name {
width: 20%;
background-color: rgba(158, 192, 200, 0.281);
}
`
],

View File

@@ -19,263 +19,258 @@ import { Layer } from "common/trace/flickerlib/common";
@Component({
selector: "property-groups",
template: `
<div>
<div class="group">
<span class="group-header">
<span class="group-heading">Visibility</span>
</span>
<div class="left-column">
<span class="key">Flags:</span>
<span class="value">{{ item.flags }}</span>
<div></div>
<div *ngIf="summary().length > 0">
<div *ngFor="let reason of summary()">
<span class="key">{{ reason.key }}:</span>
<span class="value">{{ reason.value }}</span>
</div>
</div>
</div>
<h3 class="group-header mat-subheading-2">Visibility</h3>
<div class="left-column">
<p class="mat-body-1">
<span class="mat-body-2">Flags:</span>
&ngsp;
{{ item.flags }}
</p>
<p *ngFor="let reason of summary()" class="mat-body-1">
<span class="mat-body-2">{{ reason.key }}:</span>
&ngsp;
{{ reason.value }}
</p>
</div>
<div class="group">
<span class="group-header">Geometry</span>
<div class="left-column">
<div class="column-header">Calculated</div>
<span class="key">Transform:</span>
<transform-matrix [transform]="item.transform" [formatFloat]="formatFloat"></transform-matrix>
<div></div>
</div>
<div class="group">
<h3 class="group-header mat-subheading-2">Geometry</h3>
<div class="left-column">
<p class="column-header mat-small">Calculated</p>
<p class="property mat-body-2">Transform:</p>
<transform-matrix [transform]="item.transform" [formatFloat]="formatFloat"></transform-matrix>
<p class="mat-body-1">
<span
class="key"
class="mat-body-2"
matTooltip="Raw value read from proto.bounds. This is the buffer size or
requested crop cropped by parent bounds."
>Crop:</span>
<span class="value">{{ item.bounds }}</span>
<div></div>
&ngsp;
{{ item.bounds }}
<p class="mat-body-1">
<span
class="key"
class="mat-body-2"
matTooltip="Raw value read from proto.screenBounds. This is the calculated crop
transformed."
>Final Bounds:</span>
<span class="value">{{ item.screenBounds }}</span>
</div>
<div class="right-column">
<div class="column-header">Requested</div>
<span class="key">Transform:</span>
<transform-matrix [transform]="item.requestedTransform" [formatFloat]="formatFloat"></transform-matrix>
<div></div>
<span class="key">Crop:</span>
<span class="value">{{ item.crop ? item.crop : "[empty]" }}</span>
</div>
&ngsp;
{{ item.screenBounds }}
</p>
</div>
<div class="group">
<span class="group-header">
<span class="group-heading">Buffer</span>
</span>
<div *ngIf="item.isBufferLayer" class="left-column">
<div></div>
<span class="key">Size:</span>
<span class="value">{{ item.activeBuffer }}</span>
<div></div>
<span class="key">Frame Number:</span>
<span class="value">{{ item.currFrame }}</span>
<div></div>
<div class="right-column">
<p class="column-header mat-small">Requested</p>
<p class="property mat-body-2">Transform:</p>
<transform-matrix [transform]="item.requestedTransform" [formatFloat]="formatFloat"></transform-matrix>
<p class="mat-body-1">
<span class="mat-body-2">Crop:</span>
&ngsp;
{{ item.crop
? item.crop
: "[empty]"
}}
</p>
</div>
</div>
<div class="group">
<h3 class="group-header mat-subheading-2">Buffer</h3>
<div class="left-column">
<p class="mat-body-1">
<span class="mat-body-2">Size:</span>
&ngsp;
{{ item.activeBuffer }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Frame Number:</span>
&ngsp;
{{ item.currFrame }}
</p>
<p class="mat-body-1">
<span
class="key"
class="mat-body-2"
matTooltip="Rotates or flips the buffer in place. Used with display transform
hint to cancel out any buffer transformation when sending to
HWC."
>Transform:</span>
<span class="value">{{ item.bufferTransform }}</span>
</div>
<div *ngIf="item.isBufferLayer" class="right-column">
<div></div>
&ngsp;
{{ item.bufferTransform }}
</p>
</div>
<div class="right-column">
<p class="mat-body-1">
<span
class="key"
class="mat-body-2"
matTooltip="Scales buffer to the frame by overriding the requested transform
for this item."
>Destination Frame:</span>
<span class="value">{{ getDestinationFrame() }}</span>
<div></div>
<span
*ngIf="hasIgnoreDestinationFrame()"
class="value"
>Destination Frame ignored because item has eIgnoreDestinationFrame
flag set.
</span>
</div>
<div *ngIf="item.isContainerLayer" class="left-column">
<span class="key"></span>
<span class="value">Container item</span>
</div>
<div *ngIf="item.isEffectLayer" class="left-column">
<span class="key"></span>
<span class="value">Effect item</span>
</div>
&ngsp;
{{ getDestinationFrame() }}
</p>
<p *ngIf="hasIgnoreDestinationFrame()" class="mat-body-1">
Destination Frame ignored because item has eIgnoreDestinationFrame
flag set.
</p>
</div>
<div class="group">
<span class="group-header">
<span class="group-heading">Hierarchy</span>
</span>
<div class="left-column">
<div></div>
<span class="key">z-order:</span>
<span class="value">{{ item.z }}</span>
<div></div>
</div>
<div class="group">
<h3 class="group-header mat-subheading-2">Hierarchy</h3>
<div class="left-column">
<p class="mat-body-1">
<span class="mat-body-2">z-order:</span>
&ngsp;
{{ item.z }}
</p>
<p class="mat-body-1">
<span
class="key"
class="mat-body-2"
matTooltip="item is z-ordered relative to its relative parents but its bounds
and other properties are inherited from its parents."
>relative parent:</span>
<span class="value">
{{ item.zOrderRelativeOfId == -1 ? "none" : item.zOrderRelativeOfId }}
</span>
</div>
&ngsp;
{{
item.zOrderRelativeOfId == -1
? "none"
: item.zOrderRelativeOfId
}}
</p>
</div>
<div class="group">
<span class="group-header">
<span class="group-heading">Effects</span>
</span>
<div class="left-column">
<div class="column-header">Calculated</div>
<span class="key">Color:</span>
<span class="value">{{ item.color }}</span>
<div></div>
<span class="key">Shadow:</span>
<span class="value">{{ item.shadowRadius }} px</span>
<div></div>
<span class="key">Corner Radius:</span>
<span class="value">{{ formatFloat(item.cornerRadius) }} px</span>
<div></div>
</div>
<div class="group">
<h3 class="group-header mat-subheading-2">Effects</h3>
<div class="left-column">
<p class="column-header mat-small">Calculated</p>
<p class="mat-body-1">
<span class="mat-body-2">Color:</span>
&ngsp;
{{ item.color }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Shadow:</span>
&ngsp;
{{ item.shadowRadius }} px
</p>
<p class="mat-body-1">
<span class="mat-body-2">Corner Radius:</span>
&ngsp;
{{ formatFloat(item.cornerRadius) }} px
</p>
<p class="mat-body-1">
<span
class="key"
class="mat-body-2"
matTooltip="Crop used to define the bounds of the corner radii. If the bounds
are greater than the item bounds then the rounded corner will not
be visible."
>Corner Radius Crop:</span>
<span class="value">{{ item.cornerRadiusCrop }}</span>
<div></div>
<span class="key">Blur:</span>
<span class="value">
{{
item.proto?.backgroundBlurRadius
? item.proto?.backgroundBlurRadius
: 0
}} px
</span>
</div>
<div class="right-column">
<div class="column-header">Requested</div>
<span class="key">Color:</span>
<span class="value">{{ item.requestedColor }}</span>
<div></div>
<span class="key">Shadow:</span>
<span class="value">
{{
item.proto?.requestedShadowRadius
? item.proto?.requestedShadowRadius
: 0
}} px
</span>
<div></div>
<span class="key">Corner Radius:</span>
<span class="value">
{{
item.proto?.requestedCornerRadius
? formatFloat(item.proto?.requestedCornerRadius)
: 0
}} px
</span>
</div>
&ngsp;
{{ item.cornerRadiusCrop }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Blur:</span>
&ngsp;
{{
item.proto?.backgroundBlurRadius
? item.proto?.backgroundBlurRadius
: 0
}} px
</p>
</div>
<div class="group">
<span class="group-header">
<span class="group-heading">Input</span>
</span>
<div *ngIf="hasInputChannel()" class="left-column">
<span class="key">To Display Transform:</span>
<transform-matrix [transform]="item.inputTransform" [formatFloat]="formatFloat"></transform-matrix>
<div></div>
<span class="key">Touchable Region:</span>
<span class="value">{{ item.inputRegion }}</span>
</div>
<div *ngIf="hasInputChannel()" class="right-column">
<span class="key">Config:</span>
<span class="value"></span>
<div></div>
<span class="key">Focusable:</span>
<span class="value">{{ item.proto?.inputWindowInfo.focusable }}</span>
<div></div>
<span class="key">Crop touch region with item:</span>
<span class="value">
{{
item.proto?.inputWindowInfo.cropLayerId &lt;= 0
? "none"
: item.proto?.inputWindowInfo.cropLayerId
}}
</span>
<div></div>
<span class="key">Replace touch region with crop:</span>
<span class="value">
{{
item.proto?.inputWindowInfo.replaceTouchableRegionWithCrop
}}
</span>
</div>
<div *ngIf="!hasInputChannel()" class="left-column">
<span class="key"></span>
<span class="value">No input channel set</span>
</div>
<div class="right-column">
<p class="column-header mat-small">Requested</p>
<p class="mat-body-1">
<span class="mat-body-2">Color:</span>
&ngsp;
{{ item.requestedColor }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Shadow:</span>
&ngsp;
{{
item.proto?.requestedShadowRadius
? item.proto?.requestedShadowRadius
: 0
}} px
</p>
<p class="mat-body-1">
<span class="mat-body-2">Corner Radius:</span>
&ngsp;
{{
item.proto?.requestedCornerRadius
? formatFloat(item.proto?.requestedCornerRadius)
: 0
}} px
</p>
</div>
</div>
<div class="group">
<h3 class="group-header mat-subheading-2">Input</h3>
<div *ngIf="hasInputChannel()" class="left-column">
<p class="property mat-body-2">To Display Transform:</p>
<transform-matrix [transform]="item.inputTransform" [formatFloat]="formatFloat"></transform-matrix>
<p class="mat-body-1">
<span class="mat-body-2">Touchable Region:</span>
&ngsp;
{{ item.inputRegion }}
</p>
</div>
<div *ngIf="hasInputChannel()" class="right-column">
<p class="column-header mat-small">Config</p>
<p class="mat-body-1">
<span class="mat-body-2">Focusable:</span>
&ngsp;
{{ item.proto?.inputWindowInfo.focusable }}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Crop touch region with item:</span>
&ngsp;
{{
item.proto?.inputWindowInfo.cropLayerId &lt;= 0
? "none"
: item.proto?.inputWindowInfo.cropLayerId
}}
</p>
<p class="mat-body-1">
<span class="mat-body-2">Replace touch region with crop:</span>
&ngsp;
{{ item.proto?.inputWindowInfo.replaceTouchableRegionWithCrop }}
</p>
</div>
<div *ngIf="!hasInputChannel()" class="left-column">
<p class="mat-body-1">
<span class="mat-body-2">Input channel:</span>
&ngsp;
not set
</p>
</div>
</div>
`,
styles: [
`
.group {
padding: 0.5rem;
border-bottom: thin solid rgba(0, 0, 0, 0.12);
flex-direction: row;
display: flex;
}
.group .key {
font-weight: 500;
padding-right: 5px;
}
.group .value {
color: rgba(0, 0, 0, 0.75);
flex-direction: row;
padding: 8px;
border-bottom: 1px solid var(--default-border);
}
.group-header {
justify-content: center;
padding: 0px 5px;
width: 80px;
display: inline-block;
font-size: bigger;
color: grey;
}
.left-column {
width: 320px;
max-width: 100%;
display: inline-block;
vertical-align: top;
overflow: auto;
border-right: 5px solid rgba(#000, 0.12);
padding-right: 20px;
flex: 1;
padding: 0 5px;
}
.right-column {
width: 320px;
max-width: 100%;
display: inline-block;
vertical-align: top;
overflow: auto;
border: 1px solid rgba(#000, 0.12);
flex: 1;
border: 1px solid var(--default-border);
border-left-width: 5px;
padding: 0 5px;
}
.column-header {
font-weight: lighter;
font-size: smaller;
color: grey;
}
`
],

View File

@@ -48,7 +48,7 @@ export class CanvasGraphics {
//set canvas size
this.canvas.style.width = "100%";
this.canvas.style.height = "40rem";
this.canvas.style.height = "100%";
this.orbit?.reset();
@@ -71,7 +71,7 @@ export class CanvasGraphics {
this.labelRenderer.domElement.style.position = "absolute";
this.labelRenderer.domElement.style.top = "0px";
this.labelRenderer.domElement.style.width = "100%";
this.labelRenderer.domElement.style.height = "40rem";
this.labelRenderer.domElement.style.height = "100%";
this.labelRenderer.domElement.className = "labels-canvas";
this.labelRenderer.domElement.style.pointerEvents = "none";
this.canvasContainer?.appendChild(this.labelRenderer.domElement);
@@ -87,8 +87,8 @@ export class CanvasGraphics {
let xShift = 0, yShift = 3.5, labelYShift = 0;
if (this.isLandscape) {
xShift = 1;
yShift = 1.5;
xShift = -1;
yShift = 2.5;
labelYShift = 1.25;
}
@@ -477,7 +477,7 @@ export class CanvasGraphics {
private readonly MAX_LABEL_SHIFT = 0.305;
private readonly MAX_ZOOM = 2.5;
private readonly MIN_ZOOM = 0.5;
private readonly INIT_ZOOM = 1;
private readonly INIT_ZOOM = 0.75;
private readonly INIT_FONT_SIZE = 10;
private readonly INIT_CAMERA_POS = new THREE.Vector3(4, 4, 6);
private readonly INIT_TARGET = new THREE.Vector3(0, 0, 0);

View File

@@ -23,49 +23,46 @@ import { ViewerEvents } from "viewers/common/viewer_events";
@Component({
selector: "rects-view",
template: `
<mat-card-header class="view-controls">
<div class="rects-title">
<span>Layers</span>
</div>
<div class="view-controls">
<h2 class="mat-title">Layers</h2>
<div class="top-view-controls">
<div class="top-view-controls">
<mat-checkbox
class="rects-checkbox control-item"
[checked]="visibleView()"
(change)="onChangeView($event.checked!)"
>Only visible</mat-checkbox>
<mat-checkbox
[disabled]="visibleView() || !hasVirtualDisplays"
class="rects-checkbox control-item"
[checked]="showVirtualDisplays()"
(change)="updateVirtualDisplays($event.checked!)"
>Show virtual</mat-checkbox>
<div class="right-btn-container control-item">
<button class="right-btn" (click)="updateZoom(true)">
<mat-icon aria-hidden="true">
zoom_in
</mat-icon>
</button>
<button class="right-btn" (click)="updateZoom(false)">
<mat-icon aria-hidden="true">
zoom_out
</mat-icon>
</button>
<button
class="right-btn"
(click)="resetCamera()"
matTooltip="Restore camera settings"
>
<mat-icon aria-hidden="true">
restore
</mat-icon>
</button>
</div>
<mat-checkbox
color="primary"
[checked]="visibleView()"
(change)="onChangeView($event.checked!)"
>Only visible</mat-checkbox>
<mat-checkbox
color="primary"
[disabled]="visibleView() || !hasVirtualDisplays"
[checked]="showVirtualDisplays()"
(change)="updateVirtualDisplays($event.checked!)"
>Show virtual</mat-checkbox>
<div class="right-btn-container">
<button color="primary" mat-icon-button (click)="updateZoom(true)">
<mat-icon aria-hidden="true">
zoom_in
</mat-icon>
</button>
<button color="primary" mat-icon-button (click)="updateZoom(false)">
<mat-icon aria-hidden="true">
zoom_out
</mat-icon>
</button>
<button
color="primary"
mat-icon-button
matTooltip="Restore camera settings"
(click)="resetCamera()"
>
<mat-icon aria-hidden="true">
restore
</mat-icon>
</button>
</div>
</div>
<div class="slider-view-controls">
<div class="slider" [class.rotation]="true">
<span class="slider-label">Rotation</span>
<p class="slider-label mat-body-2">Rotation</p>
<mat-slider
step="0.001"
min="0"
@@ -73,10 +70,11 @@ import { ViewerEvents } from "viewers/common/viewer_events";
aria-label="units"
[value]="xCameraPos()"
(input)="updateRotation($event.value!)"
color="primary"
></mat-slider>
</div>
<div class="slider" [class.spacing]="true">
<span class="slider-label">Spacing</span>
<p class="slider-label mat-body-2">Spacing</p>
<mat-slider
class="spacing-slider"
step="0.001"
@@ -85,111 +83,63 @@ import { ViewerEvents } from "viewers/common/viewer_events";
aria-label="units"
[value]="getLayerSeparation()"
(input)="updateLayerSeparation($event.value!)"
color="primary"
></mat-slider>
</div>
</div>
</mat-card-header>
<mat-card-content class="rects-content">
</div>
<div class="rects-content">
<div class="canvas-container">
<canvas class="rects-canvas" (click)="onRectClick($event)" oncontextmenu="return false">
</canvas>
</div>
<div class="tabs" *ngIf="displayIds.length > 1">
<button mat-raised-button *ngFor="let displayId of displayIds" (click)="changeDisplayId(displayId)">{{displayId}}</button>
<div *ngIf="displayIds.length > 1" class="tabs">
<button color="primary" mat-raised-button *ngFor="let displayId of displayIds" (click)="changeDisplayId(displayId)">{{displayId}}</button>
</div>
</mat-card-content>
</div>
`,
styles: [
`
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
:host /deep/ .mat-card-header-text {
width: 100%;
margin: 0;
.view-controls {
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--default-border);
}
.rects-title {
font-size: 16px;
font-weight: medium;
font-family: inherit;
width: 100%;
.top-view-controls, .slider-view-controls {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
margin-bottom: 12px;
}
.rects-content {
position: relative;
.right-btn-container {
margin-left: auto;
}
.canvas-container {
height: 40rem;
width: 100%;
position: relative;
}
.labels-canvas, .rects-canvas {
height: 40rem;
width: 100%;
position: absolute;
top: 0px;
}
.rects-canvas {
cursor: pointer;
}
.view-controls {
display: inline-block;
position: relative;
min-height: 4rem;
width: 100%;
}
.slider-view-controls, .top-view-controls {
display: inline-block;
position: relative;
height: 3rem;
width: 100%;
}
.top-view-controls {
vertical-align: middle;
.slider-view-controls {
justify-content: space-between;
}
.slider {
display: inline-block;
position: relative;
}
.slider-label {
position: absolute;
top: 0;
}
.slider.spacing {
float: right;
.rects-content {
height: 0;
flex-grow: 1;
}
.slider span, .slider mat-slider {
display: block;
padding-left: 0px;
padding-top: 0px;
font-weight: bold;
}
.right-btn-container {
.canvas-container {
height: 100%;
width: 100%;
position: relative;
vertical-align: middle;
float: right;
}
.right-btn {
position: relative;
display: inline-flex;
background: none;
border: none;
padding: 0;
.labels-canvas, .rects-canvas {
position: absolute;
top: 0;
}
.rects-checkbox {
font-size: 14px;
font-weight: normal;
margin-left: 5px;
}
mat-icon {
margin: 5px
}
.mat-checkbox .mat-checkbox-frame, .mat-checkbox-checked .mat-checkbox-background, .mat-checkbox-indeterminate .mat-checkbox-background {
transform: scale(0.7);
}
.control-item {
position: relative;
display: inline-block;
vertical-align: middle;
align-items: center;
.rects-canvas {
cursor: pointer;
}
`
]

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
export const nodeStyles = `
.node {position: relative;display: inline-block;padding: 2px; height: 100%; width: 100%;}
.node {position: relative;display: inline-block;padding: 2px 0; width: 100%;}
.node.clickable {cursor: pointer;}
.node:not(.selected).added,
.node:not(.selected).addedMove {
@@ -59,12 +59,18 @@ export const nodeInnerItemStyles = `
.pin-node-btn {padding: 0; transform: scale(0.7)}
.description {align-items: center; flex: 1 1 auto; vertical-align: middle; word-break: break-all;}
.leaf-node-icon-wrapper{padding-left: 6px; padding-right: 6px; min-height: 24px; width: 24px; position:relative; align-content: center; vertical-align: middle;}
.icon-button { background: none;border: none;display: inline-block;vertical-align: middle;}
.icon-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.expand-tree-btn {
float: right;
padding-left: 0px;
padding-right: 0px;
padding-left: 0;
padding-right: 0;
}
.expand-tree-btn.modified {

View File

@@ -14,15 +14,12 @@
* limitations under the License.
*/
export const treeNodeDataViewStyles = `
.kind {font-weight: bold}
span {overflow-wrap: break-word; flex: 1 1 auto; width: 0; word-break: break-all}
.tree-view-internal-chip {
display: inline-block;
}
.tree-view-chip {
margin: 0 5px;
padding: 0 10px;
border-radius: 10px;
background-color: #aaa;
@@ -31,22 +28,18 @@ export const treeNodeDataViewStyles = `
.tree-view-chip.tree-view-chip-warn {
background-color: #ffaa6b;
color: black;
}
.tree-view-chip.tree-view-chip-error {
background-color: #ff6b6b;
color: black;
}
.tree-view-chip.tree-view-chip-gpu {
background-color: #00c853;
color: black;
}
.tree-view-chip.tree-view-chip-hwc {
background-color: #448aff;
color: black;
}
`;

View File

@@ -19,22 +19,36 @@ import { Transform } from "common/trace/flickerlib/common";
@Component({
selector: "transform-matrix",
template: `
<div class="matrix" *ngIf="transform" [matTooltip]="transform.getTypeAsString()">
<div class="cell">{{ formatFloat(transform.matrix.dsdx) }}</div>
<div class="cell">{{ formatFloat(transform.matrix.dsdy) }}</div>
<div class="cell" matTooltip="Translate x">
<div *ngIf="transform" class="matrix" [matTooltip]="transform.getTypeAsString()">
<p class="cell mat-body-1">
{{ formatFloat(transform.matrix.dsdx) }}
</p>
<p class="cell mat-body-1">
{{ formatFloat(transform.matrix.dsdy) }}
</p>
<p class="cell mat-body-1" matTooltip="Translate x">
{{ formatFloat(transform.matrix.tx) }}
</div>
</p>
<div class="cell">{{ formatFloat(transform.matrix.dtdx) }}</div>
<div class="cell">{{ formatFloat(transform.matrix.dtdy) }}</div>
<div class="cell" matTooltip="Translate y">
<p class="cell mat-body-1">
{{ formatFloat(transform.matrix.dtdx) }}
</p>
<p class="cell mat-body-1">
{{ formatFloat(transform.matrix.dtdy) }}
</p>
<p class="cell mat-body-1" matTooltip="Translate y">
{{ formatFloat(transform.matrix.ty) }}
</div>
</p>
<div class="cell">0</div>
<div class="cell">0</div>
<div class="cell">1</div>
<p class="cell mat-body-1">
0
</p>
<p class="cell mat-body-1">
0
</p>
<p class="cell mat-body-1">
1
</p>
</div>
`,
styles: [
@@ -43,10 +57,10 @@ import { Transform } from "common/trace/flickerlib/common";
display: grid;
grid-gap: 1px;
grid-template-columns: repeat(3, 1fr);
text-align: center;
}
.cell {
padding-left: 10px;
background-color: #F8F9FA;
}
`

View File

@@ -22,56 +22,53 @@ import { TraceType } from "common/trace/trace_type";
@Component({
selector: "tree-view",
template: `
<div class="tree-view">
<tree-node
class="node"
*ngIf="showNode(item)"
[class.leaf]="isLeaf(this.item)"
[class.selected]="isHighlighted(item, highlightedItems)"
[class.clickable]="isClickable()"
[class.shaded]="isShaded"
[class.hover]="nodeHover"
[class.childHover]="childHover"
[isAlwaysCollapsed]="isAlwaysCollapsed"
[class]="diffClass(item)"
[style]="nodeOffsetStyle()"
[item]="item"
[flattened]="isFlattened"
[isLeaf]="isLeaf(this.item)"
[isCollapsed]="isAlwaysCollapsed ?? isCollapsed()"
[hasChildren]="hasChildren()"
[isPinned]="isPinned()"
(toggleTreeChange)="toggleTree()"
(click)="onNodeClick($event)"
(expandTreeChange)="expandTree()"
(pinNodeChange)="propagateNewPinnedItem($event)"
></tree-node>
<tree-node
*ngIf="showNode(item)"
class="node"
[class.leaf]="isLeaf(this.item)"
[class.selected]="isHighlighted(item, highlightedItems)"
[class.clickable]="isClickable()"
[class.shaded]="isShaded"
[class.hover]="nodeHover"
[class.childHover]="childHover"
[isAlwaysCollapsed]="isAlwaysCollapsed"
[class]="diffClass(item)"
[style]="nodeOffsetStyle()"
[item]="item"
[flattened]="isFlattened"
[isLeaf]="isLeaf(this.item)"
[isCollapsed]="isAlwaysCollapsed ?? isCollapsed()"
[hasChildren]="hasChildren()"
[isPinned]="isPinned()"
(toggleTreeChange)="toggleTree()"
(click)="onNodeClick($event)"
(expandTreeChange)="expandTree()"
(pinNodeChange)="propagateNewPinnedItem($event)"
></tree-node>
<div class="children" *ngIf="hasChildren()" [hidden]="!isCollapsed()" [style]="childrenIndentation()">
<ng-container *ngFor="let child of children()">
<tree-view
class="childrenTree"
[item]="child"
[store]="store"
[showNode]="showNode"
[isLeaf]="isLeaf"
[dependencies]="dependencies"
[isFlattened]="isFlattened"
[isShaded]="!isShaded"
[useGlobalCollapsedState]="useGlobalCollapsedState"
[initialDepth]="initialDepth + 1"
[highlightedItems]="highlightedItems"
[pinnedItems]="pinnedItems"
(highlightedItemChange)="propagateNewHighlightedItem($event)"
(pinnedItemChange)="propagateNewPinnedItem($event)"
(selectedTreeChange)="propagateNewSelectedTree($event)"
[itemsClickable]="itemsClickable"
(hoverStart)="childHover = true"
(hoverEnd)="childHover = false"
></tree-view>
</ng-container>
</div>
</div>
<div *ngIf="hasChildren()" class="children" [hidden]="!isCollapsed()" [style]="childrenIndentation()">
<tree-view
*ngFor="let child of children()"
class="childrenTree"
[item]="child"
[store]="store"
[showNode]="showNode"
[isLeaf]="isLeaf"
[dependencies]="dependencies"
[isFlattened]="isFlattened"
[isShaded]="!isShaded"
[useGlobalCollapsedState]="useGlobalCollapsedState"
[initialDepth]="initialDepth + 1"
[highlightedItems]="highlightedItems"
[pinnedItems]="pinnedItems"
(highlightedItemChange)="propagateNewHighlightedItem($event)"
(pinnedItemChange)="propagateNewPinnedItem($event)"
(selectedTreeChange)="propagateNewSelectedTree($event)"
[itemsClickable]="itemsClickable"
(hoverStart)="childHover = true"
(hoverEnd)="childHover = false"
></tree-view>
</div>
`,
styles: [nodeStyles, treeNodeDataViewStyles]
})

View File

@@ -21,53 +21,50 @@ import { UiTreeUtils, UiTreeNode, DiffType, HierarchyTreeNode } from "viewers/co
selector: "tree-node",
template: `
<button
*ngIf="showChevron()"
color="primary"
class="icon-button toggle-tree-btn"
(click)="toggleTree($event)"
*ngIf="showChevron()"
>
<mat-icon class="icon-button">
<mat-icon>
{{isCollapsed ? "arrow_drop_down" : "chevron_right"}}
</mat-icon>
</button>
<div
class="leaf-node-icon-wrapper"
*ngIf="showLeafNodeIcon()"
>
<div *ngIf="showLeafNodeIcon()" class="leaf-node-icon-wrapper">
<mat-icon class="leaf-node-icon"></mat-icon>
</div>
<button
*ngIf="showPinNodeIcon()"
color="primary"
class="icon-button pin-node-btn"
(click)="pinNode($event)"
*ngIf="showPinNodeIcon()"
>
<mat-icon class="icon-button">
<mat-icon>
{{isPinned ? "star" : "star_border"}}
</mat-icon>
</button>
<div class="description">
<tree-node-data-view
[item]="item"
*ngIf="!isPropertiesTreeNode()"
[item]="item"
></tree-node-data-view>
<tree-node-properties-data-view
[item]="item"
*ngIf="isPropertiesTreeNode()"
[item]="item"
></tree-node-properties-data-view>
</div>
<button
*ngIf="hasChildren && !isCollapsed"
(click)="expandTree($event)"
color="primary"
class="icon-button expand-tree-btn"
[class]="collapseDiffClass"
(click)="expandTree($event)"
>
<mat-icon
aria-hidden="true"
class="icon-button"
>
<mat-icon aria-hidden="true">
more_horiz
</mat-icon>
</button>

View File

@@ -21,11 +21,11 @@ import Chip from "viewers/common/chip";
@Component({
selector: "tree-node-data-view",
template: `
<span>
<span class="kind">{{item.kind}}</span>
<span *ngIf="item.kind && item.name">-</span>
<span class="mat-body-1">
<span class="mat-body-2">{{item.kind}}</span>
<ng-container *ngIf="item.kind && item.name">&ngsp;-&ngsp;</ng-container>
<span *ngIf="showShortName()" [matTooltip]="itemTooltip()">{{ itemShortName() }}</span>
<span *ngIf="!showShortName()">{{item.name}}</span>
<ng-container *ngIf="!showShortName()">{{item.name}}</ng-container>
<div
*ngFor="let chip of chips()"
[class]="chipClass(chip)"

View File

@@ -20,11 +20,13 @@ import { PropertiesTreeNode } from "viewers/common/ui_tree_utils";
@Component({
selector: "tree-node-properties-data-view",
template: `
<span>
<p class="mat-body-1">
<span class="key">{{ item.propertyKey }}</span>
<span *ngIf="item.propertyValue">: </span>
<span class="value" *ngIf="item.propertyValue" [class]="[valueClass()]">{{ item.propertyValue }}</span>
</span>
<ng-container *ngIf="item.propertyValue">
:&ngsp;
<span [class]="[valueClass()]" class="value">{{ item.propertyValue }}</span>
</ng-container>
</p>
`,
styles: [ treeNodePropertiesDataViewStyles ]
})
@@ -52,6 +54,7 @@ export class TreeNodePropertiesDataViewComponent {
if (!isNaN(Number(this.item.propertyValue))) {
return "number";
}
return null;
}
}

View File

@@ -25,98 +25,54 @@ import { ImeUiData } from "viewers/common/ime_ui_data";
@Component({
selector: "viewer-input-method",
template: `
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
<div class="card-grid">
<div class="left-views">
<mat-card class="hierarchy-view" [style]="hierarchyHeight()">
<hierarchy-view
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[pinnedItems]="inputData?.pinnedItems ?? []"
[tableProperties]="inputData?.hierarchyTableProperties"
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
</mat-card>
<mat-card *ngIf="inputData?.additionalProperties" class="ime-additional-properties-view">
<ime-additional-properties
[additionalProperties]="inputData?.additionalProperties!"
></ime-additional-properties>
</mat-card>
<hierarchy-view
class="hierarchy-view"
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[pinnedItems]="inputData?.pinnedItems ?? []"
[tableProperties]="inputData?.hierarchyTableProperties"
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
<ime-additional-properties
*ngIf="inputData?.additionalProperties"
class="ime-additional-properties-view"
[additionalProperties]="inputData?.additionalProperties!"
></ime-additional-properties>
</div>
<mat-card class="properties-view">
<properties-view
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
></properties-view>
</mat-card>
<properties-view
class="properties-view"
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
></properties-view>
</div>
`,
styles: [
`
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
:root {
--default-border: #DADCE0;
}
mat-icon {
margin: 5px
}
.icon-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.header-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.card-grid {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
overflow: auto;
}
.left-views {
font: inherit;
margin: 0px;
width: 50%;
height: 100%;
flex: 1;
display: flex;
flex-direction: column;
overflow: auto;
}
.hierarchy-view, .ime-additional-properties-view {
font: inherit;
margin: 0px;
border-radius: 0;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
box-shadow: none !important;
}
.ime-additional-properties-view {
height: 404px;
}
.properties-view {
font: inherit;
margin: 0px;
width: 50%;
height: 52.5rem;
border-radius: 0;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-left: 1px solid var(--default-border);
box-shadow: none !important;
}
`,
]
@@ -127,10 +83,4 @@ export class ViewerInputMethodComponent {
@Input() active = false;
TRACE_INFO = TRACE_INFO;
TraceType = TraceType;
public hierarchyHeight() {
return {
height: `${this.inputData?.additionalProperties ? 404 : 840}px`
};
}
}

View File

@@ -25,102 +25,63 @@ import { PersistentStore } from "common/persistent_store";
@Component({
selector: "viewer-surface-flinger",
template: `
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
<mat-card id="sf-rects-view" class="rects-view">
<rects-view
[rects]="inputData?.rects ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[displayIds]="inputData?.displayIds ?? []"
[forceRefresh]="active"
[hasVirtualDisplays]="inputData?.hasVirtualDisplays ?? false"
></rects-view>
</mat-card>
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
<mat-card id="sf-hierarchy-view" class="hierarchy-view">
<hierarchy-view
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[pinnedItems]="inputData?.pinnedItems ?? []"
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
</mat-card>
<mat-card id="sf-properties-view" class="properties-view">
<properties-view
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
[selectedFlickerItem]="inputData?.selectedLayer ?? {}"
[propertyGroups]="true"
[isProtoDump]="true"
></properties-view>
</mat-card>
</div>
</div>
<div class="card-grid">
<rects-view
id="sf-rects-view"
class="rects-view"
[rects]="inputData?.rects ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[displayIds]="inputData?.displayIds ?? []"
[forceRefresh]="active"
[hasVirtualDisplays]="inputData?.hasVirtualDisplays ?? false"
></rects-view>
<hierarchy-view
id="sf-hierarchy-view"
class="hierarchy-view"
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[pinnedItems]="inputData?.pinnedItems ?? []"
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
<properties-view
id="sf-properties-view"
class="properties-view"
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
[selectedFlickerItem]="inputData?.selectedLayer ?? {}"
[propertyGroups]="true"
[isProtoDump]="true"
></properties-view>
</div>
`,
styles: [
`
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
:root {
--default-border: #DADCE0;
}
mat-icon {
margin: 5px
}
.icon-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.header-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.card-grid {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
overflow: auto;
}
.rects-view {
font: inherit;
flex: none;
width: 350px;
height: 52.5rem;
margin: 0px;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
border-radius: 0;
}
.hierarchy-view {
font: inherit;
margin: 0px;
width: 50%;
height: 52.5rem;
border-radius: 0;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
border-left: 1px solid var(--default-border);
}
.properties-view {
font: inherit;
margin: 0px;
width: 50%;
height: 52.5rem;
border-radius: 0;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-left: 1px solid var(--default-border);
}
`,
]

View File

@@ -25,99 +25,60 @@ import { PersistentStore } from "common/persistent_store";
@Component({
selector: "viewer-window-manager",
template: `
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
<mat-card id="wm-rects-view" class="rects-view">
<rects-view
[rects]="inputData?.rects ?? []"
[displayIds]="inputData?.displayIds ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[forceRefresh]="active"
></rects-view>
</mat-card>
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
<mat-card id="wm-hierarchy-view" class="hierarchy-view">
<hierarchy-view
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[pinnedItems]="inputData?.pinnedItems ?? []"
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
</mat-card>
<mat-card id="wm-properties-view" class="properties-view">
<properties-view
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
[isProtoDump]="true"
></properties-view>
</mat-card>
</div>
<div class="card-grid">
<rects-view
id="wm-rects-view"
class="rects-view"
[rects]="inputData?.rects ?? []"
[displayIds]="inputData?.displayIds ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[forceRefresh]="active"
></rects-view>
<hierarchy-view
id="wm-hierarchy-view"
class="hierarchy-view"
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
[pinnedItems]="inputData?.pinnedItems ?? []"
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
<properties-view
id="wm-properties-view"
class="properties-view"
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
[isProtoDump]="true"
></properties-view>
</div>
`,
styles: [
`
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
:root {
--default-border: #DADCE0;
}
mat-icon {
margin: 5px
}
.icon-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.header-button {
background: none;
border: none;
display: inline-block;
vertical-align: middle;
}
.card-grid {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
overflow: auto;
}
.rects-view {
font: inherit;
flex: none;
width: 350px;
height: 52.5rem;
margin: 0px;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
border-radius: 0;
}
.hierarchy-view {
font: inherit;
margin: 0px;
width: 50%;
height: 52.5rem;
border-radius: 0;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
border-left: 1px solid var(--default-border);
}
.properties-view {
font: inherit;
margin: 0px;
width: 50%;
height: 52.5rem;
border-radius: 0;
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-left: 1px solid var(--default-border);
}
`,
]

View File

@@ -46,6 +46,10 @@ module.exports = {
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.s[ac]ss$/i,
use: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.proto$/,
loader: 'proto-loader',

View File

@@ -20,7 +20,10 @@ const configDev = {
mode: 'development',
entry: {
polyfills: "./src/polyfills.ts",
styles: "./src/styles.css",
styles: [
"./src/material-theme.scss",
"./src/styles.css"
],
app: "./src/main.dev.ts"
},
devtool: "source-map",

View File

@@ -23,7 +23,10 @@ const configProd = {
mode: 'production',
entry: {
polyfills: "./src/polyfills.ts",
styles: "./src/styles.css",
styles: [
"./src/material-theme.scss",
"./src/styles.css"
],
app: "./src/main.prod.ts"
},
output: {